2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-01-19 04:56:37 +03:00
2010-02-03 15:03:47 +03:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2010-02-03 15:03:47 +03:00
( at your option ) any later version .
systemd 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2010-02-03 15:03:47 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-02-03 15:03:47 +03:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-01-19 04:56:37 +03:00
# include <assert.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <stdlib.h>
# include <arpa/inet.h>
# include <stdio.h>
2010-01-23 05:35:54 +03:00
# include <net/if.h>
2010-02-12 04:02:14 +03:00
# include <sys/types.h>
# include <sys/stat.h>
2010-10-07 04:34:17 +04:00
# include <stddef.h>
# include <sys/ioctl.h>
2010-01-19 04:56:37 +03:00
# include "macro.h"
# include "util.h"
2012-04-10 23:54:31 +04:00
# include "mkdir.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2010-01-19 04:56:37 +03:00
# include "socket-util.h"
2010-07-01 19:44:13 +04:00
# include "missing.h"
2013-02-14 15:26:13 +04:00
# include "fileio.h"
2010-01-19 04:56:37 +03:00
2010-01-23 05:35:54 +03:00
int socket_address_parse ( SocketAddress * a , const char * s ) {
2010-01-19 04:56:37 +03:00
int r ;
char * e , * n ;
unsigned u ;
assert ( a ) ;
assert ( s ) ;
2010-01-24 02:39:29 +03:00
zero ( * a ) ;
2010-01-23 05:35:54 +03:00
a - > type = SOCK_STREAM ;
2010-01-19 04:56:37 +03:00
if ( * s = = ' [ ' ) {
/* IPv6 in [x:.....:z]:p notation */
2010-09-20 23:33:14 +04:00
if ( ! socket_ipv6_is_supported ( ) ) {
log_warning ( " Binding to IPv6 address not available since kernel does not support IPv6. " ) ;
return - EAFNOSUPPORT ;
}
2010-01-19 04:56:37 +03:00
if ( ! ( e = strchr ( s + 1 , ' ] ' ) ) )
return - EINVAL ;
if ( ! ( n = strndup ( s + 1 , e - s - 1 ) ) )
return - ENOMEM ;
errno = 0 ;
if ( inet_pton ( AF_INET6 , n , & a - > sockaddr . in6 . sin6_addr ) < = 0 ) {
free ( n ) ;
2013-03-28 17:24:15 +04:00
return errno > 0 ? - errno : - EINVAL ;
2010-01-19 04:56:37 +03:00
}
free ( n ) ;
e + + ;
if ( * e ! = ' : ' )
return - EINVAL ;
e + + ;
if ( ( r = safe_atou ( e , & u ) ) < 0 )
return r ;
if ( u < = 0 | | u > 0xFFFF )
return - EINVAL ;
a - > sockaddr . in6 . sin6_family = AF_INET6 ;
a - > sockaddr . in6 . sin6_port = htons ( ( uint16_t ) u ) ;
a - > size = sizeof ( struct sockaddr_in6 ) ;
} else if ( * s = = ' / ' ) {
/* AF_UNIX socket */
size_t l ;
l = strlen ( s ) ;
if ( l > = sizeof ( a - > sockaddr . un . sun_path ) )
return - EINVAL ;
a - > sockaddr . un . sun_family = AF_UNIX ;
memcpy ( a - > sockaddr . un . sun_path , s , l ) ;
2010-10-07 04:34:17 +04:00
a - > size = offsetof ( struct sockaddr_un , sun_path ) + l + 1 ;
2010-01-19 04:56:37 +03:00
2010-01-28 06:50:28 +03:00
} else if ( * s = = ' @ ' ) {
2010-01-19 04:56:37 +03:00
/* Abstract AF_UNIX socket */
size_t l ;
l = strlen ( s + 1 ) ;
if ( l > = sizeof ( a - > sockaddr . un . sun_path ) - 1 )
return - EINVAL ;
a - > sockaddr . un . sun_family = AF_UNIX ;
memcpy ( a - > sockaddr . un . sun_path + 1 , s + 1 , l ) ;
2010-10-07 04:34:17 +04:00
a - > size = offsetof ( struct sockaddr_un , sun_path ) + 1 + l ;
2010-01-19 04:56:37 +03:00
} else {
if ( ( e = strchr ( s , ' : ' ) ) ) {
2010-01-23 05:35:54 +03:00
if ( ( r = safe_atou ( e + 1 , & u ) ) < 0 )
return r ;
if ( u < = 0 | | u > 0xFFFF )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
if ( ! ( n = strndup ( s , e - s ) ) )
return - ENOMEM ;
2010-01-23 05:35:54 +03:00
/* IPv4 in w.x.y.z:p notation? */
if ( ( r = inet_pton ( AF_INET , n , & a - > sockaddr . in4 . sin_addr ) ) < 0 ) {
2010-01-19 04:56:37 +03:00
free ( n ) ;
2010-01-23 05:35:54 +03:00
return - errno ;
2010-01-19 04:56:37 +03:00
}
2010-01-23 05:35:54 +03:00
if ( r > 0 ) {
/* Gotcha, it's a traditional IPv4 address */
free ( n ) ;
2010-01-19 04:56:37 +03:00
2010-01-23 05:35:54 +03:00
a - > sockaddr . in4 . sin_family = AF_INET ;
a - > sockaddr . in4 . sin_port = htons ( ( uint16_t ) u ) ;
a - > size = sizeof ( struct sockaddr_in ) ;
} else {
unsigned idx ;
2010-01-19 04:56:37 +03:00
2010-01-27 06:31:52 +03:00
if ( strlen ( n ) > IF_NAMESIZE - 1 ) {
free ( n ) ;
return - EINVAL ;
}
2010-01-23 05:35:54 +03:00
/* Uh, our last resort, an interface name */
idx = if_nametoindex ( n ) ;
free ( n ) ;
2010-01-24 00:56:47 +03:00
if ( idx = = 0 )
2010-01-23 05:35:54 +03:00
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2010-09-20 23:33:14 +04:00
if ( ! socket_ipv6_is_supported ( ) ) {
log_warning ( " Binding to interface is not available since kernel does not support IPv6. " ) ;
return - EAFNOSUPPORT ;
}
2010-01-23 05:35:54 +03:00
a - > sockaddr . in6 . sin6_family = AF_INET6 ;
a - > sockaddr . in6 . sin6_port = htons ( ( uint16_t ) u ) ;
a - > sockaddr . in6 . sin6_scope_id = idx ;
2010-01-24 00:56:47 +03:00
a - > sockaddr . in6 . sin6_addr = in6addr_any ;
2010-01-23 05:35:54 +03:00
a - > size = sizeof ( struct sockaddr_in6 ) ;
}
2010-01-19 04:56:37 +03:00
} else {
/* Just a port */
2012-10-03 22:18:55 +04:00
r = safe_atou ( s , & u ) ;
if ( r < 0 )
2010-01-19 04:56:37 +03:00
return r ;
if ( u < = 0 | | u > 0xFFFF )
return - EINVAL ;
2010-09-20 23:33:14 +04:00
if ( socket_ipv6_is_supported ( ) ) {
a - > sockaddr . in6 . sin6_family = AF_INET6 ;
a - > sockaddr . in6 . sin6_port = htons ( ( uint16_t ) u ) ;
a - > sockaddr . in6 . sin6_addr = in6addr_any ;
a - > size = sizeof ( struct sockaddr_in6 ) ;
} else {
a - > sockaddr . in4 . sin_family = AF_INET ;
a - > sockaddr . in4 . sin_port = htons ( ( uint16_t ) u ) ;
a - > sockaddr . in4 . sin_addr . s_addr = INADDR_ANY ;
a - > size = sizeof ( struct sockaddr_in ) ;
}
2010-01-19 04:56:37 +03:00
}
}
return 0 ;
}
2011-04-10 05:27:00 +04:00
int socket_address_parse_netlink ( SocketAddress * a , const char * s ) {
int family ;
unsigned group = 0 ;
2012-10-30 17:29:38 +04:00
_cleanup_free_ char * sfamily = NULL ;
2011-04-10 05:27:00 +04:00
assert ( a ) ;
assert ( s ) ;
zero ( * a ) ;
a - > type = SOCK_RAW ;
errno = 0 ;
if ( sscanf ( s , " %ms %u " , & sfamily , & group ) < 1 )
2013-04-12 02:57:42 +04:00
return errno > 0 ? - errno : - EINVAL ;
2011-04-10 05:27:00 +04:00
2012-10-30 17:29:38 +04:00
family = netlink_family_from_string ( sfamily ) ;
if ( family < 0 )
return - EINVAL ;
2011-04-10 05:27:00 +04:00
a - > sockaddr . nl . nl_family = AF_NETLINK ;
a - > sockaddr . nl . nl_groups = group ;
a - > type = SOCK_RAW ;
a - > size = sizeof ( struct sockaddr_nl ) ;
a - > protocol = family ;
return 0 ;
}
2010-01-23 05:35:54 +03:00
int socket_address_verify ( const SocketAddress * a ) {
2010-01-19 04:56:37 +03:00
assert ( a ) ;
2010-01-23 05:35:54 +03:00
switch ( socket_address_family ( a ) ) {
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
case AF_INET :
if ( a - > size ! = sizeof ( struct sockaddr_in ) )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( a - > sockaddr . in4 . sin_port = = 0 )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( a - > type ! = SOCK_STREAM & & a - > type ! = SOCK_DGRAM )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
return 0 ;
case AF_INET6 :
if ( a - > size ! = sizeof ( struct sockaddr_in6 ) )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( a - > sockaddr . in6 . sin6_port = = 0 )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( a - > type ! = SOCK_STREAM & & a - > type ! = SOCK_DGRAM )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
return 0 ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
case AF_UNIX :
if ( a - > size < offsetof ( struct sockaddr_un , sun_path ) )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( a - > size > offsetof ( struct sockaddr_un , sun_path ) ) {
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( a - > sockaddr . un . sun_path [ 0 ] ! = 0 ) {
char * e ;
/* path */
if ( ! ( e = memchr ( a - > sockaddr . un . sun_path , 0 , sizeof ( a - > sockaddr . un . sun_path ) ) ) )
return - EINVAL ;
if ( a - > size ! = offsetof ( struct sockaddr_un , sun_path ) + ( e - a - > sockaddr . un . sun_path ) + 1 )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
}
2011-04-10 05:27:00 +04:00
}
2010-01-19 04:56:37 +03:00
2011-04-12 22:26:33 +04:00
if ( a - > type ! = SOCK_STREAM & & a - > type ! = SOCK_DGRAM & & a - > type ! = SOCK_SEQPACKET )
2011-04-10 05:27:00 +04:00
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
return 0 ;
case AF_NETLINK :
if ( a - > size ! = sizeof ( struct sockaddr_nl ) )
return - EINVAL ;
if ( a - > type ! = SOCK_RAW & & a - > type ! = SOCK_DGRAM )
return - EINVAL ;
return 0 ;
default :
return - EAFNOSUPPORT ;
2010-01-19 04:56:37 +03:00
}
}
2010-01-23 05:35:54 +03:00
int socket_address_print ( const SocketAddress * a , char * * p ) {
2010-01-19 04:56:37 +03:00
int r ;
assert ( a ) ;
assert ( p ) ;
2010-01-23 05:35:54 +03:00
if ( ( r = socket_address_verify ( a ) ) < 0 )
2010-01-19 04:56:37 +03:00
return r ;
2010-01-23 05:35:54 +03:00
switch ( socket_address_family ( a ) ) {
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
case AF_INET : {
char * ret ;
2010-01-19 04:56:37 +03:00
2013-10-12 20:15:49 +04:00
ret = new ( char , INET_ADDRSTRLEN + 1 + 5 + 1 ) ;
if ( ! ret )
2011-04-10 05:27:00 +04:00
return - ENOMEM ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( ! inet_ntop ( AF_INET , & a - > sockaddr . in4 . sin_addr , ret , INET_ADDRSTRLEN ) ) {
free ( ret ) ;
return - errno ;
2010-01-19 04:56:37 +03:00
}
2011-04-10 05:27:00 +04:00
sprintf ( strchr ( ret , 0 ) , " :%u " , ntohs ( a - > sockaddr . in4 . sin_port ) ) ;
* p = ret ;
return 0 ;
}
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
case AF_INET6 : {
char * ret ;
2010-01-19 04:56:37 +03:00
2013-10-12 20:15:49 +04:00
ret = new ( char , 1 + INET6_ADDRSTRLEN + 2 + 5 + 1 ) ;
if ( ! ret )
2011-04-10 05:27:00 +04:00
return - ENOMEM ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
ret [ 0 ] = ' [ ' ;
if ( ! inet_ntop ( AF_INET6 , & a - > sockaddr . in6 . sin6_addr , ret + 1 , INET6_ADDRSTRLEN ) ) {
free ( ret ) ;
return - errno ;
2010-01-19 04:56:37 +03:00
}
2011-04-10 05:27:00 +04:00
sprintf ( strchr ( ret , 0 ) , " ]:%u " , ntohs ( a - > sockaddr . in6 . sin6_port ) ) ;
* p = ret ;
return 0 ;
}
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
case AF_UNIX : {
char * ret ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
if ( a - > size < = offsetof ( struct sockaddr_un , sun_path ) ) {
2013-10-12 20:15:49 +04:00
ret = strdup ( " <unnamed> " ) ;
if ( ! ret )
2011-04-10 05:27:00 +04:00
return - ENOMEM ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
} else if ( a - > sockaddr . un . sun_path [ 0 ] = = 0 ) {
/* abstract */
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
/* FIXME: We assume we can print the
* socket path here and that it hasn ' t
* more than one NUL byte . That is
* actually an invalid assumption */
2010-01-19 04:56:37 +03:00
2013-10-12 20:15:49 +04:00
ret = new ( char , sizeof ( a - > sockaddr . un . sun_path ) + 1 ) ;
if ( ! ret )
2011-04-10 05:27:00 +04:00
return - ENOMEM ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
ret [ 0 ] = ' @ ' ;
memcpy ( ret + 1 , a - > sockaddr . un . sun_path + 1 , sizeof ( a - > sockaddr . un . sun_path ) - 1 ) ;
ret [ sizeof ( a - > sockaddr . un . sun_path ) ] = 0 ;
2010-01-19 04:56:37 +03:00
2011-04-10 05:27:00 +04:00
} else {
2013-10-12 20:15:49 +04:00
ret = strdup ( a - > sockaddr . un . sun_path ) ;
if ( ! ret )
2011-04-10 05:27:00 +04:00
return - ENOMEM ;
2010-01-19 04:56:37 +03:00
}
2011-04-10 05:27:00 +04:00
* p = ret ;
return 0 ;
}
case AF_NETLINK : {
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * sfamily = NULL ;
2011-04-10 05:27:00 +04:00
2012-10-30 17:29:38 +04:00
r = netlink_family_to_string_alloc ( a - > protocol , & sfamily ) ;
2011-04-10 05:27:00 +04:00
if ( r < 0 )
2012-10-30 17:29:38 +04:00
return r ;
r = asprintf ( p , " %s %u " , sfamily , a - > sockaddr . nl . nl_groups ) ;
2012-12-13 17:59:40 +04:00
if ( r < 0 )
return - ENOMEM ;
2011-04-10 05:27:00 +04:00
return 0 ;
}
default :
return - EINVAL ;
2010-01-19 04:56:37 +03:00
}
}
2010-04-15 08:19:54 +04:00
bool socket_address_can_accept ( const SocketAddress * a ) {
assert ( a ) ;
return
a - > type = = SOCK_STREAM | |
a - > type = = SOCK_SEQPACKET ;
}
2010-04-21 05:27:44 +04:00
bool socket_address_equal ( const SocketAddress * a , const SocketAddress * b ) {
assert ( a ) ;
assert ( b ) ;
/* Invalid addresses are unequal to all */
if ( socket_address_verify ( a ) < 0 | |
socket_address_verify ( b ) < 0 )
return false ;
if ( a - > type ! = b - > type )
return false ;
if ( a - > size ! = b - > size )
return false ;
if ( socket_address_family ( a ) ! = socket_address_family ( b ) )
return false ;
switch ( socket_address_family ( a ) ) {
case AF_INET :
if ( a - > sockaddr . in4 . sin_addr . s_addr ! = b - > sockaddr . in4 . sin_addr . s_addr )
return false ;
if ( a - > sockaddr . in4 . sin_port ! = b - > sockaddr . in4 . sin_port )
return false ;
break ;
case AF_INET6 :
if ( memcmp ( & a - > sockaddr . in6 . sin6_addr , & b - > sockaddr . in6 . sin6_addr , sizeof ( a - > sockaddr . in6 . sin6_addr ) ) ! = 0 )
return false ;
if ( a - > sockaddr . in6 . sin6_port ! = b - > sockaddr . in6 . sin6_port )
return false ;
break ;
case AF_UNIX :
if ( ( a - > sockaddr . un . sun_path [ 0 ] = = 0 ) ! = ( b - > sockaddr . un . sun_path [ 0 ] = = 0 ) )
return false ;
if ( a - > sockaddr . un . sun_path [ 0 ] ) {
2013-02-13 00:47:36 +04:00
if ( ! strneq ( a - > sockaddr . un . sun_path , b - > sockaddr . un . sun_path , sizeof ( a - > sockaddr . un . sun_path ) ) )
2010-04-21 05:27:44 +04:00
return false ;
} else {
2010-07-11 04:23:11 +04:00
if ( memcmp ( a - > sockaddr . un . sun_path , b - > sockaddr . un . sun_path , a - > size ) ! = 0 )
2010-04-21 05:27:44 +04:00
return false ;
}
break ;
2011-04-10 05:27:00 +04:00
case AF_NETLINK :
if ( a - > protocol ! = b - > protocol )
return false ;
if ( a - > sockaddr . nl . nl_groups ! = b - > sockaddr . nl . nl_groups )
return false ;
break ;
2010-04-21 05:27:44 +04:00
default :
/* Cannot compare, so we assume the addresses are different */
return false ;
}
return true ;
}
2010-06-05 02:52:30 +04:00
bool socket_address_is ( const SocketAddress * a , const char * s , int type ) {
2010-04-21 05:27:44 +04:00
struct SocketAddress b ;
assert ( a ) ;
assert ( s ) ;
if ( socket_address_parse ( & b , s ) < 0 )
return false ;
2010-06-05 02:52:30 +04:00
b . type = type ;
2010-04-21 05:27:44 +04:00
return socket_address_equal ( a , & b ) ;
2010-05-13 05:07:16 +04:00
}
2011-04-10 05:27:00 +04:00
bool socket_address_is_netlink ( const SocketAddress * a , const char * s ) {
struct SocketAddress b ;
assert ( a ) ;
assert ( s ) ;
if ( socket_address_parse_netlink ( & b , s ) < 0 )
return false ;
return socket_address_equal ( a , & b ) ;
}
2013-09-26 22:14:24 +04:00
const char * socket_address_get_path ( const SocketAddress * a ) {
2010-05-13 05:07:16 +04:00
assert ( a ) ;
if ( socket_address_family ( a ) ! = AF_UNIX )
2013-09-26 22:14:24 +04:00
return NULL ;
2010-05-13 05:07:16 +04:00
if ( a - > sockaddr . un . sun_path [ 0 ] = = 0 )
2013-09-26 22:14:24 +04:00
return NULL ;
2010-04-21 05:27:44 +04:00
2013-09-26 22:14:24 +04:00
return a - > sockaddr . un . sun_path ;
2010-04-21 05:27:44 +04:00
}
2010-05-22 01:41:25 +04:00
2010-09-20 23:33:14 +04:00
bool socket_ipv6_is_supported ( void ) {
2010-10-27 21:40:31 +04:00
char * l = 0 ;
bool enabled ;
if ( access ( " /sys/module/ipv6 " , F_OK ) ! = 0 )
return 0 ;
/* If we can't check "disable" parameter, assume enabled */
if ( read_one_line_file ( " /sys/module/ipv6/parameters/disable " , & l ) < 0 )
return 1 ;
/* If module was loaded with disable=1 no IPv6 available */
enabled = l [ 0 ] = = ' 0 ' ;
free ( l ) ;
return enabled ;
2010-09-20 23:33:14 +04:00
}
2012-12-22 22:30:07 +04:00
bool socket_address_matches_fd ( const SocketAddress * a , int fd ) {
union sockaddr_union sa ;
socklen_t salen = sizeof ( sa ) , solen ;
int protocol , type ;
assert ( a ) ;
assert ( fd > = 0 ) ;
if ( getsockname ( fd , & sa . sa , & salen ) < 0 )
return false ;
if ( sa . sa . sa_family ! = a - > sockaddr . sa . sa_family )
return false ;
solen = sizeof ( type ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_TYPE , & type , & solen ) < 0 )
return false ;
if ( type ! = a - > type )
return false ;
if ( a - > protocol ! = 0 ) {
solen = sizeof ( protocol ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_PROTOCOL , & protocol , & solen ) < 0 )
return false ;
if ( protocol ! = a - > protocol )
return false ;
}
switch ( sa . sa . sa_family ) {
case AF_INET :
return sa . in4 . sin_port = = a - > sockaddr . in4 . sin_port & &
sa . in4 . sin_addr . s_addr = = a - > sockaddr . in4 . sin_addr . s_addr ;
case AF_INET6 :
return sa . in6 . sin6_port = = a - > sockaddr . in6 . sin6_port & &
memcmp ( & sa . in6 . sin6_addr , & a - > sockaddr . in6 . sin6_addr , sizeof ( struct in6_addr ) ) = = 0 ;
case AF_UNIX :
return salen = = a - > size & &
memcmp ( sa . un . sun_path , a - > sockaddr . un . sun_path , salen - offsetof ( struct sockaddr_un , sun_path ) ) = = 0 ;
}
return false ;
}
2013-11-07 01:40:54 +04:00
int getpeername_pretty ( int fd , char * * ret ) {
union {
struct sockaddr sa ;
struct sockaddr_un un ;
struct sockaddr_in in ;
struct sockaddr_in6 in6 ;
struct sockaddr_storage storage ;
} sa ;
socklen_t salen ;
char * p ;
assert ( fd > = 0 ) ;
assert ( ret ) ;
salen = sizeof ( sa ) ;
if ( getpeername ( fd , & sa . sa , & salen ) < 0 )
return - errno ;
switch ( sa . sa . sa_family ) {
case AF_INET : {
uint32_t a ;
a = ntohl ( sa . in . sin_addr . s_addr ) ;
if ( asprintf ( & p ,
" %u.%u.%u.%u:%u " ,
a > > 24 , ( a > > 16 ) & 0xFF , ( a > > 8 ) & 0xFF , a & 0xFF ,
ntohs ( sa . in . sin_port ) ) < 0 )
return - ENOMEM ;
break ;
}
case AF_INET6 : {
static const unsigned char ipv4_prefix [ ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xFF , 0xFF
} ;
if ( memcmp ( & sa . in6 . sin6_addr , ipv4_prefix , sizeof ( ipv4_prefix ) ) = = 0 ) {
const uint8_t * a = sa . in6 . sin6_addr . s6_addr + 12 ;
if ( asprintf ( & p ,
" %u.%u.%u.%u:%u " ,
a [ 0 ] , a [ 1 ] , a [ 2 ] , a [ 3 ] ,
ntohs ( sa . in6 . sin6_port ) ) < 0 )
return - ENOMEM ;
} else {
char a [ INET6_ADDRSTRLEN ] ;
if ( asprintf ( & p ,
" %s:%u " ,
inet_ntop ( AF_INET6 , & sa . in6 . sin6_addr , a , sizeof ( a ) ) ,
ntohs ( sa . in6 . sin6_port ) ) < 0 )
return - ENOMEM ;
}
break ;
}
case AF_UNIX : {
struct ucred ucred ;
salen = sizeof ( ucred ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & ucred , & salen ) < 0 )
return - errno ;
if ( asprintf ( & p , " PID %lu/UID %lu " , ( unsigned long ) ucred . pid , ( unsigned long ) ucred . pid ) < 0 )
return - ENOMEM ;
break ;
}
default :
return - ENOTSUP ;
}
* ret = p ;
return 0 ;
}
2011-04-10 05:27:00 +04:00
static const char * const netlink_family_table [ ] = {
[ NETLINK_ROUTE ] = " route " ,
[ NETLINK_FIREWALL ] = " firewall " ,
[ NETLINK_INET_DIAG ] = " inet-diag " ,
[ NETLINK_NFLOG ] = " nflog " ,
[ NETLINK_XFRM ] = " xfrm " ,
[ NETLINK_SELINUX ] = " selinux " ,
[ NETLINK_ISCSI ] = " iscsi " ,
[ NETLINK_AUDIT ] = " audit " ,
[ NETLINK_FIB_LOOKUP ] = " fib-lookup " ,
[ NETLINK_CONNECTOR ] = " connector " ,
[ NETLINK_NETFILTER ] = " netfilter " ,
[ NETLINK_IP6_FW ] = " ip6-fw " ,
[ NETLINK_DNRTMSG ] = " dnrtmsg " ,
[ NETLINK_KOBJECT_UEVENT ] = " kobject-uevent " ,
[ NETLINK_GENERIC ] = " generic " ,
[ NETLINK_SCSITRANSPORT ] = " scsitransport " ,
[ NETLINK_ECRYPTFS ] = " ecryptfs "
} ;
2012-10-30 17:29:38 +04:00
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK ( netlink_family , int , INT_MAX ) ;
2011-04-10 05:27:00 +04:00
2010-05-22 01:41:25 +04:00
static const char * const socket_address_bind_ipv6_only_table [ _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX ] = {
[ SOCKET_ADDRESS_DEFAULT ] = " default " ,
[ SOCKET_ADDRESS_BOTH ] = " both " ,
[ SOCKET_ADDRESS_IPV6_ONLY ] = " ipv6-only "
} ;
DEFINE_STRING_TABLE_LOOKUP ( socket_address_bind_ipv6_only , SocketAddressBindIPv6Only ) ;