2011-05-09 16:57:15 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
2013-01-05 21:42:40 +04:00
This file is part of systemd .
2011-05-09 16:57:15 +04:00
Copyright 2008 - 2011 Lennart Poettering
2013-01-05 21:42:40 +04:00
systemd is free software ; you can redistribute it and / or modify it
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
( at your option ) any later version .
2011-05-09 16:57:15 +04:00
2013-01-05 21:42:40 +04:00
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
2011-05-09 16:57:15 +04:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
2013-01-05 21:42:40 +04:00
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
2011-05-09 16:57:15 +04:00
* * */
# include <sys/socket.h>
# include <sys/un.h>
# include <asm/types.h>
# include <inttypes.h>
# include <linux/netlink.h>
# include <linux/rtnetlink.h>
# include <string.h>
# include <assert.h>
# include <errno.h>
# include <limits.h>
# include <arpa/inet.h>
# include <unistd.h>
# include <inttypes.h>
# include <stdlib.h>
2011-06-15 18:49:24 +04:00
# include "ifconf.h"
2013-03-30 18:46:04 +04:00
# include "macro.h"
# include "util.h"
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
# define SEQ 4711
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
static int read_reply ( int fd , struct address * * list , unsigned * n_list ) {
ssize_t bytes ;
struct cmsghdr * cmsg ;
struct ucred * ucred ;
struct nlmsghdr * p ;
uint8_t cred_buffer [ CMSG_SPACE ( sizeof ( struct ucred ) ) ] ;
2011-05-09 16:57:15 +04:00
struct {
struct nlmsghdr hdr ;
2013-03-30 18:46:04 +04:00
struct ifaddrmsg ifaddrmsg ;
uint8_t payload [ 16 * 1024 ] ;
} resp ;
struct iovec iov = {
. iov_base = & resp ,
. iov_len = sizeof ( resp ) ,
} ;
struct msghdr msg = {
. msg_name = NULL ,
. msg_namelen = 0 ,
. msg_iov = & iov ,
. msg_iovlen = 1 ,
. msg_control = cred_buffer ,
. msg_controllen = sizeof ( cred_buffer ) ,
. msg_flags = 0 ,
} ;
assert ( fd > = 0 ) ;
assert ( list ) ;
bytes = recvmsg ( fd , & msg , 0 ) ;
if ( bytes < 0 )
2011-05-09 16:57:15 +04:00
return - errno ;
2013-03-30 18:46:04 +04:00
cmsg = CMSG_FIRSTHDR ( & msg ) ;
if ( ! cmsg | | cmsg - > cmsg_type ! = SCM_CREDENTIALS )
return - EIO ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
ucred = ( struct ucred * ) CMSG_DATA ( cmsg ) ;
if ( ucred - > uid ! = 0 | | ucred - > pid ! = 0 )
return 0 ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
for ( p = & resp . hdr ; bytes > 0 ; p = NLMSG_NEXT ( p , bytes ) ) {
struct ifaddrmsg * ifaddrmsg ;
struct rtattr * a ;
size_t l ;
void * local = NULL , * address = NULL ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( ! NLMSG_OK ( p , ( size_t ) bytes ) )
return - EIO ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( p - > nlmsg_seq ! = SEQ )
continue ;
if ( p - > nlmsg_type = = NLMSG_DONE )
return 1 ;
if ( p - > nlmsg_type = = NLMSG_ERROR ) {
struct nlmsgerr * nlmsgerr ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
nlmsgerr = NLMSG_DATA ( p ) ;
return - nlmsgerr - > error ;
2011-05-09 16:57:15 +04:00
}
2013-03-30 18:46:04 +04:00
if ( p - > nlmsg_type ! = RTM_NEWADDR )
2011-05-09 16:57:15 +04:00
continue ;
2013-03-30 18:46:04 +04:00
ifaddrmsg = NLMSG_DATA ( p ) ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( ifaddrmsg - > ifa_family ! = AF_INET & &
ifaddrmsg - > ifa_family ! = AF_INET6 )
continue ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( ifaddrmsg - > ifa_scope = = RT_SCOPE_HOST | |
ifaddrmsg - > ifa_scope = = RT_SCOPE_NOWHERE )
continue ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( ifaddrmsg - > ifa_flags & IFA_F_DEPRECATED )
continue ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
l = NLMSG_PAYLOAD ( p , sizeof ( struct ifaddrmsg ) ) ;
a = IFA_RTA ( ifaddrmsg ) ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
while ( RTA_OK ( a , l ) ) {
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( a - > rta_type = = IFA_ADDRESS )
address = RTA_DATA ( a ) ;
else if ( a - > rta_type = = IFA_LOCAL )
local = RTA_DATA ( a ) ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
a = RTA_NEXT ( a , l ) ;
}
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( local )
address = local ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( ! address )
continue ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
* list = realloc ( * list , ( * n_list + 1 ) * sizeof ( struct address ) ) ;
if ( ! * list )
return - ENOMEM ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
( * list ) [ * n_list ] . family = ifaddrmsg - > ifa_family ;
( * list ) [ * n_list ] . scope = ifaddrmsg - > ifa_scope ;
memcpy ( ( * list ) [ * n_list ] . address ,
address , ifaddrmsg - > ifa_family = = AF_INET ? 4 : 16 ) ;
( * list ) [ * n_list ] . ifindex = ifaddrmsg - > ifa_index ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
( * n_list ) + + ;
}
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
return 0 ;
}
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
int ifconf_acquire_addresses ( struct address * * _list , unsigned * _n_list ) {
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
struct {
struct nlmsghdr hdr ;
struct rtgenmsg gen ;
} req = { {
. nlmsg_len = NLMSG_LENGTH ( sizeof ( struct rtgenmsg ) ) ,
. nlmsg_type = RTM_GETADDR ,
. nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ACK ,
. nlmsg_seq = SEQ ,
. nlmsg_pid = 0 ,
} , {
. rtgen_family = AF_UNSPEC ,
}
} ;
int r , on = 1 ;
struct address * list = NULL ;
unsigned n_list = 0 ;
int _cleanup_close_ fd ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
fd = socket ( PF_NETLINK , SOCK_DGRAM , NETLINK_ROUTE ) ;
if ( fd < 0 )
return - errno ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( setsockopt ( fd , SOL_SOCKET , SO_PASSCRED , & on , sizeof ( on ) ) < 0 )
return - errno ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( send ( fd , & req , req . hdr . nlmsg_len , 0 ) < 0 )
return - errno ;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
while ( ( r = read_reply ( fd , & list , & n_list ) ) = = 0 )
;
2011-05-09 16:57:15 +04:00
2013-03-30 18:46:04 +04:00
if ( r < 0 ) {
2011-05-09 16:57:15 +04:00
free ( list ) ;
2013-03-30 18:46:04 +04:00
return r ;
2011-05-09 16:57:15 +04:00
}
2013-03-30 18:46:04 +04:00
assert ( n_list = = 0 | | list ) ;
qsort ( list , n_list , sizeof ( struct address ) , address_compare ) ;
* _list = list ;
* _n_list = n_list ;
return 0 ;
2011-05-09 16:57:15 +04:00
}