2009-02-28 05:08:31 +03:00
/*
ctdb system specific code to manage raw sockets on linux
Copyright ( C ) Ronnie Sahlberg 2007
Copyright ( C ) Andrew Tridgell 2007
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
2015-10-26 08:50:46 +03:00
# include "replace.h"
2009-02-28 05:08:31 +03:00
# include "system/network.h"
2015-10-26 08:50:46 +03:00
# include "lib/util/debug.h"
2015-11-02 08:03:29 +03:00
# include "protocol/protocol.h"
2014-09-04 07:33:58 +04:00
2015-11-11 06:43:56 +03:00
# include "common/logging.h"
2015-10-23 06:11:53 +03:00
# include "common/system.h"
2009-02-28 05:08:31 +03:00
/*
uint16 checksum for n bytes
*/
uint32_t uint16_checksum ( uint16_t * data , size_t n )
{
uint32_t sum = 0 ;
while ( n > = 2 ) {
sum + = ( uint32_t ) ntohs ( * data ) ;
data + + ;
n - = 2 ;
}
if ( n = = 1 ) {
sum + = ( uint32_t ) ntohs ( * ( uint8_t * ) data ) ;
}
return sum ;
}
/*
see if we currently have an interface with the given IP
we try to bind to it , and if that fails then we don ' t have that IP
on an interface
*/
bool ctdb_sys_have_ip ( ctdb_sock_addr * _addr )
{
int s ;
int ret ;
ctdb_sock_addr __addr = * _addr ;
ctdb_sock_addr * addr = & __addr ;
2013-07-04 11:00:23 +04:00
socklen_t addrlen = 0 ;
2009-02-28 05:08:31 +03:00
switch ( addr - > sa . sa_family ) {
case AF_INET :
addr - > ip . sin_port = 0 ;
2010-08-30 12:40:43 +04:00
addrlen = sizeof ( struct sockaddr_in ) ;
2009-02-28 05:08:31 +03:00
break ;
case AF_INET6 :
addr - > ip6 . sin6_port = 0 ;
2010-08-30 12:40:43 +04:00
addrlen = sizeof ( struct sockaddr_in6 ) ;
2009-02-28 05:08:31 +03:00
break ;
}
s = socket ( addr - > sa . sa_family , SOCK_STREAM , IPPROTO_TCP ) ;
if ( s = = - 1 ) {
return false ;
}
2010-08-30 12:40:43 +04:00
ret = bind ( s , ( struct sockaddr * ) addr , addrlen ) ;
2009-02-28 05:08:31 +03:00
close ( s ) ;
return ret = = 0 ;
}
2011-09-06 10:11:00 +04:00
2012-06-20 07:32:02 +04:00
/* find which interface an ip address is currently assigned to */
char * ctdb_sys_find_ifname ( ctdb_sock_addr * addr )
{
int s ;
int size ;
struct ifconf ifc ;
char * ptr ;
2016-01-28 16:05:26 +03:00
s = socket ( AF_INET , SOCK_RAW , IPPROTO_RAW ) ;
2012-06-20 07:32:02 +04:00
if ( s = = - 1 ) {
DEBUG ( DEBUG_CRIT , ( __location__ " failed to open raw socket (%s) \n " ,
strerror ( errno ) ) ) ;
return NULL ;
}
size = sizeof ( struct ifreq ) ;
ifc . ifc_buf = NULL ;
ifc . ifc_len = size ;
while ( ifc . ifc_len > ( size - sizeof ( struct ifreq ) ) ) {
size * = 2 ;
free ( ifc . ifc_buf ) ;
ifc . ifc_len = size ;
ifc . ifc_buf = malloc ( size ) ;
memset ( ifc . ifc_buf , 0 , size ) ;
if ( ioctl ( s , SIOCGIFCONF , ( caddr_t ) & ifc ) < 0 ) {
DEBUG ( DEBUG_CRIT , ( " Failed to read ifc buffer from socket \n " ) ) ;
free ( ifc . ifc_buf ) ;
close ( s ) ;
return NULL ;
}
}
for ( ptr = ( char * ) ifc . ifc_buf ; ptr < ( ( char * ) ifc . ifc_buf ) + ifc . ifc_len ; ) {
char * ifname ;
struct ifreq * ifr ;
ifr = ( struct ifreq * ) ptr ;
# ifdef HAVE_SOCKADDR_LEN
if ( ifr - > ifr_addr . sa_len > sizeof ( struct sockaddr ) ) {
ptr + = sizeof ( ifr - > ifr_name ) + ifr - > ifr_addr . sa_len ;
} else {
ptr + = sizeof ( ifr - > ifr_name ) + sizeof ( struct sockaddr ) ;
}
# else
ptr + = sizeof ( struct ifreq ) ;
# endif
if ( ifr - > ifr_addr . sa_family ! = addr - > sa . sa_family ) {
continue ;
}
switch ( addr - > sa . sa_family ) {
case AF_INET :
if ( memcmp ( & addr - > ip . sin_addr , & ( ( struct sockaddr_in * ) & ifr - > ifr_addr ) - > sin_addr , sizeof ( addr - > ip . sin_addr ) ) ) {
continue ;
}
break ;
case AF_INET6 :
if ( memcmp ( & addr - > ip6 . sin6_addr , & ( ( struct sockaddr_in6 * ) & ifr - > ifr_addr ) - > sin6_addr , sizeof ( addr - > ip6 . sin6_addr ) ) ) {
continue ;
}
break ;
}
ifname = strdup ( ifr - > ifr_name ) ;
free ( ifc . ifc_buf ) ;
close ( s ) ;
return ifname ;
}
free ( ifc . ifc_buf ) ;
close ( s ) ;
return NULL ;
}