ifcfg-rh: always read (and write) static IP addresses (rh #998135)

Static IP addresses were only read from ifcfg-* file when IP method was
'manual' (BOOTPROTO=none|static). This was to match the legacy initscripts
behaviour. However, NetworkManager supports using additional static IPs in
addition to automatically obtained (DHCP, etc.) addresses. So we now read
static IPs even for automatic methods to be able to use this feature.

https://bugzilla.redhat.com/show_bug.cgi?id=998135
This commit is contained in:
Jiří Klimeš 2013-10-21 13:12:51 +02:00
parent 9ca6fa71f1
commit 1a67f8df03
5 changed files with 251 additions and 93 deletions

View file

@ -1359,26 +1359,8 @@ make_ip4_setting (shvarFile *ifcfg,
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
return NM_SETTING (s_ip4);
/* Handle manual settings */
if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
for (i = -1; i < 256; i++) {
NMIP4Address *addr = NULL;
if (!read_full_ip4_address (ifcfg, network_file, i, &addr, error))
goto done;
if (!addr) {
/* The first mandatory variable is 2-indexed (IPADDR2)
* Variables IPADDR, IPADDR0 and IPADDR1 are optional */
if (i > 1)
break;
continue;
}
if (!nm_setting_ip4_config_add_address (s_ip4, addr))
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP4 address");
nm_ip4_address_unref (addr);
}
} else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
/* Handle DHCP settings */
if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
if (value && strlen (value))
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, value, NULL);
@ -1390,6 +1372,29 @@ make_ip4_setting (shvarFile *ifcfg,
g_free (value);
}
/* Read static IP addresses.
* Read them even for AUTO method - in this case the addresses are
* added to the automatic ones. Note that this is not currently supported by
* the legacy 'network' service (ifup-eth).
*/
for (i = -1; i < 256; i++) {
NMIP4Address *addr = NULL;
if (!read_full_ip4_address (ifcfg, network_file, i, &addr, error))
goto done;
if (!addr) {
/* The first mandatory variable is 2-indexed (IPADDR2)
* Variables IPADDR, IPADDR0 and IPADDR1 are optional */
if (i > 1)
break;
continue;
}
if (!nm_setting_ip4_config_add_address (s_ip4, addr))
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP4 address");
nm_ip4_address_unref (addr);
}
/* DNS servers
* Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
*/
@ -1516,6 +1521,8 @@ make_ip6_setting (shvarFile *ifcfg,
char *route6_path = NULL;
gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE;
char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
char *ipv6addr, *ipv6addr_secondaries;
char **list = NULL, **iter;
guint32 i;
shvarFile *network_ifcfg;
gboolean never_default = FALSE;
@ -1632,38 +1639,8 @@ make_ip6_setting (shvarFile *ifcfg,
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
return NM_SETTING (s_ip6);
if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
char *val;
char *ipv6addr, *ipv6addr_secondaries;
char **list = NULL, **iter;
ipv6addr = svGetValue (ifcfg, "IPV6ADDR", FALSE);
ipv6addr_secondaries = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
val = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
ipv6addr ? ipv6addr : "",
ipv6addr_secondaries ? ipv6addr_secondaries : "",
NULL);
g_free (ipv6addr);
g_free (ipv6addr_secondaries);
list = g_strsplit_set (val, " ", 0);
g_free (val);
for (iter = list, i = 0; iter && *iter; iter++, i++) {
NMIP6Address *addr = NULL;
if (!parse_full_ip6_address (ifcfg, network_file, *iter, i, &addr, error)) {
g_strfreev (list);
goto error;
}
if (!nm_setting_ip6_config_add_address (s_ip6, addr))
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP6 address");
nm_ip6_address_unref (addr);
}
g_strfreev (list);
} else if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
|| !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
|| !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
/* METHOD_AUTO may trigger DHCPv6, so save the hostname to send to DHCP */
value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
if (value && value[0])
@ -1671,6 +1648,37 @@ make_ip6_setting (shvarFile *ifcfg,
g_free (value);
}
/* Read static IP addresses.
* Read them even for AUTO and DHCP methods - in this case the addresses are
* added to the automatic ones. Note that this is not currently supported by
* the legacy 'network' service (ifup-eth).
*/
ipv6addr = svGetValue (ifcfg, "IPV6ADDR", FALSE);
ipv6addr_secondaries = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
ipv6addr ? ipv6addr : "",
ipv6addr_secondaries ? ipv6addr_secondaries : "",
NULL);
g_free (ipv6addr);
g_free (ipv6addr_secondaries);
list = g_strsplit_set (value, " ", 0);
g_free (value);
for (iter = list, i = 0; iter && *iter; iter++, i++) {
NMIP6Address *addr = NULL;
if (!parse_full_ip6_address (ifcfg, network_file, *iter, i, &addr, error)) {
g_strfreev (list);
goto error;
}
if (!nm_setting_ip6_config_add_address (s_ip6, addr))
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP6 address");
nm_ip6_address_unref (addr);
}
g_strfreev (list);
/* DNS servers
* Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
*/

View file

@ -5,6 +5,7 @@ EXTRA_DIST = \
ifcfg-test-wired-static \
ifcfg-test-wired-static-bootproto \
ifcfg-test-wired-dhcp \
ifcfg-test-wired-dhcp-plus-ip \
ifcfg-test-wired-dhcp6-only \
ifcfg-test-wired-global-gateway \
network-test-wired-global-gateway \

View file

@ -0,0 +1,26 @@
# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile)
TYPE=Ethernet
DEVICE=eth0
HWADDR=00:11:22:33:44:ee
BOOTPROTO=dhcp
ONBOOT=yes
IPV6INIT=yes
IPV6_AUTOCONF=yes
USERCTL=yes
NM_CONTROLLED=yes
PEERDNS=no
DNS1=4.2.2.1
DNS2=4.2.2.2
DNS3=1:2:3:4::a
DNS4=1:2:3:4::b
# additional IPs
IPADDR0=1.2.3.4
PREFIX0=24
GATEWAY0=1.1.1.1
IPADDR1=9.8.7.6
PREFIX1=16
IPV6ADDR="1001:abba::1234/56"
IPV6ADDR_SECONDARIES="2001:abba::2234/64 3001:abba::3234/96"

View file

@ -666,6 +666,93 @@ test_read_wired_dhcp (void)
g_object_unref (connection);
}
static void
test_read_wired_dhcp_plus_ip (void)
{
NMConnection *connection;
NMSettingIP4Config *s_ip4;
NMSettingIP6Config *s_ip6;
GError *error = NULL;
guint32 addr4;
struct in6_addr addr6;
NMIP4Address *ip4_addr;
NMIP6Address *ip6_addr;
gboolean success;
connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-plus-ip",
NULL, TYPE_ETHERNET, NULL, NULL,
NULL, NULL, NULL, &error, NULL);
g_assert_no_error (error);
g_assert (connection);
success = nm_connection_verify (connection, &error);
g_assert_no_error (error);
g_assert (success);
/* ===== IPv4 SETTING ===== */
s_ip4 = nm_connection_get_setting_ip4_config (connection);
g_assert (s_ip4);
g_assert_cmpstr (nm_setting_ip4_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
g_assert (nm_setting_ip4_config_get_may_fail (s_ip4));
/* DNS Addresses */
g_assert_cmpint (nm_setting_ip4_config_get_num_dns (s_ip4), ==, 2);
g_assert_cmpint (inet_pton (AF_INET, "4.2.2.1", &addr4), >, 0);
g_assert_cmpint (nm_setting_ip4_config_get_dns (s_ip4, 0), ==, addr4);
g_assert_cmpint (inet_pton (AF_INET, "4.2.2.2", &addr4), >, 0);
g_assert_cmpint (nm_setting_ip4_config_get_dns (s_ip4, 1), ==, addr4);
/* IP addresses */
g_assert_cmpint (nm_setting_ip4_config_get_num_addresses (s_ip4), ==, 2);
ip4_addr = nm_setting_ip4_config_get_address (s_ip4, 0);
g_assert (ip4_addr);
g_assert_cmpint (nm_ip4_address_get_prefix (ip4_addr), ==, 24);
g_assert_cmpint (inet_pton (AF_INET, "1.2.3.4", &addr4), >, 0);
g_assert_cmpint (nm_ip4_address_get_address (ip4_addr), ==, addr4);
g_assert_cmpint (inet_pton (AF_INET, "1.1.1.1", &addr4), >, 0);
g_assert_cmpint (nm_ip4_address_get_gateway (ip4_addr), ==, addr4);
ip4_addr = nm_setting_ip4_config_get_address (s_ip4, 1);
g_assert (ip4_addr);
g_assert_cmpint (nm_ip4_address_get_prefix (ip4_addr), ==, 16);
g_assert_cmpint (inet_pton (AF_INET, "9.8.7.6", &addr4), >, 0);
g_assert_cmpint (nm_ip4_address_get_address (ip4_addr), ==, addr4);
/* ===== IPv6 SETTING ===== */
s_ip6 = nm_connection_get_setting_ip6_config (connection);
g_assert (s_ip6);
g_assert_cmpstr (nm_setting_ip6_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
g_assert (nm_setting_ip6_config_get_may_fail (s_ip6));
/* DNS Addresses */
g_assert_cmpint (nm_setting_ip6_config_get_num_dns (s_ip6), ==, 2);
g_assert_cmpint (inet_pton (AF_INET6, "1:2:3:4::a", &addr6), >, 0);
g_assert (IN6_ARE_ADDR_EQUAL (nm_setting_ip6_config_get_dns (s_ip6, 0), &addr6));
g_assert_cmpint (inet_pton (AF_INET6, "1:2:3:4::b", &addr6), >, 0);
g_assert (IN6_ARE_ADDR_EQUAL (nm_setting_ip6_config_get_dns (s_ip6, 1), &addr6));
/* IP addresses */
g_assert_cmpint (nm_setting_ip6_config_get_num_addresses (s_ip6), ==, 3);
ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 0);
g_assert (ip6_addr);
g_assert_cmpint (nm_ip6_address_get_prefix (ip6_addr), ==, 56);
g_assert_cmpint (inet_pton (AF_INET6, "1001:abba::1234", &addr6), >, 0);
g_assert (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6));
ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 1);
g_assert (ip6_addr);
g_assert_cmpint (nm_ip6_address_get_prefix (ip6_addr), ==, 64);
g_assert_cmpint (inet_pton (AF_INET6, "2001:abba::2234", &addr6), >, 0);
g_assert (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6));
ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 2);
g_assert (ip6_addr);
g_assert_cmpint (nm_ip6_address_get_prefix (ip6_addr), ==, 96);
g_assert_cmpint (inet_pton (AF_INET6, "3001:abba::3234", &addr6), >, 0);
g_assert (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6));
g_object_unref (connection);
}
#define TEST_IFCFG_WIRED_GLOBAL_GATEWAY TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-global-gateway"
#define TEST_NETWORK_WIRED_GLOBAL_GATEWAY TEST_IFCFG_DIR"/network-scripts/network-test-wired-global-gateway"
@ -6386,6 +6473,49 @@ test_write_wired_dhcp (void)
g_object_unref (reread);
}
static void
test_write_wired_dhcp_plus_ip (void)
{
NMConnection *connection, *reread;
char *written = NULL;
GError *error = NULL;
gboolean success = FALSE;
connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp-plus-ip",
NULL, TYPE_ETHERNET, NULL, NULL,
NULL, NULL, NULL, &error, NULL);
g_assert_no_error (error);
g_assert (connection != NULL);
success = writer_new_connection (connection,
TEST_SCRATCH_DIR "/network-scripts/",
&written,
&error);
g_assert (success);
/* reread will be normalized, so we must normalize connection too. */
nm_utils_normalize_connection (connection, TRUE);
/* re-read the connection for comparison */
reread = connection_from_file (written, NULL, TYPE_ETHERNET, NULL, NULL,
NULL, NULL, NULL, &error, NULL);
unlink (written);
g_free (written);
g_assert_no_error (error);
g_assert (reread != NULL);
success = nm_connection_verify (reread, &error);
g_assert_no_error (error);
g_assert (success);
success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (success);
g_object_unref (connection);
g_object_unref (reread);
}
static void
test_write_wired_static_ip6_only (void)
{
@ -12627,6 +12757,7 @@ int main (int argc, char **argv)
test_read_wired_static (TEST_IFCFG_WIRED_STATIC, "System test-wired-static", TRUE);
test_read_wired_static (TEST_IFCFG_WIRED_STATIC_BOOTPROTO, "System test-wired-static-bootproto", FALSE);
test_read_wired_dhcp ();
g_test_add_func (TPATH "dhcp-plus-ip", test_read_wired_dhcp_plus_ip);
test_read_wired_global_gateway ();
test_read_wired_never_default ();
test_read_wired_defroute_no ();
@ -12688,6 +12819,7 @@ int main (int argc, char **argv)
test_write_wired_static_routes ();
test_read_write_static_routes_legacy ();
test_write_wired_dhcp ();
g_test_add_func (TPATH "dhcp-plus-ip", test_write_wired_dhcp_plus_ip);
test_write_wired_dhcp_8021x_peap_mschapv2 ();
test_write_wired_8021x_tls (NM_SETTING_802_1X_CK_SCHEME_PATH, NM_SETTING_SECRET_FLAG_AGENT_OWNED);
test_write_wired_8021x_tls (NM_SETTING_802_1X_CK_SCHEME_PATH, NM_SETTING_SECRET_FLAG_NOT_SAVED);

View file

@ -1955,6 +1955,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
guint32 i, num, num4;
GString *searches;
char buf[INET6_ADDRSTRLEN];
char ipv6_defaultgw[INET6_ADDRSTRLEN];
NMIP6Address *addr;
const struct in6_addr *ip;
GString *ip_str1, *ip_str2, *ip_ptr;
@ -2005,51 +2006,41 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
/* TODO */
}
if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
char ipv6_defaultgw[INET6_ADDRSTRLEN];
/* Write out IP addresses */
num = nm_setting_ip6_config_get_num_addresses (s_ip6);
ip_str1 = g_string_new (NULL);
ip_str2 = g_string_new (NULL);
ipv6_defaultgw[0] = 0;
for (i = 0; i < num; i++) {
if (i == 0)
ip_ptr = ip_str1;
else
ip_ptr = ip_str2;
/* Write out IP addresses */
num = nm_setting_ip6_config_get_num_addresses (s_ip6);
addr = nm_setting_ip6_config_get_address (s_ip6, i);
ip = nm_ip6_address_get_address (addr);
prefix = g_strdup_printf ("%u", nm_ip6_address_get_prefix (addr));
memset (buf, 0, sizeof (buf));
inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
if (i > 1)
g_string_append_c (ip_ptr, ' '); /* separate addresses in IPV6ADDR_SECONDARIES */
g_string_append (ip_ptr, buf);
g_string_append_c (ip_ptr, '/');
g_string_append (ip_ptr, prefix);
g_free (prefix);
ip_str1 = g_string_new (NULL);
ip_str2 = g_string_new (NULL);
ipv6_defaultgw[0] = 0;
for (i = 0; i < num; i++) {
if (i == 0)
ip_ptr = ip_str1;
else
ip_ptr = ip_str2;
addr = nm_setting_ip6_config_get_address (s_ip6, i);
ip = nm_ip6_address_get_address (addr);
prefix = g_strdup_printf ("%u", nm_ip6_address_get_prefix (addr));
memset (buf, 0, sizeof (buf));
inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
if (i > 1)
g_string_append_c (ip_ptr, ' '); /* separate addresses in IPV6ADDR_SECONDARIES */
g_string_append (ip_ptr, buf);
g_string_append_c (ip_ptr, '/');
g_string_append (ip_ptr, prefix);
g_free (prefix);
/* We only support gateway for the first IP address for now */
if (i == 0) {
ip = nm_ip6_address_get_gateway (addr);
if (!IN6_IS_ADDR_UNSPECIFIED (ip))
inet_ntop (AF_INET6, ip, ipv6_defaultgw, sizeof (ipv6_defaultgw));
}
/* We only support gateway for the first IP address for now */
if (i == 0) {
ip = nm_ip6_address_get_gateway (addr);
if (!IN6_IS_ADDR_UNSPECIFIED (ip))
inet_ntop (AF_INET6, ip, ipv6_defaultgw, sizeof (ipv6_defaultgw));
}
svSetValue (ifcfg, "IPV6ADDR", ip_str1->str, FALSE);
svSetValue (ifcfg, "IPV6ADDR_SECONDARIES", ip_str2->str, FALSE);
svSetValue (ifcfg, "IPV6_DEFAULTGW", ipv6_defaultgw, FALSE);
g_string_free (ip_str1, TRUE);
g_string_free (ip_str2, TRUE);
} else {
svSetValue (ifcfg, "IPV6ADDR", NULL, FALSE);
svSetValue (ifcfg, "IPV6ADDR_SECONDARIES", NULL, FALSE);
svSetValue (ifcfg, "IPV6_DEFAULTGW", NULL, FALSE);
}
svSetValue (ifcfg, "IPV6ADDR", ip_str1->str, FALSE);
svSetValue (ifcfg, "IPV6ADDR_SECONDARIES", ip_str2->str, FALSE);
svSetValue (ifcfg, "IPV6_DEFAULTGW", ipv6_defaultgw, FALSE);
g_string_free (ip_str1, TRUE);
g_string_free (ip_str2, TRUE);
/* Write out DNS - 'DNS' key is used both for IPv4 and IPv6 */
s_ip4 = nm_connection_get_setting_ip4_config (connection);