summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2019-07-05 11:17:16 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2019-07-05 11:17:16 +0200
commitf3b831aba1b319867e4b118a01a4910a3c28563d (patch)
treed4ffa477adc38b6668e74c64a9d77d88b232d598
parentbe8f7b5a5de6ed18d9e329e0151fd3065747c7b0 (diff)
parent106c156b0f6f8ba77f3dd2e144af3e1f4834ecc0 (diff)
downloadNetworkManager-f3b831aba1b319867e4b118a01a4910a3c28563d.tar.gz
dhcp: merge branch 'bg/nettools'
Introduce the nettools DHCPv4 backend. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/171
-rw-r--r--Makefile.am53
-rwxr-xr-xcontrib/scripts/checkpatch.pl2
-rw-r--r--meson_options.txt2
-rw-r--r--shared/meson.build40
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-connection.c3
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-probe.c1
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-client.c12
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-outgoing.c5
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-private.h5
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-socket.c5
-rw-r--r--shared/n-dhcp4/src/util/packet.h3
-rw-r--r--shared/systemd/nm-sd-utils-shared.c9
-rw-r--r--shared/systemd/nm-sd-utils-shared.h5
-rw-r--r--shared/systemd/src/shared/dns-domain.c (renamed from src/systemd/src/shared/dns-domain.c)2
-rw-r--r--shared/systemd/src/shared/dns-domain.h (renamed from src/systemd/src/shared/dns-domain.h)0
-rw-r--r--src/devices/nm-device.c28
-rw-r--r--src/dhcp/nm-dhcp-client.c54
-rw-r--r--src/dhcp/nm-dhcp-client.h40
-rw-r--r--src/dhcp/nm-dhcp-listener.c3
-rw-r--r--src/dhcp/nm-dhcp-manager.c13
-rw-r--r--src/dhcp/nm-dhcp-manager.h4
-rw-r--r--src/dhcp/nm-dhcp-nettools.c1380
-rw-r--r--src/meson.build2
-rw-r--r--src/nm-iface-helper.c12
-rw-r--r--src/platform/nm-platform.c13
-rw-r--r--src/platform/nm-platform.h13
-rw-r--r--src/systemd/meson.build2
27 files changed, 1656 insertions, 55 deletions
diff --git a/Makefile.am b/Makefile.am
index 3f918b04e4..5589f0550d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -266,6 +266,45 @@ endif
###############################################################################
+noinst_LTLIBRARIES += shared/libndhcp4.la
+
+shared_libndhcp4_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ -std=c11 \
+ -Wno-error=declaration-after-statement \
+ -Wno-pointer-arith \
+ $(NULL)
+
+shared_libndhcp4_la_CPPFLAGS = \
+ -D_GNU_SOURCE \
+ $(CODE_COVERAGE_CFLAGS) \
+ $(SANITIZER_LIB_CFLAGS) \
+ -I$(srcdir)/shared/c-stdaux/src \
+ -I$(srcdir)/shared/c-list/src \
+ -I$(srcdir)/shared/c-siphash/src \
+ $(NULL)
+
+shared_libndhcp4_la_LDFLAGS = \
+ $(SANITIZER_LIB_LDFLAGS)
+
+shared_libndhcp4_la_SOURCES = \
+ shared/n-dhcp4/src/n-dhcp4-c-connection.c \
+ shared/n-dhcp4/src/n-dhcp4-c-lease.c \
+ shared/n-dhcp4/src/n-dhcp4-c-probe.c \
+ shared/n-dhcp4/src/n-dhcp4-client.c \
+ shared/n-dhcp4/src/n-dhcp4-incoming.c \
+ shared/n-dhcp4/src/n-dhcp4-outgoing.c \
+ shared/n-dhcp4/src/n-dhcp4-private.h \
+ shared/n-dhcp4/src/n-dhcp4-socket.c \
+ shared/n-dhcp4/src/n-dhcp4.h \
+ shared/n-dhcp4/src/util/packet.c \
+ shared/n-dhcp4/src/util/packet.h \
+ shared/n-dhcp4/src/util/socket.c \
+ shared/n-dhcp4/src/util/socket.h \
+ $(NULL)
+
+###############################################################################
+
noinst_LTLIBRARIES += shared/nm-std-aux/libnm-std-aux.la
shared_nm_std_aux_libnm_std_aux_la_CPPFLAGS = \
@@ -1620,6 +1659,7 @@ libsystemd_cppflags = \
-I$(srcdir)/shared/systemd/ \
-I$(srcdir)/shared/systemd/sd-adapt-shared \
-I$(srcdir)/shared/systemd/src/basic \
+ -I$(srcdir)/shared/systemd/src/shared \
$(LIBSYSTEMD_NM_CFLAGS) \
$(GLIB_CFLAGS) \
$(CODE_COVERAGE_CFLAGS) \
@@ -1763,6 +1803,8 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/src/basic/utf8.h \
shared/systemd/src/basic/util.c \
shared/systemd/src/basic/util.h \
+ shared/systemd/src/shared/dns-domain.c \
+ shared/systemd/src/shared/dns-domain.h \
$(NULL)
shared_systemd_libnm_systemd_shared_la_LIBADD = \
@@ -1779,7 +1821,6 @@ src_libnm_systemd_core_la_cppflags = \
-I$(srcdir)/src \
-I$(srcdir)/src/systemd/sd-adapt-core \
-I$(srcdir)/src/systemd/src/systemd \
- -I$(srcdir)/src/systemd/src/shared \
-I$(srcdir)/src/systemd/src/libsystemd-network \
-I$(srcdir)/src/systemd/src/libsystemd/sd-event \
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD \
@@ -1840,8 +1881,6 @@ src_libnm_systemd_core_la_SOURCES = \
src/systemd/src/libsystemd/sd-id128/id128-util.c \
src/systemd/src/libsystemd/sd-id128/id128-util.h \
src/systemd/src/libsystemd/sd-id128/sd-id128.c \
- src/systemd/src/shared/dns-domain.c \
- src/systemd/src/shared/dns-domain.h \
src/systemd/src/systemd/_sd-common.h \
src/systemd/src/systemd/sd-dhcp-client.h \
src/systemd/src/systemd/sd-dhcp-lease.h \
@@ -1866,7 +1905,9 @@ EXTRA_DIST += \
###############################################################################
-src_libNetworkManagerBase_la_CPPFLAGS = $(src_cppflags)
+src_libNetworkManagerBase_la_CPPFLAGS = \
+ $(libsystemd_cppflags) \
+ $(src_cppflags)
src_libNetworkManagerBase_la_SOURCES = \
\
@@ -1920,6 +1961,7 @@ src_libNetworkManagerBase_la_SOURCES = \
src/dhcp/nm-dhcp-client.c \
src/dhcp/nm-dhcp-client.h \
src/dhcp/nm-dhcp-client-logging.h \
+ src/dhcp/nm-dhcp-nettools.c \
src/dhcp/nm-dhcp-utils.c \
src/dhcp/nm-dhcp-utils.h \
src/dhcp/nm-dhcp-systemd.c \
@@ -2141,6 +2183,7 @@ src_libNetworkManager_la_LIBADD = \
src/libnm-systemd-core.la \
shared/systemd/libnm-systemd-shared.la \
shared/libnacd.la \
+ shared/libndhcp4.la \
shared/libcrbtree.la \
shared/libcsiphash.la \
$(GLIB_LIBS) \
@@ -2228,6 +2271,7 @@ src_nm_iface_helper_LDADD = \
shared/nm-std-aux/libnm-std-aux.la \
src/libnm-systemd-core.la \
shared/systemd/libnm-systemd-shared.la \
+ shared/libndhcp4.la \
shared/libcsiphash.la \
$(GLIB_LIBS) \
$(LIBUDEV_LIBS) \
@@ -2275,6 +2319,7 @@ src_initrd_nm_initrd_generator_LDADD = \
shared/systemd/libnm-systemd-shared.la \
shared/nm-glib-aux/libnm-glib-aux.la \
shared/nm-std-aux/libnm-std-aux.la \
+ shared/libndhcp4.la \
shared/libcsiphash.la \
$(GLIB_LIBS) \
$(NULL)
diff --git a/contrib/scripts/checkpatch.pl b/contrib/scripts/checkpatch.pl
index f50b37d413..b5af6dfc2f 100755
--- a/contrib/scripts/checkpatch.pl
+++ b/contrib/scripts/checkpatch.pl
@@ -181,7 +181,7 @@ next if $filename =~ /\/nm-[^\/]+-enum-types\.[ch]$/;
next if $filename =~ /\bsrc\/systemd\//
and not $filename =~ /\/sd-adapt\//
and not $filename =~ /\/nm-/;
-next if $filename =~ /\/(n-acd|c-list|c-siphash)\//;
+next if $filename =~ /\/(n-acd|c-list|c-siphash|n-dhcp4)\//;
complain ('Tabs are only allowed at the beginning of a line') if $line =~ /[^\t]\t/;
complain ('Trailing whitespace') if $line =~ /[ \t]$/;
diff --git a/meson_options.txt b/meson_options.txt
index 3c9a84a8ad..3ffd9a54be 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -53,7 +53,7 @@ option('config_dns_rc_manager_default', type: 'combo', choices: ['symlink', 'fil
option('dhclient', type: 'string', value: '', description: 'Enable dhclient support')
option('dhcpcanon', type: 'string', value: '', description: 'Enable dhcpcanon support (experimental)')
option('dhcpcd', type: 'string', value: '', description: 'Enable dhcpcd support')
-option('config_dhcp_default', type: 'combo', choices: ['dhcpcanon', 'dhclient', 'dhcpcd', 'internal'], value: 'internal', description: 'Default configuration option for main.dhcp setting, used as fallback if the configuration option is unset')
+option('config_dhcp_default', type: 'combo', choices: ['dhcpcanon', 'dhclient', 'dhcpcd', 'internal', 'nettools'], value: 'internal', description: 'Default configuration option for main.dhcp setting, used as fallback if the configuration option is unset')
# miscellaneous
option('introspection', type: 'boolean', value: true, description: 'Enable introspection for this build')
diff --git a/shared/meson.build b/shared/meson.build
index b29a7c91b7..94229cef3f 100644
--- a/shared/meson.build
+++ b/shared/meson.build
@@ -88,6 +88,43 @@ shared_n_acd_dep = declare_dependency(
###############################################################################
+shared_n_dhcp4 = static_library(
+ 'n-dhcp4',
+ sources: files('n-dhcp4/src/n-dhcp4-c-connection.c',
+ 'n-dhcp4/src/n-dhcp4-c-lease.c',
+ 'n-dhcp4/src/n-dhcp4-c-probe.c',
+ 'n-dhcp4/src/n-dhcp4-client.c',
+ 'n-dhcp4/src/n-dhcp4-incoming.c',
+ 'n-dhcp4/src/n-dhcp4-outgoing.c',
+ 'n-dhcp4/src/n-dhcp4-private.h',
+ 'n-dhcp4/src/n-dhcp4-socket.c',
+ 'n-dhcp4/src/n-dhcp4.h',
+ 'n-dhcp4/src/util/packet.c',
+ 'n-dhcp4/src/util/packet.h',
+ 'n-dhcp4/src/util/socket.c',
+ 'n-dhcp4/src/util/socket.h'),
+ c_args: [
+ '-D_GNU_SOURCE',
+ '-Wno-declaration-after-statement',
+ '-Wno-pointer-arith',
+ ],
+ include_directories: [
+ include_directories('c-list/src'),
+ include_directories('c-siphash/src'),
+ include_directories('c-stdaux/src'),
+ ],
+ dependencies: [
+ shared_c_siphash_dep,
+ ],
+)
+
+shared_n_dhcp4_dep = declare_dependency(
+ include_directories: shared_inc,
+ link_with: shared_n_dhcp4,
+)
+
+###############################################################################
+
version_conf = configuration_data()
version_conf.set('NM_MAJOR_VERSION', nm_major_version)
version_conf.set('NM_MINOR_VERSION', nm_minor_version)
@@ -238,11 +275,13 @@ libnm_systemd_shared = static_library(
'systemd/src/basic/tmpfile-util.c',
'systemd/src/basic/utf8.c',
'systemd/src/basic/util.c',
+ 'systemd/src/shared/dns-domain.c',
'systemd/nm-sd-utils-shared.c',
),
include_directories: include_directories(
'systemd/sd-adapt-shared',
'systemd/src/basic',
+ 'systemd/src/shared',
),
dependencies: shared_nm_glib_aux_dep,
c_args: [
@@ -255,6 +294,7 @@ libnm_systemd_shared_dep = declare_dependency(
include_directories: include_directories(
'systemd/sd-adapt-shared',
'systemd/src/basic',
+ 'systemd/src/shared',
),
dependencies: [
shared_nm_glib_aux_dep,
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-connection.c b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
index 2d099b41f7..5c50dacfd8 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
@@ -8,6 +8,8 @@
#include <c-stdaux.h>
#include <errno.h>
#include <limits.h>
+#include <sys/socket.h> /* needed by linux/netdevice.h */
+#include <linux/netdevice.h>
#include <net/if_arp.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -82,6 +84,7 @@ int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
*/
void n_dhcp4_c_connection_deinit(NDhcp4CConnection *connection) {
n_dhcp4_c_connection_close(connection);
+ n_dhcp4_outgoing_free(connection->request);
*connection = (NDhcp4CConnection)N_DHCP4_C_CONNECTION_NULL(*connection);
}
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
index 67fedafffa..308cff8307 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
@@ -483,6 +483,7 @@ _c_public_ NDhcp4ClientProbe *n_dhcp4_client_probe_free(NDhcp4ClientProbe *probe
if (probe == probe->client->current_probe)
probe->client->current_probe = NULL;
+ n_dhcp4_client_lease_unref(probe->current_lease);
n_dhcp4_c_connection_deinit(&probe->connection);
n_dhcp4_client_unref(probe->client);
n_dhcp4_client_probe_config_free(probe->config);
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c
index a492a74c61..5f7794fb14 100644
--- a/shared/n-dhcp4/src/n-dhcp4-client.c
+++ b/shared/n-dhcp4/src/n-dhcp4-client.c
@@ -183,7 +183,11 @@ _c_public_ void n_dhcp4_client_config_set_request_broadcast(NDhcp4ClientConfig *
*/
_c_public_ void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
config->n_mac = n_mac;
- memcpy(config->mac, mac, c_min(n_mac, sizeof(config->mac)));
+
+ if (n_mac > sizeof(config->mac))
+ n_mac = sizeof(config->mac);
+
+ memcpy(config->mac, mac, n_mac);
}
/**
@@ -209,7 +213,11 @@ _c_public_ void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const
*/
_c_public_ void n_dhcp4_client_config_set_broadcast_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
config->n_broadcast_mac = n_mac;
- memcpy(config->broadcast_mac, mac, c_min(n_mac, sizeof(config->broadcast_mac)));
+
+ if (n_mac > sizeof(config->mac))
+ n_mac = sizeof(config->mac);
+
+ memcpy(config->broadcast_mac, mac, n_mac);
}
/**
diff --git a/shared/n-dhcp4/src/n-dhcp4-outgoing.c b/shared/n-dhcp4/src/n-dhcp4-outgoing.c
index bb33bbdbe5..c44b5880aa 100644
--- a/shared/n-dhcp4/src/n-dhcp4-outgoing.c
+++ b/shared/n-dhcp4/src/n-dhcp4-outgoing.c
@@ -220,8 +220,9 @@ int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing,
/* try fitting into allowed OPTIONs space */
if (outgoing->max_size - outgoing->i_message >= n_data + 2U + 3U + 1U) {
/* try over-allocation to reduce allocation pressure */
- n = c_min(outgoing->max_size,
- outgoing->n_message + n_data + 128);
+ n = outgoing->n_message + n_data + 128;
+ if (n > outgoing->max_size)
+ n = outgoing->max_size;
m = realloc(outgoing->message, n);
if (!m)
return -ENOMEM;
diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h
index b896a93dc1..c38ddbfc80 100644
--- a/shared/n-dhcp4/src/n-dhcp4-private.h
+++ b/shared/n-dhcp4/src/n-dhcp4-private.h
@@ -7,7 +7,6 @@
#include <endian.h>
#include <inttypes.h>
#include <limits.h>
-#include <linux/netdevice.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
@@ -234,9 +233,9 @@ struct NDhcp4ClientConfig {
int ifindex;
unsigned int transport;
bool request_broadcast;
- uint8_t mac[MAX_ADDR_LEN];
+ uint8_t mac[32]; /* MAX_ADDR_LEN */
size_t n_mac;
- uint8_t broadcast_mac[MAX_ADDR_LEN];
+ uint8_t broadcast_mac[32]; /* MAX_ADDR_LEN */
size_t n_broadcast_mac;
uint8_t *client_id;
size_t n_client_id;
diff --git a/shared/n-dhcp4/src/n-dhcp4-socket.c b/shared/n-dhcp4/src/n-dhcp4-socket.c
index 0bcc2419d0..b9ac176fd7 100644
--- a/shared/n-dhcp4/src/n-dhcp4-socket.c
+++ b/shared/n-dhcp4/src/n-dhcp4-socket.c
@@ -5,16 +5,17 @@
#include <c-stdaux.h>
#include <errno.h>
#include <linux/filter.h>
+#include <sys/socket.h> /* needed by linux/if.h */
+#include <linux/if.h>
#include <linux/if_packet.h>
+#include <linux/netdevice.h>
#include <linux/udp.h>
-#include <net/if.h>
#include <netinet/ip.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include "n-dhcp4-private.h"
#include "util/packet.h"
#include "util/socket.h"
diff --git a/shared/n-dhcp4/src/util/packet.h b/shared/n-dhcp4/src/util/packet.h
index edbf2a3e45..98dabf7fbe 100644
--- a/shared/n-dhcp4/src/util/packet.h
+++ b/shared/n-dhcp4/src/util/packet.h
@@ -7,7 +7,6 @@
#include <c-stdaux.h>
#include <inttypes.h>
#include <linux/if_packet.h>
-#include <linux/netdevice.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
@@ -25,7 +24,7 @@ struct packet_sockaddr_ll {
unsigned short sll_hatype;
unsigned char sll_pkttype;
unsigned char sll_halen;
- unsigned char sll_addr[MAX_ADDR_LEN];
+ unsigned char sll_addr[32]; /* MAX_ADDR_LEN */
};
uint16_t packet_internet_checksum(const uint8_t *data, size_t len);
diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c
index ecd2749213..a1f34c6ac4 100644
--- a/shared/systemd/nm-sd-utils-shared.c
+++ b/shared/systemd/nm-sd-utils-shared.c
@@ -24,6 +24,7 @@
#include "path-util.h"
#include "hexdecoct.h"
+#include "dns-domain.h"
/*****************************************************************************/
@@ -83,3 +84,11 @@ nm_sd_utils_unbase64mem (const char *p,
{
return unbase64mem_full (p, l, secure, (void **) mem, len);
}
+
+int nm_sd_dns_name_to_wire_format (const char *domain,
+ guint8 *buffer,
+ size_t len,
+ gboolean canonical)
+{
+ return dns_name_to_wire_format (domain, buffer, len, canonical);
+}
diff --git a/shared/systemd/nm-sd-utils-shared.h b/shared/systemd/nm-sd-utils-shared.h
index b3b77c8842..48a8cf37ac 100644
--- a/shared/systemd/nm-sd-utils-shared.h
+++ b/shared/systemd/nm-sd-utils-shared.h
@@ -39,4 +39,9 @@ int nm_sd_utils_unbase64mem (const char *p,
/*****************************************************************************/
+int nm_sd_dns_name_to_wire_format (const char *domain,
+ guint8 *buffer,
+ size_t len,
+ gboolean canonical);
+
#endif /* __NM_SD_UTILS_SHARED_H__ */
diff --git a/src/systemd/src/shared/dns-domain.c b/shared/systemd/src/shared/dns-domain.c
index 3efa381682..92543ebe9b 100644
--- a/src/systemd/src/shared/dns-domain.c
+++ b/shared/systemd/src/shared/dns-domain.c
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-#include "nm-sd-adapt-core.h"
+#include "nm-sd-adapt-shared.h"
#if 0 /* NM_IGNORED */
#if HAVE_LIBIDN2
diff --git a/src/systemd/src/shared/dns-domain.h b/shared/systemd/src/shared/dns-domain.h
index 17db7c5274..17db7c5274 100644
--- a/src/systemd/src/shared/dns-domain.h
+++ b/shared/systemd/src/shared/dns-domain.h
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index abcff229bf..569ff6289d 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -7694,9 +7694,13 @@ clear_config:
static void
dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success)
{
- if (success)
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ if (success) {
+ nm_dhcp_client_accept (priv->dhcp4.client, NULL);
nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (configs[1]));
- else {
+ } else {
+ nm_dhcp_client_decline (priv->dhcp4.client, "Address conflict detected", NULL);
nm_device_ip_method_failed (self, AF_INET,
NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE);
}
@@ -7962,9 +7966,11 @@ dhcp4_start (NMDevice *self)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingIPConfig *s_ip4;
gs_unref_bytes GBytes *hwaddr = NULL;
+ gs_unref_bytes GBytes *bcast_hwaddr = NULL;
gs_unref_bytes GBytes *client_id = NULL;
NMConnection *connection;
GError *error = NULL;
+ const NMPlatformLink *pllink;
connection = nm_device_get_applied_connection (self);
g_return_val_if_fail (connection, FALSE);
@@ -7975,8 +7981,11 @@ dhcp4_start (NMDevice *self)
nm_dbus_object_clear_and_unexport (&priv->dhcp4.config);
priv->dhcp4.config = nm_dhcp4_config_new ();
- hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self),
- nm_device_get_ip_ifindex (self));
+ pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self));
+ if (pllink) {
+ hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address);
+ bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast);
+ }
client_id = dhcp4_get_client_id (self, connection, hwaddr);
@@ -7986,6 +7995,7 @@ dhcp4_start (NMDevice *self)
nm_device_get_ip_iface (self),
nm_device_get_ip_ifindex (self),
hwaddr,
+ bcast_hwaddr,
nm_connection_get_uuid (connection),
nm_device_get_route_table (self, AF_INET),
nm_device_get_route_metric (self, AF_INET),
@@ -8763,8 +8773,10 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingIPConfig *s_ip6;
gs_unref_bytes GBytes *hwaddr = NULL;
+ gs_unref_bytes GBytes *bcast_hwaddr = NULL;
gs_unref_bytes GBytes *duid = NULL;
gboolean enforce_duid = FALSE;
+ const NMPlatformLink *pllink;
GError *error = NULL;
const NMPlatformIP6Address *ll_addr = NULL;
@@ -8784,8 +8796,11 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
return FALSE;
}
- hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self),
- nm_device_get_ip_ifindex (self));
+ pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self));
+ if (pllink) {
+ hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address);
+ bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast);
+ }
duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid);
priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (),
@@ -8793,6 +8808,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
nm_device_get_ip_iface (self),
nm_device_get_ip_ifindex (self),
hwaddr,
+ bcast_hwaddr,
&ll_addr->address,
nm_connection_get_uuid (connection),
nm_device_get_route_table (self, AF_INET6),
diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c
index 6c95d5790c..e6ac217c56 100644
--- a/src/dhcp/nm-dhcp-client.c
+++ b/src/dhcp/nm-dhcp-client.c
@@ -51,6 +51,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDhcpClient,
PROP_ADDR_FAMILY,
PROP_FLAGS,
PROP_HWADDR,
+ PROP_BROADCAST_HWADDR,
PROP_IFACE,
PROP_IFINDEX,
PROP_MULTI_IDX,
@@ -65,6 +66,7 @@ typedef struct _NMDhcpClientPrivate {
NMDedupMultiIndex *multi_idx;
char * iface;
GBytes * hwaddr;
+ GBytes * bcast_hwaddr;
char * uuid;
GBytes * client_id;
char * hostname;
@@ -143,6 +145,14 @@ nm_dhcp_client_get_hw_addr (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->hwaddr;
}
+GBytes *
+nm_dhcp_client_get_broadcast_hw_addr (NMDhcpClient *self)
+{
+ g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
+
+ return NM_DHCP_CLIENT_GET_PRIVATE (self)->bcast_hwaddr;
+}
+
guint32
nm_dhcp_client_get_route_table (NMDhcpClient *self)
{
@@ -530,6 +540,36 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
error);
}
+gboolean
+nm_dhcp_client_accept (NMDhcpClient *self,
+ GError **error)
+{
+ g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
+
+ if (NM_DHCP_CLIENT_GET_CLASS (self)->accept) {
+ return NM_DHCP_CLIENT_GET_CLASS (self)->accept (self,
+ error);
+ }
+
+ return TRUE;
+}
+
+gboolean
+nm_dhcp_client_decline (NMDhcpClient *self,
+ const char *error_message,
+ GError **error)
+{
+ g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
+
+ if (NM_DHCP_CLIENT_GET_CLASS (self)->decline) {
+ return NM_DHCP_CLIENT_GET_CLASS (self)->decline (self,
+ error_message,
+ error);
+ }
+
+ return TRUE;
+}
+
static GBytes *
get_duid (NMDhcpClient *self)
{
@@ -839,6 +879,9 @@ get_property (GObject *object, guint prop_id,
case PROP_HWADDR:
g_value_set_boxed (value, priv->hwaddr);
break;
+ case PROP_BROADCAST_HWADDR:
+ g_value_set_boxed (value, priv->bcast_hwaddr);
+ break;
case PROP_ADDR_FAMILY:
g_value_set_int (value, priv->addr_family);
break;
@@ -900,6 +943,10 @@ set_property (GObject *object, guint prop_id,
/* construct-only */
priv->hwaddr = g_value_dup_boxed (value);
break;
+ case PROP_BROADCAST_HWADDR:
+ /* construct-only */
+ priv->bcast_hwaddr = g_value_dup_boxed (value);
+ break;
case PROP_ADDR_FAMILY:
/* construct-only */
priv->addr_family = g_value_get_int (value);
@@ -966,6 +1013,7 @@ dispose (GObject *object)
g_clear_pointer (&priv->uuid, g_free);
g_clear_pointer (&priv->client_id, g_bytes_unref);
g_clear_pointer (&priv->hwaddr, g_bytes_unref);
+ g_clear_pointer (&priv->bcast_hwaddr, g_bytes_unref);
G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object);
@@ -1010,6 +1058,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_BROADCAST_HWADDR] =
+ g_param_spec_boxed (NM_DHCP_CLIENT_BROADCAST_HWADDR, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
obj_properties[PROP_ADDR_FAMILY] =
g_param_spec_int (NM_DHCP_CLIENT_ADDR_FAMILY, "", "",
0, G_MAXINT, AF_UNSPEC,
diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h
index 1a8ccaba2b..9eb76f33a8 100644
--- a/src/dhcp/nm-dhcp-client.h
+++ b/src/dhcp/nm-dhcp-client.h
@@ -34,17 +34,18 @@
#define NM_IS_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_CLIENT))
#define NM_DHCP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass))
-#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family"
-#define NM_DHCP_CLIENT_FLAGS "flags"
-#define NM_DHCP_CLIENT_HWADDR "hwaddr"
-#define NM_DHCP_CLIENT_IFINDEX "ifindex"
-#define NM_DHCP_CLIENT_INTERFACE "iface"
-#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx"
-#define NM_DHCP_CLIENT_HOSTNAME "hostname"
-#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric"
-#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table"
-#define NM_DHCP_CLIENT_TIMEOUT "timeout"
-#define NM_DHCP_CLIENT_UUID "uuid"
+#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family"
+#define NM_DHCP_CLIENT_FLAGS "flags"
+#define NM_DHCP_CLIENT_HWADDR "hwaddr"
+#define NM_DHCP_CLIENT_BROADCAST_HWADDR "broadcast-hwaddr"
+#define NM_DHCP_CLIENT_IFINDEX "ifindex"
+#define NM_DHCP_CLIENT_INTERFACE "iface"
+#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx"
+#define NM_DHCP_CLIENT_HOSTNAME "hostname"
+#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric"
+#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table"
+#define NM_DHCP_CLIENT_TIMEOUT "timeout"
+#define NM_DHCP_CLIENT_UUID "uuid"
#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated"
@@ -82,6 +83,13 @@ typedef struct {
const char *last_ip4_address,
GError **error);
+ gboolean (*accept) (NMDhcpClient *self,
+ GError **error);
+
+ gboolean (*decline) (NMDhcpClient *self,
+ const char *error_message,
+ GError **error);
+
gboolean (*ip6_start) (NMDhcpClient *self,
const char *anycast_addr,
const struct in6_addr *ll_addr,
@@ -122,6 +130,8 @@ GBytes *nm_dhcp_client_get_duid (NMDhcpClient *self);
GBytes *nm_dhcp_client_get_hw_addr (NMDhcpClient *self);
+GBytes *nm_dhcp_client_get_broadcast_hw_addr (NMDhcpClient *self);
+
guint32 nm_dhcp_client_get_route_table (NMDhcpClient *self);
void nm_dhcp_client_set_route_table (NMDhcpClient *self, guint32 route_table);
@@ -155,6 +165,13 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
guint needed_prefixes,
GError **error);
+gboolean nm_dhcp_client_accept (NMDhcpClient *self,
+ GError **error);
+
+gboolean nm_dhcp_client_decline (NMDhcpClient *self,
+ const char *error_message,
+ GError **error);
+
void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release);
/* Backend helpers for subclasses */
@@ -199,5 +216,6 @@ extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon;
extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient;
extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd;
extern const NMDhcpClientFactory _nm_dhcp_client_factory_internal;
+extern const NMDhcpClientFactory _nm_dhcp_client_factory_nettools;
#endif /* __NETWORKMANAGER_DHCP_CLIENT_H__ */
diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c
index d0656ca707..a6e4fbd202 100644
--- a/src/dhcp/nm-dhcp-listener.c
+++ b/src/dhcp/nm-dhcp-listener.c
@@ -38,7 +38,7 @@
/*****************************************************************************/
-const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = {
+const NMDhcpClientFactory *const _nm_dhcp_manager_factories[5] = {
/* the order here matters, as we will try the plugins in this order to find
* the first available plugin. */
@@ -52,6 +52,7 @@ const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = {
&_nm_dhcp_client_factory_dhcpcd,
#endif
&_nm_dhcp_client_factory_internal,
+ &_nm_dhcp_client_factory_nettools,
};
/*****************************************************************************/
diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c
index e8ca293304..304a7b9961 100644
--- a/src/dhcp/nm-dhcp-manager.c
+++ b/src/dhcp/nm-dhcp-manager.c
@@ -204,6 +204,7 @@ client_start (NMDhcpManager *self,
const char *iface,
int ifindex,
GBytes *hwaddr,
+ GBytes *bcast_hwaddr,
const char *uuid,
guint32 route_table,
guint32 route_metric,
@@ -233,10 +234,11 @@ client_start (NMDhcpManager *self,
g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL);
g_return_val_if_fail (!error || !*error, NULL);
- if (!hwaddr) {
+ if (!hwaddr || !bcast_hwaddr) {
nm_utils_error_set (error,
NM_UTILS_ERROR_UNKNOWN,
- "missing MAC address");
+ "missing %s address",
+ hwaddr ? "broadcast" : "MAC");
return NULL;
}
@@ -249,6 +251,8 @@ client_start (NMDhcpManager *self,
g_return_val_if_reached (NULL) ;
}
+ nm_assert (g_bytes_get_size (hwaddr) == g_bytes_get_size (bcast_hwaddr));
+
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
client_factory = _client_factory_get_effective (priv->client_factory, addr_family);
@@ -273,6 +277,7 @@ client_start (NMDhcpManager *self,
NM_DHCP_CLIENT_INTERFACE, iface,
NM_DHCP_CLIENT_IFINDEX, ifindex,
NM_DHCP_CLIENT_HWADDR, hwaddr,
+ NM_DHCP_CLIENT_BROADCAST_HWADDR, bcast_hwaddr,
NM_DHCP_CLIENT_UUID, uuid,
NM_DHCP_CLIENT_HOSTNAME, hostname,
NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table,
@@ -345,6 +350,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
const char *iface,
int ifindex,
GBytes *hwaddr,
+ GBytes *bcast_hwaddr,
const char *uuid,
guint32 route_table,
guint32 route_metric,
@@ -395,6 +401,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
iface,
ifindex,
hwaddr,
+ bcast_hwaddr,
uuid,
route_table,
route_metric,
@@ -419,6 +426,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
const char *iface,
int ifindex,
GBytes *hwaddr,
+ GBytes *bcast_hwaddr,
const struct in6_addr *ll_addr,
const char *uuid,
guint32 route_table,
@@ -450,6 +458,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
iface,
ifindex,
hwaddr,
+ bcast_hwaddr,
uuid,
route_table,
route_metric,
diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h
index f66930db11..ff0d6f5472 100644
--- a/src/dhcp/nm-dhcp-manager.h
+++ b/src/dhcp/nm-dhcp-manager.h
@@ -49,6 +49,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager,
const char *iface,
int ifindex,
GBytes *hwaddr,
+ GBytes *bcast_hwaddr,
const char *uuid,
guint32 route_table,
guint32 route_metric,
@@ -66,6 +67,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
const char *iface,
int ifindex,
GBytes *hwaddr,
+ GBytes *bcast_hwaddr,
const struct in6_addr *ll_addr,
const char *uuid,
guint32 route_table,
@@ -84,7 +86,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
/* For testing only */
extern const char* nm_dhcp_helper_path;
-extern const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4];
+extern const NMDhcpClientFactory *const _nm_dhcp_manager_factories[5];
void nmtst_dhcp_manager_unget (gpointer singleton_instance);
diff --git a/src/dhcp/nm-dhcp-nettools.c b/src/dhcp/nm-dhcp-nettools.c
new file mode 100644
index 0000000000..d24392e7ed
--- /dev/null
+++ b/src/dhcp/nm-dhcp-nettools.c
@@ -0,0 +1,1380 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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-2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <net/if_arp.h>
+
+#include "nm-sd-adapt-shared.h"
+#include "hostname-util.h"
+
+#include "nm-glib-aux/nm-dedup-multi.h"
+#include "nm-std-aux/unaligned.h"
+
+#include "nm-utils.h"
+#include "nm-config.h"
+#include "nm-dhcp-utils.h"
+#include "nm-core-utils.h"
+#include "NetworkManagerUtils.h"
+#include "platform/nm-platform.h"
+#include "nm-dhcp-client-logging.h"
+#include "n-dhcp4/src/n-dhcp4.h"
+#include "systemd/nm-sd-utils-shared.h"
+
+/*****************************************************************************/
+
+#define NM_TYPE_DHCP_NETTOOLS (nm_dhcp_nettools_get_type ())
+#define NM_DHCP_NETTOOLS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettools))
+#define NM_DHCP_NETTOOLS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettoolsClass))
+#define NM_IS_DHCP_NETTOOLS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP_NETTOOLS))
+#define NM_IS_DHCP_NETTOOLS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_NETTOOLS))
+#define NM_DHCP_NETTOOLS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettoolsClass))
+
+typedef struct _NMDhcpNettools NMDhcpNettools;
+typedef struct _NMDhcpNettoolsClass NMDhcpNettoolsClass;
+
+static GType nm_dhcp_nettools_get_type (void);
+
+/*****************************************************************************/
+
+typedef struct {
+ NDhcp4Client *client;
+ NDhcp4ClientProbe *probe;
+ NDhcp4ClientLease *lease;
+ GIOChannel *channel;
+ guint event_id;
+} NMDhcpNettoolsPrivate;
+
+struct _NMDhcpNettools {
+ NMDhcpClient parent;
+ NMDhcpNettoolsPrivate _priv;
+};
+
+struct _NMDhcpNettoolsClass {
+ NMDhcpClientClass parent;
+};
+
+G_DEFINE_TYPE (NMDhcpNettools, nm_dhcp_nettools, NM_TYPE_DHCP_CLIENT)
+
+#define NM_DHCP_NETTOOLS_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcpNettools, NM_IS_DHCP_NETTOOLS)
+
+/*****************************************************************************/
+
+#define DHCP_OPTION_SUBNET_MASK 1
+#define DHCP_OPTION_TIME_OFFSET 2
+#define DHCP_OPTION_ROUTER 3
+#define DHCP_OPTION_DOMAIN_NAME_SERVER 6
+#define DHCP_OPTION_HOST_NAME 12
+#define DHCP_OPTION_DOMAIN_NAME 15
+#define DHCP_OPTION_ROOT_PATH 17
+#define DHCP_OPTION_INTERFACE_MTU 26
+#define DHCP_OPTION_BROADCAST 28
+#define DHCP_OPTION_STATIC_ROUTE 33
+#define DHCP_OPTION_NIS_DOMAIN 40
+#define DHCP_OPTION_NIS_SERVERS 41
+#define DHCP_OPTION_NTP_SERVER 42
+#define DHCP_OPTION_VENDOR_SPECIFIC 43
+#define DHCP_OPTION_IP_ADDRESS_LEASE_TIME 51
+#define DHCP_OPTION_SERVER_IDENTIFIER 54
+#define DHCP_OPTION_CLIENT_IDENTIFIER 61
+#define DHCP_OPTION_CLIENT_FQDN 81
+#define DHCP_OPTION_DOMAIN_SEARCH_LIST 119
+#define DHCP_OPTION_CLASSLESS_STATIC_ROUTE 121
+#define DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE 249
+#define DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY 252
+
+/* Internal values */
+#define DHCP_OPTION_IP_ADDRESS 1024
+#define DHCP_OPTION_EXPIRY 1025
+
+#define DHCP_MAX_FQDN_LENGTH 255
+
+enum {
+ DHCP_FQDN_FLAG_S = (1 << 0),
+ DHCP_FQDN_FLAG_O = (1 << 1),
+ DHCP_FQDN_FLAG_E = (1 << 2),
+ DHCP_FQDN_FLAG_N = (1 << 3),
+};
+
+enum {
+ NM_IN_ADDR_CLASS_A,
+ NM_IN_ADDR_CLASS_B,
+ NM_IN_ADDR_CLASS_C,
+ NM_IN_ADDR_CLASS_INVALID,
+};
+
+typedef struct {
+ const char *name;
+ uint16_t option_num;
+ bool include;
+} ReqOption;
+
+#define REQPREFIX "requested_"
+
+#define REQ(_num, _name, _include) \
+ { \
+ .name = REQPREFIX""_name, \
+ .option_num = _num, \
+ .include = _include, \
+ }
+
+static const ReqOption dhcp4_requests[] = {
+ REQ (DHCP_OPTION_SUBNET_MASK, "subnet_mask", TRUE ),
+ REQ (DHCP_OPTION_TIME_OFFSET, "time_offset", TRUE ),
+ REQ (DHCP_OPTION_DOMAIN_NAME_SERVER, "domain_name_servers", TRUE ),
+ REQ (DHCP_OPTION_HOST_NAME, "host_name", TRUE ),
+ REQ (DHCP_OPTION_DOMAIN_NAME, "domain_name", TRUE ),
+ REQ (DHCP_OPTION_INTERFACE_MTU, "interface_mtu", TRUE ),
+ REQ (DHCP_OPTION_BROADCAST, "broadcast_address", TRUE ),
+
+ /* RFC 3442: The Classless Static Routes option code MUST appear in the parameter
+ * request list prior to both the Router option code and the Static
+ * Routes option code, if present. */
+ REQ (DHCP_OPTION_CLASSLESS_STATIC_ROUTE, "rfc3442_classless_static_routes", TRUE ),
+ REQ (DHCP_OPTION_ROUTER, "routers", TRUE ),
+ REQ (DHCP_OPTION_STATIC_ROUTE, "static_routes", TRUE ),
+ REQ (DHCP_OPTION_NIS_DOMAIN, "nis_domain", TRUE ),
+ REQ (DHCP_OPTION_NIS_SERVERS, "nis_servers", TRUE ),
+ REQ (DHCP_OPTION_NTP_SERVER, "ntp_servers", TRUE ),
+ REQ (DHCP_OPTION_SERVER_IDENTIFIER, "dhcp_server_identifier", TRUE ),
+ REQ (DHCP_OPTION_DOMAIN_SEARCH_LIST, "domain_search", TRUE ),
+ REQ (DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, "ms_classless_static_routes", TRUE ),
+ REQ (DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, "wpad", TRUE ),
+ REQ (DHCP_OPTION_ROOT_PATH, "root_path", TRUE ),
+
+ /* Internal values */
+ REQ (DHCP_OPTION_IP_ADDRESS_LEASE_TIME, "expiry", FALSE ),
+ REQ (DHCP_OPTION_CLIENT_IDENTIFIER, "dhcp_client_identifier", FALSE ),
+ REQ (DHCP_OPTION_IP_ADDRESS, "ip_address", FALSE ),
+
+ { 0 }
+};
+
+static int
+in_addr_class (struct in_addr addr)
+{
+ switch (ntohl (addr.s_addr) >> 24) {
+ case 0 ... 127:
+ return NM_IN_ADDR_CLASS_A;
+ case 128 ... 191:
+ return NM_IN_ADDR_CLASS_B;
+ case 192 ... 223:
+ return NM_IN_ADDR_CLASS_C;
+ default:
+ return NM_IN_ADDR_CLASS_INVALID;
+ }
+}
+
+static void
+take_option (GHashTable *options,
+ const ReqOption *requests,
+ guint option,
+ char *value)
+{
+ guint i;
+
+ nm_assert (options);
+ nm_assert (requests);
+ nm_assert (value);
+
+ for (i = 0; requests[i].name; i++) {
+ nm_assert (g_str_has_prefix (requests[i].name, REQPREFIX));
+ if (requests[i].option_num == option) {
+ g_hash_table_insert (options,
+ (gpointer) (requests[i].name + NM_STRLEN (REQPREFIX)),
+ value);
+ return;
+ }
+ }
+
+ /* Option should always be found */
+ nm_assert_not_reached ();
+}
+
+static void
+add_option (GHashTable *options, const ReqOption *requests, guint option, const char *value)
+{
+ if (options)
+ take_option (options, requests, option, g_strdup (value));
+}
+
+static void
+add_option_u64 (GHashTable *options, const ReqOption *requests, guint option, guint64 value)
+{
+ if (options)
+ take_option (options, requests, option, g_strdup_printf ("%" G_GUINT64_FORMAT, value));
+}
+
+static void
+add_requests_to_options (GHashTable *options, const ReqOption *requests)
+{
+ guint i;
+
+ if (!options)
+ return;
+
+ for (i = 0; requests[i].name; i++) {
+ if (requests[i].include)
+ g_hash_table_insert (options, (gpointer) requests[i].name, g_strdup ("1"));
+ }
+}
+
+static GHashTable *
+create_options_dict (void)
+{
+ return g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_free);
+}
+
+static gboolean
+lease_option_consume (void *out,
+ size_t n_out,
+ uint8_t **datap,
+ size_t *n_datap)
+{
+ if (*n_datap < n_out)
+ return FALSE;
+
+ memcpy (out, *datap, n_out);
+ *datap += n_out;
+ *n_datap -= n_out;
+ return TRUE;
+}
+
+static gboolean
+lease_option_next_in_addr (struct in_addr *addrp,
+ uint8_t **datap,
+ size_t *n_datap)
+{
+ return lease_option_consume (addrp, sizeof (struct in_addr), datap, n_datap);
+}
+
+static gboolean
+lease_option_next_route (struct in_addr *destp,
+ uint8_t *plenp,
+ struct in_addr *gatewayp,
+ gboolean classless,
+ uint8_t **datap,
+ size_t *n_datap)
+{
+ struct in_addr dest = {}, gateway;
+ uint8_t *data = *datap;
+ size_t n_data = *n_datap;
+ uint8_t plen;
+
+ if (classless) {
+ if (!lease_option_consume (&plen, sizeof (plen), &data, &n_data))
+ return FALSE;
+
+ if (plen > 32)
+ return FALSE;
+
+ if (!lease_option_consume (&dest, plen / 8, &data, &n_data))
+ return FALSE;
+ } else {
+ if (!lease_option_next_in_addr (&dest, &data, &n_data))
+ return FALSE;
+
+ switch (in_addr_class (dest)) {
+ case NM_IN_ADDR_CLASS_A:
+ plen = 8;
+ break;
+ case NM_IN_ADDR_CLASS_B:
+ plen = 16;
+ break;
+ case NM_IN_ADDR_CLASS_C:
+ plen = 24;
+ break;
+ case NM_IN_ADDR_CLASS_INVALID:
+ return FALSE;
+ }
+ }
+
+ dest.s_addr = nm_utils_ip4_address_clear_host_address (dest.s_addr, plen);
+
+ if (!lease_option_next_in_addr (&gateway, &data, &n_data))
+ return FALSE;
+
+ *destp = dest;
+ *plenp = plen;
+ *gatewayp = gateway;
+ *datap = data;
+ *n_datap = n_data;
+ return TRUE;
+}
+
+static gboolean
+lease_option_print_label (GString *str, size_t n_label, uint8_t **datap, size_t *n_datap)
+{
+ for (size_t i = 0; i < n_label; ++i) {
+ uint8_t c;
+
+ if (!lease_option_consume(&c, sizeof (c), datap, n_datap))
+ return FALSE;
+
+ switch (c) {
+ case 'a' ... 'z':
+ case 'A' ... 'Z':
+ case '0' ... '9':
+ case '-':
+ case '_':
+ g_string_append_c(str, c);
+ break;
+ case '.':
+ case '\\':
+ g_string_append_printf(str, "\\%c", c);
+ break;
+ default:
+ g_string_append_printf(str, "\\%3d", c);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+lease_option_print_domain_name (GString *str, uint8_t *cache, size_t *n_cachep, uint8_t **datap, size_t *n_datap)
+{
+ uint8_t *domain;
+ size_t n_domain, n_cache = *n_cachep;
+ uint8_t **domainp = datap;
+ size_t *n_domainp = n_datap;
+ gboolean first = TRUE;
+ uint8_t c;
+
+ /*
+ * We are given two adjacent memory regions. The @cache contains alreday parsed
+ * domain names, and the @datap contains the remaining data to parse.
+ *
+ * A domain name is formed from a sequence of labels. Each label start with
+ * a length byte, where the two most significant bits are unset. A zero-length
+ * label indicates the end of the domain name.
+ *
+ * Alternatively, a label can be followed by an offset (indicated by the two
+ * most significant bits being set in the next byte that is read). The offset
+ * is an offset into the cache, where the next label of the domain name can
+ * be found.
+ *
+ * Note, that each time a jump to an offset is performed, the size of the
+ * cache shrinks, so this is guaranteed to terminate.
+ */
+ if (cache + n_cache != *datap)
+ return FALSE;
+
+ for (;;) {
+ if (!lease_option_consume(&c, sizeof (c), domainp, n_domainp))
+ return FALSE;
+
+ switch (c & 0xC0) {
+ case 0x00: /* label length */
+ {
+ size_t n_label = c;
+
+ if (n_label == 0) {
+ /*
+ * We reached the final label of the domain name. Adjust
+ * the cache to include the consumed data, and return.
+ */
+ *n_cachep = *datap - cache;
+ return TRUE;
+ }
+
+ if (!first) {
+ g_string_append_c(str, '.');
+ first = FALSE;
+ }
+
+ if (!lease_option_print_label (str, n_label, domainp, n_domainp))
+ return FALSE;
+
+ break;
+ }
+ case 0xC0: /* back pointer */
+ {
+ size_t offset = (c & 0x3F) << 16;
+
+ /*
+ * The offset is given as two bytes (in big endian), where the
+ * two high bits are masked out.
+ */
+
+ if (!lease_option_consume (&c, sizeof (c), domainp, n_domainp))
+ return FALSE;
+
+ offset += c;
+
+ if (offset >= n_cache)
+ return FALSE;
+
+ domain = cache + offset;
+ n_domain = n_cache - offset;
+ n_cache = offset;
+
+ domainp = &domain;
+ n_domainp = &n_domain;
+
+ break;
+ }
+ default:
+ return FALSE;
+ }
+ }
+}
+
+static gboolean
+lease_get_in_addr (NDhcp4ClientLease *lease,
+ guint8 option,
+ struct in_addr *addrp) {
+ struct in_addr addr;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, option, &data, &n_data);
+ if (r)
+ return FALSE;
+
+ if (!lease_option_next_in_addr (&addr, &data, &n_data))
+ return FALSE;
+
+ if (n_data != 0)
+ return FALSE;
+
+ *addrp = addr;
+ return TRUE;
+}
+
+static gboolean
+lease_get_u16 (NDhcp4ClientLease *lease,
+ uint8_t option,
+ uint16_t *u16p)
+{
+ uint8_t *data;
+ size_t n_data;
+ uint16_t be16;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, option, &data, &n_data);
+ if (r)
+ return FALSE;
+
+ if (n_data != sizeof (be16))
+ return FALSE;
+
+ memcpy (&be16, data, sizeof (be16));
+
+ *u16p = ntohs(be16);
+ return TRUE;
+}
+
+#define LOG_LEASE(domain, ...) \
+ G_STMT_START { \
+ _LOG2I ((domain), (iface), " "__VA_ARGS__); \
+ } G_STMT_END
+
+static gboolean
+lease_parse_address (NDhcp4ClientLease *lease,
+ const char *iface,
+ NMIP4Config *ip4_config,
+ GHashTable *options,
+ GError **error)
+{
+ char addr_str[NM_UTILS_INET_ADDRSTRLEN];
+ const gint64 ts = nm_utils_get_monotonic_timestamp_ns ();
+ struct in_addr a_address;
+ struct in_addr a_netmask;
+ guint32 a_plen;
+ guint64 a_lifetime;
+
+ n_dhcp4_client_lease_get_yiaddr (lease, &a_address);
+ n_dhcp4_client_lease_get_lifetime (lease, &a_lifetime);
+
+ if (!lease_get_in_addr (lease, DHCP_OPTION_SUBNET_MASK, &a_netmask)) {
+ nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get netmask from lease");
+ return FALSE;
+ }
+
+ nm_utils_inet4_ntop (a_address.s_addr, addr_str);
+ a_plen = nm_utils_ip4_netmask_to_prefix (a_netmask.s_addr);
+
+ LOG_LEASE (LOGD_DHCP4, "address %s/%u", addr_str, a_plen);
+ add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, addr_str);
+ add_option (options,
+ dhcp4_requests,
+ DHCP_OPTION_SUBNET_MASK,
+ nm_utils_inet4_ntop (a_netmask.s_addr, addr_str));
+
+ LOG_LEASE (LOGD_DHCP4, "expires in %u seconds",
+ (guint) ((a_lifetime - ts)/1000000000));
+ add_option_u64 (options,
+ dhcp4_requests,
+ DHCP_OPTION_IP_ADDRESS_LEASE_TIME,
+ (guint64) (a_lifetime / 1000000000));
+
+ nm_ip4_config_add_address (ip4_config,
+ &((const NMPlatformIP4Address) {
+ .address = a_address.s_addr,
+ .peer_address = a_address.s_addr,
+ .plen = a_plen,
+ .addr_source = NM_IP_CONFIG_SOURCE_DHCP,
+ .timestamp = ts / 1000000000,
+ .lifetime = (a_lifetime - ts) / 1000000000,
+ .preferred = (a_lifetime - ts) / 1000000000,
+ }));
+
+ return TRUE;
+}
+
+static void
+lease_parse_domain_name_servers (NDhcp4ClientLease *lease,
+ const char *iface,
+ NMIP4Config *ip4_config,
+ GHashTable *options)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ char addr_str[NM_UTILS_INET_ADDRSTRLEN];
+ struct in_addr addr;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_DOMAIN_NAME_SERVER, &data, &n_data);
+ if (r)
+ return;
+
+ nm_gstring_prepare (&str);
+
+ while (lease_option_next_in_addr (&addr, &data, &n_data)) {
+
+ nm_utils_inet4_ntop (addr.s_addr, addr_str);
+ g_string_append (nm_gstring_add_space_delimiter (str), addr_str);
+
+ if ( addr.s_addr == 0
+ || nm_ip4_addr_is_localhost (addr.s_addr)) {
+ /* Skip localhost addresses, like also networkd does.
+ * See https://github.com/systemd/systemd/issues/4524. */
+ continue;
+ }
+ nm_ip4_config_add_nameserver (ip4_config, addr.s_addr);
+ }
+
+ LOG_LEASE (LOGD_DHCP4, "nameserver '%s'", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_DOMAIN_NAME_SERVER, str->str);
+}
+
+static void
+lease_parse_routes (NDhcp4ClientLease *lease,
+ const char *iface,
+ NMIP4Config *ip4_config,
+ GHashTable *options,
+ guint32 route_table,
+ guint32 route_metric)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ char dest_str[NM_UTILS_INET_ADDRSTRLEN];
+ char gateway_str[NM_UTILS_INET_ADDRSTRLEN];
+ const char *s;
+ struct in_addr dest, gateway;
+ uint8_t plen;
+ guint32 m;
+ gboolean has_router_from_classless = FALSE, has_classless = FALSE;
+ guint32 default_route_metric = route_metric;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_CLASSLESS_STATIC_ROUTE, &data, &n_data);
+ if (!r) {
+ nm_gstring_prepare (&str);
+
+ has_classless = TRUE;
+
+ while (lease_option_next_route (&dest, &plen, &gateway, TRUE, &data, &n_data)) {
+
+ nm_utils_inet4_ntop (dest.s_addr, dest_str);
+ nm_utils_inet4_ntop (gateway.s_addr, gateway_str);
+
+ LOG_LEASE (LOGD_DHCP4,
+ "classless static route %s/%d gw %s",
+ dest_str,
+ (int) plen,
+ gateway_str);
+ g_string_append_printf (nm_gstring_add_space_delimiter (str),
+ "%s/%d %s",
+ dest_str,
+ (int) plen,
+ gateway_str);
+
+ if (plen == 0) {
+ /* if there are multiple default routes, we add them with differing
+ * metrics. */
+ m = default_route_metric;
+ if (default_route_metric < G_MAXUINT32)
+ default_route_metric++;
+
+ has_router_from_classless = TRUE;
+ } else {
+ m = route_metric;
+ }
+
+ nm_ip4_config_add_route (ip4_config,
+ &((const NMPlatformIP4Route) {
+ .network = dest.s_addr,
+ .plen = plen,
+ .gateway = gateway.s_addr,
+ .rt_source = NM_IP_CONFIG_SOURCE_DHCP,
+ .metric = m,
+ .table_coerced = nm_platform_route_table_coerce (route_table),
+ }),
+ NULL);
+ }
+ add_option (options, dhcp4_requests, DHCP_OPTION_CLASSLESS_STATIC_ROUTE, str->str);
+ }
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_STATIC_ROUTE, &data, &n_data);
+ if (!r) {
+ nm_gstring_prepare (&str);
+
+ while (lease_option_next_route (&dest, &plen, &gateway, FALSE, &data, &n_data)) {
+
+ nm_utils_inet4_ntop (dest.s_addr, dest_str);
+ nm_utils_inet4_ntop (gateway.s_addr, gateway_str);
+
+ LOG_LEASE (LOGD_DHCP4,
+ "static route %s/%d gw %s",
+ dest_str,
+ (int) plen,
+ gateway_str);
+ g_string_append_printf (nm_gstring_add_space_delimiter (str),
+ "%s/%d %s",
+ dest_str,
+ (int) plen,
+ gateway_str);
+
+ if (has_classless) {
+ /* RFC 3443: if the DHCP server returns both a Classless Static Routes
+ * option and a Static Routes option, the DHCP client MUST ignore the
+ * Static Routes option. */
+ continue;
+ }
+
+ if (plen == 0) {
+ /* for option 33 (static route), RFC 2132 says:
+ *
+ * The default route (0.0.0.0) is an illegal destination for a static
+ * route. */
+ continue;
+ }
+
+ nm_ip4_config_add_route (ip4_config,
+ &((const NMPlatformIP4Route) {
+ .network = dest.s_addr,
+ .plen = plen,
+ .gateway = gateway.s_addr,
+ .rt_source = NM_IP_CONFIG_SOURCE_DHCP,
+ .metric = route_metric,
+ .table_coerced = nm_platform_route_table_coerce (route_table),
+ }),
+ NULL);
+ }
+ add_option (options, dhcp4_requests, DHCP_OPTION_STATIC_ROUTE, str->str);
+ }
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_ROUTER, &data, &n_data);
+ if (!r) {
+ nm_gstring_prepare (&str);
+
+ while (lease_option_next_in_addr (&gateway, &data, &n_data)) {
+ s = nm_utils_inet4_ntop (gateway.s_addr, gateway_str);
+ g_string_append (nm_gstring_add_space_delimiter (str), s);
+
+ if (gateway.s_addr == 0) {
+ /* silently skip 0.0.0.0 */
+ continue;
+ }
+
+ if (has_router_from_classless) {
+ /* If the DHCP server returns both a Classless Static Routes option and a
+ * Router option, the DHCP client MUST ignore the Router option [RFC 3442].
+ *
+ * Be more lenient and ignore the Router option only if Classless Static
+ * Routes contain a default gateway (as other DHCP backends do).
+ */
+ continue;
+ }
+
+ /* if there are multiple default routes, we add them with differing
+ * metrics. */
+ m = default_route_metric;
+ if (default_route_metric < G_MAXUINT32)
+ default_route_metric++;
+
+ nm_ip4_config_add_route (ip4_config,
+ &((const NMPlatformIP4Route) {
+ .rt_source = NM_IP_CONFIG_SOURCE_DHCP,
+ .gateway = gateway.s_addr,
+ .table_coerced = nm_platform_route_table_coerce (route_table),
+ .metric = m,
+ }),
+ NULL);
+ }
+ LOG_LEASE (LOGD_DHCP4, "router %s", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_ROUTER, str->str);
+ }
+}
+
+static void
+lease_parse_mtu (NDhcp4ClientLease *lease,
+ const char *iface,
+ NMIP4Config *ip4_config,
+ GHashTable *options)
+{
+ uint16_t mtu;
+
+ if (!lease_get_u16 (lease, DHCP_OPTION_INTERFACE_MTU, &mtu))
+ return;
+
+ if (mtu < 68)
+ return;
+
+ LOG_LEASE (LOGD_DHCP4, "mtu %u", mtu);
+ add_option_u64 (options, dhcp4_requests, DHCP_OPTION_INTERFACE_MTU, mtu);
+ nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP);
+}
+
+static void
+lease_parse_metered (NDhcp4ClientLease *lease,
+ const char *iface,
+ NMIP4Config *ip4_config,
+ GHashTable *options)
+{
+ gboolean metered = FALSE;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_VENDOR_SPECIFIC, &data, &n_data);
+ if (r) {
+ metered = FALSE;
+ } else {
+ metered = !!memmem (data, n_data, "ANDROID_METERED", NM_STRLEN ("ANDROID_METERED"));
+ }
+
+ LOG_LEASE (LOGD_DHCP4, "%s", metered ? "metered" : "unmetered");
+ nm_ip4_config_set_metered (ip4_config, metered);
+}
+
+static void
+lease_parse_ntps (NDhcp4ClientLease *lease,
+ const char *iface,
+ GHashTable *options)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ char addr_str[NM_UTILS_INET_ADDRSTRLEN];
+ struct in_addr addr;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_NTP_SERVER, &data, &n_data);
+ if (r)
+ return;
+
+ nm_gstring_prepare (&str);
+
+ while (lease_option_next_in_addr (&addr, &data, &n_data)) {
+ nm_utils_inet4_ntop (addr.s_addr, addr_str);
+ g_string_append (nm_gstring_add_space_delimiter (str), addr_str);
+ }
+
+ LOG_LEASE (LOGD_DHCP4, "ntp server '%s'", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_NTP_SERVER, str->str);
+}
+
+static void
+lease_parse_hostname (NDhcp4ClientLease *lease,
+ const char *iface,
+ GHashTable *options)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_HOST_NAME, &data, &n_data);
+ if (r)
+ return;
+
+ str = g_string_new_len ((char *)data, n_data);
+
+ if (is_localhost(str->str))
+ return;
+
+ LOG_LEASE (LOGD_DHCP4, "hostname '%s'", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_HOST_NAME, str->str);
+}
+
+static void
+lease_parse_domainname (NDhcp4ClientLease *lease,
+ const char *iface,
+ NMIP4Config *ip4_config,
+ GHashTable *options)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ gs_strfreev char **domains = NULL;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_DOMAIN_NAME, &data, &n_data);
+ if (r)
+ return;
+
+ str = g_string_new_len ((char *)data, n_data);
+
+ /* Multiple domains sometimes stuffed into option 15 "Domain Name". */
+ domains = g_strsplit (str->str, " ", 0);
+ nm_gstring_prepare (&str);
+
+ for (char **d = domains; *d; d++) {
+ if (is_localhost(*d))
+ return;
+
+ g_string_append (nm_gstring_add_space_delimiter (str), *d);
+ nm_ip4_config_add_domain (ip4_config, *d);
+ }
+ LOG_LEASE (LOGD_DHCP4, "domain name '%s'", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_DOMAIN_NAME, str->str);
+}
+
+static void
+lease_parse_search_domains (NDhcp4ClientLease *lease,
+ const char *iface,
+ NMIP4Config *ip4_config,
+ GHashTable *options)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ uint8_t *data, *cache;
+ size_t n_data, n_cache = 0;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_DOMAIN_SEARCH_LIST, &data, &n_data);
+ if (r)
+ return;
+
+ cache = data;
+
+ nm_gstring_prepare (&str);
+
+ for (;;) {
+ nm_auto_free_gstring GString *domain = NULL;
+
+ nm_gstring_prepare (&domain);
+
+ if (!lease_option_print_domain_name (domain, cache, &n_cache, &data, &n_data))
+ break;
+
+ g_string_append (nm_gstring_add_space_delimiter (str), domain->str);
+ nm_ip4_config_add_search (ip4_config, domain->str);
+ }
+ LOG_LEASE (LOGD_DHCP4, "domain search '%s'", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_DOMAIN_SEARCH_LIST, str->str);
+}
+
+static void
+lease_parse_root_path (NDhcp4ClientLease *lease,
+ const char *iface,
+ GHashTable *options)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_ROOT_PATH, &data, &n_data);
+ if (r)
+ return;
+
+ str = g_string_new_len ((char *)data, n_data);
+ LOG_LEASE (LOGD_DHCP4, "root path '%s'", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_ROOT_PATH, str->str);
+}
+
+static void
+lease_parse_wpad (NDhcp4ClientLease *lease,
+ const char *iface,
+ GHashTable *options)
+{
+ nm_auto_free_gstring GString *str = NULL;
+ uint8_t *data;
+ size_t n_data;
+ int r;
+
+ r = n_dhcp4_client_lease_query (lease, DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, &data, &n_data);
+ if (r)
+ return;
+
+ str = g_string_new_len ((char *)data, n_data);
+ LOG_LEASE (LOGD_DHCP4, "wpad '%s'", str->str);
+ add_option (options, dhcp4_requests, DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, str->str);
+}
+
+static NMIP4Config *
+lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
+ const char *iface,
+ int ifindex,
+ NDhcp4ClientLease *lease,
+ guint32 route_table,
+ guint32 route_metric,
+ GHashTable **out_options,
+ GError **error)
+{
+ gs_unref_object NMIP4Config *ip4_config = NULL;
+ gs_unref_hashtable GHashTable *options = NULL;
+
+ g_return_val_if_fail (lease != NULL, NULL);
+
+ ip4_config = nm_ip4_config_new (multi_idx, ifindex);
+ options = out_options ? create_options_dict () : NULL;
+
+ if (!lease_parse_address (lease, iface, ip4_config, options, error))
+ return NULL;
+
+ lease_parse_routes (lease, iface, ip4_config, options, route_table, route_metric);
+ lease_parse_domain_name_servers (lease, iface, ip4_config, options);
+ lease_parse_domainname (lease, iface, ip4_config, options);
+ lease_parse_search_domains (lease, iface, ip4_config, options);
+ lease_parse_mtu (lease, iface, ip4_config, options);
+ lease_parse_metered (lease, iface, ip4_config, options);
+
+ lease_parse_hostname (lease, iface, options);
+ lease_parse_ntps (lease, iface, options);
+ lease_parse_root_path (lease, iface, options);
+ lease_parse_wpad (lease, iface, options);
+
+ NM_SET_OUT (out_options, g_steal_pointer (&options));
+ return g_steal_pointer (&ip4_config);
+}
+
+/*****************************************************************************/
+
+static void
+bound4_handle (NMDhcpNettools *self, NDhcp4ClientLease *lease)
+{
+ const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
+ gs_unref_object NMIP4Config *ip4_config = NULL;
+ gs_unref_hashtable GHashTable *options = NULL;
+ GError *error = NULL;
+
+ _LOGT ("lease available");
+
+ ip4_config = lease_to_ip4_config (nm_dhcp_client_get_multi_idx (NM_DHCP_CLIENT (self)),
+ iface,
+ nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)),
+ lease,
+ nm_dhcp_client_get_route_table (NM_DHCP_CLIENT (self)),
+ nm_dhcp_client_get_route_metric (NM_DHCP_CLIENT (self)),
+ &options,
+ &error);
+ if (!ip4_config) {
+ _LOGW ("%s", error->message);
+ g_clear_error (&error);
+ nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
+ return;
+ }
+
+ add_requests_to_options (options, dhcp4_requests);
+
+ nm_dhcp_client_set_state (NM_DHCP_CLIENT (self),
+ NM_DHCP_STATE_BOUND,
+ NM_IP_CONFIG_CAST (ip4_config),
+ options);
+}
+
+static gboolean
+dhcp4_event_handle (NMDhcpNettools *self,
+ NDhcp4ClientEvent *event)
+{
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
+ int r;
+
+ _LOGT ("client event %d", event->event);
+
+ switch (event->event) {
+ case N_DHCP4_CLIENT_EVENT_OFFER:
+ /* always accept the first lease */
+ r = n_dhcp4_client_lease_select (event->offer.lease);
+ if (r) {
+ _LOGW ("selecting lease failed: %d", r);
+ }
+ break;
+ case N_DHCP4_CLIENT_EVENT_EXPIRED:
+ nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_EXPIRE, NULL, NULL);
+ break;
+ case N_DHCP4_CLIENT_EVENT_RETRACTED:
+ case N_DHCP4_CLIENT_EVENT_CANCELLED:
+ nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
+ break;
+ case N_DHCP4_CLIENT_EVENT_GRANTED:
+ priv->lease = n_dhcp4_client_lease_ref (event->granted.lease);
+ bound4_handle (self, event->granted.lease);
+ break;
+ case N_DHCP4_CLIENT_EVENT_EXTENDED:
+ bound4_handle (self, event->extended.lease);
+ break;
+ case N_DHCP4_CLIENT_EVENT_DOWN:
+ /* ignore down events, they are purely informational */
+ break;
+ default:
+ _LOGW ("unhandled DHCP event %d", event->event);
+ break;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+dhcp4_event_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ NMDhcpNettools *self = data;
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
+ NDhcp4ClientEvent *event;
+ int r;
+
+ r = n_dhcp4_client_dispatch (priv->client);
+ if (r < 0)
+ return G_SOURCE_CONTINUE;
+
+ while (!n_dhcp4_client_pop_event (priv->client, &event) && event) {
+ dhcp4_event_handle (self, event);
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+nettools_create (NMDhcpNettools *self,
+ const char *dhcp_anycast_addr,
+ GError **error)
+{
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
+ nm_auto (n_dhcp4_client_config_freep) NDhcp4ClientConfig *config = NULL;
+ nm_auto (n_dhcp4_client_unrefp) NDhcp4Client *client = NULL;
+ GBytes *hwaddr;
+ GBytes *bcast_hwaddr;
+ const uint8_t *hwaddr_arr;
+ const uint8_t *bcast_hwaddr_arr;
+ gsize hwaddr_len;
+ gsize bcast_hwaddr_len;
+ GBytes *client_id;
+ gs_unref_bytes GBytes *client_id_new = NULL;
+ const uint8_t *client_id_arr;
+ size_t client_id_len;
+ int r, fd, arp_type, transport;
+
+ g_return_val_if_fail (!priv->client, FALSE);
+
+ hwaddr = nm_dhcp_client_get_hw_addr (NM_DHCP_CLIENT (self));
+ if ( !hwaddr
+ || !(hwaddr_arr = g_bytes_get_data (hwaddr, &hwaddr_len))
+ || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len)) < 0) {
+ nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address");
+ return FALSE;
+ }
+
+ bcast_hwaddr = nm_dhcp_client_get_broadcast_hw_addr (NM_DHCP_CLIENT (self));
+ bcast_hwaddr_arr = g_bytes_get_data (bcast_hwaddr, &bcast_hwaddr_len);
+
+ switch (arp_type) {
+ case ARPHRD_ETHER:
+ transport = N_DHCP4_TRANSPORT_ETHERNET;
+ break;
+ case ARPHRD_INFINIBAND:
+ transport = N_DHCP4_TRANSPORT_INFINIBAND;
+ break;
+ default:
+ nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "unsupported ARP type");
+ return FALSE;
+ }
+
+ /* Note that we always set a client-id. In particular for infiniband that is necessary,
+ * see https://tools.ietf.org/html/rfc4390#section-2.1 . */
+ client_id = nm_dhcp_client_get_client_id (NM_DHCP_CLIENT (self));
+ if (!client_id) {
+ client_id_new = nm_utils_dhcp_client_id_mac (arp_type, hwaddr_arr, hwaddr_len);
+ client_id = client_id_new;
+ }
+
+ if ( !(client_id_arr = g_bytes_get_data (client_id, &client_id_len))
+ || client_id_len < 2) {
+
+ /* invalid client-ids are not expected. */
+ nm_assert_not_reached ();
+
+ nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id");
+ return FALSE;
+ }
+
+ r = n_dhcp4_client_config_new (&config);
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to create client-config: %s");
+ return FALSE;
+ }
+
+ n_dhcp4_client_config_set_ifindex (config, nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)));
+ n_dhcp4_client_config_set_transport (config, transport);
+ n_dhcp4_client_config_set_mac (config, hwaddr_arr, hwaddr_len);
+ n_dhcp4_client_config_set_broadcast_mac (config, bcast_hwaddr_arr, bcast_hwaddr_len);
+ r = n_dhcp4_client_config_set_client_id (config, client_id_arr, client_id_len);
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to set client-id: %s");
+ return FALSE;
+ }
+
+ r = n_dhcp4_client_new (&client, config);
+ if (r) {
+ nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, "failed to create client: error %d", r);
+ return FALSE;
+ }
+
+ priv->client = client;
+ client = NULL;
+
+ n_dhcp4_client_get_fd (priv->client, &fd);
+ priv->channel = g_io_channel_unix_new (fd);
+ priv->event_id = g_io_add_watch (priv->channel, G_IO_IN, dhcp4_event_cb, self);
+
+ return TRUE;
+}
+
+static gboolean
+_accept (NMDhcpClient *client,
+ GError **error)
+{
+ NMDhcpNettools *self = NM_DHCP_NETTOOLS (client);
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
+ int r;
+
+ g_return_val_if_fail (priv->lease, FALSE);
+
+ _LOGT ("accept");
+
+ r = n_dhcp4_client_lease_accept (priv->lease);
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to accept lease: %s");
+ return FALSE;
+ }
+
+ priv->lease = n_dhcp4_client_lease_unref (priv->lease);
+
+ return TRUE;
+}
+
+static gboolean
+decline (NMDhcpClient *client,
+ const char *error_message,
+ GError **error)
+{
+ NMDhcpNettools *self = NM_DHCP_NETTOOLS (client);
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
+ int r;
+
+ g_return_val_if_fail (priv->lease, FALSE);
+
+ _LOGT ("dhcp4-client: decline");
+
+ r = n_dhcp4_client_lease_decline (priv->lease, error_message);
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to decline lease: %s");
+ return FALSE;
+ }
+
+ priv->lease = n_dhcp4_client_lease_unref (priv->lease);
+
+ return TRUE;
+}
+
+static gboolean
+ip4_start (NMDhcpClient *client,
+ const char *dhcp_anycast_addr,
+ const char *last_ip4_address,
+ GError **error)
+{
+ nm_auto (n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL;
+ NMDhcpNettools *self = NM_DHCP_NETTOOLS (client);
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
+ struct in_addr last_addr = { 0 };
+ const char *hostname;
+ int r, i;
+
+ g_return_val_if_fail (!priv->probe, FALSE);
+
+ if (!nettools_create (self, dhcp_anycast_addr, error))
+ return FALSE;
+
+ r = n_dhcp4_client_probe_config_new (&config);
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to create dhcp-client-probe-config: %s");
+ return FALSE;
+ }
+
+ /*
+ * FIXME:
+ * Select, or configure, a reasonable start delay, to protect poor servers beeing flooded.
+ */
+ n_dhcp4_client_probe_config_set_start_delay (config, 1);
+
+ if (last_ip4_address) {
+ inet_pton (AF_INET, last_ip4_address, &last_addr);
+ n_dhcp4_client_probe_config_set_requested_ip (config, last_addr);
+ }
+
+ /* Add requested options */
+ for (i = 0; dhcp4_requests[i].name; i++) {
+ if (dhcp4_requests[i].include) {
+ nm_assert (dhcp4_requests[i].option_num <= 255);
+ n_dhcp4_client_probe_config_request_option (config, dhcp4_requests[i].option_num);
+ }
+ }
+
+ hostname = nm_dhcp_client_get_hostname (client);
+ if (hostname) {
+ if (nm_dhcp_client_get_use_fqdn (client)) {
+ uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
+
+ buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
+ DHCP_FQDN_FLAG_E; /* Canonical wire format */
+ buffer[1] = 0; /* RCODE1 (deprecated) */
+ buffer[2] = 0; /* RCODE2 (deprecated) */
+
+ r = nm_sd_dns_name_to_wire_format (hostname,
+ buffer + 3,
+ sizeof (buffer) - 3,
+ FALSE);
+ if (r < 0) {
+ nm_utils_error_set_errno (error, r, "failed to convert DHCP FQDN: %s");
+ return FALSE;
+ }
+
+ r = n_dhcp4_client_probe_config_append_option (config,
+ DHCP_OPTION_CLIENT_FQDN,
+ buffer,
+ 3 + r);
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to set DHCP FQDN: %s");
+ return FALSE;
+ }
+ } else {
+ r = n_dhcp4_client_probe_config_append_option (config,
+ DHCP_OPTION_HOST_NAME,
+ hostname,
+ strlen (hostname));
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to set DHCP hostname: %s");
+ return FALSE;
+ }
+ }
+ }
+
+ r = n_dhcp4_client_probe (priv->client, &priv->probe, config);
+ if (r) {
+ nm_utils_error_set_errno (error, r, "failed to start DHCP client: %s");
+ return FALSE;
+ }
+
+ _LOGT ("dhcp-client4: start %p", (gpointer) priv->client);
+
+ nm_dhcp_client_start_timeout (client);
+ return TRUE;
+}
+
+static gboolean
+ip6_start (NMDhcpClient *client,
+ const char *dhcp_anycast_addr,
+ const struct in6_addr *ll_addr,
+ NMSettingIP6ConfigPrivacy privacy,
+ guint needed_prefixes,
+ GError **error)
+{
+ nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "nettools plugin does not support IPv6");
+ return FALSE;
+}
+
+static void
+stop (NMDhcpClient *client,
+ gboolean release)
+{
+ NMDhcpNettools *self = NM_DHCP_NETTOOLS (client);
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
+
+ NM_DHCP_CLIENT_CLASS (nm_dhcp_nettools_parent_class)->stop (client, release);
+
+ _LOGT ("dhcp-client4: stop %p",
+ (gpointer) priv->client);
+
+ priv->probe = n_dhcp4_client_probe_free (priv->probe);
+}
+
+/*****************************************************************************/
+
+static void
+nm_dhcp_nettools_init (NMDhcpNettools *self)
+{
+}
+
+static void
+dispose (GObject *object)
+{
+ NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE ((NMDhcpNettools *) object);
+
+ nm_clear_pointer (&priv->channel, g_io_channel_unref);
+ nm_clear_g_source (&priv->event_id);
+ nm_clear_pointer (&priv->lease, n_dhcp4_client_lease_unref);
+ nm_clear_pointer (&priv->probe, n_dhcp4_client_probe_free);
+ nm_clear_pointer (&priv->client, n_dhcp4_client_unref);
+
+ G_OBJECT_CLASS (nm_dhcp_nettools_parent_class)->dispose (object);
+}
+
+static void
+nm_dhcp_nettools_class_init (NMDhcpNettoolsClass *class)
+{
+ NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = dispose;
+
+ client_class->ip4_start = ip4_start;
+ client_class->ip6_start = ip6_start;
+ client_class->accept = _accept;
+ client_class->decline = decline;
+ client_class->stop = stop;
+}
+
+const NMDhcpClientFactory _nm_dhcp_client_factory_nettools = {
+ .name = "nettools",
+ .get_type = nm_dhcp_nettools_get_type,
+ .get_path = NULL,
+};
diff --git a/src/meson.build b/src/meson.build
index a3ac4625ac..af0bcec99c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -22,6 +22,7 @@ cflags = nm_cflags
sources = files(
'dhcp/nm-dhcp-client.c',
'dhcp/nm-dhcp-manager.c',
+ 'dhcp/nm-dhcp-nettools.c',
'dhcp/nm-dhcp-systemd.c',
'dhcp/nm-dhcp-utils.c',
'ndisc/nm-lndp-ndisc.c',
@@ -50,6 +51,7 @@ deps = [
libsystemd_dep,
libudev_dep,
libnm_core_dep,
+ shared_n_dhcp4_dep,
]
if enable_wext
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 7f130ab4a9..dd5bb327a0 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -381,8 +381,10 @@ main (int argc, char *argv[])
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;
@@ -469,7 +471,11 @@ main (int argc, char *argv[])
/* Set up platform interaction layer */
nm_linux_platform_setup ();
- hwaddr = nm_platform_link_get_address_as_bytes (NM_PLATFORM_GET, gl.ifindex);
+ 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 (global_opt.iid_str) {
GBytes *bytes;
@@ -505,6 +511,7 @@ main (int argc, char *argv[])
global_opt.ifname,
gl.ifindex,
hwaddr,
+ bcast_hwaddr,
global_opt.uuid,
RT_TABLE_MAIN,
global_opt.priority_v4,
@@ -589,8 +596,9 @@ main (int argc, char *argv[])
/*****************************************************************************/
-const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = {
+const NMDhcpClientFactory *const _nm_dhcp_manager_factories[5] = {
&_nm_dhcp_client_factory_internal,
+ &_nm_dhcp_client_factory_nettools,
};
/*****************************************************************************/
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 2ed46fe444..6ead15ed35 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -100,6 +100,19 @@ nmp_link_address_get (const NMPLinkAddress *addr, size_t *length)
return addr->data;
}
+GBytes *
+nmp_link_address_get_as_bytes (const NMPLinkAddress *addr)
+{
+ gconstpointer data;
+ size_t length;
+
+ data = nmp_link_address_get (addr, &length);
+
+ return length > 0
+ ? g_bytes_new (data, length)
+ : NULL;
+}
+
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_PLATFORM
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 1e6007e1f1..248eca44f9 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -164,6 +164,7 @@ typedef struct {
} NMPLinkAddress;
gconstpointer nmp_link_address_get (const NMPLinkAddress *addr, size_t *length);
+GBytes *nmp_link_address_get_as_bytes (const NMPLinkAddress *addr);
typedef enum {
@@ -1407,18 +1408,6 @@ gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex
gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length);
-static inline GBytes *
-nm_platform_link_get_address_as_bytes (NMPlatform *self, int ifindex)
-{
- gconstpointer p;
- gsize l;
-
- p = nm_platform_link_get_address (self, ifindex, &l);
- return p
- ? g_bytes_new (p, l)
- : NULL;
-}
-
int nm_platform_link_get_master (NMPlatform *self, int slave);
gboolean nm_platform_link_can_assume (NMPlatform *self, int ifindex);
diff --git a/src/systemd/meson.build b/src/systemd/meson.build
index 257a9462c8..599c95e8a4 100644
--- a/src/systemd/meson.build
+++ b/src/systemd/meson.build
@@ -23,7 +23,6 @@ libnm_systemd_core = static_library(
'src/libsystemd/sd-event/sd-event.c',
'src/libsystemd/sd-id128/id128-util.c',
'src/libsystemd/sd-id128/sd-id128.c',
- 'src/shared/dns-domain.c',
'nm-sd.c',
'nm-sd-utils-core.c',
),
@@ -33,7 +32,6 @@ libnm_systemd_core = static_library(
'sd-adapt-core',
'src/libsystemd-network',
'src/libsystemd/sd-event',
- 'src/shared',
'src/systemd',
)
],