2014-10-29 09:12:18 -05:00
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* 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 2 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 , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Copyright ( C ) 2014 Red Hat , Inc .
*/
2016-02-19 14:57:48 +01:00
# include "nm-default.h"
2014-11-13 10:07:02 -05:00
2014-10-29 09:12:18 -05:00
# include <glib-unix.h>
# include <getopt.h>
# include <locale.h>
# include <errno.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <string.h>
# include <sys/resource.h>
# include <sys/stat.h>
# include <signal.h>
2016-03-11 10:25:40 +01:00
# include "main-utils.h"
2014-10-29 09:12:18 -05:00
# include "NetworkManagerUtils.h"
2016-11-21 00:43:52 +01:00
# include "platform/nm-linux-platform.h"
2016-12-26 12:00:08 +01:00
# include "platform/nm-platform-utils.h"
2016-11-21 00:43:52 +01:00
# include "dhcp/nm-dhcp-manager.h"
# include "ndisc/nm-ndisc.h"
# include "ndisc/nm-lndp-ndisc.h"
2014-10-29 09:12:18 -05:00
# include "nm-utils.h"
2015-10-03 19:44:27 +02:00
# include "nm-setting-ip6-config.h"
2016-09-27 13:35:29 +02:00
# include "systemd/nm-sd.h"
2014-10-29 09:12:18 -05:00
# if !defined(NM_DIST_VERSION)
# define NM_DIST_VERSION VERSION
# endif
# define NMIH_PID_FILE_FMT NMRUNDIR " / nm-iface-helper-%d.pid"
2016-10-05 12:04:24 +02:00
/*****************************************************************************/
static struct {
GMainLoop * main_loop ;
int ifindex ;
} gl /*obal*/ = {
. ifindex = - 1 ,
} ;
2014-10-29 09:12:18 -05:00
2015-03-13 19:59:32 +01:00
static struct {
gboolean slaac ;
gboolean show_version ;
gboolean become_daemon ;
gboolean debug ;
gboolean g_fatal_warnings ;
gboolean slaac_required ;
gboolean dhcp4_required ;
int tempaddr ;
char * ifname ;
char * uuid ;
2016-06-21 18:07:56 +02:00
char * stable_id ;
2015-03-13 19:59:32 +01:00
char * dhcp4_address ;
char * dhcp4_clientid ;
char * dhcp4_hostname ;
2015-10-13 15:13:26 +02:00
char * dhcp4_fqdn ;
2015-03-13 19:59:32 +01:00
char * iid_str ;
2015-10-03 19:44:27 +02:00
NMSettingIP6ConfigAddrGenMode addr_gen_mode ;
2015-07-08 19:34:34 +02:00
char * logging_backend ;
2015-03-13 19:59:32 +01:00
char * opt_log_level ;
char * opt_log_domains ;
2015-03-13 20:09:46 +01:00
guint32 priority_v4 ;
guint32 priority_v6 ;
2015-03-13 19:59:32 +01:00
} global_opt = {
. tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN ,
2015-03-13 20:09:46 +01:00
. priority_v4 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 ,
. priority_v6 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 ,
2015-03-13 19:59:32 +01:00
} ;
2016-10-05 12:04:24 +02:00
/*****************************************************************************/
2016-10-05 12:04:46 +02:00
# define _NMLOG_PREFIX_NAME "nm-iface-helper"
# define _NMLOG(level, domain, ...) \
2017-03-02 21:17:22 +01:00
nm_log ( ( level ) , ( domain ) , global_opt . ifname , NULL , \
2016-10-05 15:34:06 +02:00
" iface-helper: " _NM_UTILS_MACRO_FIRST ( __VA_ARGS__ ) \
2016-10-05 12:04:46 +02:00
_NM_UTILS_MACRO_REST ( __VA_ARGS__ ) )
/*****************************************************************************/
2014-10-29 09:12:18 -05:00
static void
dhcp4_state_changed ( NMDhcpClient * client ,
NMDhcpState state ,
NMIP4Config * ip4_config ,
GHashTable * options ,
2015-08-04 11:30:03 +02:00
const char * event_id ,
2014-10-29 09:12:18 -05:00
gpointer user_data )
{
static NMIP4Config * last_config = NULL ;
NMIP4Config * existing ;
2017-09-12 13:45:53 +02:00
gs_unref_ptrarray GPtrArray * ip4_dev_route_blacklist = NULL ;
2014-10-29 09:12:18 -05:00
g_return_if_fail ( ! ip4_config | | NM_IS_IP4_CONFIG ( ip4_config ) ) ;
2016-10-05 12:04:46 +02:00
_LOGD ( LOGD_DHCP4 , " new DHCPv4 client state %d " , state ) ;
2014-10-29 09:12:18 -05:00
switch ( state ) {
case NM_DHCP_STATE_BOUND :
g_assert ( ip4_config ) ;
platform: add non-exclusive routes and drop route-manager
Previously, we would add exclusive routes via netlink message flags
NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`.
Using that form of RTM_NEWROUTE message, we could only add a certain
route with a certain network/plen,metric triple once. That was already
hugely inconvenient, because
- when configuring routes, multiple (managed) interfaces may get
conflicting routes (multihoming). Only one of the routes can be actually
configured using `ip route replace`, so we need to track routes that are
currently shadowed.
- when configuring routes, we might replace externally configured
routes on unmanaged interfaces. We should not interfere with such
routes.
That was worked around by having NMRouteManager (and NMDefaultRouteManager).
NMRouteManager would keep a list of the routes which NetworkManager would like
to configure, even if momentarily being unable to do so due to conflicting routes.
This worked mostly well but was complicated. It involved bumping metrics to
avoid conflicts for device routes, as we might require them for gateway routes.
Drop that now. Instead, use the corresponding of `ip route append` to configure
routes. This allows NetworkManager to confiure (almost) all routes that we care.
Especially, it can configure all routes on a managed interface, without
replacing/interfering with routes on other interfaces. Hence, NMRouteManager
becomes obsolete.
It practice it is a bit more complicated because:
- when adding an IPv4 address, kernel will automatically create a device route
for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for
IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4
addresses yet (and we don't require such a kernel yet), we still need functionality
similar to nm_route_manager_ip4_route_register_device_route_purge_list().
This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set().
- trying to configure an IPv6 route with a source address will be rejected
by kernel as long as the address is tentative (see related bug rh#1457196).
Preferably, NMDevice would keep the list of routes which should be configured,
while kernel would have the list of what actually is configured. There is a
feed-back loop where both affect each other (for example, when externally deleting
a route, NMDevice must forget about it too). Previously, NMRouteManager would have
the task of remembering all routes which we currently want to configure, but cannot
due to conflicting routes.
We get rid of that, because now we configure non-exclusive routes. We however still
will need to remember IPv6 routes with a source address, that currently cannot be
configured yet. Hence, we will need to keep track of routes that
currently cannot be configured, but later may be.
That is still not done yet, as NMRouteManager didn't handle this
correctly either.
2017-08-14 14:18:53 +02:00
g_assert ( nm_ip4_config_get_ifindex ( ip4_config ) = = gl . ifindex ) ;
core: pass NMDedupMultiIndex instance to NMIP4Config and other
NMIP4Config, NMIP6Config, and NMPlatform shall share one
NMDedupMultiIndex instance.
For that, pass an NMDedupMultiIndex instance to NMPlatform and NMNetns.
NMNetns than passes it on to NMDevice, NMDhcpClient, NMIP4Config and NMIP6Config.
So currently NMNetns is the access point to the shared NMDedupMultiIndex
instance, and it gets it from it's NMPlatform instance.
The NMDedupMultiIndex instance is really a singleton, we don't want
multiple instances of it. However, for testing, instead of adding a
singleton instance, pass the instance explicitly around.
2017-06-12 08:16:47 +02:00
existing = nm_ip4_config_capture ( nm_platform_get_multi_idx ( NM_PLATFORM_GET ) ,
NM_PLATFORM_GET , gl . ifindex , FALSE ) ;
2014-10-29 09:12:18 -05:00
if ( last_config )
nm_ip4_config_subtract ( existing , last_config ) ;
2015-08-05 10:01:39 +02:00
nm_ip4_config_merge ( existing , ip4_config , NM_IP_CONFIG_MERGE_DEFAULT ) ;
2017-09-12 13:45:53 +02:00
nm_ip4_config_add_device_routes ( existing ,
global_opt . priority_v4 ,
& ip4_dev_route_blacklist ) ;
platform: add non-exclusive routes and drop route-manager
Previously, we would add exclusive routes via netlink message flags
NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`.
Using that form of RTM_NEWROUTE message, we could only add a certain
route with a certain network/plen,metric triple once. That was already
hugely inconvenient, because
- when configuring routes, multiple (managed) interfaces may get
conflicting routes (multihoming). Only one of the routes can be actually
configured using `ip route replace`, so we need to track routes that are
currently shadowed.
- when configuring routes, we might replace externally configured
routes on unmanaged interfaces. We should not interfere with such
routes.
That was worked around by having NMRouteManager (and NMDefaultRouteManager).
NMRouteManager would keep a list of the routes which NetworkManager would like
to configure, even if momentarily being unable to do so due to conflicting routes.
This worked mostly well but was complicated. It involved bumping metrics to
avoid conflicts for device routes, as we might require them for gateway routes.
Drop that now. Instead, use the corresponding of `ip route append` to configure
routes. This allows NetworkManager to confiure (almost) all routes that we care.
Especially, it can configure all routes on a managed interface, without
replacing/interfering with routes on other interfaces. Hence, NMRouteManager
becomes obsolete.
It practice it is a bit more complicated because:
- when adding an IPv4 address, kernel will automatically create a device route
for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for
IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4
addresses yet (and we don't require such a kernel yet), we still need functionality
similar to nm_route_manager_ip4_route_register_device_route_purge_list().
This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set().
- trying to configure an IPv6 route with a source address will be rejected
by kernel as long as the address is tentative (see related bug rh#1457196).
Preferably, NMDevice would keep the list of routes which should be configured,
while kernel would have the list of what actually is configured. There is a
feed-back loop where both affect each other (for example, when externally deleting
a route, NMDevice must forget about it too). Previously, NMRouteManager would have
the task of remembering all routes which we currently want to configure, but cannot
due to conflicting routes.
We get rid of that, because now we configure non-exclusive routes. We however still
will need to remember IPv6 routes with a source address, that currently cannot be
configured yet. Hence, we will need to keep track of routes that
currently cannot be configured, but later may be.
That is still not done yet, as NMRouteManager didn't handle this
correctly either.
2017-08-14 14:18:53 +02:00
if ( ! nm_ip4_config_commit ( existing ,
2017-09-12 13:45:53 +02:00
NM_PLATFORM_GET ) )
2016-10-05 12:04:46 +02:00
_LOGW ( LOGD_DHCP4 , " failed to apply DHCPv4 config " ) ;
2014-10-29 09:12:18 -05:00
2017-09-12 13:45:53 +02:00
nm_platform_ip4_dev_route_blacklist_set ( NM_PLATFORM_GET ,
gl . ifindex ,
ip4_dev_route_blacklist ) ;
2015-04-24 22:38:21 -04:00
if ( last_config )
2014-10-29 09:12:18 -05:00
g_object_unref ( last_config ) ;
core: pass NMDedupMultiIndex instance to NMIP4Config and other
NMIP4Config, NMIP6Config, and NMPlatform shall share one
NMDedupMultiIndex instance.
For that, pass an NMDedupMultiIndex instance to NMPlatform and NMNetns.
NMNetns than passes it on to NMDevice, NMDhcpClient, NMIP4Config and NMIP6Config.
So currently NMNetns is the access point to the shared NMDedupMultiIndex
instance, and it gets it from it's NMPlatform instance.
The NMDedupMultiIndex instance is really a singleton, we don't want
multiple instances of it. However, for testing, instead of adding a
singleton instance, pass the instance explicitly around.
2017-06-12 08:16:47 +02:00
last_config = nm_ip4_config_new ( nm_platform_get_multi_idx ( NM_PLATFORM_GET ) ,
nm_dhcp_client_get_ifindex ( client ) ) ;
2015-04-24 22:38:21 -04:00
nm_ip4_config_replace ( last_config , ip4_config , NULL ) ;
2014-10-29 09:12:18 -05:00
break ;
case NM_DHCP_STATE_TIMEOUT :
case NM_DHCP_STATE_DONE :
case NM_DHCP_STATE_FAIL :
2015-03-13 19:59:32 +01:00
if ( global_opt . dhcp4_required ) {
2016-10-05 12:04:46 +02:00
_LOGW ( LOGD_DHCP4 , " DHCPv4 timed out or failed, quitting... " ) ;
2016-10-05 12:04:24 +02:00
g_main_loop_quit ( gl . main_loop ) ;
2014-10-29 09:12:18 -05:00
} else
2016-10-05 12:04:46 +02:00
_LOGW ( LOGD_DHCP4 , " DHCPv4 timed out or failed " ) ;
2014-10-29 09:12:18 -05:00
break ;
default :
break ;
}
}
static void
2016-10-13 11:06:25 +00:00
ndisc_config_changed ( NMNDisc * ndisc , const NMNDiscData * rdata , guint changed_int , gpointer user_data )
2014-10-29 09:12:18 -05:00
{
2016-10-13 11:06:25 +00:00
NMNDiscConfigMap changed = changed_int ;
static NMIP6Config * ndisc_config = NULL ;
2014-10-29 09:12:18 -05:00
NMIP6Config * existing ;
core: pass NMDedupMultiIndex instance to NMIP4Config and other
NMIP4Config, NMIP6Config, and NMPlatform shall share one
NMDedupMultiIndex instance.
For that, pass an NMDedupMultiIndex instance to NMPlatform and NMNetns.
NMNetns than passes it on to NMDevice, NMDhcpClient, NMIP4Config and NMIP6Config.
So currently NMNetns is the access point to the shared NMDedupMultiIndex
instance, and it gets it from it's NMPlatform instance.
The NMDedupMultiIndex instance is really a singleton, we don't want
multiple instances of it. However, for testing, instead of adding a
singleton instance, pass the instance explicitly around.
2017-06-12 08:16:47 +02:00
existing = nm_ip6_config_capture ( nm_platform_get_multi_idx ( NM_PLATFORM_GET ) ,
NM_PLATFORM_GET , gl . ifindex , FALSE , global_opt . tempaddr ) ;
2016-10-13 11:06:25 +00:00
if ( ndisc_config )
nm_ip6_config_subtract ( existing , ndisc_config ) ;
core: pass NMDedupMultiIndex instance to NMIP4Config and other
NMIP4Config, NMIP6Config, and NMPlatform shall share one
NMDedupMultiIndex instance.
For that, pass an NMDedupMultiIndex instance to NMPlatform and NMNetns.
NMNetns than passes it on to NMDevice, NMDhcpClient, NMIP4Config and NMIP6Config.
So currently NMNetns is the access point to the shared NMDedupMultiIndex
instance, and it gets it from it's NMPlatform instance.
The NMDedupMultiIndex instance is really a singleton, we don't want
multiple instances of it. However, for testing, instead of adding a
singleton instance, pass the instance explicitly around.
2017-06-12 08:16:47 +02:00
else {
ndisc_config = nm_ip6_config_new ( nm_platform_get_multi_idx ( NM_PLATFORM_GET ) ,
gl . ifindex ) ;
}
2014-10-29 09:12:18 -05:00
2016-10-13 11:06:25 +00:00
if ( changed & NM_NDISC_CONFIG_GATEWAYS ) {
/* Use the first gateway as ordered in neighbor discovery cache. */
2016-07-07 13:25:38 +02:00
if ( rdata - > gateways_n )
2016-10-13 11:06:25 +00:00
nm_ip6_config_set_gateway ( ndisc_config , & rdata - > gateways [ 0 ] . address ) ;
2016-07-07 13:25:38 +02:00
else
2016-10-13 11:06:25 +00:00
nm_ip6_config_set_gateway ( ndisc_config , NULL ) ;
2014-10-29 09:12:18 -05:00
}
2016-10-13 11:06:25 +00:00
if ( changed & NM_NDISC_CONFIG_ADDRESSES ) {
2017-08-16 14:50:01 +02:00
guint8 plen ;
guint32 ifa_flags ;
/* Check, whether kernel is recent enough to help user space handling RA.
* If it ' s not supported , we have no ipv6 - privacy and must add autoconf
* addresses as / 128. The reason for the / 128 is to prevent the kernel
* from adding a prefix route for this address . */
ifa_flags = 0 ;
if ( nm_platform_check_support_kernel_extended_ifa_flags ( NM_PLATFORM_GET ) ) {
ifa_flags | = IFA_F_NOPREFIXROUTE ;
if ( NM_IN_SET ( global_opt . tempaddr , NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR ,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR ) )
ifa_flags | = IFA_F_MANAGETEMPADDR ;
plen = 64 ;
} else
plen = 128 ;
2017-08-16 13:57:01 +02:00
nm_ip6_config_reset_addresses_ndisc ( ndisc_config ,
rdata - > addresses ,
rdata - > addresses_n ,
2017-08-16 14:50:01 +02:00
plen ,
2017-08-16 13:57:01 +02:00
ifa_flags ) ;
2014-10-29 09:12:18 -05:00
}
2016-10-13 11:06:25 +00:00
if ( changed & NM_NDISC_CONFIG_ROUTES ) {
2017-08-16 13:57:01 +02:00
nm_ip6_config_reset_routes_ndisc ( ndisc_config ,
rdata - > routes ,
rdata - > routes_n ,
global_opt . priority_v6 ) ;
2014-10-29 09:12:18 -05:00
}
2016-10-13 11:06:25 +00:00
if ( changed & NM_NDISC_CONFIG_DHCP_LEVEL ) {
2014-10-29 09:12:18 -05:00
/* Unsupported until systemd DHCPv6 is ready */
}
2016-10-13 11:06:25 +00:00
if ( changed & NM_NDISC_CONFIG_HOP_LIMIT )
2016-07-07 13:25:38 +02:00
nm_platform_sysctl_set_ip6_hop_limit_safe ( NM_PLATFORM_GET , global_opt . ifname , rdata - > hop_limit ) ;
2014-10-29 09:12:18 -05:00
2016-10-13 11:06:25 +00:00
if ( changed & NM_NDISC_CONFIG_MTU ) {
2014-10-29 09:12:18 -05:00
char val [ 16 ] ;
2016-07-07 13:25:38 +02:00
g_snprintf ( val , sizeof ( val ) , " %d " , rdata - > mtu ) ;
2016-12-08 14:29:00 +01:00
nm_platform_sysctl_set ( NM_PLATFORM_GET , NMP_SYSCTL_PATHID_ABSOLUTE ( nm_utils_ip6_property_path ( global_opt . ifname , " mtu " ) ) , val ) ;
2014-10-29 09:12:18 -05:00
}
2016-10-13 11:06:25 +00:00
nm_ip6_config_merge ( existing , ndisc_config , NM_IP_CONFIG_MERGE_DEFAULT ) ;
2017-09-19 09:40:13 +02:00
nm_ip6_config_add_device_routes ( existing ,
global_opt . priority_v6 ) ;
2017-09-13 16:45:22 +02:00
if ( ! nm_ip6_config_commit ( existing , NM_PLATFORM_GET , NULL ) )
2016-10-05 12:04:46 +02:00
_LOGW ( LOGD_IP6 , " failed to apply IPv6 config " ) ;
2014-10-29 09:12:18 -05:00
}
static void
2016-10-13 11:06:25 +00:00
ndisc_ra_timeout ( NMNDisc * ndisc , gpointer user_data )
2014-10-29 09:12:18 -05:00
{
2015-03-13 19:59:32 +01:00
if ( global_opt . slaac_required ) {
2016-10-05 12:04:46 +02:00
_LOGW ( LOGD_IP6 , " IPv6 timed out or failed, quitting... " ) ;
2016-10-05 12:04:24 +02:00
g_main_loop_quit ( gl . main_loop ) ;
2014-10-29 09:12:18 -05:00
} else
2016-10-05 12:04:46 +02:00
_LOGW ( LOGD_IP6 , " IPv6 timed out or failed " ) ;
2014-10-29 09:12:18 -05:00
}
static gboolean
quit_handler ( gpointer user_data )
{
2016-10-05 12:04:24 +02:00
g_main_loop_quit ( gl . main_loop ) ;
2015-01-12 11:36:26 -05:00
return G_SOURCE_REMOVE ;
2014-10-29 09:12:18 -05:00
}
static void
2015-01-12 11:36:26 -05:00
setup_signals ( void )
2014-10-29 09:12:18 -05:00
{
signal ( SIGPIPE , SIG_IGN ) ;
2015-01-12 11:36:26 -05:00
g_unix_signal_add ( SIGINT , quit_handler , NULL ) ;
g_unix_signal_add ( SIGTERM , quit_handler , NULL ) ;
2014-10-29 09:12:18 -05:00
}
2016-10-05 15:07:46 +02:00
static gboolean
2015-03-13 20:09:46 +01:00
do_early_setup ( int * argc , char * * argv [ ] )
2014-10-29 09:12:18 -05:00
{
2015-03-13 20:09:46 +01:00
gint64 priority64_v4 = - 1 ;
gint64 priority64_v6 = - 1 ;
2014-10-29 09:12:18 -05:00
GOptionEntry options [ ] = {
/* Interface/IP config */
2016-06-21 18:07:56 +02:00
{ " ifname " , ' i ' , 0 , G_OPTION_ARG_STRING , & global_opt . ifname , N_ ( " The interface to manage " ) , " eth0 " } ,
{ " uuid " , ' u ' , 0 , G_OPTION_ARG_STRING , & global_opt . uuid , N_ ( " Connection UUID " ) , " 661e8cd0-b618-46b8-9dc9-31a52baaa16b " } ,
{ " stable-id " , ' \0 ' , 0 , G_OPTION_ARG_STRING , & global_opt . stable_id , N_ ( " Connection Token for Stable IDs " ) , " eth " } ,
2015-03-13 19:59:32 +01:00
{ " slaac " , ' s ' , 0 , G_OPTION_ARG_NONE , & global_opt . slaac , N_ ( " Whether to manage IPv6 SLAAC " ) , NULL } ,
{ " slaac-required " , ' 6 ' , 0 , G_OPTION_ARG_NONE , & global_opt . slaac_required , N_ ( " Whether SLAAC must be successful " ) , NULL } ,
{ " slaac-tempaddr " , ' t ' , 0 , G_OPTION_ARG_INT , & global_opt . tempaddr , N_ ( " Use an IPv6 temporary privacy address " ) , NULL } ,
{ " dhcp4 " , ' d ' , 0 , G_OPTION_ARG_STRING , & global_opt . dhcp4_address , N_ ( " Current DHCPv4 address " ) , NULL } ,
{ " dhcp4-required " , ' 4 ' , 0 , G_OPTION_ARG_NONE , & global_opt . dhcp4_required , N_ ( " Whether DHCPv4 must be successful " ) , NULL } ,
{ " dhcp4-clientid " , ' c ' , 0 , G_OPTION_ARG_STRING , & global_opt . dhcp4_clientid , N_ ( " Hex-encoded DHCPv4 client ID " ) , NULL } ,
{ " dhcp4-hostname " , ' h ' , 0 , G_OPTION_ARG_STRING , & global_opt . dhcp4_hostname , N_ ( " Hostname to send to DHCP server " ) , N_ ( " barbar " ) } ,
2015-10-13 15:13:26 +02:00
{ " dhcp4-fqdn " , ' F ' , 0 , G_OPTION_ARG_STRING , & global_opt . dhcp4_fqdn , N_ ( " FQDN to send to DHCP server " ) , N_ ( " host.domain.org " ) } ,
2015-03-13 20:09:46 +01:00
{ " priority4 " , ' \0 ' , 0 , G_OPTION_ARG_INT64 , & priority64_v4 , N_ ( " Route priority for IPv4 " ) , N_ ( " 0 " ) } ,
{ " priority6 " , ' \0 ' , 0 , G_OPTION_ARG_INT64 , & priority64_v6 , N_ ( " Route priority for IPv6 " ) , N_ ( " 1024 " ) } ,
2015-05-04 19:10:29 +03:00
{ " iid " , ' e ' , 0 , G_OPTION_ARG_STRING , & global_opt . iid_str , N_ ( " Hex-encoded Interface Identifier " ) , " " } ,
2015-10-03 19:44:27 +02:00
{ " addr-gen-mode " , ' e ' , 0 , G_OPTION_ARG_INT , & global_opt . addr_gen_mode , N_ ( " IPv6 SLAAC address generation mode " ) , " eui64 " } ,
2015-07-08 19:34:34 +02:00
{ " logging-backend " , ' \0 ' , 0 , G_OPTION_ARG_STRING , & global_opt . logging_backend , N_ ( " The logging backend configuration value. See logging.backend in NetworkManager.conf " ) , NULL } ,
2014-10-29 09:12:18 -05:00
/* Logging/debugging */
2015-03-13 19:59:32 +01:00
{ " version " , ' V ' , 0 , G_OPTION_ARG_NONE , & global_opt . show_version , N_ ( " Print NetworkManager version and exit " ) , NULL } ,
{ " no-daemon " , ' n ' , G_OPTION_FLAG_REVERSE , G_OPTION_ARG_NONE , & global_opt . become_daemon , N_ ( " Don't become a daemon " ) , NULL } ,
{ " debug " , ' b ' , 0 , G_OPTION_ARG_NONE , & global_opt . debug , N_ ( " Don't become a daemon, and log to stderr " ) , NULL } ,
{ " log-level " , 0 , 0 , G_OPTION_ARG_STRING , & global_opt . opt_log_level , N_ ( " Log level: one of [%s] " ) , " INFO " } ,
{ " log-domains " , 0 , 0 , G_OPTION_ARG_STRING , & global_opt . opt_log_domains ,
2014-10-29 09:12:18 -05:00
N_ ( " Log domains separated by ',': any combination of [%s] " ) ,
" PLATFORM,RFKILL,WIFI " } ,
2015-03-13 19:59:32 +01:00
{ " g-fatal-warnings " , 0 , 0 , G_OPTION_ARG_NONE , & global_opt . g_fatal_warnings , N_ ( " Make all warnings fatal " ) , NULL } ,
2014-10-29 09:12:18 -05:00
{ NULL }
} ;
if ( ! nm_main_utils_early_setup ( " nm-iface-helper " ,
2015-03-13 20:09:46 +01:00
argc ,
argv ,
2014-10-29 09:12:18 -05:00
options ,
NULL ,
2014-07-09 15:17:01 +02:00
NULL ,
2014-10-29 09:12:18 -05:00
_ ( " nm-iface-helper is a small, standalone process that manages a single network interface. " ) ) )
2016-10-05 15:07:46 +02:00
return FALSE ;
2014-10-29 09:12:18 -05:00
2015-03-13 20:09:46 +01:00
if ( priority64_v4 > = 0 & & priority64_v4 < = G_MAXUINT32 )
global_opt . priority_v4 = ( guint32 ) priority64_v4 ;
if ( priority64_v6 > = 0 & & priority64_v6 < = G_MAXUINT32 )
global_opt . priority_v6 = ( guint32 ) priority64_v6 ;
2016-10-05 15:07:46 +02:00
return TRUE ;
2015-03-13 20:09:46 +01:00
}
2015-10-03 19:50:30 +02:00
static void
ip6_address_changed ( NMPlatform * platform ,
2016-10-22 13:08:36 +02:00
int obj_type_i ,
2015-10-03 19:50:30 +02:00
int iface ,
NMPlatformIP6Address * addr ,
2016-10-22 13:08:36 +02:00
int change_type_i ,
2016-10-13 11:06:25 +00:00
NMNDisc * ndisc )
2015-10-03 19:50:30 +02:00
{
2016-10-22 13:08:36 +02:00
const NMPlatformSignalChangeType change_type = change_type_i ;
2016-02-29 16:23:16 +01:00
if ( ( change_type = = NM_PLATFORM_SIGNAL_CHANGED & & addr - > n_ifa_flags & IFA_F_DADFAILED )
| | ( change_type = = NM_PLATFORM_SIGNAL_REMOVED & & addr - > n_ifa_flags & IFA_F_TENTATIVE ) )
2016-10-13 11:06:25 +00:00
nm_ndisc_dad_failed ( ndisc , & addr - > address ) ;
2015-10-03 19:50:30 +02:00
}
2015-03-13 20:09:46 +01:00
int
main ( int argc , char * argv [ ] )
{
char * bad_domains = NULL ;
GError * error = NULL ;
gboolean wrote_pidfile = FALSE ;
gs_free char * pidfile = NULL ;
gs_unref_object NMDhcpClient * dhcp4_client = NULL ;
2016-10-13 11:06:25 +00:00
gs_unref_object NMNDisc * ndisc = NULL ;
2015-03-13 20:09:46 +01:00
GByteArray * hwaddr = NULL ;
size_t hwaddr_len = 0 ;
gconstpointer tmp ;
gs_free NMUtilsIPv6IfaceId * iid = NULL ;
2016-03-09 12:27:56 +01:00
guint sd_id ;
2015-03-13 20:09:46 +01:00
2014-07-10 10:41:31 +02:00
nm_g_type_init ( ) ;
2015-03-13 20:09:46 +01:00
setpgid ( getpid ( ) , getpid ( ) ) ;
2016-10-05 15:07:46 +02:00
if ( ! do_early_setup ( & argc , & argv ) )
return 1 ;
2015-03-13 20:09:46 +01:00
2016-10-05 17:10:42 +02:00
nm_logging_set_syslog_identifier ( " nm-iface-helper " ) ;
2016-10-05 15:34:06 +02:00
nm_logging_set_prefix ( " %s[%ld] (%s): " ,
_NMLOG_PREFIX_NAME ,
( long ) getpid ( ) ,
global_opt . ifname ? : " ??? " ) ;
2015-03-13 23:24:05 +01:00
if ( global_opt . g_fatal_warnings ) {
GLogLevelFlags fatal_mask ;
fatal_mask = g_log_set_always_fatal ( G_LOG_FATAL_MASK ) ;
fatal_mask | = G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL ;
g_log_set_always_fatal ( fatal_mask ) ;
}
2015-03-13 19:59:32 +01:00
if ( global_opt . show_version ) {
2014-10-29 09:12:18 -05:00
fprintf ( stdout , NM_DIST_VERSION " \n " ) ;
2016-10-05 15:07:46 +02:00
return 0 ;
2014-10-29 09:12:18 -05:00
}
2015-03-13 20:57:18 +01:00
nm_main_utils_ensure_root ( ) ;
2015-03-13 19:59:32 +01:00
if ( ! global_opt . ifname | | ! global_opt . uuid ) {
2014-10-29 09:12:18 -05:00
fprintf ( stderr , _ ( " An interface name and UUID are required \n " ) ) ;
2016-10-05 15:07:46 +02:00
return 1 ;
2014-10-29 09:12:18 -05:00
}
2016-12-26 12:00:08 +01:00
gl . ifindex = nmp_utils_if_nametoindex ( global_opt . ifname ) ;
2016-10-05 12:04:24 +02:00
if ( gl . ifindex < = 0 ) {
2015-03-14 17:58:23 +01:00
fprintf ( stderr , _ ( " Failed to find interface index for %s (%s) \n " ) , global_opt . ifname , strerror ( errno ) ) ;
2016-10-05 15:07:46 +02:00
return 1 ;
2015-03-14 17:58:23 +01:00
}
2016-10-05 12:04:24 +02:00
pidfile = g_strdup_printf ( NMIH_PID_FILE_FMT , gl . ifindex ) ;
2015-03-14 17:58:23 +01:00
nm_main_utils_ensure_not_running_pidfile ( pidfile ) ;
2015-03-15 15:59:02 +01:00
nm_main_utils_ensure_rundir ( ) ;
2015-03-13 19:59:32 +01:00
if ( ! nm_logging_setup ( global_opt . opt_log_level ,
global_opt . opt_log_domains ,
2014-10-29 09:12:18 -05:00
& bad_domains ,
& error ) ) {
fprintf ( stderr ,
_ ( " %s. Please use --help to see a list of valid options. \n " ) ,
error - > message ) ;
2016-10-05 15:07:46 +02:00
return 1 ;
2014-10-29 09:12:18 -05:00
} else if ( bad_domains ) {
fprintf ( stderr ,
_ ( " Ignoring unrecognized log domain(s) '%s' passed on command line. \n " ) ,
bad_domains ) ;
g_clear_pointer ( & bad_domains , g_free ) ;
}
2015-03-13 19:59:32 +01:00
if ( global_opt . become_daemon & & ! global_opt . debug ) {
2014-10-29 09:12:18 -05:00
if ( daemon ( 0 , 0 ) < 0 ) {
int saved_errno ;
saved_errno = errno ;
fprintf ( stderr , _ ( " Could not daemonize: %s [error %u] \n " ) ,
g_strerror ( saved_errno ) ,
saved_errno ) ;
2016-10-05 15:07:46 +02:00
return 1 ;
2014-10-29 09:12:18 -05:00
}
if ( nm_main_utils_write_pidfile ( pidfile ) )
wrote_pidfile = TRUE ;
}
/* Set up unix signal handling - before creating threads, but after daemonizing! */
2016-10-05 12:04:24 +02:00
gl . main_loop = g_main_loop_new ( NULL , FALSE ) ;
2015-01-12 11:36:26 -05:00
setup_signals ( ) ;
2014-10-29 09:12:18 -05:00
2017-03-01 13:34:32 +01:00
nm_logging_syslog_openlog ( global_opt . logging_backend ,
global_opt . debug ) ;
2014-10-29 09:12:18 -05:00
2016-10-05 12:04:46 +02:00
_LOGI ( LOGD_CORE , " nm-iface-helper (version " NM_DIST_VERSION " ) is starting... " ) ;
2014-10-29 09:12:18 -05:00
/* Set up platform interaction layer */
nm_linux_platform_setup ( ) ;
2016-10-05 12:04:24 +02:00
tmp = nm_platform_link_get_address ( NM_PLATFORM_GET , gl . ifindex , & hwaddr_len ) ;
2014-10-29 09:12:18 -05:00
if ( tmp ) {
hwaddr = g_byte_array_sized_new ( hwaddr_len ) ;
g_byte_array_append ( hwaddr , tmp , hwaddr_len ) ;
}
2015-03-13 19:59:32 +01:00
if ( global_opt . iid_str ) {
2014-10-29 09:12:18 -05:00
GBytes * bytes ;
gsize ignored = 0 ;
2015-03-13 19:59:32 +01:00
bytes = nm_utils_hexstr2bin ( global_opt . iid_str ) ;
2014-10-29 09:12:18 -05:00
if ( ! bytes | | g_bytes_get_size ( bytes ) ! = sizeof ( * iid ) ) {
2015-03-13 19:59:32 +01:00
fprintf ( stderr , _ ( " (%s): Invalid IID %s \n " ) , global_opt . ifname , global_opt . iid_str ) ;
2016-10-05 15:07:46 +02:00
return 1 ;
2014-10-29 09:12:18 -05:00
}
iid = g_bytes_unref_to_data ( bytes , & ignored ) ;
}
2015-03-13 19:59:32 +01:00
if ( global_opt . dhcp4_address ) {
2016-12-08 14:29:00 +01:00
nm_platform_sysctl_set ( NM_PLATFORM_GET , NMP_SYSCTL_PATHID_ABSOLUTE ( nm_utils_ip4_property_path ( global_opt . ifname , " promote_secondaries " ) ) , " 1 " ) ;
2014-10-29 09:12:18 -05:00
2015-01-05 19:30:00 +01:00
dhcp4_client = nm_dhcp_manager_start_ip4 ( nm_dhcp_manager_get ( ) ,
core: pass NMDedupMultiIndex instance to NMIP4Config and other
NMIP4Config, NMIP6Config, and NMPlatform shall share one
NMDedupMultiIndex instance.
For that, pass an NMDedupMultiIndex instance to NMPlatform and NMNetns.
NMNetns than passes it on to NMDevice, NMDhcpClient, NMIP4Config and NMIP6Config.
So currently NMNetns is the access point to the shared NMDedupMultiIndex
instance, and it gets it from it's NMPlatform instance.
The NMDedupMultiIndex instance is really a singleton, we don't want
multiple instances of it. However, for testing, instead of adding a
singleton instance, pass the instance explicitly around.
2017-06-12 08:16:47 +02:00
nm_platform_get_multi_idx ( NM_PLATFORM_GET ) ,
2015-03-13 19:59:32 +01:00
global_opt . ifname ,
2016-10-05 12:04:24 +02:00
gl . ifindex ,
2014-10-29 09:12:18 -05:00
hwaddr ,
2015-03-13 19:59:32 +01:00
global_opt . uuid ,
2015-03-13 20:09:46 +01:00
global_opt . priority_v4 ,
2015-03-13 19:59:32 +01:00
! ! global_opt . dhcp4_hostname ,
global_opt . dhcp4_hostname ,
2015-10-13 15:13:26 +02:00
global_opt . dhcp4_fqdn ,
2015-03-13 19:59:32 +01:00
global_opt . dhcp4_clientid ,
2017-09-11 10:43:48 +02:00
NM_DHCP_TIMEOUT_DEFAULT ,
2014-10-29 09:12:18 -05:00
NULL ,
2015-03-13 19:59:32 +01:00
global_opt . dhcp4_address ) ;
2014-10-29 09:12:18 -05:00
g_assert ( dhcp4_client ) ;
g_signal_connect ( dhcp4_client ,
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED ,
G_CALLBACK ( dhcp4_state_changed ) ,
NULL ) ;
}
2015-03-13 19:59:32 +01:00
if ( global_opt . slaac ) {
2016-06-21 18:07:56 +02:00
NMUtilsStableType stable_type = NM_UTILS_STABLE_TYPE_UUID ;
const char * stable_id = global_opt . uuid ;
2016-10-05 12:04:24 +02:00
nm_platform_link_set_user_ipv6ll_enabled ( NM_PLATFORM_GET , gl . ifindex , TRUE ) ;
2014-10-29 09:12:18 -05:00
2016-06-21 18:07:56 +02:00
if ( global_opt . stable_id
& & ( global_opt . stable_id [ 0 ] > = ' 0 ' & & global_opt . stable_id [ 0 ] < = ' 9 ' )
& & global_opt . stable_id [ 1 ] = = ' ' ) {
/* strict parsing of --stable-id, which is the numeric stable-type
* and the ID , joined with one space . For now , only support stable - types
* from 0 to 9. */
stable_type = ( global_opt . stable_id [ 0 ] - ' 0 ' ) ;
stable_id = & global_opt . stable_id [ 2 ] ;
}
2016-10-13 11:06:25 +00:00
ndisc = nm_lndp_ndisc_new ( NM_PLATFORM_GET , gl . ifindex , global_opt . ifname ,
2016-06-21 18:07:56 +02:00
stable_type , stable_id ,
2016-10-14 20:13:32 +02:00
global_opt . addr_gen_mode ,
NM_NDISC_NODE_TYPE_HOST ,
NULL ) ;
2016-10-13 11:06:25 +00:00
g_assert ( ndisc ) ;
2014-10-29 09:12:18 -05:00
if ( iid )
2016-10-13 11:06:25 +00:00
nm_ndisc_set_iid ( ndisc , * iid ) ;
2014-10-29 09:12:18 -05:00
2016-12-08 14:29:00 +01:00
nm_platform_sysctl_set ( NM_PLATFORM_GET , NMP_SYSCTL_PATHID_ABSOLUTE ( nm_utils_ip6_property_path ( global_opt . ifname , " accept_ra " ) ) , " 1 " ) ;
nm_platform_sysctl_set ( NM_PLATFORM_GET , NMP_SYSCTL_PATHID_ABSOLUTE ( nm_utils_ip6_property_path ( global_opt . ifname , " accept_ra_defrtr " ) ) , " 0 " ) ;
nm_platform_sysctl_set ( NM_PLATFORM_GET , NMP_SYSCTL_PATHID_ABSOLUTE ( nm_utils_ip6_property_path ( global_opt . ifname , " accept_ra_pinfo " ) ) , " 0 " ) ;
nm_platform_sysctl_set ( NM_PLATFORM_GET , NMP_SYSCTL_PATHID_ABSOLUTE ( nm_utils_ip6_property_path ( global_opt . ifname , " accept_ra_rtr_pref " ) ) , " 0 " ) ;
2014-10-29 09:12:18 -05:00
2015-10-03 19:50:30 +02:00
g_signal_connect ( NM_PLATFORM_GET ,
NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED ,
G_CALLBACK ( ip6_address_changed ) ,
2016-10-13 11:06:25 +00:00
ndisc ) ;
g_signal_connect ( ndisc ,
2016-11-09 17:21:41 +01:00
NM_NDISC_CONFIG_RECEIVED ,
2016-10-13 11:06:25 +00:00
G_CALLBACK ( ndisc_config_changed ) ,
2014-10-29 09:12:18 -05:00
NULL ) ;
2016-10-13 11:06:25 +00:00
g_signal_connect ( ndisc ,
NM_NDISC_RA_TIMEOUT ,
G_CALLBACK ( ndisc_ra_timeout ) ,
2014-10-29 09:12:18 -05:00
NULL ) ;
2016-10-13 11:06:25 +00:00
nm_ndisc_start ( ndisc ) ;
2014-10-29 09:12:18 -05:00
}
2016-03-09 12:27:56 +01:00
sd_id = nm_sd_event_attach_default ( ) ;
2016-10-05 12:04:24 +02:00
g_main_loop_run ( gl . main_loop ) ;
2014-10-29 09:12:18 -05:00
g_clear_pointer ( & hwaddr , g_byte_array_unref ) ;
if ( pidfile & & wrote_pidfile )
unlink ( pidfile ) ;
2016-10-05 12:04:46 +02:00
_LOGI ( LOGD_CORE , " exiting " ) ;
2016-03-09 12:27:56 +01:00
nm_clear_g_source ( & sd_id ) ;
2016-10-05 15:10:34 +02:00
g_clear_pointer ( & gl . main_loop , g_main_loop_unref ) ;
2016-10-05 15:07:46 +02:00
return 0 ;
2014-10-29 09:12:18 -05:00
}
2016-10-22 16:23:40 +02:00
/*****************************************************************************/
const NMDhcpClientFactory * const _nm_dhcp_manager_factories [ 3 ] = {
& _nm_dhcp_client_factory_internal ,
} ;
2016-10-02 18:22:50 +02:00
/*****************************************************************************/
2014-10-29 09:12:18 -05:00
/* Stub functions */
2016-11-25 15:07:19 +01:00
# include "nm-config.h"
# include "devices/nm-device.h"
# include "nm-active-connection.h"
# include "nm-bus-manager.h"
2014-07-09 18:36:20 +02:00
void
2015-06-25 21:10:32 +02:00
nm_main_config_reload ( int signal )
2014-07-09 18:36:20 +02:00
{
2016-10-05 12:04:46 +02:00
_LOGI ( LOGD_CORE , " reloading configuration not supported " ) ;
2014-07-09 18:36:20 +02:00
}
2016-11-25 15:07:19 +01:00
NMConfig *
2014-10-29 09:12:18 -05:00
nm_config_get ( void )
{
return GUINT_TO_POINTER ( 1 ) ;
}
2016-11-25 15:07:19 +01:00
NMConfigData *
nm_config_get_data_orig ( NMConfig * config )
{
return GUINT_TO_POINTER ( 1 ) ;
}
char *
nm_config_data_get_value ( const NMConfigData * config_data , const char * group , const char * key , NMConfigGetValueFlags flags )
2014-10-29 09:12:18 -05:00
{
2016-11-25 15:07:19 +01:00
return NULL ;
2014-10-29 09:12:18 -05:00
}
gboolean
2016-11-25 15:07:19 +01:00
nm_config_get_configure_and_quit ( NMConfig * config )
2014-10-29 09:12:18 -05:00
{
return TRUE ;
}
2016-11-25 15:07:19 +01:00
NMBusManager *
2015-04-16 14:20:51 -04:00
nm_bus_manager_get ( void )
2014-10-29 09:12:18 -05:00
{
return GUINT_TO_POINTER ( 1 ) ;
}
void
2016-11-25 15:07:19 +01:00
nm_bus_manager_register_object ( NMBusManager * bus_manager ,
GDBusObjectSkeleton * object )
2014-10-29 09:12:18 -05:00
{
}
void
2016-11-25 15:07:19 +01:00
nm_bus_manager_unregister_object ( NMBusManager * bus_manager ,
GDBusObjectSkeleton * object )
2015-04-03 10:08:52 -04:00
{
}
dbus: fix emitting D-Bus NetworkManager's old-style PropertiesChange signal
Before switching to gdbus (before 1.2.0), NetworkManager used dbus-glib.
Most objects in the D-Bus API with properties had a signal
NetworkManager-specific "PropertiesChanged" signal. Nowadays, this way of
handling of property changes is deprecated for the common "PropertiesChanged"
signal on the "org.freedesktop.DBus.Properties" interface.
There were a few pecularities in 1.0.0 and earlier:
(1) Due to the implementation with dbus-glib, a property-changed
signal was emitted on *all* interfaces. For example:
- a change on a NMDeviceVeth of "NMDeviceEthernet.HwAddress" would be
emitted both for the interfaces "fdo.NM.Device.Ethernet" and
"fdo.NM.Device.Veth". Note that NMDeviceVeth is derived from
NMDeviceEthernet and there is no "HwAddress" on veth device.
- a change of "NMVpnConnection.VpnState" was emitted on both
interfaces "fdo.NM.VPN.Connection" and "fdo.NM.Connecion.Active".
Note that NMActiveConnection is the parent type of NMVpnConnection and
only the latter has a property "VpnState".
(2) NMDevice's "fdo.NM.Device" interface doesn't have a "PropertiesChanged"
signal. From (1) follows that all property-changes for this type were instead
invoked with an interface like "fdo.NM.Device.Ethernet" (or multiple
interfaces in case of NMDeviceVeth).
1.2.0 introduced gdbus, which gives us the standard "fdo.DBus.Properties"
signal. However, it made the mistake of not realizing (1), thus instead
of emitting the signal once for each interface, it would pick the first
one in the inheritance tree.
With 1.4.0, a bug from merge commit 844345e caused signals for devices
to be only emitted for the interface "fdo.NM.Device.Statistics", instead
of "fdo.NM.Device.Ethernet" or "fdo.NM.Device.Veth" (or both).
The latter is what bgo#770629 is about and what commit 82e9439 tried to fix.
However, the fix was wrong because it tried to do the theoretically correct
thing of emitting the property-changed signal exactly once for the
interface that actually ontains the property. In addition, it missed that
NMDevice doesn't have a PropertiesChanged signal, which caused signals for
"fdo.NM.Device" to get lost *sigh*.
Now, restore the (broken) behavior of 1.0.0. These old-style property changed
signals are anyway considered deprecated and exist solely to satisfy old clients
and preserve the old API.
Fixes: 63fbfad3705db5901e6a2a6a2fc332da0f0ae4be
https://bugzilla.gnome.org/show_bug.cgi?id=770629
https://bugzilla.redhat.com/show_bug.cgi?id=1371920
2016-09-01 13:00:21 +02:00
GType
nm_device_get_type ( void )
{
g_return_val_if_reached ( 0 ) ;
}
GType
nm_active_connection_get_type ( void )
{
g_return_val_if_reached ( 0 ) ;
}