mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-08 08:20:28 +01:00
858 lines
28 KiB
C
858 lines
28 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2014 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "src/core/nm-default-daemon.h"
|
|
|
|
#include <getopt.h>
|
|
#include <locale.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/stat.h>
|
|
#include <signal.h>
|
|
#include <linux/rtnetlink.h>
|
|
|
|
#include "libnm-glib-aux/nm-c-list.h"
|
|
|
|
#include "main-utils.h"
|
|
#include "NetworkManagerUtils.h"
|
|
#include "libnm-platform/nm-linux-platform.h"
|
|
#include "libnm-platform/nm-platform-utils.h"
|
|
#include "dhcp/nm-dhcp-manager.h"
|
|
#include "ndisc/nm-ndisc.h"
|
|
#include "ndisc/nm-lndp-ndisc.h"
|
|
#include "nm-utils.h"
|
|
#include "libnm-core-intern/nm-core-internal.h"
|
|
#include "nm-setting-ip6-config.h"
|
|
#include "libnm-systemd-core/nm-sd.h"
|
|
|
|
#if !defined(NM_DIST_VERSION)
|
|
#define NM_DIST_VERSION VERSION
|
|
#endif
|
|
|
|
#define NMIH_PID_FILE_FMT NMRUNDIR "/nm-iface-helper-%d.pid"
|
|
|
|
/*****************************************************************************/
|
|
|
|
static struct {
|
|
GMainLoop *main_loop;
|
|
int ifindex;
|
|
gboolean is_vrf_device;
|
|
|
|
guint dad_failed_id;
|
|
CList dad_failed_lst_head;
|
|
} gl /*obal*/ = {
|
|
.ifindex = -1,
|
|
.is_vrf_device = FALSE,
|
|
};
|
|
|
|
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;
|
|
char * stable_id;
|
|
char * dhcp4_address;
|
|
char * dhcp4_clientid;
|
|
char * dhcp4_hostname;
|
|
char * dhcp4_fqdn;
|
|
char * mud_url;
|
|
char * iid_str;
|
|
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
|
|
char * logging_backend;
|
|
char * opt_log_level;
|
|
char * opt_log_domains;
|
|
guint32 priority_v4;
|
|
guint32 priority_v6;
|
|
} global_opt = {
|
|
.tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
|
|
.priority_v4 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4,
|
|
.priority_v6 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define _NMLOG_PREFIX_NAME "nm-iface-helper"
|
|
#define _NMLOG(level, domain, ...) \
|
|
nm_log((level), \
|
|
(domain), \
|
|
global_opt.ifname, \
|
|
NULL, \
|
|
"iface-helper: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__))
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
dhcp4_state_changed(NMDhcpClient *client,
|
|
NMDhcpState state,
|
|
NMIP4Config * ip4_config,
|
|
GHashTable * options,
|
|
gpointer user_data)
|
|
{
|
|
static NMIP4Config *last_config = NULL;
|
|
NMIP4Config * existing;
|
|
gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
|
|
g_return_if_fail(!ip4_config || NM_IS_IP4_CONFIG(ip4_config));
|
|
|
|
_LOGD(LOGD_DHCP4, "new DHCPv4 client state %d", state);
|
|
|
|
switch (state) {
|
|
case NM_DHCP_STATE_BOUND:
|
|
case NM_DHCP_STATE_EXTENDED:
|
|
g_assert(ip4_config);
|
|
g_assert(nm_ip4_config_get_ifindex(ip4_config) == gl.ifindex);
|
|
|
|
existing = nm_ip4_config_capture(nm_platform_get_multi_idx(NM_PLATFORM_GET),
|
|
NM_PLATFORM_GET,
|
|
gl.ifindex);
|
|
if (last_config)
|
|
nm_ip4_config_subtract(existing, last_config, 0);
|
|
|
|
nm_ip4_config_merge(existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
|
|
nm_ip4_config_add_dependent_routes(existing,
|
|
RT_TABLE_MAIN,
|
|
global_opt.priority_v4,
|
|
gl.is_vrf_device,
|
|
&ip4_dev_route_blacklist);
|
|
if (!nm_ip4_config_commit(existing, NM_PLATFORM_GET, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN))
|
|
_LOGW(LOGD_DHCP4, "failed to apply DHCPv4 config");
|
|
|
|
if (!last_config && !nm_dhcp_client_accept(client, &error))
|
|
_LOGW(LOGD_DHCP4, "failed to accept lease: %s", error->message);
|
|
|
|
nm_platform_ip4_dev_route_blacklist_set(NM_PLATFORM_GET,
|
|
gl.ifindex,
|
|
ip4_dev_route_blacklist);
|
|
|
|
if (last_config)
|
|
g_object_unref(last_config);
|
|
last_config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET),
|
|
nm_dhcp_client_get_ifindex(client));
|
|
nm_ip4_config_replace(last_config, ip4_config, NULL);
|
|
break;
|
|
case NM_DHCP_STATE_TIMEOUT:
|
|
case NM_DHCP_STATE_DONE:
|
|
case NM_DHCP_STATE_FAIL:
|
|
if (global_opt.dhcp4_required) {
|
|
_LOGW(LOGD_DHCP4, "DHCPv4 timed out or failed, quitting...");
|
|
g_main_loop_quit(gl.main_loop);
|
|
} else
|
|
_LOGW(LOGD_DHCP4, "DHCPv4 timed out or failed");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ndisc_config_changed(NMNDisc * ndisc,
|
|
const NMNDiscData *rdata,
|
|
guint changed_int,
|
|
gpointer user_data)
|
|
{
|
|
NMNDiscConfigMap changed = changed_int;
|
|
static NMIP6Config *ndisc_config = NULL;
|
|
NMIP6Config * existing;
|
|
|
|
existing = nm_ip6_config_capture(nm_platform_get_multi_idx(NM_PLATFORM_GET),
|
|
NM_PLATFORM_GET,
|
|
gl.ifindex,
|
|
global_opt.tempaddr);
|
|
if (ndisc_config)
|
|
nm_ip6_config_subtract(existing, ndisc_config, 0);
|
|
else {
|
|
ndisc_config = nm_ip6_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), gl.ifindex);
|
|
}
|
|
|
|
if (changed & NM_NDISC_CONFIG_ADDRESSES) {
|
|
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_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) {
|
|
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;
|
|
|
|
nm_ip6_config_reset_addresses_ndisc(ndisc_config,
|
|
rdata->addresses,
|
|
rdata->addresses_n,
|
|
plen,
|
|
ifa_flags);
|
|
}
|
|
|
|
if (NM_FLAGS_ANY(changed, NM_NDISC_CONFIG_ROUTES | NM_NDISC_CONFIG_GATEWAYS)) {
|
|
nm_ip6_config_reset_routes_ndisc(
|
|
ndisc_config,
|
|
rdata->gateways,
|
|
rdata->gateways_n,
|
|
rdata->routes,
|
|
rdata->routes_n,
|
|
RT_TABLE_MAIN,
|
|
global_opt.priority_v6,
|
|
nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF));
|
|
}
|
|
|
|
if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) {
|
|
/* Unsupported until systemd DHCPv6 is ready */
|
|
}
|
|
|
|
if (changed & NM_NDISC_CONFIG_HOP_LIMIT)
|
|
nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(NM_PLATFORM_GET,
|
|
global_opt.ifname,
|
|
rdata->hop_limit);
|
|
|
|
if (changed & NM_NDISC_CONFIG_REACHABLE_TIME) {
|
|
nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(NM_PLATFORM_GET,
|
|
global_opt.ifname,
|
|
rdata->reachable_time_ms);
|
|
}
|
|
|
|
if (changed & NM_NDISC_CONFIG_RETRANS_TIMER) {
|
|
nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(NM_PLATFORM_GET,
|
|
global_opt.ifname,
|
|
rdata->retrans_timer_ms);
|
|
}
|
|
|
|
if (changed & NM_NDISC_CONFIG_MTU) {
|
|
nm_platform_sysctl_ip_conf_set_int64(NM_PLATFORM_GET,
|
|
AF_INET6,
|
|
global_opt.ifname,
|
|
"mtu",
|
|
rdata->mtu);
|
|
}
|
|
|
|
nm_ip6_config_merge(existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
|
|
nm_ip6_config_add_dependent_routes(existing,
|
|
RT_TABLE_MAIN,
|
|
global_opt.priority_v6,
|
|
gl.is_vrf_device);
|
|
if (!nm_ip6_config_commit(existing, NM_PLATFORM_GET, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, NULL))
|
|
_LOGW(LOGD_IP6, "failed to apply IPv6 config");
|
|
}
|
|
|
|
static void
|
|
ndisc_ra_timeout(NMNDisc *ndisc, gpointer user_data)
|
|
{
|
|
if (global_opt.slaac_required) {
|
|
_LOGW(LOGD_IP6, "IPv6 timed out or failed, quitting...");
|
|
g_main_loop_quit(gl.main_loop);
|
|
} else
|
|
_LOGW(LOGD_IP6, "IPv6 timed out or failed");
|
|
}
|
|
|
|
static gboolean
|
|
quit_handler(gpointer user_data)
|
|
{
|
|
g_main_loop_quit(gl.main_loop);
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
setup_signals(void)
|
|
{
|
|
signal(SIGPIPE, SIG_IGN);
|
|
g_unix_signal_add(SIGINT, quit_handler, NULL);
|
|
g_unix_signal_add(SIGTERM, quit_handler, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
do_early_setup(int *argc, char **argv[])
|
|
{
|
|
gint64 priority64_v4 = -1;
|
|
gint64 priority64_v6 = -1;
|
|
GOptionEntry options[] = {
|
|
/* Interface/IP config */
|
|
{"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"},
|
|
{"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")},
|
|
{"dhcp4-fqdn",
|
|
'F',
|
|
0,
|
|
G_OPTION_ARG_STRING,
|
|
&global_opt.dhcp4_fqdn,
|
|
N_("FQDN to send to DHCP server"),
|
|
N_("host.domain.org")},
|
|
{"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")},
|
|
{"iid",
|
|
'e',
|
|
0,
|
|
G_OPTION_ARG_STRING,
|
|
&global_opt.iid_str,
|
|
N_("Hex-encoded Interface Identifier"),
|
|
""},
|
|
{"addr-gen-mode",
|
|
'e',
|
|
0,
|
|
G_OPTION_ARG_INT,
|
|
&global_opt.addr_gen_mode,
|
|
N_("IPv6 SLAAC address generation mode"),
|
|
"eui64"},
|
|
{"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},
|
|
|
|
/* Logging/debugging */
|
|
{"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,
|
|
N_("Log domains separated by ',': any combination of [%s]"),
|
|
"PLATFORM,RFKILL,WIFI"},
|
|
{"g-fatal-warnings",
|
|
0,
|
|
0,
|
|
G_OPTION_ARG_NONE,
|
|
&global_opt.g_fatal_warnings,
|
|
N_("Make all warnings fatal"),
|
|
NULL},
|
|
{NULL}};
|
|
|
|
if (!nm_main_utils_early_setup("nm-iface-helper",
|
|
argc,
|
|
argv,
|
|
options,
|
|
NULL,
|
|
NULL,
|
|
_("nm-iface-helper is a small, standalone process that manages "
|
|
"a single network interface.")))
|
|
return FALSE;
|
|
|
|
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;
|
|
return TRUE;
|
|
}
|
|
|
|
typedef struct {
|
|
NMPlatform *platform;
|
|
NMNDisc * ndisc;
|
|
} DadFailedHandleData;
|
|
|
|
static gboolean
|
|
dad_failed_handle_idle(gpointer user_data)
|
|
{
|
|
DadFailedHandleData *data = user_data;
|
|
NMCListElem * elem;
|
|
|
|
while ((elem = c_list_first_entry(&gl.dad_failed_lst_head, NMCListElem, lst))) {
|
|
nm_auto_nmpobj const NMPObject *obj = elem->data;
|
|
|
|
nm_c_list_elem_free(elem);
|
|
|
|
if (nm_ndisc_dad_addr_is_fail_candidate(data->platform, obj)) {
|
|
nm_ndisc_dad_failed(data->ndisc, &NMP_OBJECT_CAST_IP6_ADDRESS(obj)->address, TRUE);
|
|
}
|
|
}
|
|
|
|
gl.dad_failed_id = 0;
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
ip6_address_changed(NMPlatform * platform,
|
|
int obj_type_i,
|
|
int iface,
|
|
const NMPlatformIP6Address *addr,
|
|
int change_type_i,
|
|
NMNDisc * ndisc)
|
|
{
|
|
const NMPlatformSignalChangeType change_type = change_type_i;
|
|
DadFailedHandleData * data;
|
|
|
|
if (!nm_ndisc_dad_addr_is_fail_candidate_event(change_type, addr))
|
|
return;
|
|
|
|
c_list_link_tail(
|
|
&gl.dad_failed_lst_head,
|
|
&nm_c_list_elem_new_stale((gpointer) nmp_object_ref(NMP_OBJECT_UP_CAST(addr)))->lst);
|
|
if (gl.dad_failed_id)
|
|
return;
|
|
|
|
data = g_slice_new(DadFailedHandleData);
|
|
data->platform = platform;
|
|
data->ndisc = ndisc;
|
|
gl.dad_failed_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
|
dad_failed_handle_idle,
|
|
data,
|
|
nm_g_slice_free_fcn(DadFailedHandleData));
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
char * bad_domains = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
gboolean wrote_pidfile = FALSE;
|
|
gs_free char * pidfile = NULL;
|
|
gs_unref_object NMDhcpClient *dhcp4_client = NULL;
|
|
gs_unref_object NMNDisc *ndisc = NULL;
|
|
gs_unref_bytes GBytes *hwaddr = NULL;
|
|
gs_unref_bytes GBytes *bcast_hwaddr = NULL;
|
|
gs_unref_bytes GBytes *client_id = NULL;
|
|
gs_free NMUtilsIPv6IfaceId *iid = NULL;
|
|
const NMPlatformLink * pllink;
|
|
guint sd_id;
|
|
int errsv;
|
|
|
|
c_list_init(&gl.dad_failed_lst_head);
|
|
|
|
setpgid(getpid(), getpid());
|
|
|
|
if (!do_early_setup(&argc, &argv))
|
|
return 1;
|
|
|
|
nm_logging_init_pre("nm-iface-helper",
|
|
g_strdup_printf("%s[%ld] (%s): ",
|
|
_NMLOG_PREFIX_NAME,
|
|
(long) getpid(),
|
|
global_opt.ifname ?: "???"));
|
|
|
|
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);
|
|
}
|
|
|
|
if (global_opt.show_version) {
|
|
fprintf(stdout, NM_DIST_VERSION "\n");
|
|
return 0;
|
|
}
|
|
|
|
nm_main_utils_ensure_root();
|
|
|
|
if (!global_opt.ifname || !global_opt.uuid) {
|
|
fprintf(stderr, _("An interface name and UUID are required\n"));
|
|
return 1;
|
|
}
|
|
|
|
gl.ifindex = nmp_utils_if_nametoindex(global_opt.ifname);
|
|
if (gl.ifindex <= 0) {
|
|
errsv = errno;
|
|
fprintf(stderr,
|
|
_("Failed to find interface index for %s (%s)\n"),
|
|
global_opt.ifname,
|
|
nm_strerror_native(errsv));
|
|
return 1;
|
|
}
|
|
pidfile = g_strdup_printf(NMIH_PID_FILE_FMT, gl.ifindex);
|
|
nm_main_utils_ensure_not_running_pidfile(pidfile);
|
|
|
|
nm_main_utils_ensure_rundir();
|
|
|
|
if (!nm_logging_setup(global_opt.opt_log_level,
|
|
global_opt.opt_log_domains,
|
|
&bad_domains,
|
|
&error)) {
|
|
fprintf(stderr,
|
|
_("%s. Please use --help to see a list of valid options.\n"),
|
|
error->message);
|
|
return 1;
|
|
} else if (bad_domains) {
|
|
fprintf(stderr,
|
|
_("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
|
|
bad_domains);
|
|
nm_clear_g_free(&bad_domains);
|
|
}
|
|
|
|
if (global_opt.become_daemon && !global_opt.debug) {
|
|
if (daemon(0, 0) < 0) {
|
|
errsv = errno;
|
|
fprintf(stderr,
|
|
_("Could not daemonize: %s [error %u]\n"),
|
|
nm_strerror_native(errsv),
|
|
errsv);
|
|
return 1;
|
|
}
|
|
if (nm_main_utils_write_pidfile(pidfile))
|
|
wrote_pidfile = TRUE;
|
|
}
|
|
|
|
/* Set up unix signal handling - before creating threads, but after daemonizing! */
|
|
gl.main_loop = g_main_loop_new(NULL, FALSE);
|
|
setup_signals();
|
|
|
|
nm_logging_init(global_opt.logging_backend, global_opt.debug);
|
|
|
|
_LOGI(LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting...");
|
|
|
|
/* Set up platform interaction layer */
|
|
nm_linux_platform_setup();
|
|
|
|
pllink = nm_platform_link_get(NM_PLATFORM_GET, gl.ifindex);
|
|
if (pllink) {
|
|
hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address);
|
|
bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast);
|
|
|
|
if (pllink->master > 0) {
|
|
gl.is_vrf_device =
|
|
nm_platform_link_get_type(NM_PLATFORM_GET, pllink->master) == NM_LINK_TYPE_VRF;
|
|
}
|
|
}
|
|
|
|
if (global_opt.iid_str) {
|
|
GBytes *bytes;
|
|
gsize ignored = 0;
|
|
|
|
bytes = nm_utils_hexstr2bin(global_opt.iid_str);
|
|
if (!bytes || g_bytes_get_size(bytes) != sizeof(*iid)) {
|
|
fprintf(stderr, _("(%s): Invalid IID %s\n"), global_opt.ifname, global_opt.iid_str);
|
|
return 1;
|
|
}
|
|
iid = g_bytes_unref_to_data(bytes, &ignored);
|
|
}
|
|
|
|
if (global_opt.dhcp4_clientid) {
|
|
/* this string is just a plain hex-string. Unlike ipv4.dhcp-client-id, which
|
|
* is parsed via nm_dhcp_utils_client_id_string_to_bytes(). */
|
|
client_id = nm_utils_hexstr2bin(global_opt.dhcp4_clientid);
|
|
if (!client_id || g_bytes_get_size(client_id) < 2) {
|
|
fprintf(stderr,
|
|
_("(%s): Invalid DHCP client-id %s\n"),
|
|
global_opt.ifname,
|
|
global_opt.dhcp4_clientid);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (global_opt.dhcp4_address) {
|
|
nm_platform_sysctl_ip_conf_set(NM_PLATFORM_GET,
|
|
AF_INET,
|
|
global_opt.ifname,
|
|
"promote_secondaries",
|
|
"1");
|
|
|
|
dhcp4_client = nm_dhcp_manager_start_ip4(nm_dhcp_manager_get(),
|
|
nm_platform_get_multi_idx(NM_PLATFORM_GET),
|
|
global_opt.ifname,
|
|
gl.ifindex,
|
|
hwaddr,
|
|
bcast_hwaddr,
|
|
global_opt.uuid,
|
|
RT_TABLE_MAIN,
|
|
global_opt.priority_v4,
|
|
NM_DHCP_CLIENT_FLAGS_NONE,
|
|
!!global_opt.dhcp4_hostname,
|
|
global_opt.dhcp4_hostname,
|
|
global_opt.dhcp4_fqdn,
|
|
NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP4,
|
|
global_opt.mud_url,
|
|
client_id,
|
|
NM_DHCP_TIMEOUT_DEFAULT,
|
|
NULL,
|
|
global_opt.dhcp4_address,
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
if (!dhcp4_client)
|
|
g_error("failure to start DHCP: %s", error->message);
|
|
|
|
g_signal_connect(dhcp4_client,
|
|
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
|
|
G_CALLBACK(dhcp4_state_changed),
|
|
NULL);
|
|
}
|
|
|
|
if (global_opt.slaac) {
|
|
NMUtilsStableType stable_type = NM_UTILS_STABLE_TYPE_UUID;
|
|
const char * stable_id = global_opt.uuid;
|
|
int router_solicitation_interval;
|
|
int router_solicitations;
|
|
guint32 default_ra_timeout;
|
|
int max_addresses;
|
|
|
|
nm_platform_link_set_user_ipv6ll_enabled(NM_PLATFORM_GET, gl.ifindex, TRUE);
|
|
|
|
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];
|
|
}
|
|
|
|
nm_lndp_ndisc_get_sysctl(NM_PLATFORM_GET,
|
|
global_opt.ifname,
|
|
&max_addresses,
|
|
&router_solicitations,
|
|
&router_solicitation_interval,
|
|
&default_ra_timeout);
|
|
|
|
ndisc = nm_lndp_ndisc_new(NM_PLATFORM_GET,
|
|
gl.ifindex,
|
|
global_opt.ifname,
|
|
stable_type,
|
|
stable_id,
|
|
global_opt.addr_gen_mode,
|
|
NM_NDISC_NODE_TYPE_HOST,
|
|
max_addresses,
|
|
router_solicitations,
|
|
router_solicitation_interval,
|
|
default_ra_timeout,
|
|
NULL);
|
|
g_assert(ndisc);
|
|
|
|
if (iid)
|
|
nm_ndisc_set_iid(ndisc, *iid);
|
|
|
|
nm_platform_sysctl_ip_conf_set(NM_PLATFORM_GET,
|
|
AF_INET6,
|
|
global_opt.ifname,
|
|
"accept_ra",
|
|
"0");
|
|
|
|
g_signal_connect(NM_PLATFORM_GET,
|
|
NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
|
|
G_CALLBACK(ip6_address_changed),
|
|
ndisc);
|
|
g_signal_connect(ndisc, NM_NDISC_CONFIG_RECEIVED, G_CALLBACK(ndisc_config_changed), NULL);
|
|
g_signal_connect(ndisc, NM_NDISC_RA_TIMEOUT_SIGNAL, G_CALLBACK(ndisc_ra_timeout), NULL);
|
|
nm_ndisc_start(ndisc);
|
|
}
|
|
|
|
sd_id = nm_sd_event_attach_default();
|
|
|
|
g_main_loop_run(gl.main_loop);
|
|
|
|
nm_clear_g_source(&gl.dad_failed_id);
|
|
nm_c_list_elem_free_all(&gl.dad_failed_lst_head, (GDestroyNotify) nmp_object_unref);
|
|
|
|
if (pidfile && wrote_pidfile)
|
|
unlink(pidfile);
|
|
|
|
_LOGI(LOGD_CORE, "exiting");
|
|
|
|
nm_clear_g_source(&sd_id);
|
|
nm_clear_pointer(&gl.main_loop, g_main_loop_unref);
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
const NMDhcpClientFactory *const _nm_dhcp_manager_factories[6] = {
|
|
/* For nm-iface-helper there is no option to choose a DHCP plugin.
|
|
* It just uses the "internal" one. */
|
|
&_nm_dhcp_client_factory_internal,
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/* Stub functions */
|
|
|
|
#include "nm-config.h"
|
|
#include "devices/nm-device.h"
|
|
#include "nm-active-connection.h"
|
|
#include "nm-dbus-manager.h"
|
|
|
|
void
|
|
nm_main_config_reload(int signal)
|
|
{
|
|
_LOGI(LOGD_CORE, "reloading configuration not supported");
|
|
}
|
|
|
|
NMConfig *
|
|
nm_config_get(void)
|
|
{
|
|
return GUINT_TO_POINTER(1);
|
|
}
|
|
|
|
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)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
NMConfigConfigureAndQuitType
|
|
nm_config_get_configure_and_quit(NMConfig *config)
|
|
{
|
|
return NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED;
|
|
}
|
|
|
|
NMDBusManager *
|
|
nm_dbus_manager_get(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
gboolean
|
|
nm_dbus_manager_is_stopping(NMDBusManager *self)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
_nm_dbus_manager_obj_export(NMDBusObject *obj)
|
|
{}
|
|
|
|
void
|
|
_nm_dbus_manager_obj_unexport(NMDBusObject *obj)
|
|
{}
|
|
|
|
void
|
|
_nm_dbus_manager_obj_notify(NMDBusObject *obj, guint n_pspecs, const GParamSpec *const *pspecs)
|
|
{}
|
|
|
|
void
|
|
_nm_dbus_manager_obj_emit_signal(NMDBusObject * obj,
|
|
const NMDBusInterfaceInfoExtended *interface_info,
|
|
const GDBusSignalInfo * signal_info,
|
|
GVariant * args)
|
|
{}
|
|
|
|
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);
|
|
}
|