mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-11 15:40:17 +01:00
When initial configuration is complete, spawns helpers to preserve DHCP and RA addresses on interfaces and quits the main NM process.
This commit is contained in:
commit
289f788158
45 changed files with 2352 additions and 878 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -232,6 +232,7 @@ valgrind-*.log
|
|||
/src/dhcp-manager/tests/test-dhcp-options
|
||||
/src/dhcp-manager/tests/test-dhcp-utils
|
||||
/src/dnsmasq-manager/tests/test-dnsmasq-utils
|
||||
/src/nm-iface-helper
|
||||
/src/settings/plugins/ibft/tests/test-ibft
|
||||
/src/settings/plugins/ifcfg-rh/tests/network-scripts/*-Test_Write_*
|
||||
/src/settings/plugins/ifcfg-rh/tests/network-scripts/Test_Write_*
|
||||
|
|
|
|||
|
|
@ -2343,7 +2343,7 @@ nmc_property_set_byte_array (NMSetting *setting, const char *prop, const char *v
|
|||
char *val_strip;
|
||||
const char *delimiters = " \t,";
|
||||
long int val_int;
|
||||
char *bin;
|
||||
GBytes *bytes;
|
||||
GByteArray *array = NULL;
|
||||
gboolean success = TRUE;
|
||||
|
||||
|
|
@ -2352,11 +2352,9 @@ nmc_property_set_byte_array (NMSetting *setting, const char *prop, const char *v
|
|||
val_strip = g_strstrip (g_strdup (val));
|
||||
|
||||
/* First try hex string in the format of AAbbCCDd */
|
||||
bin = nm_utils_hexstr2bin (val_strip, strlen (val_strip));
|
||||
if (bin) {
|
||||
array = g_byte_array_sized_new (strlen (val_strip)/2);
|
||||
g_byte_array_append (array, (const guint8 *) bin, strlen (val_strip)/2);
|
||||
g_free (bin);
|
||||
bytes = nm_utils_hexstr2bin (val_strip);
|
||||
if (bytes) {
|
||||
array = g_bytes_unref_to_array (bytes);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -518,6 +518,7 @@ fi
|
|||
%{_libexecdir}/nm-dhcp-helper
|
||||
%{_libexecdir}/nm-avahi-autoipd.action
|
||||
%{_libexecdir}/nm-dispatcher
|
||||
%{_libexecdir}/nm-iface-helper
|
||||
%dir %{_libdir}/NetworkManager
|
||||
%{_libdir}/NetworkManager/libnm-settings-plugin*.so
|
||||
%{_mandir}/man1/*
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "nm-glib-compat.h"
|
||||
#include "nm-setting-private.h"
|
||||
#include "crypto.h"
|
||||
#include "gsystem-local-alloc.h"
|
||||
|
||||
#include "nm-setting-bond.h"
|
||||
#include "nm-setting-bridge.h"
|
||||
|
|
@ -2100,7 +2101,7 @@ nm_utils_rsa_key_encrypt_helper (const char *cipher,
|
|||
if (!in_password) {
|
||||
if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
|
||||
return NULL;
|
||||
in_password = tmp_password = nm_utils_bin2hexstr ((const char *) pw_buf, sizeof (pw_buf), -1);
|
||||
in_password = tmp_password = nm_utils_bin2hexstr (pw_buf, sizeof (pw_buf), -1);
|
||||
}
|
||||
|
||||
if (g_strcmp0 (cipher, CIPHER_AES_CBC) == 0)
|
||||
|
|
@ -2124,7 +2125,7 @@ nm_utils_rsa_key_encrypt_helper (const char *cipher,
|
|||
g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n");
|
||||
|
||||
/* Convert the salt to a hex string */
|
||||
tmp = nm_utils_bin2hexstr ((const char *) salt, salt_len, salt_len * 2);
|
||||
tmp = nm_utils_bin2hexstr (salt, salt_len, salt_len * 2);
|
||||
g_string_append_printf (pem, "DEK-Info: %s,%s\n\n", cipher, tmp);
|
||||
g_free (tmp);
|
||||
|
||||
|
|
@ -2876,13 +2877,13 @@ _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
|
|||
|
||||
/**
|
||||
* nm_utils_bin2hexstr:
|
||||
* @bytes: an array of bytes
|
||||
* @src: an array of bytes
|
||||
* @len: the length of the @bytes array
|
||||
* @final_len: an index where to cut off the returned string, or -1
|
||||
*
|
||||
* Converts a byte-array @bytes into a hexadecimal string.
|
||||
* If @final_len is greater than -1, the returned string is terminated at
|
||||
* that index (returned_string[final_len] == '\0'),
|
||||
* Converts the byte array @src into a hexadecimal string. If @final_len is
|
||||
* greater than -1, the returned string is terminated at that index
|
||||
* (returned_string[final_len] == '\0'),
|
||||
*
|
||||
* Return value: (transfer full): the textual form of @bytes
|
||||
*/
|
||||
|
|
@ -2891,9 +2892,10 @@ _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
|
|||
* copyright Red Hat, Inc. under terms of the LGPL.
|
||||
*/
|
||||
char *
|
||||
nm_utils_bin2hexstr (const char *bytes, int len, int final_len)
|
||||
nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
|
||||
{
|
||||
static char hex_digits[] = "0123456789abcdef";
|
||||
const guint8 *bytes = src;
|
||||
char *result;
|
||||
int i;
|
||||
gsize buflen = (len * 2) + 1;
|
||||
|
|
@ -2918,64 +2920,61 @@ nm_utils_bin2hexstr (const char *bytes, int len, int final_len)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
|
||||
/**
|
||||
* nm_utils_hex2byte:
|
||||
* @hex: a string representing a hex byte
|
||||
*
|
||||
* Converts a hex string (2 characters) into its byte representation.
|
||||
*
|
||||
* Return value: a byte, or -1 if @hex doesn't represent a hex byte
|
||||
*/
|
||||
int
|
||||
nm_utils_hex2byte (const char *hex)
|
||||
{
|
||||
int a, b;
|
||||
a = g_ascii_xdigit_value (*hex++);
|
||||
if (a < 0)
|
||||
return -1;
|
||||
b = g_ascii_xdigit_value (*hex++);
|
||||
if (b < 0)
|
||||
return -1;
|
||||
return (a << 4) | b;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_hexstr2bin:
|
||||
* @hex: an hex string
|
||||
* @len: the length of the @hex string (it has to be even)
|
||||
* @hex: a string of hexadecimal characters with optional ':' separators
|
||||
*
|
||||
* Converts a hexadecimal string @hex into a byte-array. The returned array
|
||||
* length is @len/2.
|
||||
* Converts a hexadecimal string @hex into an array of bytes. The optional
|
||||
* separator ':' may be used between single or pairs of hexadecimal characters,
|
||||
* eg "00:11" or "0:1". Any "0x" at the beginning of @hex is ignored. @hex
|
||||
* may not start or end with ':'.
|
||||
*
|
||||
* Return value: (transfer full): a array of bytes, or %NULL on error
|
||||
* Return value: (transfer full): the converted bytes, or %NULL on error
|
||||
*/
|
||||
char *
|
||||
nm_utils_hexstr2bin (const char *hex, size_t len)
|
||||
GBytes *
|
||||
nm_utils_hexstr2bin (const char *hex)
|
||||
{
|
||||
size_t i;
|
||||
int a;
|
||||
const char * ipos = hex;
|
||||
char * buf = NULL;
|
||||
char * opos;
|
||||
guint i = 0, x = 0;
|
||||
gs_free guint8 *c = NULL;
|
||||
int a, b;
|
||||
gboolean found_colon = FALSE;
|
||||
|
||||
/* Length must be a multiple of 2 */
|
||||
if ((len % 2) != 0)
|
||||
return NULL;
|
||||
g_return_val_if_fail (hex != NULL, NULL);
|
||||
|
||||
opos = buf = g_malloc0 ((len / 2) + 1);
|
||||
for (i = 0; i < len; i += 2) {
|
||||
a = nm_utils_hex2byte (ipos);
|
||||
if (a < 0) {
|
||||
g_free (buf);
|
||||
if (strncasecmp (hex, "0x", 2) == 0)
|
||||
hex += 2;
|
||||
found_colon = !!strchr (hex, ':');
|
||||
|
||||
c = g_malloc (strlen (hex) / 2 + 1);
|
||||
for (;;) {
|
||||
a = g_ascii_xdigit_value (hex[i++]);
|
||||
if (a < 0)
|
||||
return NULL;
|
||||
|
||||
if (hex[i] && hex[i] != ':') {
|
||||
b = g_ascii_xdigit_value (hex[i++]);
|
||||
if (b < 0)
|
||||
return NULL;
|
||||
c[x++] = ((guint) a << 4) | ((guint) b);
|
||||
} else
|
||||
c[x++] = (guint) a;
|
||||
|
||||
if (!hex[i])
|
||||
break;
|
||||
if (hex[i] == ':') {
|
||||
if (!hex[i + 1]) {
|
||||
/* trailing ':' is invalid */
|
||||
return NULL;
|
||||
}
|
||||
i++;
|
||||
} else if (found_colon) {
|
||||
/* If colons exist, they must delimit 1 or 2 hex chars */
|
||||
return NULL;
|
||||
}
|
||||
*opos++ = a;
|
||||
ipos += 2;
|
||||
}
|
||||
return buf;
|
||||
|
||||
return g_bytes_new (c, x);
|
||||
}
|
||||
/* End from hostap */
|
||||
|
||||
/**
|
||||
* nm_utils_iface_valid_name:
|
||||
|
|
|
|||
|
|
@ -167,9 +167,8 @@ gboolean nm_utils_hwaddr_matches (gconstpointer hwaddr1,
|
|||
gconstpointer hwaddr2,
|
||||
gssize hwaddr2_len);
|
||||
|
||||
char *nm_utils_bin2hexstr (const char *bytes, int len, int final_len);
|
||||
int nm_utils_hex2byte (const char *hex);
|
||||
char *nm_utils_hexstr2bin (const char *hex, size_t len);
|
||||
char *nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len);
|
||||
GBytes *nm_utils_hexstr2bin (const char *hex);
|
||||
|
||||
gboolean nm_utils_iface_valid_name(const char *name);
|
||||
|
||||
|
|
|
|||
|
|
@ -3550,6 +3550,41 @@ test_setting_ip6_gateway (void)
|
|||
g_object_unref (conn);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *str;
|
||||
const guint8 expected[20];
|
||||
const guint expected_len;
|
||||
} HexItem;
|
||||
|
||||
static void
|
||||
test_hexstr2bin (void)
|
||||
{
|
||||
static const HexItem items[] = {
|
||||
{ "aaBBCCddDD10496a", { 0xaa, 0xbb, 0xcc, 0xdd, 0xdd, 0x10, 0x49, 0x6a }, 8 },
|
||||
{ "aa:bb:cc:dd:10:49:6a", { 0xaa, 0xbb, 0xcc, 0xdd, 0x10, 0x49, 0x6a }, 7 },
|
||||
{ "0xccddeeff", { 0xcc, 0xdd, 0xee, 0xff }, 4 },
|
||||
{ "1:2:66:77:80", { 0x01, 0x02, 0x66, 0x77, 0x80 }, 5 },
|
||||
{ "e", { 0x0e }, 1 },
|
||||
{ "aabb1199:" },
|
||||
{ ":aabb1199" },
|
||||
{ "aabb$$dd" },
|
||||
{ "aab:ccc:ddd" },
|
||||
{ "aab::ccc:ddd" },
|
||||
};
|
||||
GBytes *b;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (items); i++) {
|
||||
b = nm_utils_hexstr2bin (items[i].str);
|
||||
if (items[i].expected_len) {
|
||||
g_assert (b);
|
||||
g_assert_cmpint (g_bytes_get_size (b), ==, items[i].expected_len);
|
||||
g_assert (memcmp (g_bytes_get_data (b, NULL), items[i].expected, g_bytes_get_size (b)) == 0);
|
||||
} else
|
||||
g_assert (b == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int main (int argc, char **argv)
|
||||
|
|
@ -3641,6 +3676,8 @@ int main (int argc, char **argv)
|
|||
g_test_add_func ("/core/general/test_setting_ip4_gateway", test_setting_ip4_gateway);
|
||||
g_test_add_func ("/core/general/test_setting_ip6_gateway", test_setting_ip6_gateway);
|
||||
|
||||
g_test_add_func ("/core/general/hexstr2bin", test_hexstr2bin);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -756,7 +756,6 @@ global:
|
|||
nm_utils_deinit;
|
||||
nm_utils_escape_ssid;
|
||||
nm_utils_file_is_pkcs12;
|
||||
nm_utils_hex2byte;
|
||||
nm_utils_hexstr2bin;
|
||||
nm_utils_hwaddr_atoba;
|
||||
nm_utils_hwaddr_aton;
|
||||
|
|
|
|||
|
|
@ -1249,6 +1249,19 @@ nm_device_get_available_connections (NMDevice *device)
|
|||
return NM_DEVICE_GET_PRIVATE (device)->available_connections;
|
||||
}
|
||||
|
||||
static inline guint8
|
||||
hex2byte (const char *hex)
|
||||
{
|
||||
int a, b;
|
||||
a = g_ascii_xdigit_value (*hex++);
|
||||
if (a < 0)
|
||||
return -1;
|
||||
b = g_ascii_xdigit_value (*hex++);
|
||||
if (b < 0)
|
||||
return -1;
|
||||
return (a << 4) | b;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_decoded_property (GUdevDevice *device, const char *property)
|
||||
{
|
||||
|
|
@ -1264,7 +1277,7 @@ get_decoded_property (GUdevDevice *device, const char *property)
|
|||
n = unescaped = g_malloc0 (len + 1);
|
||||
while (*p) {
|
||||
if ((len >= 4) && (*p == '\\') && (*(p+1) == 'x')) {
|
||||
*n++ = (char) nm_utils_hex2byte (p + 2);
|
||||
*n++ = (char) hex2byte (p + 2);
|
||||
p += 4;
|
||||
len -= 4;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<!--
|
||||
Copyright (C) 2010 - 2013 Red Hat, Inc.
|
||||
Copyright 2010 - 2014 Red Hat, Inc.
|
||||
-->
|
||||
|
||||
<refentry id="NetworkManager.conf">
|
||||
|
|
@ -199,6 +199,28 @@ Copyright (C) 2010 - 2013 Red Hat, Inc.
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>configure-and-quit</varname></term>
|
||||
<listitem>
|
||||
<para>
|
||||
When set to <literal>true</literal>, NetworkManager quits after
|
||||
performing initial network configuration but spawns small helpers
|
||||
to preserve DHCP leases and IPv6 addresses. This is useful in
|
||||
environments where network setup is more or less static or it is
|
||||
desirable to save process time but still handle some dynamic
|
||||
configurations. When this option is <literal>true</literal>,
|
||||
network configuration for WiFi, WWAN, Bluetooth, ADSL, and PPPoE
|
||||
interfaces cannot be preserved due to their use of external
|
||||
services, and these devices will be deconfigured when NetworkManager
|
||||
quits even though other interface's configuration may be preserved.
|
||||
The default value is <literal>false</literal>, meaning that
|
||||
NetworkManager will continue running after initial network
|
||||
configuration and continue responding to system and hardware events,
|
||||
D-Bus requests, and user commands.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>dns</varname></term>
|
||||
<listitem><para>Set the DNS (<filename>resolv.conf</filename>) processing mode.</para>
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ libnm/nm-vpn-plugin-old.c
|
|||
policy/org.freedesktop.NetworkManager.policy.in.in
|
||||
src/NetworkManagerUtils.c
|
||||
src/main.c
|
||||
src/main-utils.c
|
||||
src/dhcp-manager/nm-dhcp-dhclient.c
|
||||
src/dhcp-manager/nm-dhcp-dhclient-utils.c
|
||||
src/dhcp-manager/nm-dhcp-manager.c
|
||||
|
|
@ -146,6 +147,7 @@ src/devices/wifi/nm-wifi-ap-utils.c
|
|||
src/devices/wimax/nm-device-wimax.c
|
||||
src/devices/wwan/nm-modem-broadband.c
|
||||
src/nm-config.c
|
||||
src/nm-iface-helper.c
|
||||
src/nm-logging.c
|
||||
src/nm-manager.c
|
||||
src/nm-sleep-monitor-systemd.c
|
||||
|
|
|
|||
111
src/Makefile.am
111
src/Makefile.am
|
|
@ -48,7 +48,10 @@ AM_CPPFLAGS = \
|
|||
# primarily for its side effect of removing duplicates.
|
||||
AM_CPPFLAGS += $(foreach d,$(sort $(dir $(libNetworkManager_la_SOURCES))),-I$(top_srcdir)/src/$d)
|
||||
|
||||
noinst_LTLIBRARIES = libNetworkManager.la libsystemd-dhcp.la
|
||||
noinst_LTLIBRARIES = \
|
||||
libNetworkManager.la \
|
||||
libnm-iface-helper.la \
|
||||
libsystemd-dhcp.la
|
||||
|
||||
######################
|
||||
# libsystemd-dhcp
|
||||
|
|
@ -124,6 +127,9 @@ sbin_PROGRAMS = NetworkManager
|
|||
|
||||
NetworkManager_SOURCES = \
|
||||
$(nm_device_sources) $(nm_device_headers) \
|
||||
$(nm_dhcp_client_sources) $(nm_dhcp_client_headers) \
|
||||
main-utils.c \
|
||||
main-utils.h \
|
||||
main.c
|
||||
|
||||
NetworkManager_LDADD = libNetworkManager.la
|
||||
|
|
@ -153,8 +159,21 @@ nm_device_headers = \
|
|||
devices/nm-device-vlan.h \
|
||||
devices/nm-device-vxlan.h
|
||||
|
||||
nm_dhcp_client_sources = \
|
||||
dhcp-manager/nm-dhcp-dhclient.c \
|
||||
dhcp-manager/nm-dhcp-dhclient-utils.c \
|
||||
dhcp-manager/nm-dhcp-dhcpcd.c \
|
||||
dhcp-manager/nm-dhcp-systemd.c
|
||||
|
||||
nm_dhcp_client_headers = \
|
||||
dhcp-manager/nm-dhcp-dhclient.h \
|
||||
dhcp-manager/nm-dhcp-dhclient-utils.h \
|
||||
dhcp-manager/nm-dhcp-dhcpcd.h \
|
||||
dhcp-manager/nm-dhcp-systemd.h
|
||||
|
||||
nm_sources = \
|
||||
$(nm_device_headers) \
|
||||
$(nm_dhcp_client_headers) \
|
||||
devices/nm-device.c \
|
||||
devices/nm-device.h \
|
||||
devices/nm-device-ethernet-utils.c \
|
||||
|
|
@ -170,14 +189,8 @@ nm_sources = \
|
|||
dhcp-manager/nm-dhcp-client.h \
|
||||
dhcp-manager/nm-dhcp-utils.c \
|
||||
dhcp-manager/nm-dhcp-utils.h \
|
||||
dhcp-manager/nm-dhcp-dhclient.c \
|
||||
dhcp-manager/nm-dhcp-dhclient.h \
|
||||
dhcp-manager/nm-dhcp-dhclient-utils.c \
|
||||
dhcp-manager/nm-dhcp-dhclient-utils.h \
|
||||
dhcp-manager/nm-dhcp-dhcpcd.c \
|
||||
dhcp-manager/nm-dhcp-dhcpcd.h \
|
||||
dhcp-manager/nm-dhcp-systemd.h \
|
||||
dhcp-manager/nm-dhcp-systemd.c \
|
||||
dhcp-manager/nm-dhcp-listener.c \
|
||||
dhcp-manager/nm-dhcp-listener.h \
|
||||
dhcp-manager/nm-dhcp-manager.c \
|
||||
dhcp-manager/nm-dhcp-manager.h \
|
||||
\
|
||||
|
|
@ -448,6 +461,86 @@ NetworkManager_LDFLAGS = -rdynamic
|
|||
|
||||
######################
|
||||
|
||||
libnm_iface_helper_la_SOURCES = \
|
||||
dhcp-manager/nm-dhcp-client.c \
|
||||
dhcp-manager/nm-dhcp-client.h \
|
||||
dhcp-manager/nm-dhcp-utils.c \
|
||||
dhcp-manager/nm-dhcp-utils.h \
|
||||
dhcp-manager/nm-dhcp-manager.c \
|
||||
dhcp-manager/nm-dhcp-manager.h \
|
||||
\
|
||||
platform/nm-linux-platform.c \
|
||||
platform/nm-linux-platform.h \
|
||||
platform/nm-platform.c \
|
||||
platform/nm-platform.h \
|
||||
platform/wifi/wifi-utils-nl80211.c \
|
||||
platform/wifi/wifi-utils-nl80211.h \
|
||||
platform/wifi/wifi-utils-private.h \
|
||||
platform/wifi/wifi-utils.c \
|
||||
platform/wifi/wifi-utils.h \
|
||||
\
|
||||
rdisc/nm-fake-rdisc.c \
|
||||
rdisc/nm-fake-rdisc.h \
|
||||
rdisc/nm-lndp-rdisc.c \
|
||||
rdisc/nm-lndp-rdisc.h \
|
||||
rdisc/nm-rdisc.c \
|
||||
rdisc/nm-rdisc.h \
|
||||
\
|
||||
nm-ip4-config.c \
|
||||
nm-ip4-config.h \
|
||||
nm-ip6-config.c \
|
||||
nm-ip6-config.h \
|
||||
\
|
||||
nm-enum-types.c \
|
||||
nm-enum-types.h \
|
||||
nm-logging.c \
|
||||
nm-logging.h \
|
||||
nm-posix-signals.c \
|
||||
nm-posix-signals.h \
|
||||
NetworkManagerUtils.c \
|
||||
NetworkManagerUtils.h
|
||||
|
||||
if WITH_WEXT
|
||||
libnm_iface_helper_la_SOURCES += \
|
||||
platform/wifi/wifi-utils-wext.c \
|
||||
platform/wifi/wifi-utils-wext.h
|
||||
endif
|
||||
|
||||
libnm_iface_helper_la_LIBADD = \
|
||||
$(top_builddir)/libnm-core/libnm-core.la \
|
||||
libsystemd-dhcp.la \
|
||||
$(DBUS_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(GUDEV_LIBS) \
|
||||
$(LIBNL_LIBS) \
|
||||
$(LIBNDP_LIBS) \
|
||||
$(LIBDL) \
|
||||
$(LIBM)
|
||||
|
||||
libexec_PROGRAMS = nm-iface-helper
|
||||
|
||||
nm_iface_helper_SOURCES = \
|
||||
dhcp-manager/nm-dhcp-systemd.h \
|
||||
dhcp-manager/nm-dhcp-systemd.c \
|
||||
nm-iface-helper.c \
|
||||
main-utils.c \
|
||||
main-utils.h
|
||||
|
||||
nm_iface_helper_LDADD = \
|
||||
$(top_builddir)/libnm-core/libnm-core.la \
|
||||
libsystemd-dhcp.la \
|
||||
libnm-iface-helper.la \
|
||||
$(DBUS_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(GUDEV_LIBS) \
|
||||
$(LIBNL_LIBS) \
|
||||
$(LIBNDP_LIBS) \
|
||||
$(LIBM)
|
||||
|
||||
nm_iface_helper_LDFLAGS = -rdynamic
|
||||
|
||||
######################
|
||||
|
||||
dbusservicedir = $(DBUS_SYS_DIR)
|
||||
dbusservice_DATA = org.freedesktop.NetworkManager.conf
|
||||
|
||||
|
|
|
|||
|
|
@ -2156,6 +2156,32 @@ out:
|
|||
}
|
||||
|
||||
|
||||
#define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/"
|
||||
#define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/"
|
||||
G_STATIC_ASSERT (sizeof (IPV4_PROPERTY_DIR) == sizeof (IPV6_PROPERTY_DIR));
|
||||
|
||||
static const char *
|
||||
_get_property_path (const char *ifname,
|
||||
const char *property,
|
||||
gboolean ipv6)
|
||||
{
|
||||
static char path[sizeof (IPV6_PROPERTY_DIR) + IFNAMSIZ + 32];
|
||||
int len;
|
||||
|
||||
ifname = ASSERT_VALID_PATH_COMPONENT (ifname);
|
||||
property = ASSERT_VALID_PATH_COMPONENT (property);
|
||||
|
||||
len = g_snprintf (path,
|
||||
sizeof (path),
|
||||
"%s%s/%s",
|
||||
ipv6 ? IPV6_PROPERTY_DIR : IPV4_PROPERTY_DIR,
|
||||
ifname,
|
||||
property);
|
||||
g_assert (len < sizeof (path) - 1);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_ip6_property_path:
|
||||
* @ifname: an interface name
|
||||
|
|
@ -2167,18 +2193,21 @@ out:
|
|||
const char *
|
||||
nm_utils_ip6_property_path (const char *ifname, const char *property)
|
||||
{
|
||||
#define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/"
|
||||
static char path[sizeof (IPV6_PROPERTY_DIR) + IFNAMSIZ + 32];
|
||||
int len;
|
||||
return _get_property_path (ifname, property, TRUE);
|
||||
}
|
||||
|
||||
ifname = ASSERT_VALID_PATH_COMPONENT (ifname);
|
||||
property = ASSERT_VALID_PATH_COMPONENT (property);
|
||||
|
||||
len = g_snprintf (path, sizeof (path), IPV6_PROPERTY_DIR "%s/%s",
|
||||
ifname, property);
|
||||
g_assert (len < sizeof (path) - 1);
|
||||
|
||||
return path;
|
||||
/**
|
||||
* nm_utils_ip4_property_path:
|
||||
* @ifname: an interface name
|
||||
* @property: a property name
|
||||
*
|
||||
* Returns the path to IPv4 property @property on @ifname. Note that
|
||||
* this uses a static buffer.
|
||||
*/
|
||||
const char *
|
||||
nm_utils_ip4_property_path (const char *ifname, const char *property)
|
||||
{
|
||||
return _get_property_path (ifname, property, FALSE);
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ gint32 nm_utils_get_monotonic_timestamp_s (void);
|
|||
|
||||
const char *ASSERT_VALID_PATH_COMPONENT (const char *name) G_GNUC_WARN_UNUSED_RESULT;
|
||||
const char *nm_utils_ip6_property_path (const char *ifname, const char *property);
|
||||
const char *nm_utils_ip4_property_path (const char *ifname, const char *property);
|
||||
|
||||
gboolean nm_utils_is_specific_hostname (const char *name);
|
||||
|
||||
|
|
|
|||
|
|
@ -2975,7 +2975,8 @@ dhcp4_start (NMDevice *self,
|
|||
nm_setting_ip_config_get_dhcp_hostname (s_ip4),
|
||||
nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)),
|
||||
priv->dhcp_timeout,
|
||||
priv->dhcp_anycast_address);
|
||||
priv->dhcp_anycast_address,
|
||||
NULL);
|
||||
|
||||
if (tmp)
|
||||
g_byte_array_free (tmp, TRUE);
|
||||
|
|
@ -6989,6 +6990,173 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason)
|
|||
_cleanup_generic_post (self, TRUE);
|
||||
}
|
||||
|
||||
static char *
|
||||
bin2hexstr (const char *bytes, gsize len)
|
||||
{
|
||||
GString *str;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (bytes != NULL, NULL);
|
||||
g_return_val_if_fail (len > 0, NULL);
|
||||
|
||||
str = g_string_sized_new (len * 2 + 1);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (str->len)
|
||||
g_string_append_c (str, ':');
|
||||
g_string_append_printf (str, "%02x", (guint8) bytes[i]);
|
||||
}
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
static char *
|
||||
find_dhcp4_address (NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
guint i, n;
|
||||
|
||||
if (!priv->ip4_config)
|
||||
return NULL;
|
||||
|
||||
n = nm_ip4_config_get_num_addresses (priv->ip4_config);
|
||||
for (i = 0; i < n; i++) {
|
||||
const NMPlatformIP4Address *a = nm_ip4_config_get_address (priv->ip4_config, i);
|
||||
|
||||
if (a->source == NM_IP_CONFIG_SOURCE_DHCP)
|
||||
return g_strdup (nm_utils_inet4_ntop (a->address, NULL));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_spawn_iface_helper (NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
gboolean priority_set = FALSE, configured = FALSE;
|
||||
NMConnection *connection;
|
||||
GError *error = NULL;
|
||||
const char *method;
|
||||
GPtrArray *argv;
|
||||
gs_free char *dhcp4_address = NULL;
|
||||
|
||||
if (priv->state != NM_DEVICE_STATE_ACTIVATED)
|
||||
return;
|
||||
if (!nm_device_can_assume_connections (self))
|
||||
return;
|
||||
|
||||
connection = nm_device_get_connection (self);
|
||||
g_assert (connection);
|
||||
|
||||
argv = g_ptr_array_sized_new (10);
|
||||
g_ptr_array_set_free_func (argv, g_free);
|
||||
|
||||
g_ptr_array_add (argv, g_strdup (LIBEXECDIR "/nm-iface-helper"));
|
||||
g_ptr_array_add (argv, g_strdup ("--ifname"));
|
||||
g_ptr_array_add (argv, g_strdup (nm_device_get_ip_iface (self)));
|
||||
g_ptr_array_add (argv, g_strdup ("--uuid"));
|
||||
g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection)));
|
||||
|
||||
dhcp4_address = find_dhcp4_address (self);
|
||||
|
||||
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
if ( priv->ip4_config
|
||||
&& priv->ip4_state == IP_DONE
|
||||
&& g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0
|
||||
&& priv->dhcp4_client
|
||||
&& dhcp4_address) {
|
||||
NMSettingIPConfig *s_ip4;
|
||||
GBytes *client_id;
|
||||
char *hex_client_id;
|
||||
const char *hostname;
|
||||
|
||||
s_ip4 = nm_connection_get_setting_ip4_config (connection);
|
||||
g_assert (s_ip4);
|
||||
|
||||
g_ptr_array_add (argv, g_strdup ("--priority"));
|
||||
g_ptr_array_add (argv, g_strdup_printf ("%u", nm_dhcp_client_get_priority (priv->dhcp4_client)));
|
||||
priority_set = TRUE;
|
||||
|
||||
g_ptr_array_add (argv, g_strdup ("--dhcp4"));
|
||||
g_ptr_array_add (argv, g_strdup (dhcp4_address));
|
||||
if (nm_setting_ip_config_get_may_fail (s_ip4) == FALSE)
|
||||
g_ptr_array_add (argv, g_strdup ("--dhcp4-required"));
|
||||
|
||||
client_id = nm_dhcp_client_get_client_id (priv->dhcp4_client);
|
||||
if (client_id) {
|
||||
g_ptr_array_add (argv, g_strdup ("--dhcp4-clientid"));
|
||||
hex_client_id = bin2hexstr (g_bytes_get_data (client_id, NULL),
|
||||
g_bytes_get_size (client_id));
|
||||
g_ptr_array_add (argv, hex_client_id);
|
||||
}
|
||||
|
||||
hostname = nm_dhcp_client_get_hostname (priv->dhcp4_client);
|
||||
if (client_id) {
|
||||
g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname"));
|
||||
g_ptr_array_add (argv, g_strdup (hostname));
|
||||
}
|
||||
|
||||
configured = TRUE;
|
||||
}
|
||||
|
||||
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
|
||||
if ( priv->ip6_config
|
||||
&& priv->ip6_state == IP_DONE
|
||||
&& g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0
|
||||
&& priv->rdisc
|
||||
&& priv->ac_ip6_config) {
|
||||
NMSettingIPConfig *s_ip6;
|
||||
char *hex_iid;
|
||||
NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT;
|
||||
|
||||
s_ip6 = nm_connection_get_setting_ip6_config (connection);
|
||||
g_assert (s_ip6);
|
||||
|
||||
g_ptr_array_add (argv, g_strdup ("--slaac"));
|
||||
|
||||
if (nm_setting_ip_config_get_may_fail (s_ip6) == FALSE)
|
||||
g_ptr_array_add (argv, g_strdup ("--slaac-required"));
|
||||
|
||||
g_ptr_array_add (argv, g_strdup ("--slaac-tempaddr"));
|
||||
g_ptr_array_add (argv, g_strdup_printf ("%d", priv->rdisc_use_tempaddr));
|
||||
|
||||
if (nm_device_get_ip_iface_identifier (self, &iid)) {
|
||||
g_ptr_array_add (argv, g_strdup ("--iid"));
|
||||
hex_iid = bin2hexstr ((const char *) iid.id_u8, sizeof (NMUtilsIPv6IfaceId));
|
||||
g_ptr_array_add (argv, hex_iid);
|
||||
}
|
||||
|
||||
configured = TRUE;
|
||||
}
|
||||
|
||||
if (configured) {
|
||||
GPid pid;
|
||||
|
||||
if (!priority_set) {
|
||||
g_ptr_array_add (argv, g_strdup ("--priority"));
|
||||
g_ptr_array_add (argv, g_strdup_printf ("%u", nm_device_get_priority (self)));
|
||||
}
|
||||
|
||||
g_ptr_array_add (argv, NULL);
|
||||
|
||||
if (nm_logging_enabled (LOGL_DEBUG, LOGD_DEVICE)) {
|
||||
char *tmp;
|
||||
|
||||
tmp = g_strjoinv (" ", (char **) argv->pdata);
|
||||
_LOGD (LOGD_DEVICE, "running '%s'", tmp);
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
if (g_spawn_async (NULL, (char **) argv->pdata, NULL,
|
||||
G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error)) {
|
||||
_LOGI (LOGD_DEVICE, "spawned helper PID %u", (guint) pid);
|
||||
} else {
|
||||
_LOGW (LOGD_DEVICE, "failed to spawn helper: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_unref (argv);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
static gboolean
|
||||
|
|
|
|||
|
|
@ -365,6 +365,8 @@ NMConnection *nm_device_new_default_connection (NMDevice *self);
|
|||
const NMPlatformIP4Route *nm_device_get_ip4_default_route (NMDevice *self);
|
||||
const NMPlatformIP6Route *nm_device_get_ip6_default_route (NMDevice *self);
|
||||
|
||||
void nm_device_spawn_iface_helper (NMDevice *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
/* For testing only */
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ typedef struct {
|
|||
guint32 priority;
|
||||
guint32 timeout;
|
||||
GByteArray * duid;
|
||||
GBytes * client_id;
|
||||
char * hostname;
|
||||
|
||||
NMDhcpState state;
|
||||
pid_t pid;
|
||||
|
|
@ -143,6 +145,37 @@ nm_dhcp_client_get_priority (NMDhcpClient *self)
|
|||
return NM_DHCP_CLIENT_GET_PRIVATE (self)->priority;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
nm_dhcp_client_get_client_id (NMDhcpClient *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
|
||||
|
||||
return NM_DHCP_CLIENT_GET_PRIVATE (self)->client_id;
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_client_set_client_id (NMDhcpClient *self, GBytes *client_id)
|
||||
{
|
||||
NMDhcpClientPrivate *priv;
|
||||
|
||||
g_return_if_fail (NM_IS_DHCP_CLIENT (self));
|
||||
|
||||
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
|
||||
|
||||
if (priv->client_id && client_id && g_bytes_equal (priv->client_id, client_id))
|
||||
return;
|
||||
g_clear_pointer (&priv->client_id, g_bytes_unref);
|
||||
priv->client_id = client_id ? g_bytes_ref (client_id) : NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_dhcp_client_get_hostname (NMDhcpClient *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
|
||||
|
||||
return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname;
|
||||
}
|
||||
|
||||
/********************************************/
|
||||
|
||||
static const char *state_table[NM_DHCP_STATE_MAX + 1] = {
|
||||
|
|
@ -360,7 +393,8 @@ gboolean
|
|||
nm_dhcp_client_start_ip4 (NMDhcpClient *self,
|
||||
const char *dhcp_client_id,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname)
|
||||
const char *hostname,
|
||||
const char *last_ip4_address)
|
||||
{
|
||||
NMDhcpClientPrivate *priv;
|
||||
|
||||
|
|
@ -374,7 +408,12 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
|
|||
nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv4 transaction (timeout in %d seconds)",
|
||||
priv->iface, priv->timeout);
|
||||
|
||||
return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_client_id, dhcp_anycast_addr, hostname);
|
||||
nm_dhcp_client_set_client_id (self, dhcp_client_id ? nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id) : NULL);
|
||||
|
||||
g_clear_pointer (&priv->hostname, g_free);
|
||||
priv->hostname = g_strdup (hostname);
|
||||
|
||||
return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address);
|
||||
}
|
||||
|
||||
/* uuid_parse does not work for machine-id, so we use our own converter */
|
||||
|
|
@ -518,6 +557,9 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
|||
g_free (str);
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->hostname, g_free);
|
||||
priv->hostname = g_strdup (hostname);
|
||||
|
||||
priv->info_only = info_only;
|
||||
|
||||
nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv6 transaction (timeout in %d seconds)",
|
||||
|
|
@ -525,7 +567,6 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
|||
|
||||
return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self,
|
||||
dhcp_anycast_addr,
|
||||
hostname,
|
||||
info_only,
|
||||
privacy,
|
||||
priv->duid);
|
||||
|
|
@ -673,10 +714,13 @@ copy_option (const char * key,
|
|||
g_hash_table_insert (hash, g_strdup (key), str_value);
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_client_new_options (NMDhcpClient *self,
|
||||
GHashTable *options,
|
||||
const char *reason)
|
||||
gboolean
|
||||
nm_dhcp_client_handle_event (gpointer unused,
|
||||
const char *iface,
|
||||
gint64 pid,
|
||||
GHashTable *options,
|
||||
const char *reason,
|
||||
NMDhcpClient *self)
|
||||
{
|
||||
NMDhcpClientPrivate *priv;
|
||||
guint32 old_state;
|
||||
|
|
@ -684,11 +728,19 @@ nm_dhcp_client_new_options (NMDhcpClient *self,
|
|||
GHashTable *str_options = NULL;
|
||||
GObject *ip_config = NULL;
|
||||
|
||||
g_return_if_fail (NM_IS_DHCP_CLIENT (self));
|
||||
g_return_if_fail (options != NULL);
|
||||
g_return_if_fail (reason != NULL);
|
||||
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
|
||||
g_return_val_if_fail (iface != NULL, FALSE);
|
||||
g_return_val_if_fail (pid > 0, FALSE);
|
||||
g_return_val_if_fail (options != NULL, FALSE);
|
||||
g_return_val_if_fail (reason != NULL, FALSE);
|
||||
|
||||
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
|
||||
|
||||
if (g_strcmp0 (priv->iface, iface) != 0)
|
||||
return FALSE;
|
||||
if (priv->pid != pid)
|
||||
return FALSE;
|
||||
|
||||
old_state = priv->state;
|
||||
new_state = reason_to_state (priv->iface, reason);
|
||||
|
||||
|
|
@ -719,6 +771,8 @@ nm_dhcp_client_new_options (NMDhcpClient *self,
|
|||
if (str_options)
|
||||
g_hash_table_destroy (str_options);
|
||||
g_clear_object (&ip_config);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/********************************************/
|
||||
|
|
|
|||
|
|
@ -64,13 +64,11 @@ typedef struct {
|
|||
/* Methods */
|
||||
|
||||
gboolean (*ip4_start) (NMDhcpClient *self,
|
||||
const char *dhcp_client_id,
|
||||
const char *anycast_addr,
|
||||
const char *hostname);
|
||||
const char *last_ip4_address);
|
||||
|
||||
gboolean (*ip6_start) (NMDhcpClient *self,
|
||||
const char *anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid);
|
||||
|
|
@ -99,6 +97,17 @@ typedef struct {
|
|||
|
||||
GType nm_dhcp_client_get_type (void);
|
||||
|
||||
typedef const char *(*NMDhcpClientGetPathFunc) (void);
|
||||
|
||||
typedef GSList * (*NMDhcpClientGetLeaseConfigsFunc) (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6);
|
||||
|
||||
void _nm_dhcp_client_register (GType gtype,
|
||||
const char *name,
|
||||
NMDhcpClientGetPathFunc get_path_func,
|
||||
NMDhcpClientGetLeaseConfigsFunc get_lease_configs_func);
|
||||
|
||||
pid_t nm_dhcp_client_get_pid (NMDhcpClient *self);
|
||||
|
||||
const char *nm_dhcp_client_get_iface (NMDhcpClient *self);
|
||||
|
|
@ -115,10 +124,15 @@ const GByteArray *nm_dhcp_client_get_hw_addr (NMDhcpClient *self);
|
|||
|
||||
guint32 nm_dhcp_client_get_priority (NMDhcpClient *self);
|
||||
|
||||
GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self);
|
||||
|
||||
const char *nm_dhcp_client_get_hostname (NMDhcpClient *self);
|
||||
|
||||
gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self,
|
||||
const char *dhcp_client_id,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname);
|
||||
const char *hostname,
|
||||
const char *last_ip4_address);
|
||||
|
||||
gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
||||
const char *dhcp_anycast_addr,
|
||||
|
|
@ -128,10 +142,6 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
|||
|
||||
void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release);
|
||||
|
||||
void nm_dhcp_client_new_options (NMDhcpClient *self,
|
||||
GHashTable *options,
|
||||
const char *reason);
|
||||
|
||||
/* Backend helpers for subclasses */
|
||||
void nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name);
|
||||
|
||||
|
|
@ -144,5 +154,14 @@ void nm_dhcp_client_set_state (NMDhcpClient *self,
|
|||
GObject *ip_config, /* NMIP4Config or NMIP6Config */
|
||||
GHashTable *options); /* str:str hash */
|
||||
|
||||
gboolean nm_dhcp_client_handle_event (gpointer unused,
|
||||
const char *iface,
|
||||
gint64 pid,
|
||||
GHashTable *options,
|
||||
const char *reason,
|
||||
NMDhcpClient *self);
|
||||
|
||||
void nm_dhcp_client_set_client_id (NMDhcpClient *self, GBytes *client_id);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_CLIENT_H__ */
|
||||
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@
|
|||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-dhcp-dhclient-utils.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-ip4-config.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-platform.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "gsystem-local-alloc.h"
|
||||
|
||||
#define CLIENTID_TAG "send dhcp-client-identifier"
|
||||
#define CLIENTID_FORMAT CLIENTID_TAG " \"%s\"; # added by NetworkManager"
|
||||
#define CLIENTID_FORMAT_OCTETS CLIENTID_TAG " %s; # added by NetworkManager"
|
||||
|
||||
#define HOSTNAME4_TAG "send host-name"
|
||||
#define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager"
|
||||
|
|
@ -73,40 +73,39 @@ add_hostname (GString *str, const char *format, const char *hostname)
|
|||
}
|
||||
|
||||
static void
|
||||
add_ip4_config (GString *str, const char *dhcp_client_id, const char *hostname)
|
||||
add_ip4_config (GString *str, GBytes *client_id, const char *hostname)
|
||||
{
|
||||
if (dhcp_client_id && *dhcp_client_id) {
|
||||
gboolean is_octets = TRUE;
|
||||
int i = 0;
|
||||
if (client_id) {
|
||||
const char *p;
|
||||
gsize l;
|
||||
guint i;
|
||||
|
||||
while (dhcp_client_id[i]) {
|
||||
if (!g_ascii_isxdigit (dhcp_client_id[i])) {
|
||||
is_octets = FALSE;
|
||||
p = g_bytes_get_data (client_id, &l);
|
||||
g_assert (p);
|
||||
|
||||
/* Allow type 0 (non-hardware address) to be represented as a string
|
||||
* as long as all the characters are printable.
|
||||
*/
|
||||
for (i = 1; (p[0] == 0) && i < l; i++) {
|
||||
if (!g_ascii_isprint (p[i]))
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
if (!dhcp_client_id[i])
|
||||
break;
|
||||
if (g_ascii_isxdigit (dhcp_client_id[i])) {
|
||||
i++;
|
||||
if (!dhcp_client_id[i])
|
||||
break;
|
||||
}
|
||||
if (dhcp_client_id[i] != ':') {
|
||||
is_octets = FALSE;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
/* If the client ID is just hex digits and : then don't use quotes,
|
||||
* because dhclient expects either a quoted ASCII string, or a byte
|
||||
* array formated as hex octets separated by :
|
||||
*/
|
||||
if (is_octets)
|
||||
g_string_append_printf (str, CLIENTID_FORMAT_OCTETS "\n", dhcp_client_id);
|
||||
else
|
||||
g_string_append_printf (str, CLIENTID_FORMAT "\n", dhcp_client_id);
|
||||
g_string_append (str, CLIENTID_TAG " ");
|
||||
if (i < l) {
|
||||
/* Unprintable; convert to a hex string */
|
||||
for (i = 0; i < l; i++) {
|
||||
if (i > 0)
|
||||
g_string_append_c (str, ':');
|
||||
g_string_append_printf (str, "%02x", (guint8) p[i]);
|
||||
}
|
||||
} else {
|
||||
/* Printable; just add to the line minus the 'type' */
|
||||
g_string_append_c (str, '"');
|
||||
g_string_append_len (str, p + 1, l - 1);
|
||||
g_string_append_c (str, '"');
|
||||
}
|
||||
g_string_append (str, "; # added by NetworkManager\n");
|
||||
}
|
||||
|
||||
add_hostname (str, HOSTNAME4_FORMAT "\n", hostname);
|
||||
|
|
@ -134,14 +133,67 @@ add_ip6_config (GString *str, const char *hostname)
|
|||
"send fqdn.server-update on;\n");
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
read_client_id (const char *str)
|
||||
{
|
||||
gs_free char *s = NULL;
|
||||
char *p;
|
||||
|
||||
g_assert (!strncmp (str, CLIENTID_TAG, STRLEN (CLIENTID_TAG)));
|
||||
|
||||
str += STRLEN (CLIENTID_TAG);
|
||||
while (g_ascii_isspace (*str))
|
||||
str++;
|
||||
|
||||
if (*str == '"') {
|
||||
s = g_strdup (str + 1);
|
||||
p = strrchr (s, '"');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
s = g_strdup (str);
|
||||
|
||||
g_strchomp (s);
|
||||
if (s[strlen (s) - 1] == ';')
|
||||
s[strlen (s) - 1] = '\0';
|
||||
|
||||
return nm_dhcp_utils_client_id_string_to_bytes (s);
|
||||
}
|
||||
|
||||
GBytes *
|
||||
nm_dhcp_dhclient_get_client_id_from_config_file (const char *path)
|
||||
{
|
||||
gs_free char *contents = NULL;
|
||||
gs_strfreev char **lines = NULL;
|
||||
char **line;
|
||||
|
||||
g_return_val_if_fail (path != NULL, NULL);
|
||||
|
||||
if (!g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
return NULL;
|
||||
|
||||
if (!g_file_get_contents (path, &contents, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
lines = g_strsplit_set (contents, "\n\r", 0);
|
||||
for (line = lines; lines && *line; line++) {
|
||||
if (!strncmp (*line, CLIENTID_TAG, STRLEN (CLIENTID_TAG)))
|
||||
return read_client_id (*line);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
nm_dhcp_dhclient_create_config (const char *interface,
|
||||
gboolean is_ip6,
|
||||
const char *dhcp_client_id,
|
||||
GBytes *client_id,
|
||||
const char *anycast_addr,
|
||||
const char *hostname,
|
||||
const char *orig_path,
|
||||
const char *orig_contents)
|
||||
const char *orig_contents,
|
||||
GBytes **out_new_client_id)
|
||||
{
|
||||
GString *new_contents;
|
||||
GPtrArray *alsoreq;
|
||||
|
|
@ -165,11 +217,15 @@ nm_dhcp_dhclient_create_config (const char *interface,
|
|||
if (!strlen (g_strstrip (p)))
|
||||
continue;
|
||||
|
||||
/* Override config file "dhcp-client-id" and use one from the
|
||||
* connection.
|
||||
*/
|
||||
if (dhcp_client_id && !strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG)))
|
||||
continue;
|
||||
if (!strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG))) {
|
||||
/* Override config file "dhcp-client-id" and use one from the connection */
|
||||
if (client_id)
|
||||
continue;
|
||||
|
||||
/* Otherwise capture and return the existing client id */
|
||||
if (out_new_client_id)
|
||||
*out_new_client_id = read_client_id (p);
|
||||
}
|
||||
|
||||
/* Override config file hostname and use one from the connection */
|
||||
if (hostname) {
|
||||
|
|
@ -238,7 +294,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
|
|||
add_also_request (alsoreq, "dhcp6.domain-search");
|
||||
add_also_request (alsoreq, "dhcp6.client-id");
|
||||
} else {
|
||||
add_ip4_config (new_contents, dhcp_client_id, hostname);
|
||||
add_ip4_config (new_contents, client_id, hostname);
|
||||
add_also_request (alsoreq, "rfc3442-classless-static-routes");
|
||||
add_also_request (alsoreq, "ms-classless-static-routes");
|
||||
add_also_request (alsoreq, "static-routes");
|
||||
|
|
|
|||
|
|
@ -27,11 +27,12 @@
|
|||
|
||||
char *nm_dhcp_dhclient_create_config (const char *interface,
|
||||
gboolean is_ip6,
|
||||
const char *dhcp_client_id,
|
||||
GBytes *client_id,
|
||||
const char *anycast_addr,
|
||||
const char *hostname,
|
||||
const char *orig_path,
|
||||
const char *orig_contents);
|
||||
const char *orig_contents,
|
||||
GBytes **out_new_client_id);
|
||||
|
||||
char *nm_dhcp_dhclient_escape_duid (const GByteArray *duid);
|
||||
|
||||
|
|
@ -48,5 +49,7 @@ GSList *nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
|
|||
gboolean ipv6,
|
||||
GDateTime *now);
|
||||
|
||||
GBytes *nm_dhcp_dhclient_get_client_id_from_config_file (const char *path);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ */
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
#include "nm-dhcp-manager.h"
|
||||
#include "nm-posix-signals.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-dhcp-listener.h"
|
||||
#include "gsystem-local-alloc.h"
|
||||
|
||||
G_DEFINE_TYPE (NMDhcpDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
|
||||
|
||||
|
|
@ -55,7 +57,7 @@ typedef struct {
|
|||
char *pid_file;
|
||||
} NMDhcpDhclientPrivate;
|
||||
|
||||
const char *
|
||||
static const char *
|
||||
nm_dhcp_dhclient_get_path (void)
|
||||
{
|
||||
const char *path = NULL;
|
||||
|
|
@ -122,7 +124,7 @@ get_dhclient_leasefile (const char *iface,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
GSList *
|
||||
static GSList *
|
||||
nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
|
|
@ -151,10 +153,11 @@ static gboolean
|
|||
merge_dhclient_config (const char *iface,
|
||||
const char *conf_file,
|
||||
gboolean is_ip6,
|
||||
const char *dhcp_client_id,
|
||||
GBytes *client_id,
|
||||
const char *anycast_addr,
|
||||
const char *hostname,
|
||||
const char *orig_path,
|
||||
GBytes **out_new_client_id,
|
||||
GError **error)
|
||||
{
|
||||
char *orig = NULL, *new;
|
||||
|
|
@ -173,7 +176,7 @@ merge_dhclient_config (const char *iface,
|
|||
}
|
||||
}
|
||||
|
||||
new = nm_dhcp_dhclient_create_config (iface, is_ip6, dhcp_client_id, anycast_addr, hostname, orig_path, orig);
|
||||
new = nm_dhcp_dhclient_create_config (iface, is_ip6, client_id, anycast_addr, hostname, orig_path, orig, out_new_client_id);
|
||||
g_assert (new);
|
||||
success = g_file_set_contents (conf_file, new, -1, error);
|
||||
g_free (new);
|
||||
|
|
@ -257,9 +260,10 @@ static char *
|
|||
create_dhclient_config (const char *iface,
|
||||
gboolean is_ip6,
|
||||
const char *uuid,
|
||||
const char *dhcp_client_id,
|
||||
GBytes *client_id,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname)
|
||||
const char *hostname,
|
||||
GBytes **out_new_client_id)
|
||||
{
|
||||
char *orig = NULL, *new = NULL;
|
||||
GError *error = NULL;
|
||||
|
|
@ -284,7 +288,7 @@ create_dhclient_config (const char *iface,
|
|||
}
|
||||
|
||||
error = NULL;
|
||||
success = merge_dhclient_config (iface, new, is_ip6, dhcp_client_id, dhcp_anycast_addr, hostname, orig, &error);
|
||||
success = merge_dhclient_config (iface, new, is_ip6, client_id, dhcp_anycast_addr, hostname, orig, out_new_client_id, &error);
|
||||
if (!success) {
|
||||
nm_log_warn (LOGD_DHCP, "(%s): error creating dhclient%s configuration: %s",
|
||||
iface, is_ip6 ? "6" : "", error->message);
|
||||
|
|
@ -473,41 +477,45 @@ dhclient_start (NMDhcpClient *client,
|
|||
}
|
||||
|
||||
static gboolean
|
||||
ip4_start (NMDhcpClient *client,
|
||||
const char *dhcp_client_id,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname)
|
||||
ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
|
||||
{
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
|
||||
const char *iface, *uuid;
|
||||
GBytes *client_id;
|
||||
gs_unref_bytes GBytes *new_client_id = NULL;
|
||||
const char *iface, *uuid, *hostname;
|
||||
gboolean success = FALSE;
|
||||
|
||||
iface = nm_dhcp_client_get_iface (client);
|
||||
uuid = nm_dhcp_client_get_uuid (client);
|
||||
client_id = nm_dhcp_client_get_client_id (client);
|
||||
hostname = nm_dhcp_client_get_hostname (client);
|
||||
|
||||
priv->conf_file = create_dhclient_config (iface, FALSE, uuid, dhcp_client_id, dhcp_anycast_addr, hostname);
|
||||
if (!priv->conf_file) {
|
||||
priv->conf_file = create_dhclient_config (iface, FALSE, uuid, client_id, dhcp_anycast_addr, hostname, &new_client_id);
|
||||
if (priv->conf_file) {
|
||||
if (new_client_id)
|
||||
nm_dhcp_client_set_client_id (client, new_client_id);
|
||||
success = dhclient_start (client, NULL, NULL, FALSE, NULL);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): error creating dhclient configuration file.", iface);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return dhclient_start (client, NULL, NULL, FALSE, NULL);
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_start (NMDhcpClient *client,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
{
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
|
||||
const char *iface, *uuid;
|
||||
const char *iface, *uuid, *hostname;
|
||||
|
||||
iface = nm_dhcp_client_get_iface (client);
|
||||
uuid = nm_dhcp_client_get_uuid (client);
|
||||
hostname = nm_dhcp_client_get_hostname (client);
|
||||
|
||||
priv->conf_file = create_dhclient_config (iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname);
|
||||
priv->conf_file = create_dhclient_config (iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname, NULL);
|
||||
if (!priv->conf_file) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): error creating dhclient6 configuration file.", iface);
|
||||
return FALSE;
|
||||
|
|
@ -544,6 +552,24 @@ stop (NMDhcpClient *client, gboolean release, const GByteArray *duid)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
state_changed (NMDhcpClient *client,
|
||||
NMDhcpState state,
|
||||
GObject *ip_config,
|
||||
GHashTable *options)
|
||||
{
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
|
||||
gs_unref_bytes GBytes *client_id = NULL;
|
||||
|
||||
if (nm_dhcp_client_get_client_id (client))
|
||||
return;
|
||||
if (state != NM_DHCP_STATE_BOUND)
|
||||
return;
|
||||
|
||||
client_id = nm_dhcp_dhclient_get_client_id_from_config_file (priv->conf_file);
|
||||
nm_dhcp_client_set_client_id (client, client_id);
|
||||
}
|
||||
|
||||
static GByteArray *
|
||||
get_duid (NMDhcpClient *client)
|
||||
{
|
||||
|
|
@ -612,6 +638,11 @@ nm_dhcp_dhclient_init (NMDhcpDhclient *self)
|
|||
/* Fallback option */
|
||||
if (!priv->def_leasefile)
|
||||
priv->def_leasefile = SYSCONFDIR "/dhclient6.leases";
|
||||
|
||||
g_signal_connect (nm_dhcp_listener_get (),
|
||||
NM_DHCP_LISTENER_EVENT,
|
||||
G_CALLBACK (nm_dhcp_client_handle_event),
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -619,6 +650,10 @@ dispose (GObject *object)
|
|||
{
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (nm_dhcp_listener_get (),
|
||||
G_CALLBACK (nm_dhcp_client_handle_event),
|
||||
NM_DHCP_DHCLIENT (object));
|
||||
|
||||
g_free (priv->pid_file);
|
||||
g_free (priv->conf_file);
|
||||
g_free (priv->lease_file);
|
||||
|
|
@ -641,5 +676,16 @@ nm_dhcp_dhclient_class_init (NMDhcpDhclientClass *dhclient_class)
|
|||
client_class->ip6_start = ip6_start;
|
||||
client_class->stop = stop;
|
||||
client_class->get_duid = get_duid;
|
||||
client_class->state_changed = state_changed;
|
||||
}
|
||||
|
||||
static void __attribute__((constructor))
|
||||
register_dhcp_dhclient (void)
|
||||
{
|
||||
g_type_init ();
|
||||
_nm_dhcp_client_register (NM_TYPE_DHCP_DHCLIENT,
|
||||
"dhclient",
|
||||
nm_dhcp_dhclient_get_path,
|
||||
nm_dhcp_dhclient_get_lease_ip_configs);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,11 +41,5 @@ typedef struct {
|
|||
|
||||
GType nm_dhcp_dhclient_get_type (void);
|
||||
|
||||
GSList *nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6);
|
||||
|
||||
const char *nm_dhcp_dhclient_get_path (void);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_DHCLIENT_H__ */
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "nm-logging.h"
|
||||
#include "nm-posix-signals.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-dhcp-listener.h"
|
||||
|
||||
G_DEFINE_TYPE (NMDhcpDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_CLIENT)
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ typedef struct {
|
|||
char *pid_file;
|
||||
} NMDhcpDhcpcdPrivate;
|
||||
|
||||
const char *
|
||||
static const char *
|
||||
nm_dhcp_dhcpcd_get_path (void)
|
||||
{
|
||||
const char *path = NULL;
|
||||
|
|
@ -72,17 +73,14 @@ dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
ip4_start (NMDhcpClient *client,
|
||||
const char *dhcp_client_id,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname)
|
||||
ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
|
||||
{
|
||||
NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client);
|
||||
GPtrArray *argv = NULL;
|
||||
pid_t pid = -1;
|
||||
GError *error = NULL;
|
||||
char *pid_contents = NULL, *binary_name, *cmd_str;
|
||||
const char *iface, *dhcpcd_path = NULL;
|
||||
const char *iface, *dhcpcd_path, *hostname;
|
||||
|
||||
g_return_val_if_fail (priv->pid_file == NULL, FALSE);
|
||||
|
||||
|
|
@ -129,7 +127,8 @@ ip4_start (NMDhcpClient *client,
|
|||
g_ptr_array_add (argv, (gpointer) "-4");
|
||||
#endif
|
||||
|
||||
if (hostname && strlen (hostname)) {
|
||||
hostname = nm_dhcp_client_get_hostname (client);
|
||||
if (hostname) {
|
||||
g_ptr_array_add (argv, (gpointer) "-h"); /* Send hostname to DHCP server */
|
||||
g_ptr_array_add (argv, (gpointer) hostname );
|
||||
}
|
||||
|
|
@ -160,7 +159,6 @@ ip4_start (NMDhcpClient *client,
|
|||
static gboolean
|
||||
ip6_start (NMDhcpClient *client,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
|
|
@ -190,6 +188,10 @@ stop (NMDhcpClient *client, gboolean release, const GByteArray *duid)
|
|||
static void
|
||||
nm_dhcp_dhcpcd_init (NMDhcpDhcpcd *self)
|
||||
{
|
||||
g_signal_connect (nm_dhcp_listener_get (),
|
||||
NM_DHCP_LISTENER_EVENT,
|
||||
G_CALLBACK (nm_dhcp_client_handle_event),
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -197,6 +199,10 @@ dispose (GObject *object)
|
|||
{
|
||||
NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (nm_dhcp_listener_get (),
|
||||
G_CALLBACK (nm_dhcp_client_handle_event),
|
||||
NM_DHCP_DHCPCD (object));
|
||||
|
||||
g_free (priv->pid_file);
|
||||
|
||||
G_OBJECT_CLASS (nm_dhcp_dhcpcd_parent_class)->dispose (object);
|
||||
|
|
@ -218,3 +224,13 @@ nm_dhcp_dhcpcd_class_init (NMDhcpDhcpcdClass *dhcpcd_class)
|
|||
client_class->stop = stop;
|
||||
}
|
||||
|
||||
static void __attribute__((constructor))
|
||||
register_dhcp_dhclient (void)
|
||||
{
|
||||
g_type_init ();
|
||||
_nm_dhcp_client_register (NM_TYPE_DHCP_DHCPCD,
|
||||
"dhcpcd",
|
||||
nm_dhcp_dhcpcd_get_path,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,5 @@ typedef struct {
|
|||
|
||||
GType nm_dhcp_dhcpcd_get_type (void);
|
||||
|
||||
const char *nm_dhcp_dhcpcd_get_path (void);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_DHCPCD_H__ */
|
||||
|
||||
|
|
|
|||
289
src/dhcp-manager/nm-dhcp-listener.c
Normal file
289
src/dhcp-manager/nm-dhcp-listener.c
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, 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 2014 Red Hat, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <dbus/dbus.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nm-dhcp-listener.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "nm-dbus-glib-types.h"
|
||||
#include "nm-glib-compat.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client"
|
||||
#define PRIV_SOCK_PATH NMRUNDIR "/private-dhcp"
|
||||
#define PRIV_SOCK_TAG "dhcp"
|
||||
|
||||
typedef struct {
|
||||
NMDBusManager * dbus_mgr;
|
||||
guint new_conn_id;
|
||||
guint dis_conn_id;
|
||||
GHashTable * proxies;
|
||||
DBusGProxy * proxy;
|
||||
} NMDhcpListenerPrivate;
|
||||
|
||||
#define NM_DHCP_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_LISTENER, NMDhcpListenerPrivate))
|
||||
|
||||
G_DEFINE_TYPE (NMDhcpListener, nm_dhcp_listener, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
EVENT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
/***************************************************/
|
||||
|
||||
static char *
|
||||
garray_to_string (GArray *array, const char *key)
|
||||
{
|
||||
GString *str;
|
||||
int i;
|
||||
unsigned char c;
|
||||
char *converted = NULL;
|
||||
|
||||
g_return_val_if_fail (array != NULL, NULL);
|
||||
|
||||
/* Since the DHCP options come through environment variables, they should
|
||||
* already be UTF-8 safe, but just make sure.
|
||||
*/
|
||||
str = g_string_sized_new (array->len);
|
||||
for (i = 0; i < array->len; i++) {
|
||||
c = array->data[i];
|
||||
|
||||
/* Convert NULLs to spaces and non-ASCII characters to ? */
|
||||
if (c == '\0')
|
||||
c = ' ';
|
||||
else if (c > 127)
|
||||
c = '?';
|
||||
str = g_string_append_c (str, c);
|
||||
}
|
||||
str = g_string_append_c (str, '\0');
|
||||
|
||||
converted = str->str;
|
||||
if (!g_utf8_validate (converted, -1, NULL))
|
||||
nm_log_warn (LOGD_DHCP, "DHCP option '%s' couldn't be converted to UTF-8", key);
|
||||
g_string_free (str, FALSE);
|
||||
return converted;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_option (GHashTable *hash, const char *key)
|
||||
{
|
||||
GValue *value;
|
||||
|
||||
value = g_hash_table_lookup (hash, key);
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
|
||||
if (G_VALUE_TYPE (value) != DBUS_TYPE_G_UCHAR_ARRAY) {
|
||||
nm_log_warn (LOGD_DHCP, "unexpected key %s value type was not "
|
||||
"DBUS_TYPE_G_UCHAR_ARRAY",
|
||||
(char *) key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return garray_to_string ((GArray *) g_value_get_boxed (value), key);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_event (DBusGProxy *proxy,
|
||||
GHashTable *options,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDhcpListener *self = NM_DHCP_LISTENER (user_data);
|
||||
char *iface = NULL;
|
||||
char *pid_str = NULL;
|
||||
char *reason = NULL;
|
||||
gint32 pid;
|
||||
gboolean handled = FALSE;
|
||||
|
||||
iface = get_option (options, "interface");
|
||||
if (iface == NULL) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP event: didn't have associated interface.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pid_str = get_option (options, "pid");
|
||||
pid = (gint32) nm_utils_ascii_str_to_int64 (pid_str, 10, 0, G_MAXINT32, -1);
|
||||
if (pid == -1 || pid != (GPid) pid) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP event: couldn't convert PID '%s' to an integer", pid_str ? pid_str : "(null)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
reason = get_option (options, "reason");
|
||||
if (reason == NULL) {
|
||||
nm_log_warn (LOGD_DHCP, "(pid %d) DHCP event didn't have a reason", pid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_signal_emit (self, signals[EVENT], 0, iface, pid, options, reason, &handled);
|
||||
if (!handled) {
|
||||
if (g_ascii_strcasecmp (reason, "RELEASE") == 0) {
|
||||
/* Ignore event when the dhcp client gets killed and we receive its last message */
|
||||
nm_log_dbg (LOGD_DHCP, "(pid %d) unhandled RELEASE DHCP event for interface %s", pid, iface);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP, "(pid %d) unhandled DHCP event for interface %s", pid, iface);
|
||||
}
|
||||
|
||||
out:
|
||||
g_free (iface);
|
||||
g_free (pid_str);
|
||||
g_free (reason);
|
||||
}
|
||||
|
||||
#if HAVE_DBUS_GLIB_100
|
||||
static void
|
||||
new_connection_cb (NMDBusManager *mgr,
|
||||
DBusGConnection *connection,
|
||||
NMDhcpListener *self)
|
||||
{
|
||||
DBusGProxy *proxy;
|
||||
|
||||
/* Create a new proxy for the client */
|
||||
proxy = dbus_g_proxy_new_for_peer (connection, "/", NM_DHCP_CLIENT_DBUS_IFACE);
|
||||
dbus_g_proxy_add_signal (proxy, "Event", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (proxy, "Event", G_CALLBACK (handle_event), self, NULL);
|
||||
|
||||
g_hash_table_insert (NM_DHCP_LISTENER_GET_PRIVATE (self)->proxies, connection, proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
dis_connection_cb (NMDBusManager *mgr,
|
||||
DBusGConnection *connection,
|
||||
NMDhcpListener *self)
|
||||
{
|
||||
NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self);
|
||||
DBusGProxy *proxy;
|
||||
|
||||
proxy = g_hash_table_lookup (priv->proxies, connection);
|
||||
if (proxy) {
|
||||
dbus_g_proxy_disconnect_signal (proxy, "Event", G_CALLBACK (handle_event), self);
|
||||
g_hash_table_remove (priv->proxies, connection);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************/
|
||||
|
||||
NMDhcpListener *
|
||||
nm_dhcp_listener_get (void)
|
||||
{
|
||||
static NMDhcpListener *singleton = NULL;
|
||||
|
||||
if (G_UNLIKELY (singleton == NULL))
|
||||
singleton = g_object_new (NM_TYPE_DHCP_LISTENER, NULL);
|
||||
g_assert (singleton);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
static void
|
||||
nm_dhcp_listener_init (NMDhcpListener *self)
|
||||
{
|
||||
NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self);
|
||||
#if !HAVE_DBUS_GLIB_100
|
||||
DBusGConnection *g_connection;
|
||||
#endif
|
||||
|
||||
/* Maps DBusGConnection :: DBusGProxy */
|
||||
priv->proxies = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
||||
|
||||
priv->dbus_mgr = nm_dbus_manager_get ();
|
||||
|
||||
#if HAVE_DBUS_GLIB_100
|
||||
/* Register the socket our DHCP clients will return lease info on */
|
||||
nm_dbus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG);
|
||||
priv->new_conn_id = g_signal_connect (priv->dbus_mgr,
|
||||
NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG,
|
||||
G_CALLBACK (new_connection_cb),
|
||||
self);
|
||||
priv->dis_conn_id = g_signal_connect (priv->dbus_mgr,
|
||||
NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG,
|
||||
G_CALLBACK (dis_connection_cb),
|
||||
self);
|
||||
#else
|
||||
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
||||
priv->proxy = dbus_g_proxy_new_for_name (g_connection,
|
||||
"org.freedesktop.nm_dhcp_client",
|
||||
"/",
|
||||
NM_DHCP_CLIENT_DBUS_IFACE);
|
||||
g_assert (priv->proxy);
|
||||
dbus_g_proxy_add_signal (priv->proxy, "Event", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (priv->proxy, "Event", G_CALLBACK (handle_event), self, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (object);
|
||||
|
||||
if (priv->new_conn_id) {
|
||||
g_signal_handler_disconnect (priv->dbus_mgr, priv->new_conn_id);
|
||||
priv->new_conn_id = 0;
|
||||
}
|
||||
if (priv->dis_conn_id) {
|
||||
g_signal_handler_disconnect (priv->dbus_mgr, priv->dis_conn_id);
|
||||
priv->dis_conn_id = 0;
|
||||
}
|
||||
priv->dbus_mgr = NULL;
|
||||
|
||||
if (priv->proxies) {
|
||||
g_hash_table_destroy (priv->proxies);
|
||||
priv->proxies = NULL;
|
||||
}
|
||||
g_clear_object (&priv->proxy);
|
||||
|
||||
G_OBJECT_CLASS (nm_dhcp_listener_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_dhcp_listener_class_init (NMDhcpListenerClass *listener_class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (listener_class);
|
||||
|
||||
g_type_class_add_private (listener_class, sizeof (NMDhcpListenerPrivate));
|
||||
|
||||
/* virtual methods */
|
||||
object_class->dispose = dispose;
|
||||
|
||||
/* signals */
|
||||
signals[EVENT] =
|
||||
g_signal_new (NM_DHCP_LISTENER_EVENT,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST, 0,
|
||||
g_signal_accumulator_true_handled,
|
||||
NULL, NULL,
|
||||
G_TYPE_BOOLEAN, /* listeners return TRUE if handled */
|
||||
4,
|
||||
G_TYPE_STRING, /* iface */
|
||||
G_TYPE_INT64, /* pid */
|
||||
G_TYPE_HASH_TABLE, /* options */
|
||||
G_TYPE_STRING); /* reason */
|
||||
}
|
||||
39
src/dhcp-manager/nm-dhcp-listener.h
Normal file
39
src/dhcp-manager/nm-dhcp-listener.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, 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 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORKMANAGER_DHCP_LISTENER_H__
|
||||
#define __NETWORKMANAGER_DHCP_LISTENER_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#define NM_TYPE_DHCP_LISTENER (nm_dhcp_listener_get_type ())
|
||||
#define NM_DHCP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListener))
|
||||
#define NM_IS_DHCP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP_LISTENER))
|
||||
#define NM_DHCP_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListenerClass))
|
||||
|
||||
#define NM_DHCP_LISTENER_EVENT "event"
|
||||
|
||||
typedef GObject NMDhcpListener;
|
||||
typedef GObjectClass NMDhcpListenerClass;
|
||||
|
||||
GType nm_dhcp_listener_get_type (void);
|
||||
|
||||
NMDhcpListener *nm_dhcp_listener_get (void);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_LISTENER_H__ */
|
||||
|
|
@ -23,7 +23,6 @@
|
|||
#include "config.h"
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <dbus/dbus.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -39,19 +38,13 @@
|
|||
#include "nm-dhcp-dhcpcd.h"
|
||||
#include "nm-dhcp-systemd.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "nm-config.h"
|
||||
#include "nm-dbus-glib-types.h"
|
||||
#include "nm-glib-compat.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client"
|
||||
|
||||
#define DHCP_TIMEOUT 45 /* default DHCP timeout, in seconds */
|
||||
|
||||
#define PRIV_SOCK_PATH NMRUNDIR "/private-dhcp"
|
||||
#define PRIV_SOCK_TAG "dhcp"
|
||||
|
||||
/* default to installed helper, but can be modified for testing */
|
||||
const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper";
|
||||
|
||||
|
|
@ -59,78 +52,89 @@ typedef GSList * (*GetLeaseConfigFunc) (const char *iface, const char *uuid, gbo
|
|||
|
||||
typedef struct {
|
||||
GType client_type;
|
||||
GetLeaseConfigFunc get_lease_ip_configs_func;
|
||||
|
||||
NMDBusManager * dbus_mgr;
|
||||
guint new_conn_id;
|
||||
guint dis_conn_id;
|
||||
GHashTable * proxies;
|
||||
|
||||
GHashTable * clients;
|
||||
DBusGProxy * proxy;
|
||||
char * default_hostname;
|
||||
} NMDhcpManagerPrivate;
|
||||
|
||||
|
||||
#define NM_DHCP_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_MANAGER, NMDhcpManagerPrivate))
|
||||
|
||||
G_DEFINE_TYPE (NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT)
|
||||
|
||||
static char *
|
||||
garray_to_string (GArray *array, const char *key)
|
||||
/***************************************************/
|
||||
|
||||
typedef struct {
|
||||
GType gtype;
|
||||
const char *name;
|
||||
NMDhcpClientGetPathFunc get_path_func;
|
||||
NMDhcpClientGetLeaseConfigsFunc get_lease_configs_func;
|
||||
} ClientDesc;
|
||||
|
||||
static GSList *client_descs = NULL;
|
||||
|
||||
void
|
||||
_nm_dhcp_client_register (GType gtype,
|
||||
const char *name,
|
||||
NMDhcpClientGetPathFunc get_path_func,
|
||||
NMDhcpClientGetLeaseConfigsFunc get_lease_configs_func)
|
||||
{
|
||||
GString *str;
|
||||
int i;
|
||||
unsigned char c;
|
||||
char *converted = NULL;
|
||||
ClientDesc *desc;
|
||||
GSList *iter;
|
||||
|
||||
g_return_val_if_fail (array != NULL, NULL);
|
||||
g_return_if_fail (gtype != G_TYPE_INVALID);
|
||||
g_return_if_fail (name != NULL);
|
||||
|
||||
/* Since the DHCP options come through environment variables, they should
|
||||
* already be UTF-8 safe, but just make sure.
|
||||
*/
|
||||
str = g_string_sized_new (array->len);
|
||||
for (i = 0; i < array->len; i++) {
|
||||
c = array->data[i];
|
||||
|
||||
/* Convert NULLs to spaces and non-ASCII characters to ? */
|
||||
if (c == '\0')
|
||||
c = ' ';
|
||||
else if (c > 127)
|
||||
c = '?';
|
||||
str = g_string_append_c (str, c);
|
||||
for (iter = client_descs; iter; iter = iter->next) {
|
||||
desc = iter->data;
|
||||
g_return_if_fail (desc->gtype != gtype);
|
||||
g_return_if_fail (strcmp (desc->name, name) != 0);
|
||||
}
|
||||
str = g_string_append_c (str, '\0');
|
||||
|
||||
converted = str->str;
|
||||
if (!g_utf8_validate (converted, -1, NULL))
|
||||
nm_log_warn (LOGD_DHCP, "DHCP option '%s' couldn't be converted to UTF-8", key);
|
||||
g_string_free (str, FALSE);
|
||||
return converted;
|
||||
desc = g_slice_new0 (ClientDesc);
|
||||
desc->gtype = gtype;
|
||||
desc->name = name;
|
||||
desc->get_path_func = get_path_func;
|
||||
desc->get_lease_configs_func = get_lease_configs_func;
|
||||
client_descs = g_slist_prepend (client_descs, desc);
|
||||
|
||||
nm_log_info (LOGD_DHCP, "Registered DHCP client '%s'", name);
|
||||
}
|
||||
|
||||
static NMDhcpClient *
|
||||
get_client_for_pid (NMDhcpManager *manager, GPid pid)
|
||||
static ClientDesc *
|
||||
find_client_desc (const char *name, GType gtype)
|
||||
{
|
||||
NMDhcpManagerPrivate *priv;
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
GSList *iter;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL);
|
||||
g_return_val_if_fail (name || gtype, NULL);
|
||||
|
||||
priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
|
||||
for (iter = client_descs; iter; iter = iter->next) {
|
||||
ClientDesc *desc = iter->data;
|
||||
|
||||
g_hash_table_iter_init (&iter, priv->clients);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value)) {
|
||||
NMDhcpClient *candidate = NM_DHCP_CLIENT (value);
|
||||
|
||||
if (nm_dhcp_client_get_pid (candidate) == pid)
|
||||
return candidate;
|
||||
if (name && strcmp (desc->name, name) != 0)
|
||||
continue;
|
||||
if (gtype && desc->name != 0)
|
||||
continue;
|
||||
return desc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GType
|
||||
is_client_enabled (const char *name, GError **error)
|
||||
{
|
||||
ClientDesc *desc;
|
||||
|
||||
desc = find_client_desc (name, G_TYPE_INVALID);
|
||||
if (desc && (!desc->get_path_func || desc->get_path_func()))
|
||||
return desc->gtype;
|
||||
|
||||
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
_("'%s' support not found or not enabled."),
|
||||
name);
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
static NMDhcpClient *
|
||||
get_client_for_ifindex (NMDhcpManager *manager, int ifindex, gboolean ip6)
|
||||
{
|
||||
|
|
@ -155,172 +159,26 @@ get_client_for_ifindex (NMDhcpManager *manager, int ifindex, gboolean ip6)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_option (GHashTable *hash, const char *key)
|
||||
{
|
||||
GValue *value;
|
||||
|
||||
value = g_hash_table_lookup (hash, key);
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
|
||||
if (G_VALUE_TYPE (value) != DBUS_TYPE_G_UCHAR_ARRAY) {
|
||||
nm_log_warn (LOGD_DHCP, "unexpected key %s value type was not "
|
||||
"DBUS_TYPE_G_UCHAR_ARRAY",
|
||||
(char *) key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return garray_to_string ((GArray *) g_value_get_boxed (value), key);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_dhcp_manager_handle_event (DBusGProxy *proxy,
|
||||
GHashTable *options,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDhcpManager *manager = NM_DHCP_MANAGER (user_data);
|
||||
NMDhcpClient *client;
|
||||
char *iface = NULL;
|
||||
char *pid_str = NULL;
|
||||
char *reason = NULL;
|
||||
long pid;
|
||||
|
||||
iface = get_option (options, "interface");
|
||||
if (iface == NULL) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP event: didn't have associated interface.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pid_str = get_option (options, "pid");
|
||||
pid = nm_utils_ascii_str_to_int64 (pid_str, 10, 0, LONG_MAX, -1);
|
||||
if (pid == -1 || pid != (GPid)pid) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP event: couldn't convert PID '%s' to an integer", pid_str ? pid_str : "(null)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
reason = get_option (options, "reason");
|
||||
client = get_client_for_pid (manager, (GPid) pid);
|
||||
if (client == NULL) {
|
||||
if (reason && g_ascii_strcasecmp (reason, "RELEASE") == 0) {
|
||||
/* This happens regularly, when the dhcp client gets killed and we receive its last message.
|
||||
* Don't log a warning in this case. */
|
||||
nm_log_dbg (LOGD_DHCP, "(pid %ld) unhandled RELEASE DHCP event for interface %s", pid, iface);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP, "(pid %ld) unhandled DHCP event for interface %s", pid, iface);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp (iface, nm_dhcp_client_get_iface (client))) {
|
||||
nm_log_warn (LOGD_DHCP, "(pid %ld) received DHCP event from unexpected interface '%s' (expected '%s')",
|
||||
pid, iface, nm_dhcp_client_get_iface (client));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (reason == NULL) {
|
||||
nm_log_warn (LOGD_DHCP, "(pid %ld) DHCP event didn't have a reason", pid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nm_dhcp_client_new_options (client, options, reason);
|
||||
|
||||
out:
|
||||
g_free (iface);
|
||||
g_free (pid_str);
|
||||
g_free (reason);
|
||||
}
|
||||
|
||||
#if HAVE_DBUS_GLIB_100
|
||||
static void
|
||||
new_connection_cb (NMDBusManager *mgr,
|
||||
DBusGConnection *connection,
|
||||
NMDhcpManager *self)
|
||||
{
|
||||
NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
DBusGProxy *proxy;
|
||||
|
||||
/* Create a new proxy for the client */
|
||||
proxy = dbus_g_proxy_new_for_peer (connection, "/", NM_DHCP_CLIENT_DBUS_IFACE);
|
||||
dbus_g_proxy_add_signal (proxy,
|
||||
"Event",
|
||||
DBUS_TYPE_G_MAP_OF_VARIANT,
|
||||
G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (proxy,
|
||||
"Event",
|
||||
G_CALLBACK (nm_dhcp_manager_handle_event),
|
||||
self,
|
||||
NULL);
|
||||
g_hash_table_insert (priv->proxies, connection, proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
dis_connection_cb (NMDBusManager *mgr,
|
||||
DBusGConnection *connection,
|
||||
NMDhcpManager *self)
|
||||
{
|
||||
NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
DBusGProxy *proxy;
|
||||
|
||||
proxy = g_hash_table_lookup (priv->proxies, connection);
|
||||
if (proxy) {
|
||||
dbus_g_proxy_disconnect_signal (proxy,
|
||||
"Event",
|
||||
G_CALLBACK (nm_dhcp_manager_handle_event),
|
||||
self);
|
||||
g_hash_table_remove (priv->proxies, connection);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static GType
|
||||
get_client_type (const char *client, GError **error)
|
||||
{
|
||||
gboolean use_dhclient, use_dhcpcd;
|
||||
GType client_gtype;
|
||||
|
||||
/* If a client was disabled at build-time, these will return FALSE */
|
||||
use_dhclient = !!nm_dhcp_dhclient_get_path ();
|
||||
use_dhcpcd = !!nm_dhcp_dhcpcd_get_path ();
|
||||
|
||||
if (!client) {
|
||||
if (use_dhclient)
|
||||
return NM_TYPE_DHCP_DHCLIENT;
|
||||
else if (use_dhcpcd)
|
||||
return NM_TYPE_DHCP_DHCPCD;
|
||||
else {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
_("no usable DHCP client could be found."));
|
||||
return G_TYPE_INVALID;
|
||||
if (client)
|
||||
client_gtype = is_client_enabled (client, error);
|
||||
else {
|
||||
/* Fallbacks */
|
||||
client_gtype = is_client_enabled ("dhclient", NULL);
|
||||
if (client_gtype == G_TYPE_INVALID)
|
||||
client_gtype = is_client_enabled ("dhcpcd", NULL);
|
||||
if (client_gtype == G_TYPE_INVALID)
|
||||
client_gtype = is_client_enabled ("internal", NULL);
|
||||
if (client_gtype == G_TYPE_INVALID) {
|
||||
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
_("no usable DHCP client could be found."));
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp (client, "dhclient")) {
|
||||
if (!use_dhclient) {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
_("'dhclient' could not be found or was disabled."));
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
return NM_TYPE_DHCP_DHCLIENT;
|
||||
}
|
||||
|
||||
if (!strcmp (client, "dhcpcd")) {
|
||||
if (!use_dhcpcd) {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
_("'dhcpcd' could not be found or was disabled."));
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
return NM_TYPE_DHCP_DHCPCD;
|
||||
}
|
||||
|
||||
if (!strcmp (client, "internal"))
|
||||
return NM_TYPE_DHCP_SYSTEMD;
|
||||
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
_("unsupported DHCP client '%s'"), client);
|
||||
return G_TYPE_INVALID;
|
||||
return client_gtype;
|
||||
}
|
||||
|
||||
static void client_state_changed (NMDhcpClient *client,
|
||||
|
|
@ -366,7 +224,8 @@ client_start (NMDhcpManager *self,
|
|||
const char *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy)
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const char *last_ip4_address)
|
||||
{
|
||||
NMDhcpManagerPrivate *priv;
|
||||
NMDhcpClient *client;
|
||||
|
|
@ -407,7 +266,7 @@ client_start (NMDhcpManager *self,
|
|||
if (ipv6)
|
||||
success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, hostname, info_only, privacy);
|
||||
else
|
||||
success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname);
|
||||
success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address);
|
||||
|
||||
if (!success) {
|
||||
remove_client (self, client);
|
||||
|
|
@ -438,7 +297,8 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
|
|||
const char *dhcp_hostname,
|
||||
const char *dhcp_client_id,
|
||||
guint32 timeout,
|
||||
const char *dhcp_anycast_addr)
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *last_ip_address)
|
||||
{
|
||||
const char *hostname = NULL;
|
||||
|
||||
|
|
@ -448,7 +308,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
|
|||
hostname = get_send_hostname (self, dhcp_hostname);
|
||||
return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE,
|
||||
dhcp_client_id, timeout, dhcp_anycast_addr, hostname,
|
||||
FALSE, 0);
|
||||
FALSE, 0, last_ip_address);
|
||||
}
|
||||
|
||||
/* Caller owns a reference to the NMDhcpClient on return */
|
||||
|
|
@ -474,7 +334,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
|
|||
hostname = get_send_hostname (self, dhcp_hostname);
|
||||
return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE,
|
||||
NULL, timeout, dhcp_anycast_addr, hostname, info_only,
|
||||
privacy);
|
||||
privacy, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -497,16 +357,15 @@ nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
|
|||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
{
|
||||
NMDhcpManagerPrivate *priv;
|
||||
ClientDesc *desc;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
g_return_val_if_fail (uuid != NULL, NULL);
|
||||
|
||||
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
if (priv->get_lease_ip_configs_func)
|
||||
return priv->get_lease_ip_configs_func (iface, uuid, ipv6);
|
||||
desc = find_client_desc (NULL, NM_DHCP_MANAGER_GET_PRIVATE (self)->client_type);
|
||||
if (desc && desc->get_lease_configs_func)
|
||||
return desc->get_lease_configs_func (iface, uuid, ipv6);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -527,24 +386,20 @@ static void
|
|||
nm_dhcp_manager_init (NMDhcpManager *self)
|
||||
{
|
||||
NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
NMConfig *config = nm_config_get ();
|
||||
const char *client;
|
||||
GError *error = NULL;
|
||||
#if !HAVE_DBUS_GLIB_100
|
||||
DBusGConnection *g_connection;
|
||||
#endif
|
||||
|
||||
/* Maps DBusGConnection :: DBusGProxy */
|
||||
priv->proxies = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
||||
|
||||
/* Client-specific setup */
|
||||
client = nm_config_get_dhcp_client (nm_config_get ());
|
||||
priv->client_type = get_client_type (client, &error);
|
||||
client = nm_config_get_dhcp_client (config);
|
||||
if (nm_config_get_configure_and_quit (config)) {
|
||||
if (g_strcmp0 (client, "internal") != 0)
|
||||
nm_log_warn (LOGD_DHCP, "Using internal DHCP client since configure-and-quit is set.");
|
||||
client = "internal";
|
||||
}
|
||||
|
||||
if (priv->client_type == NM_TYPE_DHCP_DHCLIENT)
|
||||
priv->get_lease_ip_configs_func = nm_dhcp_dhclient_get_lease_ip_configs;
|
||||
else if (priv->client_type == NM_TYPE_DHCP_SYSTEMD)
|
||||
priv->get_lease_ip_configs_func = nm_dhcp_systemd_get_lease_ip_configs;
|
||||
else if (priv->client_type == G_TYPE_INVALID) {
|
||||
priv->client_type = get_client_type (client, &error);
|
||||
if (priv->client_type == G_TYPE_INVALID) {
|
||||
nm_log_warn (LOGD_DHCP, "No usable DHCP client found (%s)! DHCP configurations will fail.",
|
||||
error->message);
|
||||
}
|
||||
|
|
@ -554,33 +409,6 @@ nm_dhcp_manager_init (NMDhcpManager *self)
|
|||
NULL,
|
||||
(GDestroyNotify) g_object_unref);
|
||||
g_assert (priv->clients);
|
||||
|
||||
priv->dbus_mgr = nm_dbus_manager_get ();
|
||||
|
||||
#if HAVE_DBUS_GLIB_100
|
||||
/* Register the socket our DHCP clients will return lease info on */
|
||||
nm_dbus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG);
|
||||
priv->new_conn_id = g_signal_connect (priv->dbus_mgr,
|
||||
NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG,
|
||||
(GCallback) new_connection_cb,
|
||||
self);
|
||||
priv->dis_conn_id = g_signal_connect (priv->dbus_mgr,
|
||||
NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG,
|
||||
(GCallback) dis_connection_cb,
|
||||
self);
|
||||
#else
|
||||
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
||||
priv->proxy = dbus_g_proxy_new_for_name (g_connection,
|
||||
"org.freedesktop.nm_dhcp_client",
|
||||
"/",
|
||||
NM_DHCP_CLIENT_DBUS_IFACE);
|
||||
g_assert (priv->proxy);
|
||||
dbus_g_proxy_add_signal (priv->proxy, "Event", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (priv->proxy, "Event",
|
||||
G_CALLBACK (nm_dhcp_manager_handle_event),
|
||||
self,
|
||||
NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -596,23 +424,6 @@ dispose (GObject *object)
|
|||
g_list_free (values);
|
||||
}
|
||||
|
||||
if (priv->new_conn_id) {
|
||||
g_signal_handler_disconnect (priv->dbus_mgr, priv->new_conn_id);
|
||||
priv->new_conn_id = 0;
|
||||
}
|
||||
if (priv->dis_conn_id) {
|
||||
g_signal_handler_disconnect (priv->dbus_mgr, priv->dis_conn_id);
|
||||
priv->dis_conn_id = 0;
|
||||
}
|
||||
priv->dbus_mgr = NULL;
|
||||
|
||||
if (priv->proxies) {
|
||||
g_hash_table_destroy (priv->proxies);
|
||||
priv->proxies = NULL;
|
||||
}
|
||||
if (priv->proxy)
|
||||
g_object_unref (priv->proxy);
|
||||
|
||||
G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager,
|
|||
const char *dhcp_hostname,
|
||||
const char *dhcp_client_id,
|
||||
guint32 timeout,
|
||||
const char *dhcp_anycast_addr);
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *last_ip_address);
|
||||
|
||||
NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
|
||||
const char *iface,
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ get_leasefile_path (const char *iface, const char *uuid, gboolean ipv6)
|
|||
iface);
|
||||
}
|
||||
|
||||
GSList *
|
||||
static GSList *
|
||||
nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
|
|
@ -401,6 +401,28 @@ nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
|
|||
|
||||
/************************************************************/
|
||||
|
||||
static void
|
||||
_save_client_id (NMDhcpSystemd *self,
|
||||
uint8_t type,
|
||||
const uint8_t *client_id,
|
||||
size_t len)
|
||||
{
|
||||
gs_unref_bytes GBytes *b = NULL;
|
||||
gs_free char *buf = NULL;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (client_id != NULL);
|
||||
g_return_if_fail (len > 0);
|
||||
|
||||
if (!nm_dhcp_client_get_client_id (NM_DHCP_CLIENT (self))) {
|
||||
buf = g_malloc (len + 1);
|
||||
buf[0] = type;
|
||||
memcpy (buf + 1, client_id, len);
|
||||
b = g_bytes_new (buf, len + 1);
|
||||
nm_dhcp_client_set_client_id (NM_DHCP_CLIENT (self), b);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bound4_handle (NMDhcpSystemd *self)
|
||||
{
|
||||
|
|
@ -428,9 +450,17 @@ bound4_handle (NMDhcpSystemd *self)
|
|||
TRUE,
|
||||
&error);
|
||||
if (ip4_config) {
|
||||
const uint8_t *client_id = NULL;
|
||||
size_t client_id_len = 0;
|
||||
uint8_t type = 0;
|
||||
|
||||
add_requests_to_options (options, dhcp4_requests);
|
||||
sd_dhcp_lease_save (lease, priv->lease_file);
|
||||
|
||||
client_id = sd_dhcp_client_get_client_id(priv->client4, &type, &client_id_len);
|
||||
if (client_id)
|
||||
_save_client_id (self, type, client_id, client_id_len);
|
||||
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (self),
|
||||
NM_DHCP_STATE_BOUND,
|
||||
G_OBJECT (ip4_config),
|
||||
|
|
@ -485,18 +515,17 @@ get_arp_type (const GByteArray *hwaddr)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
ip4_start (NMDhcpClient *client,
|
||||
const char *dhcp_client_id,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname)
|
||||
ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
|
||||
{
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (client);
|
||||
const char *iface = nm_dhcp_client_get_iface (client);
|
||||
const GByteArray *hwaddr;
|
||||
sd_dhcp_lease *lease = NULL;
|
||||
GBytes *override_client_id;
|
||||
const uint8_t *client_id = NULL;
|
||||
size_t client_id_len = 0;
|
||||
struct in_addr last_addr;
|
||||
struct in_addr last_addr = { 0 };
|
||||
const char *hostname;
|
||||
int r, i;
|
||||
|
||||
g_assert (priv->client4 == NULL);
|
||||
|
|
@ -549,36 +578,38 @@ ip4_start (NMDhcpClient *client,
|
|||
|
||||
sd_dhcp_lease_load (priv->lease_file, &lease);
|
||||
|
||||
if (lease) {
|
||||
r = sd_dhcp_lease_get_address (lease, &last_addr);
|
||||
if (r == 0) {
|
||||
r = sd_dhcp_client_set_request_address (priv->client4, &last_addr);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set last IPv4 address (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
if (last_ip4_address)
|
||||
inet_pton (AF_INET, last_ip4_address, &last_addr);
|
||||
else if (lease)
|
||||
sd_dhcp_lease_get_address (lease, &last_addr);
|
||||
|
||||
if (last_addr.s_addr) {
|
||||
r = sd_dhcp_client_set_request_address (priv->client4, &last_addr);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set last IPv4 address (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (dhcp_client_id) {
|
||||
gs_unref_bytes GBytes *b = NULL;
|
||||
|
||||
b = nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id);
|
||||
if (b) {
|
||||
client_id = (const guint8 *) g_bytes_get_data (b, &client_id_len);
|
||||
g_assert (client_id && client_id_len);
|
||||
sd_dhcp_client_set_client_id (priv->client4,
|
||||
client_id[0],
|
||||
client_id + 1,
|
||||
client_id_len - 1);
|
||||
}
|
||||
} else {
|
||||
override_client_id = nm_dhcp_client_get_client_id (client);
|
||||
if (override_client_id) {
|
||||
client_id = g_bytes_get_data (override_client_id, &client_id_len);
|
||||
g_assert (client_id && client_id_len);
|
||||
sd_dhcp_client_set_client_id (priv->client4,
|
||||
client_id[0],
|
||||
client_id + 1,
|
||||
client_id_len - 1);
|
||||
} else if (lease) {
|
||||
r = sd_dhcp_lease_get_client_id (lease, &client_id, &client_id_len);
|
||||
if (r == 0 && client_id_len) {
|
||||
sd_dhcp_client_set_client_id (priv->client4,
|
||||
client_id[0],
|
||||
client_id + 1,
|
||||
client_id_len - 1);
|
||||
_save_client_id (NM_DHCP_SYSTEMD (client),
|
||||
client_id[0],
|
||||
client_id + 1,
|
||||
client_id_len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -591,6 +622,7 @@ ip4_start (NMDhcpClient *client,
|
|||
sd_dhcp_client_set_request_option (priv->client4, dhcp4_requests[i].num);
|
||||
}
|
||||
|
||||
hostname = nm_dhcp_client_get_hostname (client);
|
||||
if (hostname) {
|
||||
r = sd_dhcp_client_set_hostname (priv->client4, hostname);
|
||||
if (r < 0) {
|
||||
|
|
@ -653,7 +685,6 @@ dhcp6_event_cb (sd_dhcp6_client *client, int event, gpointer user_data)
|
|||
static gboolean
|
||||
ip6_start (NMDhcpClient *client,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
|
|
@ -808,3 +839,13 @@ nm_dhcp_systemd_class_init (NMDhcpSystemdClass *sdhcp_class)
|
|||
client_class->stop = stop;
|
||||
}
|
||||
|
||||
static void __attribute__((constructor))
|
||||
register_dhcp_dhclient (void)
|
||||
{
|
||||
g_type_init ();
|
||||
_nm_dhcp_client_register (NM_TYPE_DHCP_SYSTEMD,
|
||||
"internal",
|
||||
NULL,
|
||||
nm_dhcp_systemd_get_lease_ip_configs);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,9 +41,5 @@ typedef struct {
|
|||
|
||||
GType nm_dhcp_systemd_get_type (void);
|
||||
|
||||
GSList *nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6);
|
||||
|
||||
#endif /* NM_DHCP_SYSTEMD_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -709,46 +709,17 @@ GBytes *
|
|||
nm_dhcp_utils_client_id_string_to_bytes (const char *client_id)
|
||||
{
|
||||
GBytes *bytes = NULL;
|
||||
guint i = 0, x = 0;
|
||||
guint len;
|
||||
char *c;
|
||||
int a;
|
||||
|
||||
g_return_val_if_fail (client_id && client_id[0], NULL);
|
||||
|
||||
/* Accept a binary client ID in hex digits with the ':' delimiter,
|
||||
* otherwise treat it as a string.
|
||||
*/
|
||||
len = strlen (client_id);
|
||||
c = g_malloc0 (len / 2 + 1);
|
||||
while (client_id[i]) {
|
||||
a = g_ascii_xdigit_value (client_id[i++]);
|
||||
if (a >= 0) {
|
||||
if (client_id[i] != ':') {
|
||||
c[x] = ((guint8) a << 4);
|
||||
a = g_ascii_xdigit_value (client_id[i++]);
|
||||
}
|
||||
if (a >= 0)
|
||||
c[x++] |= (guint8) a;
|
||||
}
|
||||
if (client_id[i]) {
|
||||
if (client_id[i] != ':' || !client_id[i + 1]) {
|
||||
/* missing or trailing ':' is invalid for hex-format */
|
||||
a = -1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (a < 0) {
|
||||
g_clear_pointer (&c, g_free);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
g_assert (x > 0);
|
||||
bytes = g_bytes_new_take (c, x);
|
||||
} else {
|
||||
/* Try as hex encoded */
|
||||
if (strchr (client_id, ':'))
|
||||
bytes = nm_utils_hexstr2bin (client_id);
|
||||
if (!bytes) {
|
||||
/* Fall back to string */
|
||||
len = strlen (client_id);
|
||||
c = g_malloc (len + 1);
|
||||
c[0] = 0; /* type: non-hardware address per RFC 2132 section 9.14 */
|
||||
memcpy (c + 1, client_id, len);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ noinst_PROGRAMS = \
|
|||
####### dhclient leases test #######
|
||||
|
||||
test_dhcp_dhclient_SOURCES = \
|
||||
$(top_srcdir)/src/dhcp-manager/nm-dhcp-dhclient-utils.h \
|
||||
$(top_srcdir)/src/dhcp-manager/nm-dhcp-dhclient-utils.c \
|
||||
$(top_srcdir)/src/dhcp-manager/nm-dhcp-utils.h \
|
||||
$(top_srcdir)/src/dhcp-manager/nm-dhcp-utils.c \
|
||||
test-dhcp-dhclient.c
|
||||
|
||||
test_dhcp_dhclient_LDADD = \
|
||||
|
|
|
|||
|
|
@ -23,30 +23,42 @@
|
|||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "gsystem-local-alloc.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-dhcp-dhclient-utils.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-ip4-config.h"
|
||||
#include "nm-platform.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#define DEBUG 1
|
||||
|
||||
static void
|
||||
test_config (const char *orig,
|
||||
const char *expected,
|
||||
const char *hostname,
|
||||
const char *dhcp_client_id,
|
||||
GBytes *expected_new_client_id,
|
||||
const char *iface,
|
||||
const char *anycast_addr)
|
||||
{
|
||||
char *new;
|
||||
gs_free char *new = NULL;
|
||||
gs_unref_bytes GBytes *client_id = NULL;
|
||||
gs_unref_bytes GBytes *new_client_id = NULL;
|
||||
|
||||
if (dhcp_client_id) {
|
||||
client_id = nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id);
|
||||
g_assert (client_id);
|
||||
}
|
||||
|
||||
new = nm_dhcp_dhclient_create_config (iface,
|
||||
FALSE,
|
||||
dhcp_client_id,
|
||||
client_id,
|
||||
anycast_addr,
|
||||
hostname,
|
||||
"/path/to/dhclient.conf",
|
||||
orig);
|
||||
orig,
|
||||
&new_client_id);
|
||||
g_assert (new != NULL);
|
||||
|
||||
#if DEBUG
|
||||
|
|
@ -60,9 +72,13 @@ test_config (const char *orig,
|
|||
new, expected);
|
||||
}
|
||||
#endif
|
||||
g_assert (strlen (new) == strlen (expected));
|
||||
g_assert (strcmp (new, expected) == 0);
|
||||
g_free (new);
|
||||
g_assert_cmpstr (new, ==, expected);
|
||||
|
||||
if (expected_new_client_id) {
|
||||
g_assert (new_client_id);
|
||||
g_assert (g_bytes_equal (new_client_id, expected_new_client_id));
|
||||
} else
|
||||
g_assert (new_client_id == NULL);
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
|
@ -84,11 +100,7 @@ static const char *orig_missing_expected = \
|
|||
static void
|
||||
test_orig_missing (void)
|
||||
{
|
||||
test_config (NULL, orig_missing_expected,
|
||||
NULL,
|
||||
NULL,
|
||||
"eth0",
|
||||
NULL);
|
||||
test_config (NULL, orig_missing_expected, NULL, NULL, NULL, "eth0", NULL);
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
|
@ -119,6 +131,7 @@ test_override_client_id (void)
|
|||
test_config (override_client_id_orig, override_client_id_expected,
|
||||
NULL,
|
||||
"11:22:33:44:55:66",
|
||||
NULL,
|
||||
"eth0",
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -147,6 +160,7 @@ test_quote_client_id (void)
|
|||
test_config (NULL, quote_client_id_expected,
|
||||
NULL,
|
||||
"1234",
|
||||
NULL,
|
||||
"eth0",
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -175,6 +189,7 @@ test_ascii_client_id (void)
|
|||
test_config (NULL, ascii_client_id_expected,
|
||||
NULL,
|
||||
"qb:cd:ef:12:34:56",
|
||||
NULL,
|
||||
"eth0",
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -184,7 +199,7 @@ test_ascii_client_id (void)
|
|||
static const char *hex_single_client_id_expected = \
|
||||
"# Created by NetworkManager\n"
|
||||
"\n"
|
||||
"send dhcp-client-identifier ab:cd:e:12:34:56; # added by NetworkManager\n"
|
||||
"send dhcp-client-identifier ab:cd:0e:12:34:56; # added by NetworkManager\n"
|
||||
"\n"
|
||||
"option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
|
||||
"option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
|
||||
|
|
@ -203,6 +218,84 @@ test_hex_single_client_id (void)
|
|||
test_config (NULL, hex_single_client_id_expected,
|
||||
NULL,
|
||||
"ab:cd:e:12:34:56",
|
||||
NULL,
|
||||
"eth0",
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
||||
static const char *existing_hex_client_id_orig = \
|
||||
"send dhcp-client-identifier 00:30:04:20:7A:08;\n";
|
||||
|
||||
static const char *existing_hex_client_id_expected = \
|
||||
"# Created by NetworkManager\n"
|
||||
"# Merged from /path/to/dhclient.conf\n"
|
||||
"\n"
|
||||
"send dhcp-client-identifier 00:30:04:20:7A:08;\n"
|
||||
"\n"
|
||||
"option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
|
||||
"option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
|
||||
"option wpad code 252 = string;\n"
|
||||
"\n"
|
||||
"also request rfc3442-classless-static-routes;\n"
|
||||
"also request ms-classless-static-routes;\n"
|
||||
"also request static-routes;\n"
|
||||
"also request wpad;\n"
|
||||
"also request ntp-servers;\n"
|
||||
"\n";
|
||||
|
||||
static void
|
||||
test_existing_hex_client_id (void)
|
||||
{
|
||||
gs_unref_bytes GBytes *new_client_id = NULL;
|
||||
const guint8 bytes[] = { 0x00, 0x30, 0x04,0x20, 0x7A, 0x08 };
|
||||
|
||||
new_client_id = g_bytes_new (bytes, sizeof (bytes));
|
||||
test_config (existing_hex_client_id_orig, existing_hex_client_id_expected,
|
||||
NULL,
|
||||
NULL,
|
||||
new_client_id,
|
||||
"eth0",
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
||||
#define EACID "qb:cd:ef:12:34:56"
|
||||
|
||||
static const char *existing_ascii_client_id_orig = \
|
||||
"send dhcp-client-identifier \"" EACID "\";\n";
|
||||
|
||||
static const char *existing_ascii_client_id_expected = \
|
||||
"# Created by NetworkManager\n"
|
||||
"# Merged from /path/to/dhclient.conf\n"
|
||||
"\n"
|
||||
"send dhcp-client-identifier \"" EACID "\";\n"
|
||||
"\n"
|
||||
"option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
|
||||
"option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
|
||||
"option wpad code 252 = string;\n"
|
||||
"\n"
|
||||
"also request rfc3442-classless-static-routes;\n"
|
||||
"also request ms-classless-static-routes;\n"
|
||||
"also request static-routes;\n"
|
||||
"also request wpad;\n"
|
||||
"also request ntp-servers;\n"
|
||||
"\n";
|
||||
|
||||
static void
|
||||
test_existing_ascii_client_id (void)
|
||||
{
|
||||
gs_unref_bytes GBytes *new_client_id = NULL;
|
||||
char buf[STRLEN (EACID) + 1] = { 0 };
|
||||
|
||||
memcpy (buf + 1, EACID, STRLEN (EACID));
|
||||
new_client_id = g_bytes_new (buf, sizeof (buf));
|
||||
test_config (existing_ascii_client_id_orig, existing_ascii_client_id_expected,
|
||||
NULL,
|
||||
NULL,
|
||||
new_client_id,
|
||||
"eth0",
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -235,6 +328,7 @@ test_override_hostname (void)
|
|||
test_config (override_hostname_orig, override_hostname_expected,
|
||||
"blahblah",
|
||||
NULL,
|
||||
NULL,
|
||||
"eth0",
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -267,6 +361,7 @@ static void
|
|||
test_existing_alsoreq (void)
|
||||
{
|
||||
test_config (existing_alsoreq_orig, existing_alsoreq_expected,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"eth0",
|
||||
|
|
@ -305,6 +400,7 @@ static void
|
|||
test_existing_multiline_alsoreq (void)
|
||||
{
|
||||
test_config (existing_multiline_alsoreq_orig, existing_multiline_alsoreq_expected,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"eth0",
|
||||
|
|
@ -616,6 +712,8 @@ main (int argc, char **argv)
|
|||
g_test_add_func ("/dhcp/dhclient/quote_client_id", test_quote_client_id);
|
||||
g_test_add_func ("/dhcp/dhclient/ascii_client_id", test_ascii_client_id);
|
||||
g_test_add_func ("/dhcp/dhclient/hex_single_client_id", test_hex_single_client_id);
|
||||
g_test_add_func ("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id);
|
||||
g_test_add_func ("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id);
|
||||
g_test_add_func ("/dhcp/dhclient/override_hostname", test_override_hostname);
|
||||
g_test_add_func ("/dhcp/dhclient/existing_alsoreq", test_existing_alsoreq);
|
||||
g_test_add_func ("/dhcp/dhclient/existing_multiline_alsoreq", test_existing_multiline_alsoreq);
|
||||
|
|
|
|||
281
src/main-utils.c
Normal file
281
src/main-utils.c
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* NetworkManager -- Network link manager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2004 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2005 - 2008 Novell, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#include "main-utils.h"
|
||||
#include "nm-posix-signals.h"
|
||||
#include "nm-logging.h"
|
||||
|
||||
static sigset_t signal_set;
|
||||
static gboolean *quit_early = NULL;
|
||||
|
||||
/*
|
||||
* Thread function waiting for signals and processing them.
|
||||
* Wait for signals in signal set. The semantics of sigwait() require that all
|
||||
* threads (including the thread calling sigwait()) have the signal masked, for
|
||||
* reliable operation. Otherwise, a signal that arrives while this thread is
|
||||
* not blocked in sigwait() might be delivered to another thread.
|
||||
*/
|
||||
static void *
|
||||
signal_handling_thread (void *arg)
|
||||
{
|
||||
GMainLoop *main_loop = arg;
|
||||
int signo;
|
||||
|
||||
while (1) {
|
||||
sigwait (&signal_set, &signo);
|
||||
|
||||
switch (signo) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
nm_log_info (LOGD_CORE, "caught signal %d, shutting down normally.", signo);
|
||||
*quit_early = TRUE; /* for quitting before entering the main loop */
|
||||
g_main_loop_quit (main_loop);
|
||||
break;
|
||||
case SIGHUP:
|
||||
/* Reread config stuff like system config files, VPN service files, etc */
|
||||
nm_log_info (LOGD_CORE, "caught signal %d, not supported yet.", signo);
|
||||
break;
|
||||
case SIGPIPE:
|
||||
/* silently ignore signal */
|
||||
break;
|
||||
default:
|
||||
nm_log_err (LOGD_CORE, "caught unexpected signal %d", signo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_main_utils_setup_signals:
|
||||
* @main_loop: the #GMainLoop to quit when SIGINT or SIGTERM is received
|
||||
* @quit_early: location of a variable that will be set to TRUE when
|
||||
* SIGINT or SIGTERM is received
|
||||
*
|
||||
* Mask the signals we are interested in and create a signal handling thread.
|
||||
* Because all threads inherit the signal mask from their creator, all threads
|
||||
* in the process will have the signals masked. That's why setup_signals() has
|
||||
* to be called before creating other threads.
|
||||
*
|
||||
* Returns: %TRUE on success
|
||||
*/
|
||||
gboolean
|
||||
nm_main_utils_setup_signals (GMainLoop *main_loop, gboolean *quit_early_ptr)
|
||||
{
|
||||
pthread_t signal_thread_id;
|
||||
sigset_t old_sig_mask;
|
||||
int status;
|
||||
|
||||
g_return_val_if_fail (main_loop != NULL, FALSE);
|
||||
g_return_val_if_fail (quit_early_ptr != NULL, FALSE);
|
||||
|
||||
quit_early = quit_early_ptr;
|
||||
|
||||
sigemptyset (&signal_set);
|
||||
sigaddset (&signal_set, SIGHUP);
|
||||
sigaddset (&signal_set, SIGINT);
|
||||
sigaddset (&signal_set, SIGTERM);
|
||||
sigaddset (&signal_set, SIGPIPE);
|
||||
|
||||
/* Block all signals of interest. */
|
||||
status = pthread_sigmask (SIG_BLOCK, &signal_set, &old_sig_mask);
|
||||
if (status != 0) {
|
||||
fprintf (stderr, _("Failed to set signal mask: %d"), status);
|
||||
return FALSE;
|
||||
}
|
||||
/* Save original mask so that we could use it for child processes. */
|
||||
nm_save_original_signal_mask (old_sig_mask);
|
||||
|
||||
/* Create the signal handling thread. */
|
||||
status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, main_loop);
|
||||
if (status != 0) {
|
||||
fprintf (stderr, _("Failed to create signal handling thread: %d"), status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_main_utils_write_pidfile (const char *pidfile)
|
||||
{
|
||||
char pid[16];
|
||||
int fd;
|
||||
gboolean success = FALSE;
|
||||
|
||||
if ((fd = open (pidfile, O_CREAT|O_WRONLY|O_TRUNC, 00644)) < 0) {
|
||||
fprintf (stderr, _("Opening %s failed: %s\n"), pidfile, strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_snprintf (pid, sizeof (pid), "%d", getpid ());
|
||||
if (write (fd, pid, strlen (pid)) < 0)
|
||||
fprintf (stderr, _("Writing to %s failed: %s\n"), pidfile, strerror (errno));
|
||||
else
|
||||
success = TRUE;
|
||||
|
||||
if (close (fd))
|
||||
fprintf (stderr, _("Closing %s failed: %s\n"), pidfile, strerror (errno));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_main_utils_check_pidfile:
|
||||
* @pidfile: the pid file
|
||||
* @name: the process name
|
||||
*
|
||||
* Checks whether the pidfile already exists and contains PID of a running
|
||||
* process.
|
||||
*
|
||||
* Returns: %TRUE if the specified pidfile already exists and contains the PID
|
||||
* of a running process named @name, or %FALSE if not
|
||||
*/
|
||||
gboolean
|
||||
nm_main_utils_check_pidfile (const char *pidfile, const char *name)
|
||||
{
|
||||
char *contents = NULL;
|
||||
gsize len = 0;
|
||||
glong pid;
|
||||
char *proc_cmdline = NULL;
|
||||
gboolean nm_running = FALSE;
|
||||
const char *process_name;
|
||||
|
||||
/* Setup runtime directory */
|
||||
if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) {
|
||||
nm_log_err (LOGD_CORE, "Cannot create '%s': %s", NMRUNDIR, strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (!g_file_get_contents (pidfile, &contents, &len, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (len <= 0)
|
||||
goto done;
|
||||
|
||||
errno = 0;
|
||||
pid = strtol (contents, NULL, 10);
|
||||
if (pid <= 0 || pid > 65536 || errno)
|
||||
goto done;
|
||||
|
||||
g_free (contents);
|
||||
proc_cmdline = g_strdup_printf ("/proc/%ld/cmdline", pid);
|
||||
if (!g_file_get_contents (proc_cmdline, &contents, &len, NULL))
|
||||
goto done;
|
||||
|
||||
process_name = strrchr (contents, '/');
|
||||
if (process_name)
|
||||
process_name++;
|
||||
else
|
||||
process_name = contents;
|
||||
if (strcmp (process_name, name) == 0) {
|
||||
/* Check that the process exists */
|
||||
if (kill (pid, 0) == 0) {
|
||||
fprintf (stderr, _("%s is already running (pid %ld)\n"), name, pid);
|
||||
nm_running = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
g_free (proc_cmdline);
|
||||
g_free (contents);
|
||||
return nm_running;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_main_utils_early_setup (const char *progname,
|
||||
char **argv[],
|
||||
int *argc,
|
||||
GOptionEntry *options,
|
||||
GOptionEntry *more_options,
|
||||
const char *summary)
|
||||
{
|
||||
GOptionContext *opt_ctx = NULL;
|
||||
GError *error = NULL;
|
||||
gboolean success = FALSE;
|
||||
int i;
|
||||
|
||||
/* Make GIO ignore the remote VFS service; otherwise it tries to use the
|
||||
* session bus to contact the remote service, and NM shouldn't ever be
|
||||
* talking on the session bus. See rh #588745
|
||||
*/
|
||||
setenv ("GIO_USE_VFS", "local", 1);
|
||||
|
||||
/*
|
||||
* Set the umask to 0022, which results in 0666 & ~0022 = 0644.
|
||||
* Otherwise, if root (or an su'ing user) has a wacky umask, we could
|
||||
* write out an unreadable resolv.conf.
|
||||
*/
|
||||
umask (022);
|
||||
|
||||
/* Ensure gettext() gets the right environment (bgo #666516) */
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
bindtextdomain (GETTEXT_PACKAGE, NMLOCALEDIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
|
||||
if (getuid () != 0) {
|
||||
fprintf (stderr, _("You must be root to run %s!\n"), progname);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for (i = 0; options[i].long_name; i++) {
|
||||
if (!strcmp (options[i].long_name, "log-level"))
|
||||
options[i].description = g_strdup_printf (options[i].description, nm_logging_all_levels_to_string ());
|
||||
else if (!strcmp (options[i].long_name, "log-domains"))
|
||||
options[i].description = g_strdup_printf (options[i].description, nm_logging_all_domains_to_string ());
|
||||
}
|
||||
|
||||
/* Parse options */
|
||||
opt_ctx = g_option_context_new (NULL);
|
||||
g_option_context_set_translation_domain (opt_ctx, GETTEXT_PACKAGE);
|
||||
g_option_context_set_ignore_unknown_options (opt_ctx, FALSE);
|
||||
g_option_context_set_help_enabled (opt_ctx, TRUE);
|
||||
g_option_context_add_main_entries (opt_ctx, options, NULL);
|
||||
if (more_options)
|
||||
g_option_context_add_main_entries (opt_ctx, more_options, NULL);
|
||||
g_option_context_set_summary (opt_ctx, summary);
|
||||
|
||||
success = g_option_context_parse (opt_ctx, argc, argv, &error);
|
||||
if (!success) {
|
||||
fprintf (stderr, _("%s. Please use --help to see a list of valid options.\n"),
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_option_context_free (opt_ctx);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
39
src/main-utils.h
Normal file
39
src/main-utils.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* NetworkManager -- Network link manager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __MAIN_UTILS_H__
|
||||
#define __MAIN_UTILS_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
gboolean nm_main_utils_setup_signals (GMainLoop *main_loop, gboolean *quit_early_ptr);
|
||||
|
||||
gboolean nm_main_utils_write_pidfile (const char *pidfile);
|
||||
|
||||
gboolean nm_main_utils_check_pidfile (const char *pidfile, const char *name);
|
||||
|
||||
gboolean nm_main_utils_early_setup (const char *progname,
|
||||
char **argv[],
|
||||
int *argc,
|
||||
GOptionEntry *options,
|
||||
GOptionEntry *more_options,
|
||||
const char *summary);
|
||||
|
||||
#endif /* __MAIN_UTILS_H__ */
|
||||
253
src/main.c
253
src/main.c
|
|
@ -42,6 +42,7 @@
|
|||
#include "gsystem-local-alloc.h"
|
||||
#include "nm-dbus-interface.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "main-utils.h"
|
||||
#include "nm-manager.h"
|
||||
#include "nm-linux-platform.h"
|
||||
#include "nm-dns-manager.h"
|
||||
|
|
@ -65,161 +66,7 @@
|
|||
#define NM_DEFAULT_PID_FILE NMRUNDIR "/NetworkManager.pid"
|
||||
#define NM_DEFAULT_SYSTEM_STATE_FILE NMSTATEDIR "/NetworkManager.state"
|
||||
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
static GMainLoop *main_loop = NULL;
|
||||
static gboolean quit_early = FALSE;
|
||||
static sigset_t signal_set;
|
||||
|
||||
void *signal_handling_thread (void *arg);
|
||||
/*
|
||||
* Thread function waiting for signals and processing them.
|
||||
* Wait for signals in signal set. The semantics of sigwait() require that all
|
||||
* threads (including the thread calling sigwait()) have the signal masked, for
|
||||
* reliable operation. Otherwise, a signal that arrives while this thread is
|
||||
* not blocked in sigwait() might be delivered to another thread.
|
||||
*/
|
||||
void *
|
||||
signal_handling_thread (void *arg)
|
||||
{
|
||||
int signo;
|
||||
|
||||
while (1) {
|
||||
sigwait (&signal_set, &signo);
|
||||
|
||||
switch (signo) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
nm_log_info (LOGD_CORE, "caught signal %d, shutting down normally.", signo);
|
||||
quit_early = TRUE; /* for quitting before entering the main loop */
|
||||
g_main_loop_quit (main_loop);
|
||||
break;
|
||||
case SIGHUP:
|
||||
/* Reread config stuff like system config files, VPN service files, etc */
|
||||
nm_log_info (LOGD_CORE, "caught signal %d, not supported yet.", signo);
|
||||
break;
|
||||
case SIGPIPE:
|
||||
/* silently ignore signal */
|
||||
break;
|
||||
default:
|
||||
nm_log_err (LOGD_CORE, "caught unexpected signal %d", signo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mask the signals we are interested in and create a signal handling thread.
|
||||
* Because all threads inherit the signal mask from their creator, all threads
|
||||
* in the process will have the signals masked. That's why setup_signals() has
|
||||
* to be called before creating other threads.
|
||||
*/
|
||||
static gboolean
|
||||
setup_signals (void)
|
||||
{
|
||||
pthread_t signal_thread_id;
|
||||
sigset_t old_sig_mask;
|
||||
int status;
|
||||
|
||||
sigemptyset (&signal_set);
|
||||
sigaddset (&signal_set, SIGHUP);
|
||||
sigaddset (&signal_set, SIGINT);
|
||||
sigaddset (&signal_set, SIGTERM);
|
||||
sigaddset (&signal_set, SIGPIPE);
|
||||
|
||||
/* Block all signals of interest. */
|
||||
status = pthread_sigmask (SIG_BLOCK, &signal_set, &old_sig_mask);
|
||||
if (status != 0) {
|
||||
fprintf (stderr, _("Failed to set signal mask: %d"), status);
|
||||
return FALSE;
|
||||
}
|
||||
/* Save original mask so that we could use it for child processes. */
|
||||
nm_save_original_signal_mask (old_sig_mask);
|
||||
|
||||
/* Create the signal handling thread. */
|
||||
status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, NULL);
|
||||
if (status != 0) {
|
||||
fprintf (stderr, _("Failed to create signal handling thread: %d"), status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
write_pidfile (const char *pidfile)
|
||||
{
|
||||
char pid[16];
|
||||
int fd;
|
||||
gboolean success = FALSE;
|
||||
|
||||
if ((fd = open (pidfile, O_CREAT|O_WRONLY|O_TRUNC, 00644)) < 0) {
|
||||
fprintf (stderr, _("Opening %s failed: %s\n"), pidfile, strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_snprintf (pid, sizeof (pid), "%d", getpid ());
|
||||
if (write (fd, pid, strlen (pid)) < 0)
|
||||
fprintf (stderr, _("Writing to %s failed: %s\n"), pidfile, strerror (errno));
|
||||
else
|
||||
success = TRUE;
|
||||
|
||||
if (close (fd))
|
||||
fprintf (stderr, _("Closing %s failed: %s\n"), pidfile, strerror (errno));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Check whether the pidfile already exists and contains PID of a running NetworkManager
|
||||
* Returns: FALSE - specified pidfile doesn't exist or doesn't contain PID of a running NM process
|
||||
* TRUE - specified pidfile already exists and contains PID of a running NM process
|
||||
*/
|
||||
static gboolean
|
||||
check_pidfile (const char *pidfile)
|
||||
{
|
||||
char *contents = NULL;
|
||||
gsize len = 0;
|
||||
glong pid;
|
||||
char *proc_cmdline = NULL;
|
||||
gboolean nm_running = FALSE;
|
||||
const char *process_name;
|
||||
|
||||
if (!g_file_get_contents (pidfile, &contents, &len, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (len <= 0)
|
||||
goto done;
|
||||
|
||||
errno = 0;
|
||||
pid = strtol (contents, NULL, 10);
|
||||
if (pid <= 0 || pid > 65536 || errno)
|
||||
goto done;
|
||||
|
||||
g_free (contents);
|
||||
proc_cmdline = g_strdup_printf ("/proc/%ld/cmdline", pid);
|
||||
if (!g_file_get_contents (proc_cmdline, &contents, &len, NULL))
|
||||
goto done;
|
||||
|
||||
process_name = strrchr (contents, '/');
|
||||
if (process_name)
|
||||
process_name++;
|
||||
else
|
||||
process_name = contents;
|
||||
if (strcmp (process_name, "NetworkManager") == 0) {
|
||||
/* Check that the process exists */
|
||||
if (kill (pid, 0) == 0) {
|
||||
fprintf (stderr, _("NetworkManager is already running (pid %ld)\n"), pid);
|
||||
nm_running = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
g_free (proc_cmdline);
|
||||
g_free (contents);
|
||||
return nm_running;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_state_file (const char *filename,
|
||||
|
|
@ -330,6 +177,13 @@ _init_nm_debug (const char *debug)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
manager_configure_quit (NMManager *manager, gpointer user_data)
|
||||
{
|
||||
nm_log_info (LOGD_CORE, "quitting now that startup is complete");
|
||||
g_main_loop_quit (main_loop);
|
||||
}
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
|
|
@ -337,7 +191,6 @@ _init_nm_debug (const char *debug)
|
|||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GOptionContext *opt_ctx = NULL;
|
||||
char *opt_log_level = NULL;
|
||||
char *opt_log_domains = NULL;
|
||||
gboolean become_daemon = TRUE, run_from_build_dir = FALSE;
|
||||
|
|
@ -347,7 +200,6 @@ main (int argc, char *argv[])
|
|||
gs_free char *state_file = NULL;
|
||||
gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
|
||||
gboolean success, show_version = FALSE;
|
||||
int i;
|
||||
NMManager *manager = NULL;
|
||||
gs_unref_object NMVpnManager *vpn_manager = NULL;
|
||||
gs_unref_object NMDnsManager *dns_mgr = NULL;
|
||||
|
|
@ -361,6 +213,7 @@ main (int argc, char *argv[])
|
|||
GError *error = NULL;
|
||||
gboolean wrote_pidfile = FALSE;
|
||||
char *bad_domains = NULL;
|
||||
gboolean quit_early = FALSE;
|
||||
|
||||
GOptionEntry options[] = {
|
||||
{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
|
||||
|
|
@ -377,66 +230,15 @@ main (int argc, char *argv[])
|
|||
{NULL}
|
||||
};
|
||||
|
||||
/* Make GIO ignore the remote VFS service; otherwise it tries to use the
|
||||
* session bus to contact the remote service, and NM shouldn't ever be
|
||||
* talking on the session bus. See rh #588745
|
||||
*/
|
||||
setenv ("GIO_USE_VFS", "local", 1);
|
||||
main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/*
|
||||
* Set the umask to 0022, which results in 0666 & ~0022 = 0644.
|
||||
* Otherwise, if root (or an su'ing user) has a wacky umask, we could
|
||||
* write out an unreadable resolv.conf.
|
||||
*/
|
||||
umask (022);
|
||||
|
||||
/* Set locale to be able to use environment variables */
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
bindtextdomain (GETTEXT_PACKAGE, NMLOCALEDIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
|
||||
if (!g_module_supported ()) {
|
||||
fprintf (stderr, _("GModules are not supported on your platform!\n"));
|
||||
if (!nm_main_utils_early_setup ("NetworkManager",
|
||||
&argv,
|
||||
&argc,
|
||||
options,
|
||||
nm_config_get_options (),
|
||||
_("NetworkManager monitors all network connections and automatically\nchooses the best connection to use. It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.")))
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (getuid () != 0) {
|
||||
fprintf (stderr, _("You must be root to run NetworkManager!\n"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for (i = 0; options[i].long_name; i++) {
|
||||
if (!strcmp (options[i].long_name, "log-level")) {
|
||||
options[i].description = g_strdup_printf (options[i].description,
|
||||
nm_logging_all_levels_to_string ());
|
||||
} else if (!strcmp (options[i].long_name, "log-domains")) {
|
||||
options[i].description = g_strdup_printf (options[i].description,
|
||||
nm_logging_all_domains_to_string ());
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse options */
|
||||
opt_ctx = g_option_context_new (NULL);
|
||||
g_option_context_set_translation_domain (opt_ctx, GETTEXT_PACKAGE);
|
||||
g_option_context_set_ignore_unknown_options (opt_ctx, FALSE);
|
||||
g_option_context_set_help_enabled (opt_ctx, TRUE);
|
||||
g_option_context_add_main_entries (opt_ctx, options, NULL);
|
||||
g_option_context_add_main_entries (opt_ctx, nm_config_get_options (), NULL);
|
||||
|
||||
g_option_context_set_summary (opt_ctx,
|
||||
_("NetworkManager monitors all network connections and automatically\nchooses the best connection to use. It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with."));
|
||||
|
||||
success = g_option_context_parse (opt_ctx, &argc, &argv, &error);
|
||||
g_option_context_free (opt_ctx);
|
||||
|
||||
if (!success) {
|
||||
fprintf (stderr, _("%s. Please use --help to see a list of valid options.\n"),
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (show_version) {
|
||||
fprintf (stdout, NM_DIST_VERSION "\n");
|
||||
|
|
@ -482,12 +284,6 @@ main (int argc, char *argv[])
|
|||
g_free (path);
|
||||
}
|
||||
|
||||
/* Setup runtime directory */
|
||||
if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) {
|
||||
nm_log_err (LOGD_CORE, "Cannot create '%s': %s", NMRUNDIR, strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Ensure state directory exists */
|
||||
if (g_mkdir_with_parents (NMSTATEDIR, 0755) != 0) {
|
||||
nm_log_err (LOGD_CORE, "Cannot create '%s': %s", NMSTATEDIR, strerror (errno));
|
||||
|
|
@ -498,7 +294,7 @@ main (int argc, char *argv[])
|
|||
state_file = state_file ? state_file : g_strdup (NM_DEFAULT_SYSTEM_STATE_FILE);
|
||||
|
||||
/* check pid file */
|
||||
if (check_pidfile (pidfile))
|
||||
if (nm_main_utils_check_pidfile (pidfile, "NetworkManager"))
|
||||
exit (1);
|
||||
|
||||
/* Read the config file and CLI overrides */
|
||||
|
|
@ -549,14 +345,13 @@ main (int argc, char *argv[])
|
|||
saved_errno);
|
||||
exit (1);
|
||||
}
|
||||
if (write_pidfile (pidfile))
|
||||
wrote_pidfile = TRUE;
|
||||
wrote_pidfile = nm_main_utils_write_pidfile (pidfile);
|
||||
}
|
||||
|
||||
_init_nm_debug (nm_config_get_debug (config));
|
||||
|
||||
/* Set up unix signal handling - before creating threads, but after daemonizing! */
|
||||
if (!setup_signals ())
|
||||
if (!nm_main_utils_setup_signals (main_loop, &quit_early))
|
||||
exit (1);
|
||||
|
||||
if (g_fatal_warnings) {
|
||||
|
|
@ -592,8 +387,6 @@ main (int argc, char *argv[])
|
|||
#endif
|
||||
);
|
||||
|
||||
main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* Set up platform interaction layer */
|
||||
nm_linux_platform_setup ();
|
||||
|
||||
|
|
@ -662,6 +455,8 @@ main (int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);
|
||||
|
||||
nm_manager_start (manager);
|
||||
|
||||
/* Make sure the loopback interface is up. If interface is down, we bring
|
||||
|
|
@ -680,10 +475,10 @@ main (int argc, char *argv[])
|
|||
success = TRUE;
|
||||
|
||||
/* Told to quit before getting to the mainloop by the signal handler */
|
||||
if (quit_early == TRUE)
|
||||
goto done;
|
||||
if (!quit_early)
|
||||
g_main_loop_run (main_loop);
|
||||
|
||||
g_main_loop_run (main_loop);
|
||||
nm_manager_stop (manager);
|
||||
|
||||
done:
|
||||
g_clear_object (&manager);
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ typedef struct {
|
|||
|
||||
char **no_auto_default;
|
||||
char **ignore_carrier;
|
||||
|
||||
gboolean configure_and_quit;
|
||||
} NMConfigPrivate;
|
||||
|
||||
static NMConfig *singleton = NULL;
|
||||
|
|
@ -72,41 +74,36 @@ G_DEFINE_TYPE (NMConfig, nm_config, G_TYPE_OBJECT)
|
|||
/************************************************************************/
|
||||
|
||||
static gboolean
|
||||
_parse_bool_str (const char *str, gboolean *out_value)
|
||||
_get_bool_value (GKeyFile *keyfile,
|
||||
const char *section,
|
||||
const char *key,
|
||||
gboolean default_value)
|
||||
{
|
||||
gboolean value;
|
||||
gsize len;
|
||||
char *s = NULL;
|
||||
gboolean value = default_value;
|
||||
char *str;
|
||||
|
||||
g_return_val_if_fail (str, FALSE);
|
||||
g_return_val_if_fail (keyfile != NULL, default_value);
|
||||
g_return_val_if_fail (section != NULL, default_value);
|
||||
g_return_val_if_fail (key != NULL, default_value);
|
||||
|
||||
while (g_ascii_isspace (*str))
|
||||
str++;
|
||||
str = g_key_file_get_value (keyfile, section, key, NULL);
|
||||
if (!str)
|
||||
return default_value;
|
||||
|
||||
if (!*str)
|
||||
return FALSE;
|
||||
|
||||
len = strlen (str);
|
||||
|
||||
if (g_ascii_isspace (str[len-1])) {
|
||||
str = s = g_strdup (str);
|
||||
g_strchomp (s);
|
||||
g_strstrip (str);
|
||||
if (str[0]) {
|
||||
if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1"))
|
||||
value = TRUE;
|
||||
else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0"))
|
||||
value = FALSE;
|
||||
else {
|
||||
nm_log_warn (LOGD_CORE, "Unrecognized value for %s.%s: '%s'. Assuming '%s'",
|
||||
section, key, str, default_value ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1"))
|
||||
value = TRUE;
|
||||
else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0"))
|
||||
value = FALSE;
|
||||
else {
|
||||
g_free (s);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out_value)
|
||||
*out_value = value;
|
||||
|
||||
g_free (s);
|
||||
return TRUE;
|
||||
g_free (str);
|
||||
return value;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
|
@ -218,6 +215,12 @@ nm_config_get_connectivity_response (NMConfig *config)
|
|||
return NM_CONFIG_GET_PRIVATE (config)->connectivity_response;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_config_get_configure_and_quit (NMConfig *config)
|
||||
{
|
||||
return NM_CONFIG_GET_PRIVATE (config)->configure_and_quit;
|
||||
}
|
||||
|
||||
char *
|
||||
nm_config_get_value (NMConfig *config, const char *group, const char *key, GError **error)
|
||||
{
|
||||
|
|
@ -513,7 +516,6 @@ nm_config_new (GError **error)
|
|||
GFileInfo *info;
|
||||
GPtrArray *confs;
|
||||
const char *name;
|
||||
char *value;
|
||||
int i;
|
||||
GString *config_description;
|
||||
|
||||
|
|
@ -583,23 +585,9 @@ nm_config_new (GError **error)
|
|||
if (!priv->plugins && STRLEN (CONFIG_PLUGINS_DEFAULT) > 0)
|
||||
priv->plugins = g_strsplit (CONFIG_PLUGINS_DEFAULT, ",", -1);
|
||||
|
||||
value = g_key_file_get_value (priv->keyfile, "main", "monitor-connection-files", NULL);
|
||||
priv->monitor_connection_files = FALSE;
|
||||
if (value) {
|
||||
if (!_parse_bool_str (value, &priv->monitor_connection_files))
|
||||
nm_log_warn (LOGD_CORE, "Unrecognized value for main.monitor-connection-files: %s. Assuming 'false'", value);
|
||||
g_free (value);
|
||||
}
|
||||
priv->monitor_connection_files = _get_bool_value (priv->keyfile, "main", "monitor-connection-files", FALSE);
|
||||
|
||||
value = g_key_file_get_value (priv->keyfile, "main", "auth-polkit", NULL);
|
||||
priv->auth_polkit = NM_CONFIG_DEFAULT_AUTH_POLKIT;
|
||||
if (value) {
|
||||
if (!_parse_bool_str (value, &priv->auth_polkit)) {
|
||||
nm_log_warn (LOGD_CORE, "Unrecognized value for main.auth-polkit: %s. Assuming '%s'", value,
|
||||
NM_CONFIG_DEFAULT_AUTH_POLKIT ? "true" : "false");
|
||||
}
|
||||
g_free (value);
|
||||
}
|
||||
priv->auth_polkit = _get_bool_value (priv->keyfile, "main", "auth-polkit", NM_CONFIG_DEFAULT_AUTH_POLKIT);
|
||||
|
||||
priv->dhcp_client = g_key_file_get_value (priv->keyfile, "main", "dhcp", NULL);
|
||||
priv->dns_mode = g_key_file_get_value (priv->keyfile, "main", "dns", NULL);
|
||||
|
|
@ -623,6 +611,8 @@ nm_config_new (GError **error)
|
|||
|
||||
priv->ignore_carrier = g_key_file_get_string_list (priv->keyfile, "main", "ignore-carrier", NULL, NULL);
|
||||
|
||||
priv->configure_and_quit = _get_bool_value (priv->keyfile, "main", "configure-and-quit", FALSE);
|
||||
|
||||
return singleton;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ const char *nm_config_get_debug (NMConfig *config);
|
|||
const char *nm_config_get_connectivity_uri (NMConfig *config);
|
||||
guint nm_config_get_connectivity_interval (NMConfig *config);
|
||||
const char *nm_config_get_connectivity_response (NMConfig *config);
|
||||
gboolean nm_config_get_configure_and_quit (NMConfig *config);
|
||||
|
||||
gboolean nm_config_get_ethernet_can_auto_default (NMConfig *config, NMDevice *device);
|
||||
void nm_config_set_ethernet_no_auto_default (NMConfig *config, NMDevice *device);
|
||||
|
|
|
|||
529
src/nm-iface-helper.c
Normal file
529
src/nm-iface-helper.c
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* NetworkManager -- Network link manager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <glib-unix.h>
|
||||
#include <getopt.h>
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "gsystem-local-alloc.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-linux-platform.h"
|
||||
#include "nm-dhcp-manager.h"
|
||||
#include "nm-logging.h"
|
||||
#include "main-utils.h"
|
||||
#include "nm-rdisc.h"
|
||||
#include "nm-lndp-rdisc.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
#if !defined(NM_DIST_VERSION)
|
||||
# define NM_DIST_VERSION VERSION
|
||||
#endif
|
||||
|
||||
#define NMIH_PID_FILE_FMT NMRUNDIR "/nm-iface-helper-%d.pid"
|
||||
|
||||
static GMainLoop *main_loop = NULL;
|
||||
static char *ifname = NULL;
|
||||
static int ifindex = -1;
|
||||
static gboolean slaac_required = FALSE;
|
||||
static gboolean dhcp4_required = FALSE;
|
||||
static int tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
|
||||
static int priority = -1;
|
||||
|
||||
static void
|
||||
dhcp4_state_changed (NMDhcpClient *client,
|
||||
NMDhcpState state,
|
||||
NMIP4Config *ip4_config,
|
||||
GHashTable *options,
|
||||
gpointer user_data)
|
||||
{
|
||||
static NMIP4Config *last_config = NULL;
|
||||
NMIP4Config *existing;
|
||||
|
||||
g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
|
||||
|
||||
nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d", ifname, state);
|
||||
|
||||
switch (state) {
|
||||
case NM_DHCP_STATE_BOUND:
|
||||
g_assert (ip4_config);
|
||||
existing = nm_ip4_config_capture (ifindex, FALSE);
|
||||
if (last_config)
|
||||
nm_ip4_config_subtract (existing, last_config);
|
||||
|
||||
nm_ip4_config_merge (existing, ip4_config);
|
||||
if (!nm_ip4_config_commit (existing, ifindex))
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to apply DHCPv4 config", ifname);
|
||||
|
||||
if (last_config) {
|
||||
g_object_unref (last_config);
|
||||
last_config = nm_ip4_config_new ();
|
||||
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 (dhcp4_required) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed, quitting...", ifname);
|
||||
g_main_loop_quit (main_loop);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed", ifname);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_data)
|
||||
{
|
||||
static NMIP6Config *last_config = NULL;
|
||||
NMIP6Config *existing;
|
||||
NMIP6Config *ip6_config;
|
||||
static int system_support = -1;
|
||||
guint ifa_flags = 0x00;
|
||||
int i;
|
||||
|
||||
if (system_support == -1) {
|
||||
/*
|
||||
* Check, if both libnl and the kernel are 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.
|
||||
**/
|
||||
system_support = nm_platform_check_support_libnl_extended_ifa_flags () &&
|
||||
nm_platform_check_support_kernel_extended_ifa_flags ();
|
||||
}
|
||||
|
||||
if (system_support)
|
||||
ifa_flags = IFA_F_NOPREFIXROUTE;
|
||||
if (tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|
||||
|| tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
|
||||
{
|
||||
/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
|
||||
ifa_flags |= IFA_F_MANAGETEMPADDR;
|
||||
}
|
||||
|
||||
ip6_config = nm_ip6_config_new ();
|
||||
|
||||
if (changed & NM_RDISC_CONFIG_GATEWAYS) {
|
||||
/* Use the first gateway as ordered in router discovery cache. */
|
||||
if (rdisc->gateways->len) {
|
||||
NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, 0);
|
||||
|
||||
nm_ip6_config_set_gateway (ip6_config, &gateway->address);
|
||||
} else
|
||||
nm_ip6_config_set_gateway (ip6_config, NULL);
|
||||
}
|
||||
|
||||
if (changed & NM_RDISC_CONFIG_ADDRESSES) {
|
||||
/* Rebuild address list from router discovery cache. */
|
||||
nm_ip6_config_reset_addresses (ip6_config);
|
||||
|
||||
/* rdisc->addresses contains at most max_addresses entries.
|
||||
* This is different from what the kernel does, which
|
||||
* also counts static and temporary addresses when checking
|
||||
* max_addresses.
|
||||
**/
|
||||
for (i = 0; i < rdisc->addresses->len; i++) {
|
||||
NMRDiscAddress *discovered_address = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
|
||||
NMPlatformIP6Address address;
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
address.address = discovered_address->address;
|
||||
address.plen = system_support ? 64 : 128;
|
||||
address.timestamp = discovered_address->timestamp;
|
||||
address.lifetime = discovered_address->lifetime;
|
||||
address.preferred = discovered_address->preferred;
|
||||
if (address.preferred > address.lifetime)
|
||||
address.preferred = address.lifetime;
|
||||
address.source = NM_IP_CONFIG_SOURCE_RDISC;
|
||||
address.flags = ifa_flags;
|
||||
|
||||
nm_ip6_config_add_address (ip6_config, &address);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & NM_RDISC_CONFIG_ROUTES) {
|
||||
/* Rebuild route list from router discovery cache. */
|
||||
nm_ip6_config_reset_routes (ip6_config);
|
||||
|
||||
for (i = 0; i < rdisc->routes->len; i++) {
|
||||
NMRDiscRoute *discovered_route = &g_array_index (rdisc->routes, NMRDiscRoute, i);
|
||||
NMPlatformIP6Route route;
|
||||
|
||||
/* Only accept non-default routes. The router has no idea what the
|
||||
* local configuration or user preferences are, so sending routes
|
||||
* with a prefix length of 0 is quite rude and thus ignored.
|
||||
*/
|
||||
if (discovered_route->plen > 0) {
|
||||
memset (&route, 0, sizeof (route));
|
||||
route.network = discovered_route->network;
|
||||
route.plen = discovered_route->plen;
|
||||
route.gateway = discovered_route->gateway;
|
||||
route.source = NM_IP_CONFIG_SOURCE_RDISC;
|
||||
route.metric = priority;
|
||||
|
||||
nm_ip6_config_add_route (ip6_config, &route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) {
|
||||
/* Unsupported until systemd DHCPv6 is ready */
|
||||
}
|
||||
|
||||
/* hop_limit == 0 is a special value "unspecified", so do not touch
|
||||
* in this case */
|
||||
if (changed & NM_RDISC_CONFIG_HOP_LIMIT && rdisc->hop_limit > 0) {
|
||||
char val[16];
|
||||
|
||||
g_snprintf (val, sizeof (val), "%d", rdisc->hop_limit);
|
||||
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "hop_limit"), val);
|
||||
}
|
||||
|
||||
if (changed & NM_RDISC_CONFIG_MTU) {
|
||||
char val[16];
|
||||
|
||||
g_snprintf (val, sizeof (val), "%d", rdisc->mtu);
|
||||
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "mtu"), val);
|
||||
}
|
||||
|
||||
existing = nm_ip6_config_capture (ifindex, FALSE, tempaddr);
|
||||
if (last_config)
|
||||
nm_ip6_config_subtract (existing, last_config);
|
||||
|
||||
nm_ip6_config_merge (existing, ip6_config);
|
||||
if (!nm_ip6_config_commit (existing, ifindex))
|
||||
nm_log_warn (LOGD_IP6, "(%s): failed to apply IPv6 config", ifname);
|
||||
|
||||
if (last_config) {
|
||||
g_object_unref (last_config);
|
||||
last_config = nm_ip6_config_new ();
|
||||
nm_ip6_config_replace (last_config, ip6_config, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rdisc_ra_timeout (NMRDisc *rdisc, gpointer user_data)
|
||||
{
|
||||
if (slaac_required) {
|
||||
nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed, quitting...", ifname);
|
||||
g_main_loop_quit (main_loop);
|
||||
} else
|
||||
nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed", ifname);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
quit_handler (gpointer user_data)
|
||||
{
|
||||
gboolean *quit_early_ptr = user_data;
|
||||
|
||||
*quit_early_ptr = TRUE;
|
||||
g_main_loop_quit (main_loop);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_signals (gboolean *quit_early_ptr)
|
||||
{
|
||||
sigset_t sigmask;
|
||||
|
||||
sigemptyset (&sigmask);
|
||||
pthread_sigmask (SIG_SETMASK, &sigmask, NULL);
|
||||
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
g_unix_signal_add (SIGINT, quit_handler, quit_early_ptr);
|
||||
g_unix_signal_add (SIGTERM, quit_handler, quit_early_ptr);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
char *opt_log_level = NULL;
|
||||
char *opt_log_domains = NULL;
|
||||
gboolean debug = FALSE, g_fatal_warnings = FALSE, become_daemon = FALSE;
|
||||
gboolean show_version = FALSE, slaac = FALSE;
|
||||
char *bad_domains = NULL, *dhcp4_hostname = NULL, *uuid = NULL;
|
||||
char *iid_str = NULL, *dhcp4_clientid = NULL, *dhcp4_address = NULL;
|
||||
gs_unref_object NMDhcpManager *dhcp_mgr = NULL;
|
||||
GError *error = NULL;
|
||||
gboolean wrote_pidfile = FALSE;
|
||||
gs_free char *pidfile = NULL;
|
||||
gboolean quit_early = FALSE;
|
||||
gs_unref_object NMDhcpClient *dhcp4_client = NULL;
|
||||
gs_unref_object NMRDisc *rdisc = NULL;
|
||||
GByteArray *hwaddr = NULL;
|
||||
size_t hwaddr_len = 0;
|
||||
gconstpointer tmp;
|
||||
gs_free NMUtilsIPv6IfaceId *iid = NULL;
|
||||
|
||||
GOptionEntry options[] = {
|
||||
/* Interface/IP config */
|
||||
{ "ifname", 'i', 0, G_OPTION_ARG_STRING, &ifname, N_("The interface to manage"), N_("eth0") },
|
||||
{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &uuid, N_("Connection UUID"), N_("661e8cd0-b618-46b8-9dc9-31a52baaa16b") },
|
||||
{ "slaac", 's', 0, G_OPTION_ARG_NONE, &slaac, N_("Whether to manage IPv6 SLAAC"), NULL },
|
||||
{ "slaac-required", '6', 0, G_OPTION_ARG_NONE, &slaac_required, N_("Whether SLAAC must be successful"), NULL },
|
||||
{ "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &tempaddr, N_("Use an IPv6 temporary privacy address"), NULL },
|
||||
{ "dhcp4", 'd', 0, G_OPTION_ARG_STRING, &dhcp4_address, N_("Current DHCPv4 address"), NULL },
|
||||
{ "dhcp4-required", '4', 0, G_OPTION_ARG_NONE, &dhcp4_required, N_("Whether DHCPv4 must be successful"), NULL },
|
||||
{ "dhcp4-clientid", 'c', 0, G_OPTION_ARG_STRING, &dhcp4_clientid, N_("Hex-encoded DHCPv4 client ID"), NULL },
|
||||
{ "dhcp4-hostname", 'h', 0, G_OPTION_ARG_STRING, &dhcp4_hostname, N_("Hostname to send to DHCP server"), N_("barbar") },
|
||||
{ "priority", 'p', 0, G_OPTION_ARG_INT, &priority, N_("Route priority"), N_("10") },
|
||||
{ "iid", 'e', 0, G_OPTION_ARG_STRING, &iid_str, N_("Hex-encoded Interface Identifier"), N_("") },
|
||||
|
||||
/* Logging/debugging */
|
||||
{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
|
||||
{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &become_daemon, N_("Don't become a daemon"), NULL },
|
||||
{ "debug", 'b', 0, G_OPTION_ARG_NONE, &debug, N_("Don't become a daemon, and log to stderr"), NULL },
|
||||
{ "log-level", 0, 0, G_OPTION_ARG_STRING, &opt_log_level, N_("Log level: one of [%s]"), "INFO" },
|
||||
{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &opt_log_domains,
|
||||
N_("Log domains separated by ',': any combination of [%s]"),
|
||||
"PLATFORM,RFKILL,WIFI" },
|
||||
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, N_("Make all warnings fatal"), NULL },
|
||||
{NULL}
|
||||
};
|
||||
|
||||
setpgid (getpid (), getpid ());
|
||||
|
||||
if (!nm_main_utils_early_setup ("nm-iface-helper",
|
||||
&argv,
|
||||
&argc,
|
||||
options,
|
||||
NULL,
|
||||
_("nm-iface-helper is a small, standalone process that manages a single network interface.")))
|
||||
exit (1);
|
||||
|
||||
if (show_version) {
|
||||
fprintf (stdout, NM_DIST_VERSION "\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (!ifname || !uuid) {
|
||||
fprintf (stderr, _("An interface name and UUID are required\n"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (!nm_logging_setup (opt_log_level,
|
||||
opt_log_domains,
|
||||
&bad_domains,
|
||||
&error)) {
|
||||
fprintf (stderr,
|
||||
_("%s. Please use --help to see a list of valid options.\n"),
|
||||
error->message);
|
||||
exit (1);
|
||||
} else if (bad_domains) {
|
||||
fprintf (stderr,
|
||||
_("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
|
||||
bad_domains);
|
||||
g_clear_pointer (&bad_domains, g_free);
|
||||
}
|
||||
|
||||
pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, ifindex);
|
||||
g_assert (pidfile);
|
||||
|
||||
/* check pid file */
|
||||
if (nm_main_utils_check_pidfile (pidfile, "nm-iface-helper"))
|
||||
exit (1);
|
||||
|
||||
if (become_daemon && !debug) {
|
||||
if (daemon (0, 0) < 0) {
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
fprintf (stderr, _("Could not daemonize: %s [error %u]\n"),
|
||||
g_strerror (saved_errno),
|
||||
saved_errno);
|
||||
exit (1);
|
||||
}
|
||||
if (nm_main_utils_write_pidfile (pidfile))
|
||||
wrote_pidfile = TRUE;
|
||||
}
|
||||
|
||||
/* Set up unix signal handling - before creating threads, but after daemonizing! */
|
||||
main_loop = g_main_loop_new (NULL, FALSE);
|
||||
setup_signals (&quit_early);
|
||||
|
||||
if (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);
|
||||
}
|
||||
|
||||
nm_logging_syslog_openlog (debug);
|
||||
|
||||
#if !GLIB_CHECK_VERSION (2, 35, 0)
|
||||
g_type_init ();
|
||||
#endif
|
||||
|
||||
nm_log_info (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting...");
|
||||
|
||||
/* Set up platform interaction layer */
|
||||
nm_linux_platform_setup ();
|
||||
|
||||
ifindex = nm_platform_link_get_ifindex (ifname);
|
||||
if (ifindex <= 0) {
|
||||
fprintf (stderr, _("Failed to find interface index for %s\n"), ifname);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
tmp = nm_platform_link_get_address (ifindex, &hwaddr_len);
|
||||
if (tmp) {
|
||||
hwaddr = g_byte_array_sized_new (hwaddr_len);
|
||||
g_byte_array_append (hwaddr, tmp, hwaddr_len);
|
||||
}
|
||||
|
||||
if (iid_str) {
|
||||
GBytes *bytes;
|
||||
gsize ignored = 0;
|
||||
|
||||
bytes = nm_utils_hexstr2bin (iid_str);
|
||||
if (!bytes || g_bytes_get_size (bytes) != sizeof (*iid)) {
|
||||
fprintf (stderr, _("(%s): Invalid IID %s\n"), ifname, iid_str);
|
||||
exit (1);
|
||||
}
|
||||
iid = g_bytes_unref_to_data (bytes, &ignored);
|
||||
}
|
||||
|
||||
priority = MAX (0, priority);
|
||||
|
||||
if (dhcp4_address) {
|
||||
nm_platform_sysctl_set (nm_utils_ip4_property_path (ifname, "promote_secondaries"), "1");
|
||||
|
||||
/* Initialize DHCP manager */
|
||||
dhcp_mgr = nm_dhcp_manager_get ();
|
||||
g_assert (dhcp_mgr != NULL);
|
||||
|
||||
dhcp4_client = nm_dhcp_manager_start_ip4 (dhcp_mgr,
|
||||
ifname,
|
||||
ifindex,
|
||||
hwaddr,
|
||||
uuid,
|
||||
priority,
|
||||
!!dhcp4_hostname,
|
||||
dhcp4_hostname,
|
||||
dhcp4_clientid,
|
||||
45,
|
||||
NULL,
|
||||
dhcp4_address);
|
||||
g_assert (dhcp4_client);
|
||||
g_signal_connect (dhcp4_client,
|
||||
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
|
||||
G_CALLBACK (dhcp4_state_changed),
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (slaac) {
|
||||
nm_platform_link_set_user_ipv6ll_enabled (ifindex, TRUE);
|
||||
|
||||
rdisc = nm_lndp_rdisc_new (ifindex, ifname);
|
||||
g_assert (rdisc);
|
||||
|
||||
if (iid)
|
||||
nm_rdisc_set_iid (rdisc, *iid);
|
||||
|
||||
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra"), "1");
|
||||
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_defrtr"), "0");
|
||||
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_pinfo"), "0");
|
||||
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_rtr_pref"), "0");
|
||||
|
||||
g_signal_connect (rdisc,
|
||||
NM_RDISC_CONFIG_CHANGED,
|
||||
G_CALLBACK (rdisc_config_changed),
|
||||
NULL);
|
||||
g_signal_connect (rdisc,
|
||||
NM_RDISC_RA_TIMEOUT,
|
||||
G_CALLBACK (rdisc_ra_timeout),
|
||||
NULL);
|
||||
nm_rdisc_start (rdisc);
|
||||
}
|
||||
|
||||
if (!quit_early)
|
||||
g_main_loop_run (main_loop);
|
||||
|
||||
g_clear_pointer (&hwaddr, g_byte_array_unref);
|
||||
|
||||
nm_logging_syslog_closelog ();
|
||||
|
||||
if (pidfile && wrote_pidfile)
|
||||
unlink (pidfile);
|
||||
|
||||
nm_log_info (LOGD_CORE, "exiting");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/*******************************************************/
|
||||
/* Stub functions */
|
||||
|
||||
gconstpointer nm_config_get (void);
|
||||
const char *nm_config_get_dhcp_client (gpointer unused);
|
||||
gboolean nm_config_get_configure_and_quit (gpointer unused);
|
||||
gconstpointer nm_dbus_manager_get (void);
|
||||
void nm_dbus_manager_register_exported_type (gpointer unused, GType gtype, gconstpointer unused2);
|
||||
void nm_dbus_manager_register_object (gpointer unused, const char *path, gpointer object);
|
||||
|
||||
gconstpointer
|
||||
nm_config_get (void)
|
||||
{
|
||||
return GUINT_TO_POINTER (1);
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_config_get_dhcp_client (gpointer unused)
|
||||
{
|
||||
return "internal";
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_config_get_configure_and_quit (gpointer unused)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gconstpointer
|
||||
nm_dbus_manager_get (void)
|
||||
{
|
||||
return GUINT_TO_POINTER (1);
|
||||
}
|
||||
|
||||
void
|
||||
nm_dbus_manager_register_exported_type (gpointer unused, GType gtype, gconstpointer unused2)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nm_dbus_manager_register_object (gpointer unused, const char *path, gpointer object)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +83,7 @@ nm_ip4_config_new (void)
|
|||
}
|
||||
|
||||
|
||||
#ifndef NM_IFACE_HELPER
|
||||
void
|
||||
nm_ip4_config_export (NMIP4Config *config)
|
||||
{
|
||||
|
|
@ -94,6 +95,7 @@ nm_ip4_config_export (NMIP4Config *config)
|
|||
nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, config);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *
|
||||
nm_ip4_config_get_dbus_path (const NMIP4Config *config)
|
||||
|
|
@ -1952,7 +1954,9 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
|
|||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
|
||||
|
||||
#ifndef NM_IFACE_HELPER
|
||||
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
||||
G_TYPE_FROM_CLASS (config_class),
|
||||
&dbus_glib_nm_ip4_config_object_info);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ nm_ip6_config_new (void)
|
|||
return (NMIP6Config *) g_object_new (NM_TYPE_IP6_CONFIG, NULL);
|
||||
}
|
||||
|
||||
#ifndef NM_IFACE_HELPER
|
||||
void
|
||||
nm_ip6_config_export (NMIP6Config *config)
|
||||
{
|
||||
|
|
@ -84,6 +85,7 @@ nm_ip6_config_export (NMIP6Config *config)
|
|||
nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, config);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *
|
||||
nm_ip6_config_get_dbus_path (const NMIP6Config *config)
|
||||
|
|
@ -1863,7 +1865,9 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
|
|||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
|
||||
|
||||
#ifndef NM_IFACE_HELPER
|
||||
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
||||
G_TYPE_FROM_CLASS (config_class),
|
||||
&dbus_glib_nm_ip6_config_object_info);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include "nm-session-monitor.h"
|
||||
#include "nm-activation-request.h"
|
||||
#include "nm-core-internal.h"
|
||||
#include "nm-config.h"
|
||||
|
||||
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
|
||||
#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
|
||||
|
|
@ -214,6 +215,7 @@ enum {
|
|||
USER_PERMISSIONS_CHANGED,
|
||||
ACTIVE_CONNECTION_ADDED,
|
||||
ACTIVE_CONNECTION_REMOVED,
|
||||
CONFIGURE_QUIT,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
|
@ -706,6 +708,9 @@ check_if_startup_complete (NMManager *self)
|
|||
|
||||
g_signal_handlers_disconnect_by_func (dev, G_CALLBACK (device_has_pending_action_changed), self);
|
||||
}
|
||||
|
||||
if (nm_config_get_configure_and_quit (nm_config_get ()))
|
||||
g_signal_emit (self, signals[CONFIGURE_QUIT], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -745,6 +750,8 @@ remove_device (NMManager *manager,
|
|||
nm_device_set_unmanaged_quitting (device);
|
||||
else
|
||||
nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_REMOVED);
|
||||
} else if (quitting && nm_config_get_configure_and_quit (nm_config_get ())) {
|
||||
nm_device_spawn_iface_helper (device);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4167,6 +4174,16 @@ nm_manager_start (NMManager *self)
|
|||
check_if_startup_complete (self);
|
||||
}
|
||||
|
||||
void
|
||||
nm_manager_stop (NMManager *self)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
/* Remove all devices */
|
||||
while (priv->devices)
|
||||
remove_device (self, NM_DEVICE (priv->devices->data), TRUE, TRUE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_firmware_changed (gpointer user_data)
|
||||
{
|
||||
|
|
@ -4990,9 +5007,7 @@ dispose (GObject *object)
|
|||
G_CALLBACK (authority_changed_cb),
|
||||
manager);
|
||||
|
||||
/* Remove all devices */
|
||||
while (priv->devices)
|
||||
remove_device (manager, NM_DEVICE (priv->devices->data), TRUE, TRUE);
|
||||
g_assert (priv->devices == NULL);
|
||||
|
||||
if (priv->ac_cleanup_id) {
|
||||
g_source_remove (priv->ac_cleanup_id);
|
||||
|
|
@ -5258,6 +5273,13 @@ nm_manager_class_init (NMManagerClass *manager_class)
|
|||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_OBJECT);
|
||||
|
||||
signals[CONFIGURE_QUIT] =
|
||||
g_signal_new (NM_MANAGER_CONFIGURE_QUIT,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
||||
G_TYPE_FROM_CLASS (manager_class),
|
||||
&dbus_glib_nm_manager_object_info);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
/* Internal signals */
|
||||
#define NM_MANAGER_ACTIVE_CONNECTION_ADDED "active-connection-added"
|
||||
#define NM_MANAGER_ACTIVE_CONNECTION_REMOVED "active-connection-removed"
|
||||
#define NM_MANAGER_CONFIGURE_QUIT "configure-quit"
|
||||
|
||||
|
||||
struct _NMManager {
|
||||
|
|
@ -88,6 +89,7 @@ NMManager * nm_manager_new (NMSettings *settings,
|
|||
NMManager * nm_manager_get (void);
|
||||
|
||||
void nm_manager_start (NMManager *manager);
|
||||
void nm_manager_stop (NMManager *manager);
|
||||
NMState nm_manager_get_state (NMManager *manager);
|
||||
const GSList *nm_manager_get_active_connections (NMManager *manager);
|
||||
GSList * nm_manager_get_activatable_connections (NMManager *manager);
|
||||
|
|
|
|||
|
|
@ -3224,7 +3224,6 @@ make_wireless_setting (shvarFile *ifcfg,
|
|||
GError **error)
|
||||
{
|
||||
NMSettingWireless *s_wireless;
|
||||
GBytes *bytes = NULL;
|
||||
char *value = NULL;
|
||||
gint64 chan = 0;
|
||||
|
||||
|
|
@ -3256,19 +3255,19 @@ make_wireless_setting (shvarFile *ifcfg,
|
|||
|
||||
value = svGetValue (ifcfg, "ESSID", TRUE);
|
||||
if (value) {
|
||||
gsize ssid_len = 0, value_len = strlen (value);
|
||||
char *p = value, *tmp;
|
||||
char buf[33];
|
||||
GBytes *bytes = NULL;
|
||||
gsize ssid_len = 0;
|
||||
gsize value_len = strlen (value);
|
||||
|
||||
ssid_len = value_len;
|
||||
if ( (value_len >= 2)
|
||||
&& (value[0] == '"')
|
||||
&& (value[value_len - 1] == '"')) {
|
||||
/* Strip the quotes and unescape */
|
||||
p = value + 1;
|
||||
char *p = value + 1;
|
||||
|
||||
value[value_len - 1] = '\0';
|
||||
svUnescape (p);
|
||||
ssid_len = strlen (p);
|
||||
bytes = g_bytes_new (p, strlen (p));
|
||||
} else if ((value_len > 2) && (strncmp (value, "0x", 2) == 0)) {
|
||||
/* Hex representation */
|
||||
if (value_len % 2) {
|
||||
|
|
@ -3279,34 +3278,27 @@ make_wireless_setting (shvarFile *ifcfg,
|
|||
goto error;
|
||||
}
|
||||
|
||||
p = value + 2;
|
||||
while (*p) {
|
||||
if (!g_ascii_isxdigit (*p)) {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Invalid SSID '%s' character (looks like hex SSID but '%c' isn't a hex digit)",
|
||||
value, *p);
|
||||
g_free (value);
|
||||
goto error;
|
||||
}
|
||||
p++;
|
||||
bytes = nm_utils_hexstr2bin (value);
|
||||
if (!bytes) {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Invalid SSID '%s' (looks like hex SSID but isn't)",
|
||||
value);
|
||||
g_free (value);
|
||||
goto error;
|
||||
}
|
||||
} else
|
||||
bytes = g_bytes_new (value, value_len);
|
||||
|
||||
tmp = nm_utils_hexstr2bin (value + 2, value_len - 2);
|
||||
ssid_len = (value_len - 2) / 2;
|
||||
memcpy (buf, tmp, ssid_len);
|
||||
p = &buf[0];
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
ssid_len = g_bytes_get_size (bytes);
|
||||
if (ssid_len > 32 || ssid_len == 0) {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
|
||||
value, ssid_len);
|
||||
g_bytes_unref (bytes);
|
||||
g_free (value);
|
||||
goto error;
|
||||
}
|
||||
|
||||
bytes = g_bytes_new (p, ssid_len);
|
||||
g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, bytes, NULL);
|
||||
g_bytes_unref (bytes);
|
||||
g_free (value);
|
||||
|
|
|
|||
|
|
@ -43,8 +43,16 @@ connection_id_from_ifnet_name (const char *conn_name)
|
|||
int name_len = strlen (conn_name);
|
||||
|
||||
/* Convert a hex-encoded conn_name (only used for wifi SSIDs) to human-readable one */
|
||||
if ((name_len > 2) && (g_str_has_prefix (conn_name, "0x")))
|
||||
return nm_utils_hexstr2bin (conn_name + 2, name_len - 2);
|
||||
if ((name_len > 2) && (g_str_has_prefix (conn_name, "0x"))) {
|
||||
GBytes *bytes = nm_utils_hexstr2bin (conn_name);
|
||||
char *buf;
|
||||
|
||||
if (bytes) {
|
||||
buf = g_strndup (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
|
||||
g_bytes_unref (bytes);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
return g_strdup (conn_name);
|
||||
}
|
||||
|
|
@ -882,7 +890,6 @@ make_wireless_connection_setting (const char *conn_name,
|
|||
NMSetting8021x **s_8021x,
|
||||
GError **error)
|
||||
{
|
||||
GBytes *bytes;
|
||||
const char *mac = NULL;
|
||||
NMSettingWireless *wireless_setting = NULL;
|
||||
gboolean adhoc = FALSE;
|
||||
|
|
@ -913,9 +920,8 @@ make_wireless_connection_setting (const char *conn_name,
|
|||
|
||||
/* handle ssid (hex and ascii) */
|
||||
if (conn_name) {
|
||||
GBytes *bytes;
|
||||
gsize ssid_len = 0, value_len = strlen (conn_name);
|
||||
const char *p;
|
||||
char *tmp, *converted = NULL;
|
||||
|
||||
ssid_len = value_len;
|
||||
if ((value_len > 2) && (g_str_has_prefix (conn_name, "0x"))) {
|
||||
|
|
@ -926,32 +932,27 @@ make_wireless_connection_setting (const char *conn_name,
|
|||
conn_name);
|
||||
goto error;
|
||||
}
|
||||
// ignore "0x"
|
||||
p = conn_name + 2;
|
||||
if (!is_hex (p)) {
|
||||
|
||||
bytes = nm_utils_hexstr2bin (conn_name);
|
||||
if (!bytes) {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Invalid SSID '%s' character (looks like hex SSID but '%c' isn't a hex digit)",
|
||||
conn_name, *p);
|
||||
"Invalid SSID '%s' (looks like hex SSID but isn't)",
|
||||
conn_name);
|
||||
goto error;
|
||||
|
||||
}
|
||||
tmp = nm_utils_hexstr2bin (p, value_len - 2);
|
||||
ssid_len = (value_len - 2) / 2;
|
||||
converted = g_malloc0 (ssid_len + 1);
|
||||
memcpy (converted, tmp, ssid_len);
|
||||
g_free (tmp);
|
||||
}
|
||||
} else
|
||||
bytes = g_bytes_new (conn_name, value_len);
|
||||
|
||||
ssid_len = g_bytes_get_size (bytes);
|
||||
if (ssid_len > 32 || ssid_len == 0) {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
|
||||
conn_name, ssid_len);
|
||||
goto error;
|
||||
}
|
||||
bytes = g_bytes_new (converted ? converted : conn_name, ssid_len);
|
||||
|
||||
g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, bytes, NULL);
|
||||
g_bytes_unref (bytes);
|
||||
g_free (converted);
|
||||
} else {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Missing SSID");
|
||||
|
|
@ -1095,7 +1096,7 @@ add_one_wep_key (const char *ssid,
|
|||
|
||||
}
|
||||
|
||||
converted = nm_utils_bin2hexstr (tmp, strlen (tmp), strlen (tmp) * 2);
|
||||
converted = nm_utils_bin2hexstr (tmp, strlen (tmp), -1);
|
||||
g_free (tmp);
|
||||
} else {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
|
|
|
|||
|
|
@ -542,8 +542,8 @@ add_wep_key (NMSupplicantConfig *self,
|
|||
const char *name,
|
||||
NMWepKeyType wep_type)
|
||||
{
|
||||
char *value;
|
||||
gboolean success;
|
||||
GBytes *bytes;
|
||||
gboolean success = FALSE;
|
||||
size_t key_len = key ? strlen (key) : 0;
|
||||
|
||||
if (!key || !key_len)
|
||||
|
|
@ -552,9 +552,15 @@ add_wep_key (NMSupplicantConfig *self,
|
|||
if ( (wep_type == NM_WEP_KEY_TYPE_UNKNOWN)
|
||||
|| (wep_type == NM_WEP_KEY_TYPE_KEY)) {
|
||||
if ((key_len == 10) || (key_len == 26)) {
|
||||
value = nm_utils_hexstr2bin (key, strlen (key));
|
||||
success = nm_supplicant_config_add_option (self, name, value, key_len / 2, TRUE);
|
||||
g_free (value);
|
||||
bytes = nm_utils_hexstr2bin (key);
|
||||
if (bytes) {
|
||||
success = nm_supplicant_config_add_option (self,
|
||||
name,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes),
|
||||
TRUE);
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
if (!success) {
|
||||
nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name);
|
||||
return FALSE;
|
||||
|
|
@ -590,8 +596,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
|
|||
NMSetting8021x *setting_8021x,
|
||||
const char *con_uuid)
|
||||
{
|
||||
char *value;
|
||||
gboolean success;
|
||||
gboolean success = FALSE;
|
||||
const char *key_mgmt, *auth_alg;
|
||||
const char *psk;
|
||||
|
||||
|
|
@ -612,10 +617,18 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
|
|||
size_t psk_len = strlen (psk);
|
||||
|
||||
if (psk_len == 64) {
|
||||
GBytes *bytes;
|
||||
|
||||
/* Hex PSK */
|
||||
value = nm_utils_hexstr2bin (psk, psk_len);
|
||||
success = nm_supplicant_config_add_option (self, "psk", value, psk_len / 2, TRUE);
|
||||
g_free (value);
|
||||
bytes = nm_utils_hexstr2bin (psk);
|
||||
if (bytes) {
|
||||
success = nm_supplicant_config_add_option (self,
|
||||
"psk",
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes),
|
||||
TRUE);
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
if (!success) {
|
||||
nm_log_warn (LOGD_SUPPLICANT, "Error adding 'psk' to supplicant config.");
|
||||
return FALSE;
|
||||
|
|
@ -653,6 +666,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
|
|||
const char *wep1 = nm_setting_wireless_security_get_wep_key (setting, 1);
|
||||
const char *wep2 = nm_setting_wireless_security_get_wep_key (setting, 2);
|
||||
const char *wep3 = nm_setting_wireless_security_get_wep_key (setting, 3);
|
||||
char *value;
|
||||
|
||||
if (!add_wep_key (self, wep0, "wep_key0", wep_type))
|
||||
return FALSE;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue