2017-11-18 19:09:20 +03:00
/* SPDX-License-Identifier: LGPL-2.1+ */
2017-02-11 02:47:55 +03:00
2019-05-09 03:33:45 +03:00
# include <netinet/in.h>
2017-02-11 02:47:55 +03:00
# include <linux/if.h>
# include <unistd.h>
# include "fileio.h"
# include "netlink-util.h"
# include "networkd-ipv6-proxy-ndp.h"
# include "networkd-link.h"
# include "networkd-manager.h"
# include "networkd-network.h"
2017-12-13 07:47:10 +03:00
# include "socket-util.h"
2019-02-18 08:30:32 +03:00
# include "string-util.h"
# include "sysctl-util.h"
2017-02-11 02:47:55 +03:00
static bool ipv6_proxy_ndp_is_needed ( Link * link ) {
assert ( link ) ;
if ( link - > flags & IFF_LOOPBACK )
return false ;
if ( ! link - > network )
return false ;
2017-12-13 07:47:10 +03:00
if ( link - > network - > ipv6_proxy_ndp > = 0 )
2017-05-09 21:04:55 +03:00
return link - > network - > ipv6_proxy_ndp ;
2017-02-11 02:47:55 +03:00
if ( link - > network - > n_ipv6_proxy_ndp_addresses = = 0 )
return false ;
return true ;
}
static int ipv6_proxy_ndp_set ( Link * link ) {
2019-02-18 08:30:32 +03:00
bool v ;
int r ;
2017-02-11 02:47:55 +03:00
assert ( link ) ;
2017-12-13 07:47:10 +03:00
if ( ! socket_ipv6_is_supported ( ) )
return 0 ;
2017-02-11 02:47:55 +03:00
v = ipv6_proxy_ndp_is_needed ( link ) ;
2019-02-18 08:30:32 +03:00
r = sysctl_write_ip_property_boolean ( AF_INET6 , link - > ifname , " proxy_ndp " , v ) ;
2017-02-11 02:47:55 +03:00
if ( r < 0 )
log_link_warning_errno ( link , r , " Cannot configure proxy NDP for interface: %m " ) ;
return 0 ;
}
2019-03-01 07:19:53 +03:00
static int ipv6_proxy_ndp_address_new_static ( Network * network , IPv6ProxyNDPAddress * * ret ) {
2017-02-11 02:47:55 +03:00
_cleanup_ ( ipv6_proxy_ndp_address_freep ) IPv6ProxyNDPAddress * ipv6_proxy_ndp_address = NULL ;
assert ( network ) ;
assert ( ret ) ;
/* allocate space for IPv6ProxyNDPAddress entry */
2018-11-12 08:55:52 +03:00
ipv6_proxy_ndp_address = new ( IPv6ProxyNDPAddress , 1 ) ;
2017-02-11 02:47:55 +03:00
if ( ! ipv6_proxy_ndp_address )
return - ENOMEM ;
2018-11-12 08:55:52 +03:00
* ipv6_proxy_ndp_address = ( IPv6ProxyNDPAddress ) {
. network = network ,
} ;
2017-02-11 02:47:55 +03:00
LIST_PREPEND ( ipv6_proxy_ndp_addresses , network - > ipv6_proxy_ndp_addresses , ipv6_proxy_ndp_address ) ;
network - > n_ipv6_proxy_ndp_addresses + + ;
2018-11-12 08:55:52 +03:00
* ret = TAKE_PTR ( ipv6_proxy_ndp_address ) ;
2017-02-11 02:47:55 +03:00
return 0 ;
}
void ipv6_proxy_ndp_address_free ( IPv6ProxyNDPAddress * ipv6_proxy_ndp_address ) {
if ( ! ipv6_proxy_ndp_address )
return ;
if ( ipv6_proxy_ndp_address - > network ) {
LIST_REMOVE ( ipv6_proxy_ndp_addresses , ipv6_proxy_ndp_address - > network - > ipv6_proxy_ndp_addresses ,
ipv6_proxy_ndp_address ) ;
assert ( ipv6_proxy_ndp_address - > network - > n_ipv6_proxy_ndp_addresses > 0 ) ;
ipv6_proxy_ndp_address - > network - > n_ipv6_proxy_ndp_addresses - - ;
}
free ( ipv6_proxy_ndp_address ) ;
}
int config_parse_ipv6_proxy_ndp_address (
2018-11-01 21:14:07 +03:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2017-02-11 02:47:55 +03:00
Network * network = userdata ;
_cleanup_ ( ipv6_proxy_ndp_address_freep ) IPv6ProxyNDPAddress * ipv6_proxy_ndp_address = NULL ;
int r ;
union in_addr_union buffer ;
assert ( filename ) ;
assert ( section ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
r = ipv6_proxy_ndp_address_new_static ( network , & ipv6_proxy_ndp_address ) ;
if ( r < 0 )
return r ;
r = in_addr_from_string ( AF_INET6 , rvalue , & buffer ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse IPv6 proxy NDP address, ignoring: %s " ,
rvalue ) ;
return 0 ;
}
2019-02-03 01:08:10 +03:00
if ( in_addr_is_null ( AF_INET6 , & buffer ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
2018-02-08 12:34:52 +03:00
" IPv6 proxy NDP address cannot be the ANY address, ignoring: %s " , rvalue ) ;
2017-02-11 02:47:55 +03:00
return 0 ;
}
ipv6_proxy_ndp_address - > in_addr = buffer . in6 ;
ipv6_proxy_ndp_address = NULL ;
return 0 ;
}
2018-11-28 23:06:52 +03:00
static int set_ipv6_proxy_ndp_address_handler ( sd_netlink * rtnl , sd_netlink_message * m , Link * link ) {
2017-02-11 02:47:55 +03:00
int r ;
assert ( link ) ;
r = sd_netlink_message_get_errno ( m ) ;
if ( r < 0 & & r ! = - EEXIST )
log_link_error_errno ( link , r , " Could not add IPv6 proxy ndp address entry: %m " ) ;
return 1 ;
}
/* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
int ipv6_proxy_ndp_address_configure ( Link * link , IPv6ProxyNDPAddress * ipv6_proxy_ndp_address ) {
_cleanup_ ( sd_netlink_message_unrefp ) sd_netlink_message * req = NULL ;
sd_netlink * rtnl ;
int r ;
assert ( link ) ;
assert ( link - > network ) ;
assert ( link - > manager ) ;
assert ( ipv6_proxy_ndp_address ) ;
rtnl = link - > manager - > rtnl ;
/* create new netlink message */
r = sd_rtnl_message_new_neigh ( rtnl , & req , RTM_NEWNEIGH , link - > ifindex , AF_INET6 ) ;
if ( r < 0 )
return rtnl_log_create_error ( r ) ;
r = sd_rtnl_message_neigh_set_flags ( req , NLM_F_REQUEST | NTF_PROXY ) ;
if ( r < 0 )
return rtnl_log_create_error ( r ) ;
r = sd_netlink_message_append_in6_addr ( req , NDA_DST , & ipv6_proxy_ndp_address - > in_addr ) ;
if ( r < 0 )
return rtnl_log_create_error ( r ) ;
2018-11-28 23:06:52 +03:00
r = netlink_call_async ( rtnl , NULL , req , set_ipv6_proxy_ndp_address_handler ,
link_netlink_destroy_callback , link ) ;
2017-02-11 02:47:55 +03:00
if ( r < 0 )
return log_link_error_errno ( link , r , " Could not send rtnetlink message: %m " ) ;
2018-10-06 07:55:19 +03:00
link_ref ( link ) ;
2017-02-11 02:47:55 +03:00
return 0 ;
}
/* configure all ipv6 proxy ndp addresses */
int ipv6_proxy_ndp_addresses_configure ( Link * link ) {
IPv6ProxyNDPAddress * ipv6_proxy_ndp_address ;
int r ;
2017-12-13 07:47:10 +03:00
assert ( link ) ;
2017-02-11 02:47:55 +03:00
/* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
r = ipv6_proxy_ndp_set ( link ) ;
if ( r ! = 0 )
return r ;
LIST_FOREACH ( ipv6_proxy_ndp_addresses , ipv6_proxy_ndp_address , link - > network - > ipv6_proxy_ndp_addresses ) {
r = ipv6_proxy_ndp_address_configure ( link , ipv6_proxy_ndp_address ) ;
if ( r ! = 0 )
return r ;
}
return 0 ;
}