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 <arpa/inet.h>
2015-10-24 23:58:24 +03:00
# include <errno.h>
2015-11-30 23:43:37 +03:00
# include <limits.h>
2010-01-23 05:35:54 +03:00
# include <net/if.h>
2014-06-30 03:24:56 +04:00
# include <netdb.h>
2015-10-26 03:09:02 +03:00
# include <netinet/ip.h>
2015-10-24 23:58:24 +03:00
# include <stddef.h>
2015-11-30 23:43:37 +03:00
# include <stdint.h>
2015-10-24 23:58:24 +03:00
# include <stdio.h>
2015-11-30 23:43:37 +03:00
# include <stdlib.h>
2015-10-24 23:58:24 +03:00
# include <string.h>
# include <unistd.h>
2010-01-19 04:56:37 +03:00
2015-10-27 05:01:06 +03:00
# include "alloc-util.h"
2015-10-26 03:09:02 +03:00
# include "fd-util.h"
2015-10-24 23:58:24 +03:00
# include "fileio.h"
# include "formats-util.h"
2015-12-02 01:22:03 +03:00
# include "log.h"
2010-01-19 04:56:37 +03:00
# include "macro.h"
2015-10-24 23:58:24 +03:00
# include "missing.h"
2015-10-26 18:18:16 +03:00
# include "parse-util.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2015-10-26 03:09:02 +03:00
# include "socket-util.h"
2015-10-27 00:31:05 +03:00
# include "string-table.h"
2015-10-24 23:58:24 +03:00
# include "string-util.h"
2015-10-27 02:42:07 +03:00
# include "user-util.h"
2015-02-14 11:44:31 +03:00
# include "util.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
char * e , * n ;
unsigned u ;
2013-11-07 03:03:54 +04:00
int r ;
2010-01-19 04:56:37 +03:00
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 */
2013-11-07 03:03:54 +04:00
e = strchr ( s + 1 , ' ] ' ) ;
if ( ! e )
2010-01-19 04:56:37 +03:00
return - EINVAL ;
2013-11-07 03:03:54 +04:00
n = strndupa ( s + 1 , e - s - 1 ) ;
2010-01-19 04:56:37 +03:00
errno = 0 ;
2013-11-07 03:03:54 +04:00
if ( inet_pton ( AF_INET6 , n , & a - > sockaddr . in6 . sin6_addr ) < = 0 )
2013-03-28 17:24:15 +04:00
return errno > 0 ? - errno : - EINVAL ;
2010-01-19 04:56:37 +03:00
e + + ;
if ( * e ! = ' : ' )
return - EINVAL ;
e + + ;
2013-11-07 03:03:54 +04:00
r = safe_atou ( e , & u ) ;
if ( r < 0 )
2010-01-19 04:56:37 +03:00
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 {
2013-11-07 03:03:54 +04:00
e = strchr ( s , ' : ' ) ;
if ( e ) {
r = safe_atou ( e + 1 , & u ) ;
if ( r < 0 )
2010-01-23 05:35:54 +03:00
return r ;
if ( u < = 0 | | u > 0xFFFF )
return - EINVAL ;
2010-01-19 04:56:37 +03:00
2013-11-07 03:03:54 +04:00
n = strndupa ( s , e - s ) ;
2010-01-19 04:56:37 +03:00
2010-01-23 05:35:54 +03:00
/* IPv4 in w.x.y.z:p notation? */
2013-11-07 03:03:54 +04:00
r = inet_pton ( AF_INET , n , & a - > sockaddr . in . sin_addr ) ;
if ( r < 0 )
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 */
2013-11-07 03:03:54 +04:00
a - > sockaddr . in . sin_family = AF_INET ;
a - > sockaddr . in . sin_port = htons ( ( uint16_t ) u ) ;
2010-01-23 05:35:54 +03:00
a - > size = sizeof ( struct sockaddr_in ) ;
} else {
unsigned idx ;
2010-01-19 04:56:37 +03:00
2013-11-07 03:03:54 +04:00
if ( strlen ( n ) > IF_NAMESIZE - 1 )
2010-01-27 06:31:52 +03:00
return - EINVAL ;
2010-01-23 05:35:54 +03:00
/* Uh, our last resort, an interface name */
idx = if_nametoindex ( 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-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 {
2013-11-07 03:03:54 +04:00
a - > sockaddr . in . sin_family = AF_INET ;
a - > sockaddr . in . sin_port = htons ( ( uint16_t ) u ) ;
a - > sockaddr . in . sin_addr . s_addr = INADDR_ANY ;
2010-09-20 23:33:14 +04:00
a - > size = sizeof ( struct sockaddr_in ) ;
}
2010-01-19 04:56:37 +03:00
}
}
return 0 ;
}
2015-05-15 21:15:59 +03:00
int socket_address_parse_and_warn ( SocketAddress * a , const char * s ) {
SocketAddress b ;
int r ;
/* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
r = socket_address_parse ( & b , s ) ;
if ( r < 0 )
return r ;
if ( ! socket_ipv6_is_supported ( ) & & b . sockaddr . sa . sa_family = = AF_INET6 ) {
log_warning ( " Binding to IPv6 address not available since kernel does not support IPv6. " ) ;
return - EAFNOSUPPORT ;
}
* a = b ;
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
2013-11-07 03:03:54 +04:00
if ( a - > sockaddr . in . sin_port = = 0 )
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
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 */
2013-11-07 03:03:54 +04:00
e = memchr ( a - > sockaddr . un . sun_path , 0 , sizeof ( a - > sockaddr . un . sun_path ) ) ;
if ( ! e )
2011-04-10 05:27:00 +04:00
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
}
}
2013-11-07 03:03:54 +04:00
int socket_address_print ( const SocketAddress * a , char * * ret ) {
2010-01-19 04:56:37 +03:00
int r ;
2013-11-07 03:03:54 +04:00
2010-01-19 04:56:37 +03:00
assert ( a ) ;
2013-11-07 03:03:54 +04:00
assert ( ret ) ;
2010-01-19 04:56:37 +03:00
2013-11-07 03:03:54 +04:00
r = socket_address_verify ( a ) ;
if ( r < 0 )
2010-01-19 04:56:37 +03:00
return r ;
2013-11-07 03:03:54 +04:00
if ( socket_address_family ( a ) = = 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 ;
2013-11-07 03:03:54 +04:00
r = asprintf ( ret , " %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 ;
}
2015-03-10 14:41:59 +03:00
return sockaddr_pretty ( & a - > sockaddr . sa , a - > size , false , true , ret ) ;
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 ( socket_address_family ( a ) ! = socket_address_family ( b ) )
return false ;
switch ( socket_address_family ( a ) ) {
case AF_INET :
2013-11-07 03:03:54 +04:00
if ( a - > sockaddr . in . sin_addr . s_addr ! = b - > sockaddr . in . sin_addr . s_addr )
2010-04-21 05:27:44 +04:00
return false ;
2013-11-07 03:03:54 +04:00
if ( a - > sockaddr . in . sin_port ! = b - > sockaddr . in . sin_port )
2010-04-21 05:27:44 +04:00
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 :
2015-02-20 04:25:16 +03:00
if ( a - > size < = offsetof ( struct sockaddr_un , sun_path ) | |
b - > size < = offsetof ( struct sockaddr_un , sun_path ) )
return false ;
2010-04-21 05:27:44 +04:00
if ( ( a - > sockaddr . un . sun_path [ 0 ] = = 0 ) ! = ( b - > sockaddr . un . sun_path [ 0 ] = = 0 ) )
return false ;
if ( a - > sockaddr . un . sun_path [ 0 ] ) {
2015-02-20 01:12:38 +03:00
if ( ! path_equal_or_files_same ( a - > sockaddr . un . sun_path , b - > sockaddr . un . sun_path ) )
2010-04-21 05:27:44 +04:00
return false ;
} else {
2015-02-20 01:12:38 +03:00
if ( a - > size ! = b - > size )
return false ;
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 ) {
2015-12-10 15:24:45 +03:00
if ( access ( " /proc/net/sockstat6 " , F_OK ) ! = 0 )
2014-08-13 17:00:12 +04:00
return false ;
2010-10-27 21:40:31 +04:00
2015-12-10 15:24:45 +03:00
return true ;
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 ) {
2015-02-20 04:04:05 +03:00
SocketAddress b ;
socklen_t solen ;
2012-12-22 22:30:07 +04:00
assert ( a ) ;
assert ( fd > = 0 ) ;
2015-02-20 04:04:05 +03:00
b . size = sizeof ( b . sockaddr ) ;
if ( getsockname ( fd , & b . sockaddr . sa , & b . size ) < 0 )
2012-12-22 22:30:07 +04:00
return false ;
2015-02-20 04:04:05 +03:00
if ( b . sockaddr . sa . sa_family ! = a - > sockaddr . sa . sa_family )
2012-12-22 22:30:07 +04:00
return false ;
2015-02-20 04:04:05 +03:00
solen = sizeof ( b . type ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_TYPE , & b . type , & solen ) < 0 )
2012-12-22 22:30:07 +04:00
return false ;
2015-02-20 04:04:05 +03:00
if ( b . type ! = a - > type )
2012-12-22 22:30:07 +04:00
return false ;
if ( a - > protocol ! = 0 ) {
2015-02-20 04:04:05 +03:00
solen = sizeof ( b . protocol ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_PROTOCOL , & b . protocol , & solen ) < 0 )
2012-12-22 22:30:07 +04:00
return false ;
2015-02-20 04:04:05 +03:00
if ( b . protocol ! = a - > protocol )
2012-12-22 22:30:07 +04:00
return false ;
}
2015-02-20 04:13:03 +03:00
return socket_address_equal ( a , & b ) ;
2012-12-22 22:30:07 +04:00
}
2015-03-10 14:41:59 +03:00
int sockaddr_port ( const struct sockaddr * _sa ) {
union sockaddr_union * sa = ( union sockaddr_union * ) _sa ;
assert ( sa ) ;
if ( ! IN_SET ( sa - > sa . sa_family , AF_INET , AF_INET6 ) )
return - EAFNOSUPPORT ;
return ntohs ( sa - > sa . sa_family = = AF_INET6 ?
sa - > in6 . sin6_port :
sa - > in . sin_port ) ;
}
int sockaddr_pretty ( const struct sockaddr * _sa , socklen_t salen , bool translate_ipv6 , bool include_port , char * * ret ) {
2013-11-07 03:03:54 +04:00
union sockaddr_union * sa = ( union sockaddr_union * ) _sa ;
2013-11-07 01:40:54 +04:00
char * p ;
2015-03-10 19:30:12 +03:00
int r ;
2013-11-07 01:40:54 +04:00
2013-11-07 03:03:54 +04:00
assert ( sa ) ;
assert ( salen > = sizeof ( sa - > sa . sa_family ) ) ;
2013-11-07 01:40:54 +04:00
2013-11-07 03:03:54 +04:00
switch ( sa - > sa . sa_family ) {
2013-11-07 01:40:54 +04:00
case AF_INET : {
uint32_t a ;
2013-11-07 03:03:54 +04:00
a = ntohl ( sa - > in . sin_addr . s_addr ) ;
2013-11-07 01:40:54 +04:00
2015-03-10 19:30:12 +03:00
if ( include_port )
r = asprintf ( & p ,
2015-03-10 14:41:59 +03:00
" %u.%u.%u.%u:%u " ,
a > > 24 , ( a > > 16 ) & 0xFF , ( a > > 8 ) & 0xFF , a & 0xFF ,
2015-03-10 19:30:12 +03:00
ntohs ( sa - > in . sin_port ) ) ;
else
r = asprintf ( & p ,
2015-03-10 14:41:59 +03:00
" %u.%u.%u.%u " ,
2015-03-10 19:30:12 +03:00
a > > 24 , ( a > > 16 ) & 0xFF , ( a > > 8 ) & 0xFF , a & 0xFF ) ;
if ( r < 0 )
return - ENOMEM ;
2013-11-07 01:40:54 +04:00
break ;
}
case AF_INET6 : {
static const unsigned char ipv4_prefix [ ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xFF , 0xFF
} ;
2015-03-10 19:30:12 +03:00
if ( translate_ipv6 & &
memcmp ( & sa - > in6 . sin6_addr , ipv4_prefix , sizeof ( ipv4_prefix ) ) = = 0 ) {
2013-11-07 03:03:54 +04:00
const uint8_t * a = sa - > in6 . sin6_addr . s6_addr + 12 ;
2015-03-10 19:30:12 +03:00
if ( include_port )
r = asprintf ( & p ,
2015-03-10 14:41:59 +03:00
" %u.%u.%u.%u:%u " ,
a [ 0 ] , a [ 1 ] , a [ 2 ] , a [ 3 ] ,
2015-03-10 19:30:12 +03:00
ntohs ( sa - > in6 . sin6_port ) ) ;
else
r = asprintf ( & p ,
2015-03-10 14:41:59 +03:00
" %u.%u.%u.%u " ,
2015-03-10 19:30:12 +03:00
a [ 0 ] , a [ 1 ] , a [ 2 ] , a [ 3 ] ) ;
if ( r < 0 )
return - ENOMEM ;
2013-11-07 01:40:54 +04:00
} else {
char a [ INET6_ADDRSTRLEN ] ;
2015-03-10 14:41:59 +03:00
inet_ntop ( AF_INET6 , & sa - > in6 . sin6_addr , a , sizeof ( a ) ) ;
if ( include_port ) {
2015-03-10 19:30:12 +03:00
r = asprintf ( & p ,
2015-03-10 14:41:59 +03:00
" [%s]:%u " ,
a ,
2015-03-10 19:30:12 +03:00
ntohs ( sa - > in6 . sin6_port ) ) ;
if ( r < 0 )
2015-03-10 14:41:59 +03:00
return - ENOMEM ;
} else {
p = strdup ( a ) ;
if ( ! p )
return - ENOMEM ;
}
2013-11-07 01:40:54 +04:00
}
break ;
}
2013-11-07 03:03:54 +04:00
case AF_UNIX :
if ( salen < = offsetof ( struct sockaddr_un , sun_path ) ) {
p = strdup ( " <unnamed> " ) ;
if ( ! p )
return - ENOMEM ;
2013-11-07 01:40:54 +04:00
2013-11-07 03:03:54 +04:00
} else if ( sa - > un . sun_path [ 0 ] = = 0 ) {
/* abstract */
2013-11-07 01:40:54 +04:00
2013-11-07 03:03:54 +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 */
p = new ( char , sizeof ( sa - > un . sun_path ) + 1 ) ;
if ( ! p )
return - ENOMEM ;
p [ 0 ] = ' @ ' ;
memcpy ( p + 1 , sa - > un . sun_path + 1 , sizeof ( sa - > un . sun_path ) - 1 ) ;
p [ sizeof ( sa - > un . sun_path ) ] = 0 ;
} else {
p = strndup ( sa - > un . sun_path , sizeof ( sa - > un . sun_path ) ) ;
2015-07-31 12:51:33 +03:00
if ( ! p )
2013-11-07 03:03:54 +04:00
return - ENOMEM ;
}
2013-11-07 01:40:54 +04:00
break ;
default :
2015-03-13 16:08:00 +03:00
return - EOPNOTSUPP ;
2013-11-07 01:40:54 +04:00
}
2013-11-07 03:03:54 +04:00
2013-11-07 01:40:54 +04:00
* ret = p ;
return 0 ;
}
2015-12-01 20:29:59 +03:00
int getpeername_pretty ( int fd , bool include_port , char * * ret ) {
2013-11-07 03:03:54 +04:00
union sockaddr_union sa ;
2014-06-30 03:24:56 +04:00
socklen_t salen = sizeof ( sa ) ;
2013-12-24 18:53:04 +04:00
int r ;
2013-11-07 03:03:54 +04:00
assert ( fd > = 0 ) ;
assert ( ret ) ;
if ( getpeername ( fd , & sa . sa , & salen ) < 0 )
return - errno ;
if ( sa . sa . sa_family = = AF_UNIX ) {
2014-02-19 20:47:11 +04:00
struct ucred ucred = { } ;
2013-11-07 03:03:54 +04:00
/* UNIX connection sockets are anonymous, so let's use
* PID / UID as pretty credentials instead */
2013-12-24 18:53:04 +04:00
r = getpeercred ( fd , & ucred ) ;
if ( r < 0 )
return r ;
2013-11-07 03:03:54 +04:00
2014-04-25 15:45:15 +04:00
if ( asprintf ( ret , " PID " PID_FMT " /UID " UID_FMT , ucred . pid , ucred . uid ) < 0 )
2013-11-07 03:03:54 +04:00
return - ENOMEM ;
return 0 ;
}
/* For remote sockets we translate IPv6 addresses back to IPv4
* if applicable , since that ' s nicer . */
2015-12-01 20:29:59 +03:00
return sockaddr_pretty ( & sa . sa , salen , true , include_port , ret ) ;
2013-11-07 03:03:54 +04:00
}
int getsockname_pretty ( int fd , char * * ret ) {
union sockaddr_union sa ;
2014-06-30 03:24:56 +04:00
socklen_t salen = sizeof ( sa ) ;
2013-11-07 03:03:54 +04:00
assert ( fd > = 0 ) ;
assert ( ret ) ;
if ( getsockname ( fd , & sa . sa , & salen ) < 0 )
return - errno ;
/* For local sockets we do not translate IPv6 addresses back
* to IPv6 if applicable , since this is usually used for
* listening sockets where the difference between IPv4 and
* IPv6 matters . */
2015-03-10 14:41:59 +03:00
return sockaddr_pretty ( & sa . sa , salen , false , true , ret ) ;
2013-11-07 03:03:54 +04:00
}
2014-06-30 03:24:56 +04:00
int socknameinfo_pretty ( union sockaddr_union * sa , socklen_t salen , char * * _ret ) {
int r ;
char host [ NI_MAXHOST ] , * ret ;
assert ( _ret ) ;
r = getnameinfo ( & sa - > sa , salen , host , sizeof ( host ) , NULL , 0 ,
NI_IDN | NI_IDN_USE_STD3_ASCII_RULES ) ;
if ( r ! = 0 ) {
int saved_errno = errno ;
2015-03-10 14:41:59 +03:00
r = sockaddr_pretty ( & sa - > sa , salen , true , true , & ret ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
2015-07-29 13:33:44 +03:00
return r ;
2014-06-30 03:24:56 +04:00
2014-11-28 16:45:55 +03:00
log_debug_errno ( saved_errno , " getnameinfo(%s) failed: %m " , ret ) ;
2014-10-22 07:20:59 +04:00
} else {
ret = strdup ( host ) ;
if ( ! ret )
2015-07-29 13:33:44 +03:00
return - ENOMEM ;
2014-10-22 07:20:59 +04:00
}
2014-06-30 03:24:56 +04:00
* _ret = ret ;
return 0 ;
}
int getnameinfo_pretty ( int fd , char * * ret ) {
union sockaddr_union sa ;
socklen_t salen = sizeof ( sa ) ;
assert ( fd > = 0 ) ;
assert ( ret ) ;
2014-11-28 21:57:32 +03:00
if ( getsockname ( fd , & sa . sa , & salen ) < 0 )
2015-07-29 13:33:44 +03:00
return - errno ;
2014-06-30 03:24:56 +04:00
return socknameinfo_pretty ( & sa , salen , ret ) ;
}
2014-06-04 15:10:43 +04:00
int socket_address_unlink ( SocketAddress * a ) {
assert ( a ) ;
if ( socket_address_family ( a ) ! = AF_UNIX )
return 0 ;
if ( a - > sockaddr . un . sun_path [ 0 ] = = 0 )
return 0 ;
if ( unlink ( a - > sockaddr . un . sun_path ) < 0 )
return - errno ;
return 1 ;
}
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 ) ;
2014-08-12 16:54:32 +04:00
bool sockaddr_equal ( const union sockaddr_union * a , const union sockaddr_union * b ) {
assert ( a ) ;
assert ( b ) ;
if ( a - > sa . sa_family ! = b - > sa . sa_family )
return false ;
if ( a - > sa . sa_family = = AF_INET )
return a - > in . sin_addr . s_addr = = b - > in . sin_addr . s_addr ;
if ( a - > sa . sa_family = = AF_INET6 )
return memcmp ( & a - > in6 . sin6_addr , & b - > in6 . sin6_addr , sizeof ( a - > in6 . sin6_addr ) ) = = 0 ;
return false ;
}
2015-10-26 03:09:02 +03:00
int fd_inc_sndbuf ( int fd , size_t n ) {
int r , value ;
socklen_t l = sizeof ( value ) ;
r = getsockopt ( fd , SOL_SOCKET , SO_SNDBUF , & value , & l ) ;
if ( r > = 0 & & l = = sizeof ( value ) & & ( size_t ) value > = n * 2 )
return 0 ;
/* If we have the privileges we will ignore the kernel limit. */
value = ( int ) n ;
if ( setsockopt ( fd , SOL_SOCKET , SO_SNDBUFFORCE , & value , sizeof ( value ) ) < 0 )
if ( setsockopt ( fd , SOL_SOCKET , SO_SNDBUF , & value , sizeof ( value ) ) < 0 )
return - errno ;
return 1 ;
}
int fd_inc_rcvbuf ( int fd , size_t n ) {
int r , value ;
socklen_t l = sizeof ( value ) ;
r = getsockopt ( fd , SOL_SOCKET , SO_RCVBUF , & value , & l ) ;
if ( r > = 0 & & l = = sizeof ( value ) & & ( size_t ) value > = n * 2 )
return 0 ;
/* If we have the privileges we will ignore the kernel limit. */
value = ( int ) n ;
if ( setsockopt ( fd , SOL_SOCKET , SO_RCVBUFFORCE , & value , sizeof ( value ) ) < 0 )
if ( setsockopt ( fd , SOL_SOCKET , SO_RCVBUF , & value , sizeof ( value ) ) < 0 )
return - errno ;
return 1 ;
}
static const char * const ip_tos_table [ ] = {
[ IPTOS_LOWDELAY ] = " low-delay " ,
[ IPTOS_THROUGHPUT ] = " throughput " ,
[ IPTOS_RELIABILITY ] = " reliability " ,
[ IPTOS_LOWCOST ] = " low-cost " ,
} ;
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK ( ip_tos , int , 0xff ) ;
int getpeercred ( int fd , struct ucred * ucred ) {
socklen_t n = sizeof ( struct ucred ) ;
struct ucred u ;
int r ;
assert ( fd > = 0 ) ;
assert ( ucred ) ;
r = getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & u , & n ) ;
if ( r < 0 )
return - errno ;
if ( n ! = sizeof ( struct ucred ) )
return - EIO ;
/* Check if the data is actually useful and not suppressed due
* to namespacing issues */
if ( u . pid < = 0 )
return - ENODATA ;
if ( u . uid = = UID_INVALID )
return - ENODATA ;
if ( u . gid = = GID_INVALID )
return - ENODATA ;
* ucred = u ;
return 0 ;
}
int getpeersec ( int fd , char * * ret ) {
socklen_t n = 64 ;
char * s ;
int r ;
assert ( fd > = 0 ) ;
assert ( ret ) ;
s = new0 ( char , n ) ;
if ( ! s )
return - ENOMEM ;
r = getsockopt ( fd , SOL_SOCKET , SO_PEERSEC , s , & n ) ;
if ( r < 0 ) {
free ( s ) ;
if ( errno ! = ERANGE )
return - errno ;
s = new0 ( char , n ) ;
if ( ! s )
return - ENOMEM ;
r = getsockopt ( fd , SOL_SOCKET , SO_PEERSEC , s , & n ) ;
if ( r < 0 ) {
free ( s ) ;
return - errno ;
}
}
if ( isempty ( s ) ) {
free ( s ) ;
return - EOPNOTSUPP ;
}
* ret = s ;
return 0 ;
}
2015-12-03 10:20:39 +03:00
int send_one_fd_sa (
int transport_fd ,
int fd ,
const struct sockaddr * sa , socklen_t len ,
int flags ) {
2015-10-26 03:09:02 +03:00
union {
struct cmsghdr cmsghdr ;
uint8_t buf [ CMSG_SPACE ( sizeof ( int ) ) ] ;
} control = { } ;
struct msghdr mh = {
2015-12-03 10:20:39 +03:00
. msg_name = ( struct sockaddr * ) sa ,
. msg_namelen = len ,
2015-10-26 03:09:02 +03:00
. msg_control = & control ,
. msg_controllen = sizeof ( control ) ,
} ;
2016-02-08 23:16:08 +03:00
struct cmsghdr * cmsg ;
2015-10-26 03:09:02 +03:00
assert ( transport_fd > = 0 ) ;
assert ( fd > = 0 ) ;
cmsg = CMSG_FIRSTHDR ( & mh ) ;
cmsg - > cmsg_level = SOL_SOCKET ;
cmsg - > cmsg_type = SCM_RIGHTS ;
cmsg - > cmsg_len = CMSG_LEN ( sizeof ( int ) ) ;
memcpy ( CMSG_DATA ( cmsg ) , & fd , sizeof ( int ) ) ;
mh . msg_controllen = CMSG_SPACE ( sizeof ( int ) ) ;
if ( sendmsg ( transport_fd , & mh , MSG_NOSIGNAL | flags ) < 0 )
return - errno ;
return 0 ;
}
int receive_one_fd ( int transport_fd , int flags ) {
union {
struct cmsghdr cmsghdr ;
uint8_t buf [ CMSG_SPACE ( sizeof ( int ) ) ] ;
} control = { } ;
struct msghdr mh = {
. msg_control = & control ,
. msg_controllen = sizeof ( control ) ,
} ;
struct cmsghdr * cmsg , * found = NULL ;
assert ( transport_fd > = 0 ) ;
/*
* Receive a single FD via @ transport_fd . We don ' t care for
* the transport - type . We retrieve a single FD at most , so for
* packet - based transports , the caller must ensure to send
* only a single FD per packet . This is best used in
* combination with send_one_fd ( ) .
*/
if ( recvmsg ( transport_fd , & mh , MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags ) < 0 )
return - errno ;
CMSG_FOREACH ( cmsg , & mh ) {
if ( cmsg - > cmsg_level = = SOL_SOCKET & &
cmsg - > cmsg_type = = SCM_RIGHTS & &
cmsg - > cmsg_len = = CMSG_LEN ( sizeof ( int ) ) ) {
assert ( ! found ) ;
found = cmsg ;
break ;
}
}
if ( ! found ) {
cmsg_close_all ( & mh ) ;
return - EIO ;
}
return * ( int * ) CMSG_DATA ( found ) ;
}