diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2020-11-25 17:39:48 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2020-11-26 17:41:40 +0100 |
commit | b0c018830e7884e7457b8ea44553946ff680eb89 (patch) | |
tree | fad4689a913e401a94beadf8f6dbf3c0a9f49b8b | |
parent | e7d828f6a0b63f83e8888578c393434311240aea (diff) | |
download | NetworkManager-b0c018830e7884e7457b8ea44553946ff680eb89.tar.gz |
initrd: fix parsing of ip= arguments with empty first tokenbg/initrd-ip-empty-rh1900260
The parser checks if the first token of an ip= argument is an IP
address to determine which of the two possible syntaxes is used:
ip=<interface>:{dhcp|on|any|dhcp6|auto6}[:[<mtu>][:<macaddr>]]
ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<mtu>][:<macaddr>]]
This works as long as the first token is not empty, which - according
to the dracut.cmdline man page - seems to be guaranteed.
However, the network-legacy dracut plugin accepts an empty interface
or client IP. Also, if a user needs DHCP and wants to specify a
hostname, the only possible syntax is:
ip=::::<hostname>::dhcp
Change the parser to check the second token instead, similarly to what
the network-legacy module does [1].
[1] https://github.com/dracutdevs/dracut/blob/050/modules.d/40network/net-lib.sh#L490
https://bugzilla.redhat.com/show_bug.cgi?id=1900260
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/693
-rw-r--r-- | src/initrd/nmi-cmdline-reader.c | 39 | ||||
-rw-r--r-- | src/initrd/tests/test-cmdline-reader.c | 112 |
2 files changed, 140 insertions, 11 deletions
diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index 5d6afa74e4..eedcf17878 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -390,6 +390,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) NMSettingIPConfig *s_ip4 = NULL, *s_ip6 = NULL; gs_unref_hashtable GHashTable *ibft = NULL; const char * tmp; + const char * tmp2; const char * kind = NULL; const char * client_ip = NULL; const char * peer = NULL; @@ -418,17 +419,37 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) /* ip={dhcp|on|any|dhcp6|auto6|ibft} */ kind = tmp; } else { - client_ip_family = get_ip_address_family(tmp, TRUE); - if (client_ip_family != AF_UNSPEC) { - /* <client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>: */ - client_ip = tmp; - peer = get_word(&argument, ':'); + tmp2 = get_word(&argument, ':'); + if (NM_IN_STRSET(tmp2, + "none", + "off", + "dhcp", + "on" + "any", + "dhcp6", + "auto", + "auto6", + "ibft")) { + /* <ifname>:{none|off|dhcp|on|any|dhcp6|auto|auto6|ibft} */ + iface_spec = tmp; + kind = tmp2; + } else { + /* <client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<kind> */ + client_ip = tmp; + if (client_ip) { + client_ip_family = get_ip_address_family(client_ip, TRUE); + if (client_ip_family == AF_UNSPEC) { + _LOGW(LOGD_CORE, "Invalid IP address '%s'.", client_ip); + return; + } + } + + peer = tmp2; gateway_ip = get_word(&argument, ':'); netmask = get_word(&argument, ':'); client_hostname = get_word(&argument, ':'); iface_spec = get_word(&argument, ':'); - } else { - iface_spec = tmp; + kind = get_word(&argument, ':'); } if (client_hostname && !nm_sd_hostname_is_valid(client_hostname, FALSE)) @@ -439,10 +460,6 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) reader->hostname = g_strdup(client_hostname); } - /* <ifname>:{none|off|dhcp|on|any|dhcp6|auto6|ibft} */ - - kind = get_word(&argument, ':'); - tmp = get_word(&argument, ':'); dns_addr_family[0] = get_ip_address_family(tmp, FALSE); if (dns_addr_family[0] != AF_UNSPEC) { diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index ef664b7035..14a83c084a 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -80,6 +80,116 @@ test_auto(void) } static void +test_dhcp_with_hostname(void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + const char *const * ARGV = NM_MAKE_STRV("ip=::::host1::dhcp"); + NMConnection * connection; + NMSettingConnection * s_con; + NMSettingWired * s_wired; + NMSettingIPConfig * s_ip4; + NMSettingIPConfig * s_ip6; + gs_free char * hostname = NULL; + + connections = nmi_cmdline_reader_parse(TEST_INITRD_DIR "/sysfs", ARGV, &hostname); + g_assert(connections); + g_assert_cmpint(g_hash_table_size(connections), ==, 1); + g_assert_cmpstr(hostname, ==, "host1"); + + connection = g_hash_table_lookup(connections, "default_connection"); + g_assert(connection); + nmtst_assert_connection_verifies_without_normalization(connection); + + g_assert(!nm_connection_get_setting_vlan(connection)); + + s_con = nm_connection_get_setting_connection(connection); + g_assert(s_con); + g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), + ==, + NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection"); + g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); + g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), + ==, + NM_CONNECTION_MULTI_CONNECT_MULTIPLE); + g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); + + g_assert(nm_setting_connection_get_autoconnect(s_con)); + + s_wired = nm_connection_get_setting_wired(connection); + g_assert(s_wired); + g_assert(!nm_setting_wired_get_mac_address(s_wired)); + g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); +} + +static void +test_dhcp_with_mtu(void) +{ + const char *const *ARGV0 = NM_MAKE_STRV("ip=:dhcp:1499"); + const char *const *ARGV1 = NM_MAKE_STRV("ip=::::::dhcp:1499"); + const char *const *ARGV[] = {ARGV0, ARGV1}; + guint i; + + for (i = 0; i < G_N_ELEMENTS(ARGV); i++) { + gs_unref_hashtable GHashTable *connections = NULL; + NMConnection * connection; + NMSettingConnection * s_con; + NMSettingWired * s_wired; + NMSettingIPConfig * s_ip4; + NMSettingIPConfig * s_ip6; + gs_free char * hostname = NULL; + + connections = nmi_cmdline_reader_parse(TEST_INITRD_DIR "/sysfs", ARGV[i], &hostname); + g_assert(connections); + g_assert_cmpint(g_hash_table_size(connections), ==, 1); + g_assert_cmpstr(hostname, ==, NULL); + + connection = g_hash_table_lookup(connections, "default_connection"); + g_assert(connection); + nmtst_assert_connection_verifies_without_normalization(connection); + + s_con = nm_connection_get_setting_connection(connection); + g_assert(s_con); + g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), + ==, + NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection"); + g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); + g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), + ==, + NM_CONNECTION_MULTI_CONNECT_MULTIPLE); + g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); + + g_assert(nm_setting_connection_get_autoconnect(s_con)); + + s_wired = nm_connection_get_setting_wired(connection); + g_assert(s_wired); + g_assert(!nm_setting_wired_get_mac_address(s_wired)); + g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1499); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_AUTO); + } +} + +static void test_if_auto_with_mtu(void) { gs_unref_hashtable GHashTable *connections = NULL; @@ -2071,6 +2181,8 @@ main(int argc, char **argv) nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); g_test_add_func("/initrd/cmdline/auto", test_auto); + g_test_add_func("/initrd/cmdline/dhcp_with_hostname", test_dhcp_with_hostname); + g_test_add_func("/initrd/cmdline/dhcp_with_mtu", test_dhcp_with_mtu); g_test_add_func("/initrd/cmdline/if_auto_with_mtu", test_if_auto_with_mtu); g_test_add_func("/initrd/cmdline/if_dhcp6", test_if_dhcp6); g_test_add_func("/initrd/cmdline/if_auto_with_mtu_and_mac", test_if_auto_with_mtu_and_mac); |