[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1071574: bookworm-pu: package netcfg/1.187+deb12u1



Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: debian-boot@lists.debian.org
Control: affects -1 + src:netcfg

[ Reason ]
Certain kinds of network architectures in Debian deployments (e.g.
https://phabricator.wikimedia.org/phame/post/view/312/ganeti_on_modern_network_design/,
https://blog.fhrnet.eu/2020/03/07/dhcp-server-on-a-32-subnet/) are
difficult because the installer doesn't support single-address netmasks
out of the box (https://bugs.debian.org/1064005).  You can sort of
handle this with point-to-point preseeding, but that isn't quite
identical and it doesn't work for IPv6.

I've just fixed this in unstable, but it would be helpful to have it in
place for installs of bookworm too.

[ Impact ]
It's possible to work around this without changing netcfg, but it
requires messy and fragile early_command preseeding to defeat netcfg's
behaviour (see #1064005).

[ Tests ]
The change includes automated tests for the changes to the gateway
reachability test.  For the changes to the routing table setup and to
confirm that no changes were needed to network configuration in the
installed system, I used libvirt machines with a DHCP server along the
lines of https://blog.fhrnet.eu/2020/03/07/dhcp-server-on-a-32-subnet/;
Wikimedia has also tested this using their own setup and confirmed that
it now works out of the box.

[ Risks ]
I've taken care that all the new code is guarded by interface->masklen
checks, so it should be obvious that it's a no-op on any system that
isn't using this unusual single-address netmask setup.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
It turns out that fixing this is very straightforward: it's just a
matter of special-casing the gateway reachability test and then telling
the routing table to pretend that the gateway is directly attached to
the relevant link.  The installed system (ifupdown, NetworkManager)
already gets this right; it's just the installer that had trouble with
it.

[ Other info ]
This work was requested and sponsored by the Wikimedia Foundation.

-- 
Colin Watson (he/him)                              [cjwatson@debian.org]
diff -Nru netcfg-1.187/debian/changelog netcfg-1.187+deb12u1/debian/changelog
--- netcfg-1.187/debian/changelog	2023-05-23 19:24:01.000000000 +0100
+++ netcfg-1.187+deb12u1/debian/changelog	2024-05-14 11:27:14.000000000 +0100
@@ -1,3 +1,9 @@
+netcfg (1.187+deb12u1) UNRELEASED; urgency=medium
+
+  * Handle routing for single-address netmasks (closes: #1064005).
+
+ -- Colin Watson <cjwatson@debian.org>  Tue, 14 May 2024 11:27:14 +0100
+
 netcfg (1.187) unstable; urgency=medium
 
   * Team upload
diff -Nru netcfg-1.187/netcfg-common.c netcfg-1.187+deb12u1/netcfg-common.c
--- netcfg-1.187/netcfg-common.c	2022-06-03 19:25:43.000000000 +0100
+++ netcfg-1.187+deb12u1/netcfg-common.c	2024-05-14 11:26:51.000000000 +0100
@@ -1680,8 +1680,22 @@
     inet_pton(interface->address_family, interface->gateway, &gw_addr);
 
     if (interface->address_family == AF_INET) {
+        if (interface->masklen == 32) {
+            /* Special case for single-address networks.  We'll handle
+             * routing manually in this case.
+             */
+            return 1;
+        }
+
         return (gw_addr.in4.s_addr && ((gw_addr.in4.s_addr & mask.in4.s_addr) == net.in4.s_addr));
     } else if (interface->address_family == AF_INET6) {
+        if (interface->masklen == 128) {
+            /* Special case for single-address networks.  We'll handle
+             * routing manually in this case.
+             */
+            return 1;
+        }
+
         if ((ntohs(gw_addr.in6.s6_addr16[0]) & 0xffc0) == (0xfe80 & 0xffc0)) {
             return 1;
         }
diff -Nru netcfg-1.187/static.c netcfg-1.187+deb12u1/static.c
--- netcfg-1.187/static.c	2021-09-22 19:07:01.000000000 +0100
+++ netcfg-1.187+deb12u1/static.c	2024-05-14 11:27:14.000000000 +0100
@@ -338,6 +338,12 @@
         di_snprintfcat(buf, sizeof(buf), "%s", interface->ipaddress);
         rv |= di_exec_shell_log(buf);
     } else if (!empty_str(interface->gateway)) {
+        if (interface->masklen == 32) {
+            snprintf(buf, sizeof(buf), "route add -interface %s %s", interface->gateway, interface->ipaddress);
+            di_info("executing: %s", buf);
+            rv |= di_exec_shell_log(buf);
+        }
+
         snprintf(buf, sizeof(buf), "route add default %s", interface->gateway);
         rv |= di_exec_shell_log(buf);
     }
@@ -373,6 +379,8 @@
     }
     else if (!empty_str(interface->gateway)) {
         snprintf(buf, sizeof(buf), "ip route add default via %s", interface->gateway);
+        if (interface->masklen == 32)
+            di_snprintfcat(buf, sizeof(buf), " dev %s onlink", interface->name);
         rv |= di_exec_shell_log(buf);
     }
 #endif
@@ -442,6 +450,12 @@
     rv |= di_exec_shell_log(buf);
     
     if (!empty_str(interface->gateway)) {
+        if (interface->masklen == 128) {
+            snprintf(buf, sizeof(buf), "/lib/freebsd/route add -inet6 -interface %s %s", interface->gateway, interface->ipaddress);
+            di_info("executing: %s", buf);
+            rv |= di_exec_shell_log(buf);
+        }
+
         snprintf(buf, sizeof(buf), "/lib/freebsd/route add -inet6 default %s", interface->gateway);
         rv |= di_exec_shell_log(buf);
     }
@@ -475,6 +489,8 @@
 
     if (!empty_str(interface->gateway)) {
         snprintf(buf, sizeof(buf), "ip route add default via %s dev %s", interface->gateway, interface->name);
+        if (interface->masklen == 128)
+            di_snprintfcat(buf, sizeof(buf), " onlink");
         di_info("executing: %s", buf);
         rv |= di_exec_shell_log(buf);
     }
diff -Nru netcfg-1.187/test/test_netcfg_gateway_reachable.c netcfg-1.187+deb12u1/test/test_netcfg_gateway_reachable.c
--- netcfg-1.187/test/test_netcfg_gateway_reachable.c	2021-09-22 19:07:01.000000000 +0100
+++ netcfg-1.187+deb12u1/test/test_netcfg_gateway_reachable.c	2024-05-14 11:26:51.000000000 +0100
@@ -41,6 +41,21 @@
 }
 END_TEST
 
+START_TEST(test_netcfg_gateway_reachable_v4_32)
+{
+	struct netcfg_interface iface;
+	netcfg_interface_init(&iface);
+
+	strcpy(iface.ipaddress, "192.168.1.2");
+	strcpy(iface.gateway, "192.168.1.1");
+	iface.masklen = 32;
+	iface.address_family = AF_INET;
+
+	ck_assert_msg (netcfg_gateway_reachable(&iface),
+	             "Gateway erroneously unreachable");
+}
+END_TEST
+
 START_TEST(test_netcfg_gateway_reachable_v6_64)
 {
 	struct netcfg_interface iface;
@@ -81,6 +96,21 @@
 }
 END_TEST
 
+START_TEST(test_netcfg_gateway_reachable_v6_128)
+{
+	struct netcfg_interface iface;
+	netcfg_interface_init(&iface);
+	
+	strcpy(iface.ipaddress, "2001:3:5:7::71");
+	strcpy(iface.gateway, "2001:3:5::1");
+	iface.masklen = 128;
+	iface.address_family = AF_INET6;
+	
+	ck_assert_msg (netcfg_gateway_reachable(&iface),
+	             "Gateway erroneously unreachable");
+}
+END_TEST
+
 START_TEST(test_netcfg_gateway_reachable_v6_fe80)
 {
 	struct netcfg_interface iface;
@@ -111,8 +141,10 @@
 	TCase *tc = tcase_create ("netcfg_gateway_reachable");
 	tcase_add_test (tc, test_netcfg_gateway_reachable_v4_24);
 	tcase_add_test (tc, test_netcfg_gateway_reachable_v4_22);
+	tcase_add_test (tc, test_netcfg_gateway_reachable_v4_32);
 	tcase_add_test (tc, test_netcfg_gateway_reachable_v6_64);
 	tcase_add_test (tc, test_netcfg_gateway_reachable_v6_48);
+	tcase_add_test (tc, test_netcfg_gateway_reachable_v6_128);
 	tcase_add_test (tc, test_netcfg_gateway_reachable_v6_fe80);
 	
 	suite_add_tcase (s, tc);

Reply to: