From d8290b041b5b4c1cd0972ab7302125c5d35e50bc Mon Sep 17 00:00:00 2001 From: "David W. Hankins" Date: Tue, 11 Apr 2023 15:19:06 -0700 Subject: [PATCH 1/2] Clarify the reason `perfdhcp -4` defaults to port 67. PROBLEM ======= I spent several hours trying to figure out why `perfdhcp -L 68` was resulting in a 100% rate of drops and strange Kea log messages. My configuration is probably pretty normal; perfdhcp running on the same server as kea-dhcp4. First perfdhcp would not run because it could not bind the socket to port 67 (which I thought it wouldn't need to anyway). Specifying `-L 68` gets over this hurdle, but then Kea logs messages about receiving DHCPOFFERs on its socket, and `perfdhcp` never recieves the responses. It turns out Kea is replying to port 67 because `giaddr` is set, and that winds up sending the response packet (DHCPOFFER) to itself. SOLUTION ======== I think a broader solution to this problem would be to add support for a v4 client. This is complicated by the strange mechanics of DHCPv4 client packets in INIT and INIT-REBOOT states; generally requiring raw sockets. That's a pretty heavy lift. A milder solution might be to simulate clients in RENEWING state by default, then at least normal BSD sockets may be used but the command line interface would require lease address(es). It still feels awkward to implement. For now I figure we can at least remove the `@todo` questioning this, provide a warning to users that specify any port other than 67 for `-4` mode, and update the manpage. --- doc/sphinx/man/perfdhcp.8.rst | 4 ++++ src/bin/perfdhcp/perf_socket.cc | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/doc/sphinx/man/perfdhcp.8.rst b/doc/sphinx/man/perfdhcp.8.rst index 222486d3fc..e3867bac3e 100644 --- a/doc/sphinx/man/perfdhcp.8.rst +++ b/doc/sphinx/man/perfdhcp.8.rst @@ -225,6 +225,10 @@ Options integer up to 65535. A value of 0 (the default) allows ``perfdhcp`` to choose its own port. + Note that ``perfdhcp -4`` behaves as a relay agent, and the server may send + replies to the BOOTPS port (67) irrespective of what port ``perfdhcp`` is + listening on. + ``-M mac-list-file`` Specifies a text file containing a list of MAC addresses, one per line. If provided, a MAC address is chosen randomly from this list for diff --git a/src/bin/perfdhcp/perf_socket.cc b/src/bin/perfdhcp/perf_socket.cc index aa67796a1d..bd1fc4e24c 100644 --- a/src/bin/perfdhcp/perf_socket.cc +++ b/src/bin/perfdhcp/perf_socket.cc @@ -13,6 +13,7 @@ #include #include +#include using namespace isc::dhcp; using namespace isc::asiolink; @@ -53,8 +54,17 @@ PerfSocket::openSocket(CommandOptions& options) const { port = DHCP6_SERVER_PORT; } } else if (options.getIpVersion() == 4) { - port = 67; /// @todo: find out why port 68 is wrong here. + // perfdhcp sets giaddr to the bound socket address, so kea always + // responds to port 67. perfdhcp doesn't currently have a client + // behavior for DHCPv4; it either sets giaddr to the bound socket + // address or to a random address in the multi_subnet_ case. + port = 67; } + } else if ((options.getIpVersion() == 4) && (port != 67)) { + // No matter what port a user specifies, the server will reply to the + // address specified in giaddr on port 67. Try and warn the user. + std::cout << "WARNING: Port " << port << " specified, but server will " + << "respond to port 67." << std::endl; } // Local name is specified along with '-l' option. From b160b4230c83fd433fdc362b385bf18543c8c156 Mon Sep 17 00:00:00 2001 From: "David W. Hankins" Date: Thu, 13 Apr 2023 12:29:39 -0700 Subject: [PATCH 2/2] Use DHCP4_SERVER_PORT static const instead of literal 67. Also, I think the second comment is redundant. --- src/bin/perfdhcp/perf_socket.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/bin/perfdhcp/perf_socket.cc b/src/bin/perfdhcp/perf_socket.cc index bd1fc4e24c..4cf1a9388f 100644 --- a/src/bin/perfdhcp/perf_socket.cc +++ b/src/bin/perfdhcp/perf_socket.cc @@ -55,16 +55,15 @@ PerfSocket::openSocket(CommandOptions& options) const { } } else if (options.getIpVersion() == 4) { // perfdhcp sets giaddr to the bound socket address, so kea always - // responds to port 67. perfdhcp doesn't currently have a client - // behavior for DHCPv4; it either sets giaddr to the bound socket - // address or to a random address in the multi_subnet_ case. - port = 67; + // responds to the server port. perfdhcp doesn't currently have a + // client behavior for DHCPv4; it either sets giaddr to the bound + // socket address or to a random address in the multi_subnet_ case. + port = DHCP4_SERVER_PORT; } - } else if ((options.getIpVersion() == 4) && (port != 67)) { - // No matter what port a user specifies, the server will reply to the - // address specified in giaddr on port 67. Try and warn the user. - std::cout << "WARNING: Port " << port << " specified, but server will " - << "respond to port 67." << std::endl; + } else if ((options.getIpVersion() == 4) && (port != DHCP4_SERVER_PORT)) { + std::cerr << "WARNING: Port " << port << " specified, but server will " + << "respond to port " << DHCP4_SERVER_PORT << "." + << std::endl; } // Local name is specified along with '-l' option.