dhcpcd icon indicating copy to clipboard operation
dhcpcd copied to clipboard

dhcpcd Does Not Send an ARP Probe to Detect Duplicate Address by Default

Open shuangye opened this issue 11 months ago • 4 comments

I use dhcpcd with the default /etc/dhcpcd.conf, and enabled "hostname" option, no other changes.

root@localhost:~# ip a show eth0.168
3: eth0.168@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether ba:cd:d7:65:ae:14 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::b8cd:d7ff:fe65:ae14/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever
root@localhost:~# dhcpcd -T eth0.168
dhcpcd-10.0.5 starting
duid_get: cannot write duid: Read-only file system
DUID 00:03:00:01:ba:cd:d7:65:ae:14
eth0.168: IAID ff:00:00:a8
eth0.168: soliciting an IPv6 router
eth0.168: soliciting a DHCP lease
eth0.168: offered 192.168.31.151 from 192.168.31.1
interface=eth0.168
pid=1892
protocol=dhcp
reason=TEST
ifcarrier=up
ifflags=69699
ifmetric=1003
ifmtu=1500
ifwireless=0
new_broadcast_address=192.168.31.255
new_dhcp_lease_time=43200
new_dhcp_message_type=2
new_dhcp_rebinding_time=37800
new_dhcp_renewal_time=21600
new_dhcp_server_identifier=192.168.31.1
new_domain_name_servers=192.168.31.1
new_host_name=MiWiFi-R3G-srv
new_ip_address=192.168.31.151
new_network_number=192.168.31.0
new_routers=192.168.31.1
new_subnet_cidr=24
new_subnet_mask=255.255.255.0
new_vendor_encapsulated_options=6d69776966692d5233472d322e32382e32342d313031
dhcpcd exited
root@localhost:~# uname -a
Linux localhost 6.1.75-dirty #111 SMP Thu Mar 13 10:25:09 CST 2025 aarch64 GNU/Linux

In another terminal, I run tcpdump -v -i eth0.168 and found that no arp probe was sent.

Is there an option to enable DAD?

shuangye avatar Mar 14 '25 08:03 shuangye

Just noticed that sometimes it sends the probe:

root@localhost:~# dhcpcd  eth0.168
dhcpcd-10.0.5 starting
duid_get: cannot write duid: Read-only file system
DUID 00:03:00:01:ba:cd:d7:65:ae:14
eth0.168: IAID ff:00:00:a8
eth0.168: soliciting an IPv6 router
eth0.168: soliciting a DHCP lease
eth0.168: offered 192.168.31.151 from 192.168.31.1
eth0.168: probing address 192.168.31.151/24
eth0.168: leased 192.168.31.151 for 43200 seconds
dhcp_writefile: /var/db/dhcpcd/eth0.168.lease: Read-only file system
eth0.168: adding route to 192.168.31.0/24
eth0.168: adding default route via 192.168.31.1

Sometimes not:

root@localhost:~# dhcpcd  eth0.168
dhcpcd-10.0.5 starting
duid_get: cannot write duid: Read-only file system
DUID 00:03:00:01:ba:cd:d7:65:ae:14
eth0.168: IAID ff:00:00:a8
eth0.168: soliciting a DHCP lease
eth0.168: offered 192.168.31.151 from 192.168.31.1
eth0.168: leased 192.168.31.151 for 43200 seconds
dhcp_writefile: /var/db/dhcpcd/eth0.168.lease: Read-only file system
eth0.168: adding route to 192.168.31.0/24
eth0.168: adding default route via 192.168.31.1

shuangye avatar Mar 14 '25 08:03 shuangye

After studying dhcpcd code, seems if the interface already has an IP address before the DHCP offer, dhcpcd will skip probing.

The problem is that, even I use the following commands to remove all IP addresses from the interface:

root@localhost:~# ip a flush dev eth0.168
root@localhost:~# ip a show dev eth0.168
3: eth0.168@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether ba:cd:d7:65:ae:14 brd ff:ff:ff:ff:ff:ff

dhcpcd still gets an IP address from eth0.168. Code:

// src/dhcp.c
static int
dhcp_arp_address(struct interface *ifp)
{
		// ia is not NULL here. I printed ia->addr.s_addr, it is still the previous IP address before it was removed
		if (ia == NULL) {
			state->state = DHS_PROBE;
			get_lease(ifp, &l, state->offer, state->offer_len);
			logerr("%s: probing address %s/%d",
			    ifp->name, inet_ntoa(l.addr), inet_ntocidr(l.mask));
			/* We need to handle DAD. */
			arp_probe(astate);
			return 0;
		}
}

As a workaround, I have to use these commands:

ip a flush dev eth0.168
ip a show dev eth0.168
ip link set dev eth0.168 down
ip link set dev eth0.168 up
killall -9 dhcpcd
dhcpcd eth0.168

shuangye avatar Mar 14 '25 09:03 shuangye

You are correct, dhcpcd will only perform the initial ARP probe if the address does not exist on the interface. Once dhcpcd is running, it will listen to ARP and Defend it's address if someone else wants to claim it via ARP.

I suppose the question becomes what value do you think you gain from ARP probing an address which exists on your interface already?

rsmarples avatar Mar 14 '25 10:03 rsmarples

I think skipping ARP probing is reasonable when the interface already has an IP address. But since I have removed all IP addresses with ip a flush dev eth0.168, dhcpcd should perform the probe. It does not because it uses a stale IP address here https://github.com/NetworkConfiguration/dhcpcd/blob/e8b2c8f29aa9d9ceaa14a7951935c662dc8af307/src/dhcp.c#L2641

BTW, if DHCP server offers a different IP adress as the existing one, I think dhcpcd should perform the probe too.

shuangye avatar Mar 14 '25 11:03 shuangye