From b98780139c5f39dbd25e0118de165d90ddd1f13a Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Thu, 14 Dec 2017 16:21:28 +0300 Subject: [PATCH] dhcp.c: Remove temporary default route properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DHCP is implemented in propagator in a rather lazy way: to dynamically configure a network interface, say `eno1', instead of slinging raw Ethernet frames around like everyone else, it sets up a (temporary) default null route through that interface and throws UDP messages with actual bootp payload. `ip' utility describes such a route as `default dev eno1 scope link' The idea behind this presumably was to avoid generating IP and UDP headers manually while the null route is sufficient to send a couple of link-wide (maybe broadcast) messages and generic enough to work anywhere. To this date propagator didn't bother to remove that route, so *in some networks* it had persisted even after the initramfs (and propagator itself) was long gone, and in other networks did not, having been luckily replaced by the default route to DHCP gateway. In the cases where it did the real problem showed itself after the real userspace (for example, in a live distro) eventually tried to reconfigure the network (because why not?). The pesky null route was most often left untouched by the DHCP client (ALT live distros mostly use dhcpcd), managing to squeeze its way up the routing table and effectively preventing the host from network access beyond a router. If the NFS root is behind a couple routers, any attempt to access the file system gets stuck — the system keeps tirelessly looking for the NFS host via ARP. --- dhcp.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dhcp.c b/dhcp.c index 86e3a74..bb4a2d6 100644 --- a/dhcp.c +++ b/dhcp.c @@ -228,6 +228,37 @@ static int initial_setup_interface(char * device, int s) { return 0; } +static int interface_cleanup(char * device, int s) { + /* + * Removing the auxiliary route + * made by initial_setup_interface() + */ + struct rtentry route; + struct sockaddr_in* address; + + memset(&route, 0, sizeof(route)); + + route.rt_dev = device; + route.rt_flags = RTF_UP | RTF_GATEWAY; + route.rt_metric = 0; + + address = &route.rt_dst; + address->sin_family = AF_INET; + + address = &route.rt_gateway; + address->sin_family = AF_INET; + + address = &route.rt_genmask; + address->sin_family = AF_INET; + + if (ioctl(s, SIOCDELRT, &route)) { + close(s); + log_perror("SIOCDELRT"); + return -1; + } + + return 0; +} void set_missing_ip_info(struct interface_info * intf) { @@ -669,6 +700,7 @@ enum return_type perform_dhcp(struct interface_info * intf) } lease = ntohl(lease); + interface_cleanup(intf->device, s); close(s); free(vendorClass); -- 2.10.4