Multiple response packets if multiple IP addresses per interface
Describe the bug
While working on authoritative support I noticed that Kea is responding with multiple packets to each client packet received on an interface with multiple IP addresses. The number of response packets matches the number of IP addresses configured on the interface.
Debugging with gdb showed that getIOService()->poll()
in dhcp4_srv.cc
returned multiple times and running ss -l0up
showed that dhcp4
has one UDP and one RAW socket per IP address. Using one UDP socket for each address makes sense, because Kea bind(2)
s each IP address on the interface. Employing multiple RAW sockets per interface on the other hand doesn't make sense, in my humble opinion, because RAW sockets are bound to interfaces instead of addresses and will result in the same packet being returned via multiple sockets.
% sudo ip netns exec keatest ss -lp0u
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
p_raw UNCONN 0 0 *:eth0 * users:(("lt-kea-dhcp4",pid=20879,fd=18))
p_raw UNCONN 0 0 *:eth0 * users:(("lt-kea-dhcp4",pid=20879,fd=16))
p_raw UNCONN 0 0 *:eth0 * users:(("lt-kea-dhcp4",pid=20879,fd=14))
p_raw UNCONN 0 0 *:eth0 * users:(("lt-kea-dhcp4",pid=20879,fd=12))
udp UNCONN 0 0 192.0.4.1:bootps 0.0.0.0:* users:(("lt-kea-dhcp4",pid=20879,fd=17))
udp UNCONN 0 0 192.0.3.1:bootps 0.0.0.0:* users:(("lt-kea-dhcp4",pid=20879,fd=15))
udp UNCONN 0 0 192.0.1.1:bootps 0.0.0.0:* users:(("lt-kea-dhcp4",pid=20879,fd=13))
udp UNCONN 0 0 192.0.2.1:bootps 0.0.0.0:* users:(("lt-kea-dhcp4",pid=20879,fd=11))
To Reproduce
Steps to reproduce the behavior:
- Setup a test setup with multiple IP addresses (192.0.1.1/24, 192.0.2.1/24, 192.0.3.1/24, 10.0.0.1/24) per interface (e.g. with network namespaces):
sudo ip netns create keatest
sudo ip -n keatest link add eth0 type veth peer eth1
sudo ip -n keatest addr add 192.0.1.1/24
sudo ip -n keatest addr add 192.0.2.1/24
sudo ip -n keatest addr add 192.0.3.1/24
sudo ip -n keatest addr add 10.0.0.1/24
- Use the following config for
kea-dhcp4
:
{
"Dhcp4": {
"interfaces-config": {
"interfaces": [ "eth0" ]
},
"lease-database": {
"type": "memfile",
"lfc-interval": 3600
},
"subnet4": [ {
"interface": "eth0",
"renew-timer": 100,
"rebind-timer": 150,
"reservation-mode": "all",
"pools": [ { "pool": "192.0.1.100 - 192.0.1.200" } ],
"subnet": "192.0.1.1/24",
"valid-lifetime": 200
} ]
},
"Logging": {
"loggers" : [ {
"name": "kea-dhcp4",
"severity": "INFO",
"output_options": [ { "output": "stderr" } ]
} ]
}
- Run
kea-dhcp4
with the above config:
KEA_LOGGER_DESTINATION=stderr sudo -E ip netns exec keatest ./src/bin/dhcp4/kea-dhcp4 -c /tmp/bug.json -d
- Capture packets or observe logs
- Send proper DHCP packets to Kea, which yield responses, e.g.
sudo ip netns exec keatest dhcpcd -B -K -L -A -G -4 eth1
- Notice multiple responses sent by Kea in the debug output or packet analyzer like
tcpdump
:
sudo ip netns exec keatest tcpdump -nei eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:40:32.175791 02:13:da:a8:fb:81 > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 403: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 02:13:da:a8:fb:81, length 361
16:40:32.184364 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.101.68: BOOTP/DHCP, Reply, length 305
16:40:32.185058 02:13:da:a8:fb:81 > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 413: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 02:13:da:a8:fb:81, length 371
16:40:32.192521 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.102.68: BOOTP/DHCP, Reply, length 305
16:40:32.200710 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.101.68: BOOTP/DHCP, Reply, length 305
16:40:32.206687 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.101.68: BOOTP/DHCP, Reply, length 305
16:40:32.210306 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.101.68: BOOTP/DHCP, Reply, length 305
16:40:32.213946 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.101.68: BOOTP/DHCP, Reply, length 305
16:40:32.215543 02:13:da:a8:fb:81 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 192.0.1.101 tell 192.0.1.101, length 28
16:40:32.217240 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.101.68: BOOTP/DHCP, Reply, length 305
16:40:32.222563 0e:8c:11:82:80:ed > 02:13:da:a8:fb:81, ethertype IPv4 (0x0800), length 347: 192.0.2.1.67 > 192.0.1.101.68: BOOTP/DHCP, Reply, length 305
16:40:34.217768 02:13:da:a8:fb:81 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 192.0.1.101 tell 192.0.1.101, length 28
Expected behavior
Kea should respond to each client packet only once.
Environment:
- Kea version:
./src/bin/dhcp4/kea-dhcp4 -V :(
1.4.0-git
git ad898b1269bd0f29cc29596acf530028947f3163
linked with:
log4cplus 2.0.2
Botan 2.7.0 (release, dated 20180702, revision git:5874000d42c338ec95a7ff24cdc0c64e70f967b5, distribution unspecified)
database:
MySQL backend 7.0, library 10.1.36-MariaDB
PostgreSQL backend 5.0, library 100005
Memfile backend 2.1
- OS: Linux 4.18, glibc 2.28
- no hooks
Make sure you anonymize your config files (at the very lease make sure you obfuscate your database credentials, but you may also replace your actual IP addresses and host names with example.com and 10.0.0.0/8 or 2001:db8::/32).
Describe the solution you'd like
Open only one RAW socket per interface.