Hi,

as part of a project at Axis I've modified the busybox udhcp client to make it perform a final check of
the offered IP.

The final check is mentioned in the DHCP rfc as:

 The client SHOULD perform a check on the suggested address to
 ensure that the address is not already in use.  For example, if the
 client is on a network that supports ARP, the client may issue an
 ARP request for the suggested request.  When broadcasting an ARP
 request for the suggested address, the client must fill in its own
 hardware address as the sender's hardware address, and 0 as the
 sender's IP address, to avoid confusing ARP caches in other hosts
 on the same subnet.  If the network address appears to be in use,
 the client MUST send a DHCPDECLINE message to the server. The
 client SHOULD broadcast an ARP reply to announce the client's new
 IP address and clear any outdated ARP cache entries in hosts on the
 client's subnet.

I've added a CONFIGURE_FEATURE_UDHCPC_ARPING to enable this functionality and command-line-options -a, --arping to use it. I've also added a -W, --wait to set how long to wait after sending the DHCPDECLINE before restarting the discovery process (minimum 10 seconds).

The client uses the arpping function from arpping.c. And I've modified the arpping function. Why? The arpping-function performed validation on the arp reply by checking the target hardware address field in the arp reply against the client mac address. This will not work when working with Linux machines.

When the Linux kernel receives an arp probe (arp request with sender ip 0) it will return an arp reply with the target ip field and target hardware field set to the same as the source fields. I've sent a patch to the Linux kernel to fix this, the discussion about it can be seen here: http://thread.gmane.org/gmane.linux.kernel/603586. The patch has been applied to David Millers tree.

In the discussion I mention the check performed in udhcp arping (and also dhcpcd from Debian) and got the following response from Alexey Kuznetov:
"Do not do this. Mainly, because you already know that this does not work
with linux. :-) Logically, target hw address in arp reply is just
a nonsensial redundancy, it should not be checked and even looked at."

So the check of target hardware address in arpping has been removed in my patch.

Revision used: The patch is from the daily snapshot from 071120.

Is this something you would consider to apply?

- Jonas
diff -u -r ./include/usage.h ../busybox-20071120-jd/include/usage.h
--- ./include/usage.h	2007-11-20 09:20:21.000000000 +0100
+++ ../busybox-20071120-jd/include/usage.h	2007-11-20 14:42:27.000000000 +0100
@@ -3838,6 +3838,12 @@
 #define tune2fs_full_usage \
        "Adjust filesystem options on ext[23] filesystems"
 
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+#  define USAGE_UDHCPC_ARPING(a) a
+#else
+#  define USAGE_UDHCPC_ARPING(a)
+#endif
+
 #define udhcpc_trivial_usage \
        "[-Cfbnqtv] [-c CID] [-V VCLS] [-H HOSTNAME] [-i INTERFACE]\n" \
        "	[-p pidfile] [-r IP] [-s script]"
@@ -3861,6 +3867,8 @@
        "\n	-q,--quit	Quit after obtaining lease" \
        "\n	-R,--release	Release IP on quit" \
        "\n	-v,--version	Display version" \
+	USAGE_UDHCPC_ARPING("\n	-a,--arping	Use arping to validate offered address") \
+	USAGE_UDHCPC_ARPING("\n	-W,--wait=TIME	Set time to wait in seconds after declining (default: 10)") \
 	) \
 	SKIP_GETOPT_LONG( \
        "	-V CLASSID	Set vendor class identifier" \
@@ -3881,6 +3889,8 @@
        "\n	-q		Quit after obtaining lease" \
        "\n	-R		Release IP on quit" \
        "\n	-v		Display version" \
+	USAGE_UDHCPC_ARPING("\n	-a	Use arping to validate offered address") \
+	USAGE_UDHCPC_ARPING("\n	-W time	Set time to wait in seconds adter declining (default 10)") \
 	)
 
 #define udhcpd_trivial_usage \
diff -u -r ./networking/udhcp/arpping.c ../busybox-20071120-jd/networking/udhcp/arpping.c
--- ./networking/udhcp/arpping.c	2007-11-20 09:20:04.000000000 +0100
+++ ../busybox-20071120-jd/networking/udhcp/arpping.c	2007-11-20 14:24:42.000000000 +0100
@@ -88,7 +88,6 @@
 			if (read(s, &arp, sizeof(arp)) < 0)
 				break;
 			if (arp.operation == htons(ARPOP_REPLY)
-			 && memcmp(arp.tHaddr, from_mac, 6) == 0
 			 && *((uint32_t *) arp.sInaddr) == test_ip
 			) {
 				rv = 0;
diff -u -r ./networking/udhcp/clientpacket.c ../busybox-20071120-jd/networking/udhcp/clientpacket.c
--- ./networking/udhcp/clientpacket.c	2007-11-20 09:20:04.000000000 +0100
+++ ../busybox-20071120-jd/networking/udhcp/clientpacket.c	2007-11-20 14:49:54.000000000 +0100
@@ -18,6 +18,7 @@
 #include <linux/if_ether.h>
 #endif
 
+#include "busybox.h"
 #include "common.h"
 #include "dhcpd.h"
 #include "dhcpc.h"
@@ -69,6 +70,21 @@
 
 }
 
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+/* Unicast a DHCP decline message */
+int send_decline(unsigned long xid, unsigned long server) {
+  struct dhcpMessage packet;
+
+  init_packet(&packet, DHCPDECLINE);
+  packet.xid = xid;
+  add_requests(&packet);
+
+  bb_info_msg("Sending decline...");
+
+  return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
+		    SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
+}
+#endif
 
 /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
 int send_discover(uint32_t xid, uint32_t requested)
diff -u -r ./networking/udhcp/Config.in ../busybox-20071120-jd/networking/udhcp/Config.in
--- ./networking/udhcp/Config.in	2007-11-20 09:20:04.000000000 +0100
+++ ../busybox-20071120-jd/networking/udhcp/Config.in	2007-11-20 14:00:02.000000000 +0100
@@ -54,6 +54,16 @@
 
 	  See http://udhcp.busybox.net for further details.
 
+config FEATURE_UDHCPC_ARPING
+	bool "Ask udhcpc to verify that the offered address is free, using arpping"
+	default y
+	depends on APP_UDHCPC
+	help
+	  If selected, udhcpc will use arpping to make sure the offered address
+	  is really available. The client will DHCPDECLINE the offer if the
+	  address is in use, and restart the discover process.
+
+
 config FEATURE_UDHCP_DEBUG
 	bool "Compile udhcp with noisy debugging messages"
 	default n
diff -u -r ./networking/udhcp/dhcpc.c ../busybox-20071120-jd/networking/udhcp/dhcpc.c
--- ./networking/udhcp/dhcpc.c	2007-11-20 09:20:04.000000000 +0100
+++ ../busybox-20071120-jd/networking/udhcp/dhcpc.c	2007-11-21 09:59:12.000000000 +0100
@@ -17,7 +17,12 @@
 #include "dhcpd.h"
 #include "dhcpc.h"
 #include "options.h"
+#include "busybox.h"
 
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+static int arpcheck = 0;
+static int decline_wait = 10;
+#endif
 
 /* Something is definitely wrong here. IPv4 addresses
  * in variables of type long?? BTW, we use inet_ntoa()
@@ -145,6 +150,9 @@
 {
 	uint8_t *temp, *message;
 	char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_A, *str_t;
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+	char *str_W;
+#endif
 	uint32_t xid = 0;
 	uint32_t lease = 0; /* can be given as 32-bit quantity */
 	unsigned t1 = 0, t2 = 0; /* what a wonderful names */
@@ -180,6 +188,10 @@
 		OPT_v = 1 << 17,
 		OPT_S = 1 << 18,
 		OPT_A = 1 << 19,
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+		OPT_a = 1 << 20,
+		OPT_W = 1 << 21,
+#endif
 	};
 #if ENABLE_GETOPT_LONG
 	static const char udhcpc_longopts[] ALIGN1 =
@@ -203,6 +215,10 @@
 		"retries\0"       Required_argument "t"
 		"tryagain\0"      Required_argument "A"
 		"syslog\0"        No_argument       "S"
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+		"arping\0"	    No_argument       "a"
+		"wait\0"	    Required_argument "W"
+#endif
 		;
 #endif
 	/* Default options. */
@@ -218,10 +234,16 @@
 #if ENABLE_GETOPT_LONG
 	applet_long_options = udhcpc_longopts;
 #endif
-	opt = getopt32(argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:vSA:",
-		&str_c, &str_V, &str_h, &str_h, &str_F,
+	opt = getopt32(argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:vSA:"
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+				"aW:"
+#endif
+		,&str_c, &str_V, &str_h, &str_h, &str_F,
 		&client_config.interface, &client_config.pidfile, &str_r,
 		&client_config.script, &str_T, &str_t, &str_A
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+		,&str_W
+#endif
 		);
 
 	if (opt & OPT_c)
@@ -274,6 +296,18 @@
 		logmode |= LOGMODE_SYSLOG;
 	}
 
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+	if (opt & OPT_a)
+		arpcheck = 1;
+	if (opt & OPT_W) {
+		decline_wait = xatoi_u(str_W);
+	 	if(decline_wait < 10) {
+		       fprintf(stderr, "Invalid wait time, using default value.\n");
+			decline_wait = 10;
+		}
+	}
+#endif
+
 	if (read_interface(client_config.interface, &client_config.ifindex,
 			   NULL, client_config.arp))
 		return 1;
@@ -491,6 +525,28 @@
 						lease = ntohl(lease);
 					}
 
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+					if(arpcheck) {
+						if(!arpping(packet.yiaddr,
+							    (uint32_t) 0,
+							    client_config.arp,
+							    client_config.interface)) {
+							bb_info_msg("Offered address is taken,"
+								     " declining.");
+							send_decline(xid, server_addr);
+
+							if (state != REQUESTING)
+								udhcp_run_script(NULL, "deconfig");
+							state = INIT_SELECTING;
+							timeout = now;
+							requested_ip = 0;
+							packet_num = 0;
+							change_mode(LISTEN_RAW);
+							sleep(decline_wait); /* avoid excessive network traffic */
+							break;
+					        }
+					}
+#endif
 					/* enter bound state */
 					t1 = lease / 2;
 
diff -u -r ./networking/udhcp/dhcpc.h ../busybox-20071120-jd/networking/udhcp/dhcpc.h
--- ./networking/udhcp/dhcpc.h	2007-11-20 09:20:04.000000000 +0100
+++ ../busybox-20071120-jd/networking/udhcp/dhcpc.h	2007-11-20 14:49:47.000000000 +0100
@@ -1,5 +1,6 @@
 /* vi: set sw=4 ts=4: */
 /* dhcpc.h */
+
 #ifndef _DHCPC_H
 #define _DHCPC_H
 
@@ -42,6 +43,9 @@
 uint32_t random_xid(void);
 int send_discover(uint32_t xid, uint32_t requested);
 int send_selecting(uint32_t xid, uint32_t server, uint32_t requested);
+#ifdef CONFIG_FEATURE_UDHCPC_ARPING
+int send_decline(unsigned long xid, unsigned long server);
+#endif
 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
 int send_release(uint32_t server, uint32_t ciaddr);
diff -u -r ./networking/udhcp/Kbuild ../busybox-20071120-jd/networking/udhcp/Kbuild
--- ./networking/udhcp/Kbuild	2007-11-20 09:20:04.000000000 +0100
+++ ../busybox-20071120-jd/networking/udhcp/Kbuild	2007-11-20 14:57:18.000000000 +0100
@@ -12,6 +12,10 @@
                                    signalpipe.o socket.o
 lib-$(CONFIG_APP_UDHCPC)        += dhcpc.o clientpacket.o clientsocket.o \
                                    script.o
+ifeq ($(strip $(CONFIG_FEATURE_UDHCPC_ARPING)),y)
+lib-$(CONFIG_APP_UDHCPC)	    += arpping.o
+endif
+
 lib-$(CONFIG_APP_UDHCPD)        += dhcpd.o arpping.o files.o leases.o \
                                    serverpacket.o static_leases.o
 lib-$(CONFIG_APP_DUMPLEASES)    += dumpleases.o
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to