Page MenuHomeVyOS Platform

DHCP `ping-check` enabled by default
Closed, ResolvedPublicBUG

Description

It appears that in Sagitta the ping-check option of the DHCP server is enabled by default.

This conflicts with the per-network ping-check option, which allows us to enable to feature on a per network basis. As this option only allows us to enable the feature, there is no way of turning the check off.

The impact of having the ping-check enabled by default is noticeable when you have Linux users, using network-manager, roaming on your wireless. As NM will verify its DHCP lease when hopping BSSID's, but keeps its IP in the meantime (behavior described here: https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/527). Which will result in the following entry in our DHCP log:

dhcpd[2316]: ICMP Echo reply while lease 192.168.10.117 valid.
dhcpd[2316]: Abandoning IP address 192.168.10.117: pinged before offer

As a workaround you can disable the ping-check using custom parameters, like so:

set service dhcp-server global-parameters "ping-check false;"

If the feature should be enabled by default is up to the maintainers, but there should at least be the option to toggle it.

Details

Difficulty level
Easy (less than an hour)
Version
VyOS 1.4-rolling-202207290217
Why the issue appeared?
Will be filled on close
Is it a breaking change?
Behavior change
Issue type
Bug (incorrect behavior)

Event Timeline

ping-check shouldn't be allowed by default
To enable it you have to set set service dhcp-server shared-network-name Lan01 ping-check
There is no configuration in generated .conf:

vyos@r14# cat /run/dhcp-server/dhcpd.conf | grep ping
[edit]
vyos@r14#

So maybe it is default isc-dhcp-server behaviour

As remarked and as expected, this option is not enable by default.
Proofs:

  • Fist scenario: no ping-check option introduced in configuration:
###########################
## VyOS dhcp-server configuration
vyos@vyos# run show config comm | grep dhcp
set service dhcp-server shared-network-name ETH3-LAN subnet 198.51.100.0/24 default-router '198.51.100.1'
set service dhcp-server shared-network-name ETH3-LAN subnet 198.51.100.0/24 name-server '8.8.8.8'
set service dhcp-server shared-network-name ETH3-LAN subnet 198.51.100.0/24 range 0 start '198.51.100.100'
set service dhcp-server shared-network-name ETH3-LAN subnet 198.51.100.0/24 range 0 stop '198.51.100.200'


####################################
### See no ping-check option in config file ###

vyos@vyos# cat /run/dhcp-server/dhcpd.conf
### Autogenerated by dhcp_server.py ###

# For options please consult the following website:
# https://www.isc.org/wp-content/uploads/2017/08/dhcp43options.html
#
# log-facility local7;

ddns-update-style none;
option rfc3442-static-route code 121 = array of integer 8;
option windows-static-route code 249 = array of integer 8;
option wpad-url code 252 = text;

# Vendor specific options - Ubiquiti Networks
option space ubnt;
option ubnt.unifi-controller code 1 = ip-address;
class "ubnt" {
    match if substring (option vendor-class-identifier , 0, 4) = "ubnt";
    option vendor-class-identifier "ubnt";
    vendor-option-space ubnt;
}

# Shared network configration(s)
shared-network ETH3-LAN {
    subnet 198.51.100.0 netmask 255.255.255.0 {
        option domain-name-servers 8.8.8.8;
        option routers 198.51.100.1;
        default-lease-time 86400;
        max-lease-time 86400;
        pool {
            range 198.51.100.100 198.51.100.200;
        }  
    }
    on commit {
        set shared-networkname = "ETH3-LAN";
    }
}


### TCPDUMP on interface, shows no icmp entry while a client request ip address.
vyos@vyos# sudo tcpdump -i eth3
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:00:02.583914 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 00:50:79:66:68:05 (oui Unknown), length 364
17:00:02.584551 IP 198.51.100.1 > 198.51.100.101: ICMP echo request, id 25271, seq 0, length 28
17:00:02.584837 IP 198.51.100.101 > 198.51.100.1: ICMP echo reply, id 25271, seq 0, length 28
17:00:03.583854 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 00:50:79:66:68:05 (oui Unknown), length 364
17:00:03.584209 ARP, Request who-has 198.51.100.102 tell 198.51.100.1, length 28
17:00:04.584547 IP 198.51.100.1.bootps > 198.51.100.102.bootpc: BOOTP/DHCP, Reply, length 300
17:00:04.601124 ARP, Request who-has 198.51.100.102 tell 198.51.100.1, length 28
17:00:05.625126 ARP, Request who-has 198.51.100.102 tell 198.51.100.1, length 28
17:00:06.583975 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 00:50:79:66:68:05 (oui Unknown), length 364
17:00:06.586376 IP 198.51.100.1.bootps > 198.51.100.102.bootpc: BOOTP/DHCP, Reply, length 300
17:00:07.584043 ARP, Request who-has 198.51.100.102 (Broadcast) tell 198.51.100.102, length 50
17:00:07.929143 ARP, Request who-has 198.51.100.101 tell 198.51.100.1, length 28
17:00:08.584255 ARP, Request who-has 198.51.100.102 (Broadcast) tell 198.51.100.102, length 50
17:00:08.953145 ARP, Request who-has 198.51.100.101 tell 198.51.100.1, length 28
17:00:09.585198 ARP, Request who-has 198.51.100.102 (Broadcast) tell 198.51.100.102, length 50
17:00:09.977119 ARP, Request who-has 198.51.100.101 tell 198.51.100.1, length 28

And after adding ping-check option: we see:

### Print config comm with ping check
vyos@vyos# run show config comm | grep ping-check
set service dhcp-server shared-network-name ETH3-LAN ping-check
[edit]

## Verify config is present in config file
vyos@vyos# cat /run/dhcp-server/dhcpd.conf | grep ping
    ping-check true;
[edit]


## Finally, tcpdump
vyos@vyos# sudo tcpdump -i eth3
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:04:14.823826 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 00:50:79:66:68:05 (oui Unknown), length 364
17:04:14.824294 IP 198.51.100.1 > 198.51.100.102: ICMP echo request, id 58325, seq 0, length 28
17:04:15.823879 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 00:50:79:66:68:05 (oui Unknown), length 364
17:04:15.824608 IP 198.51.100.1.bootps > 198.51.100.102.bootpc: BOOTP/DHCP, Reply, length 300
17:04:18.824030 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 00:50:79:66:68:05 (oui Unknown), length 364
17:04:18.824238 IP 198.51.100.1.bootps > 198.51.100.102.bootpc: BOOTP/DHCP, Reply, length 300
17:04:19.824061 ARP, Request who-has 198.51.100.102 (Broadcast) tell 198.51.100.102, length 50
17:04:19.833123 ARP, Request who-has 198.51.100.102 tell 198.51.100.1, length 28
17:04:19.833246 ARP, Reply 198.51.100.102 is-at 00:50:79:66:68:05 (oui Unknown), length 28
17:04:20.824617 ARP, Request who-has 198.51.100.102 (Broadcast) tell 198.51.100.102, length 50
17:04:21.825454 ARP, Request who-has 198.51.100.102 (Broadcast) tell 198.51.100.102, length 50

Allow me to proof the opposite.

Explicitly disabling ping-check using the workaround

vyos@mauer:~$ cat /run/dhcp-server/dhcpd.conf | grep ping
ping-check false;

vyos@mauer:~$ tcpdump -ni bond0.10 port bootps or port bootpc or icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on bond0.10, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:06:13.555352 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 289
20:06:13.555353 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 289
20:06:13.556404 IP 192.168.10.1.67 > 192.168.10.93.68: BOOTP/DHCP, Reply, length 318
20:06:13.557034 IP 192.168.10.1.67 > 192.168.10.93.68: BOOTP/DHCP, Reply, length 318
20:06:13.558845 IP 192.168.10.93 > 192.168.10.1: ICMP 192.168.10.93 udp port 68 unreachable, length 354
20:06:13.559012 IP 192.168.10.93 > 192.168.10.1: ICMP 192.168.10.93 udp port 68 unreachable, length 354
20:06:13.559233 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 295
20:06:13.559321 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 295
20:06:14.150639 IP 192.168.10.1.67 > 192.168.10.93.68: BOOTP/DHCP, Reply, length 318
20:06:14.153244 IP 192.168.10.93 > 192.168.10.1: ICMP 192.168.10.93 udp port 68 unreachable, length 354
20:06:14.726676 IP 192.168.10.1.67 > 192.168.10.93.68: BOOTP/DHCP, Reply, length 318
### Autogenerated by dhcp_server.py ###

# For options please consult the following website:
# https://www.isc.org/wp-content/uploads/2017/08/dhcp43options.html
#
# log-facility local7;
on release {
    set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name);
    set ClientIp = binary-to-ascii(10, 8, ".",leased-address);
    execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", "", ClientIp, "", "");
}
on expiry {
    set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name);
    set ClientIp = binary-to-ascii(10, 8, ".",leased-address);
    execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", "", ClientIp, "", "");
}

use-host-decl-names on;
ddns-update-style none;
option rfc3442-static-route code 121 = array of integer 8;
option windows-static-route code 249 = array of integer 8;
option wpad-url code 252 = text;

# Vendor specific options - Ubiquiti Networks
option space ubnt;
option ubnt.unifi-controller code 1 = ip-address;
class "ubnt" {
    match if substring (option vendor-class-identifier , 0, 4) = "ubnt";
    option vendor-class-identifier "ubnt";
    vendor-option-space ubnt;
}

# The following 1 line(s) have been added as
# global-parameters in the CLI and have not been validated !!!
ping-check false;


# Shared network configration(s)
shared-network LAN {
    authoritative;
    option domain-name "redacted";
    option domain-search "redacted";
    subnet 192.168.10.0 netmask 255.255.255.128 {
        option domain-name-servers 192.168.10.1;
        option routers 192.168.10.1;
        default-lease-time 86400;
        max-lease-time 86400;
        pool {
            range 192.168.10.80 192.168.10.120;
        }
    }
    on commit {
        set shared-networkname = "LAN";
        set ClientIp = binary-to-ascii(10, 8, ".", leased-address);
        set ClientMac = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
        set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name, "empty_hostname");
        if not (ClientName = "empty_hostname") {
            set ClientDomain = pick-first-value(config-option domain-name, "..YYZ!");
            execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "commit", ClientName, ClientIp, ClientMac, ClientDomain);
        } else {
            log(concat("Hostname is not defined for client with IP: ", ClientIP, " MAC: ", ClientMac));
        }
    }
}

No special DHCP options set

vyos@mauer:~$ cat /run/dhcp-server/dhcpd.conf | grep ping

vyos@mauer:~$ tcpdump -ni bond0.10 port bootps or port bootpc or icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on bond0.10, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:07:41.030229 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 300
20:07:41.030229 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 300
20:07:41.031508 IP 192.168.10.1 > 192.168.10.93: ICMP echo request, id 22262, seq 0, length 28
20:07:41.035771 IP 192.168.10.93 > 192.168.10.1: ICMP echo reply, id 22262, seq 0, length 28
20:07:43.228146 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 300
20:07:43.228146 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 300
20:07:44.230192 IP 192.168.10.1.67 > 192.168.10.103.68: BOOTP/DHCP, Reply, length 318
20:07:44.237352 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 300
20:07:44.237353 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:f0:11:67:dd:d3, length 300

vyos@mauer:~$ show log dhcp server·
--- %< ---  SNIP --- %< ---
Aug 09 20:07:14 dhcpd[13734]: Server starting service.
Aug 09 20:07:41 dhcpd[13734]: reuse_lease: lease age 21119 (secs) under 25% threshold, reply with unaltered, existing lease for 192.168.10.93
Aug 09 20:07:41 dhcpd[13734]: DHCPDISCOVER from 3c:f0:11:67:dd:d3 (greta) via bond0.10
Aug 09 20:07:41 dhcpd[13734]: ICMP Echo reply while lease 192.168.10.93 valid.
Aug 09 20:07:41 dhcpd[13734]: Abandoning IP address 192.168.10.93: pinged before offer
### Autogenerated by dhcp_server.py ###

# For options please consult the following website:
# https://www.isc.org/wp-content/uploads/2017/08/dhcp43options.html
#
# log-facility local7;
on release {
    set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name);
    set ClientIp = binary-to-ascii(10, 8, ".",leased-address);
    execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", "", ClientIp, "", "");
}
on expiry {
    set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name);
    set ClientIp = binary-to-ascii(10, 8, ".",leased-address);
    execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", "", ClientIp, "", "");
}

use-host-decl-names on;
ddns-update-style none;
option rfc3442-static-route code 121 = array of integer 8;
option windows-static-route code 249 = array of integer 8;
option wpad-url code 252 = text;

# Vendor specific options - Ubiquiti Networks
option space ubnt;
option ubnt.unifi-controller code 1 = ip-address;
class "ubnt" {
    match if substring (option vendor-class-identifier , 0, 4) = "ubnt";
    option vendor-class-identifier "ubnt";
    vendor-option-space ubnt;
}


# Shared network configration(s)
shared-network LAN {
    authoritative;
    option domain-name "redacted";
    option domain-search "redacted";
    subnet 192.168.10.0 netmask 255.255.255.128 {
        option domain-name-servers 192.168.10.1;
        option routers 192.168.10.1;
        default-lease-time 86400;
        max-lease-time 86400;
        pool {
            range 192.168.10.80 192.168.10.120;
        }
    }
    on commit {
        set shared-networkname = "LAN";
        set ClientIp = binary-to-ascii(10, 8, ".", leased-address);
        set ClientMac = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
        set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name, "empty_hostname");
        if not (ClientName = "empty_hostname") {
            set ClientDomain = pick-first-value(config-option domain-name, "..YYZ!");
            execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "commit", ClientName, ClientIp, ClientMac, ClientDomain);
        } else {
            log(concat("Hostname is not defined for client with IP: ", ClientIP, " MAC: ", ClientMac));
        }
    }
}

diff of the two configs

vyos@mauer:~$ diff /tmp/dhcp-no-workaround.conf /tmp/dhcp-with-workaround.conf
32a33,36
> # The following 1 line(s) have been added as
> # global-parameters in the CLI and have not been validated !!!
> ping-check false;
>

What version you are using?

In my labs:

  • I see no ICMP with defaults config (no global-paramenter set)
  • I see no ICMP with global-option set like set service dhcp-server global-parameters 'ping-check false;'
  • I see ICMP packets if:
    • Add global-parameter -->set service dhcp-server global-parameters 'ping-check true;'
    • Or, adding ping-check option in shared-nework --> set service dhcp-server shared-network-name ETH3-LAN ping-check

I've verified this behavior with 1.4-rolling-202207290217 and 1.4-rolling-202204250217.

I would expect the most important software package version to be isc-dhcp-server, which is currently at version 4.4.1-2.3.

I'm happy to provide a more complete configuration dump if needed, but I can't imagine anything outside of the dhcpd.conf to influence this.

m4rcu5 claimed this task.

I've recently migrated from a PCEngines APU2C4 to a Wyse 5070 with a X520 card, as well as upgrading to VyOS 1.4-rolling-202305081003
After which I was unable to reproduce this issue. Roaming now works fine without the ICMP check.

I'll mark this one as resolved, even though I am not sure what fixed it in the end.