Hey!

We noticed that the DHCPv6 client included with busybox does not set the IPv6 
link-local address of the interface as the source IP in 
d6_mcast_from_client_config_ifindex().
RFC3315 mentions that:

a) In "4.1. IPv6 Terminology":
"Every interface has a link-local address."

and

b) In "16. Client Source Address and Interface Selection":
"The client MUST use a link-local address assigned to the interface for which 
it is requesting configuration information as the source address in the header 
of the IP datagram.

In the current codebase, udhcp sets the source address to NULL when it's 
calling d6_send_raw_packet (--> 
https://git.busybox.net/busybox/tree/networking/udhcp/d6_dhcpc.c#n314).
While this isn't quite RFC conform as far as I can tell, it seems to work fine 
with most switches. We did however see some cases where the switch doesn't 
correctly forward DHCP responses back to the client if the link local address 
is missing.

I created a patch that parses the address from /proc/net/if_inet6 and we've 
been running it in production successfully for a few weeks.
A lot of the code is taken from ife_print6() in interface.c and could probably 
be abstracted and reused.

I don't think it's quite ready to be merged yet, but I just wanted to gather 
some initial feedback/concerns.
Things like: Do we want to fall back to the old "just use NULL" approach if we 
fail to discover a link local address for whatever reason?

Cheers,
Marc



diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 345ca5e..eda474a 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -434,9 +434,65 @@ static int d6_mcast_from_client_config_ifindex(struct 
d6_packet *packet, uint8_t
                0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
        };
 
+       #define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
+       #define IPV6_ADDR_LINKLOCAL             0x0020U
+       #define IPV6_ADDR_SCOPE_MASK            0x00f0U
+
+       FILE *f;
+       char addr6[40], devname[21];
+       struct sockaddr_in6 sap;
+       int plen, scope, dad_status, if_idx;
+       char addr6p[8][5];
+       int link_local_parsing_success = 0;
+
+       f = fopen_for_read(_PATH_PROCNET_IFINET6);
+       if (f == NULL){
+               log1("Could not find /proc/net/if_inet6, can't set link local 
addr, not sending package.");
+               return;
+       }
+       // cat /proc/net/if_inet6
+       // 00000000000000000000000000000001 01 80 10 80       lo
+       // 2401db000020a01eface000000230000 02 40 00 80     eth0
+       // fe8000000000000062eb69fffe9bb5c2 02 40 20 80     eth0
+       // Iterate over every one of those lines and extract the parts into 
variables
+       while (fscanf
+                          (f,"%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x 
%20s\n",
+                       addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
+                       addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
+                       &dad_status, devname) != EOF
+       ) {
+               // check that it's the interface we're currently listening on
+               if (!strcmp(devname, client_config.interface)) {
+                       // See if it's link-local. if not we don't care
+                       // about it at this point
+                       if ((scope & IPV6_ADDR_SCOPE_MASK) == 
IPV6_ADDR_LINKLOCAL) {
+                               // Re-assemble the readable v6 address into 
addr6
+                               sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
+                                               addr6p[0], addr6p[1], 
addr6p[2], addr6p[3],
+                                               addr6p[4], addr6p[5], 
addr6p[6], addr6p[7]);
+                               log1("Found Link Local address for %s: %s", 
devname, addr6);
+                               // Set the socket address to all zeros
+                               memset(&sap, 0, sizeof(sap));
+                               // Convert the printable v6 address to the 
binary equivalent
+                               // and write it to the sockaddr_in6 struct into 
&sap.sin6_addr
+                               inet_pton(AF_INET6, addr6, (struct sockaddr *) 
&sap.sin6_addr);
+                               // Set the family to v6 just to have a proper 
data structure
+                               sap.sin6_family = AF_INET6;
+                               // Cool, we found what we're looking for. Our 
work here is done!
+                               link_local_parsing_success = 1;
+                               break;
+                       }
+               }
+       }
+       fclose(f);
+
+       if (link_local_parsing_success == 0) {
+               log1("Could not find link local addr among interfaces, not 
sending package.");
+               return;
+       }
        return d6_send_raw_packet(
                packet, (end - (uint8_t*) packet),
-               /*src*/ NULL, CLIENT_PORT6,
+               /*src*/ (struct in6_addr*)&sap.sin6_addr, CLIENT_PORT6,
                /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, 
MAC_BCAST_ADDR,
                client_config.ifindex
        );
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to