ell.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
From: Andrew Zaborowski <andrew.zaborowski@intel.com>
To: ell@lists.01.org
Subject: [PATCH 03/15] dhcp-server: Respect client's broadcast flag
Date: Mon, 02 Aug 2021 16:04:12 +0200	[thread overview]
Message-ID: <20210802140424.170150-3-andrew.zaborowski@intel.com> (raw)
In-Reply-To: <20210802140424.170150-1-andrew.zaborowski@intel.com>

[-- Attachment #1: Type: text/plain, Size: 5639 bytes --]

Follow notes in RFC2131 4.1, 4.3.2 and 4.4.4 when deciding whether we
can use unicast for a given message.  We want to prefer unicast when
possible but we should follow the spec on the broadcast flag and the
destination address.
---
 ell/dhcp-private.h |  3 ++
 ell/dhcp-server.c  | 90 +++++++++++++++++++++++++++++++++++-----------
 2 files changed, 72 insertions(+), 21 deletions(-)

diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index c422322..f761162 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -66,6 +66,9 @@ enum dhcp_option_overload {
 #define DHCP_OPTION_MAXIMUM_MESSAGE_SIZE 57 /* Section 9.10 */
 #define DHCP_OPTION_CLIENT_IDENTIFIER 61 /* Section 9.14 */
 
+/* RFC 2131, Figure 2 */
+#define DHCP_FLAG_BROADCAST (1 << 15)
+
 /* RFC 2131, Figure 1 */
 struct dhcp_message {
 	uint8_t op;
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index 0e18cf8..910aed7 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -420,6 +420,71 @@ static void server_message_init(struct l_dhcp_server *server,
 	reply->ciaddr = client_msg->ciaddr;
 }
 
+static bool server_message_send(struct l_dhcp_server *server,
+				struct dhcp_message *reply, size_t len,
+				uint8_t type)
+{
+	uint32_t daddr;
+	uint16_t dport;
+	const uint8_t *dest_mac;
+
+	/*
+	 * RFC2131 Section 4.1: "If the 'giaddr' field in a DHCP message from
+	 * a client is non-zero, the server sends any return messages to the
+	 * 'DHCP server' port on the BOOTP relay agent whose address appears
+	 * in 'giaddr'. If the 'giaddr' field is zero and the 'ciaddr' field
+	 * is nonzero, then the server unicasts DHCPOFFER and DHCPACK messages
+	 * to the address in 'ciaddr'.  If 'giaddr' is zero and 'ciaddr' is
+	 * zero, and the broadcast bit is set, then the server broadcasts
+	 * DHCPOFFER and DHCPACK messages to 0xffffffff. If the broadcast bit
+	 * is not set and 'giaddr' is zero and 'ciaddr' is zero, then the
+	 * server unicasts DHCPOFFER and DHCPACK messages to the client's
+	 * hardware address and 'yiaddr' address.  In all cases, when 'giaddr'
+	 * is zero, the server broadcasts any DHCPNAK messages to 0xffffffff."
+	 *
+	 * 4.3.2: "If 'giaddr' is set in the DHCPREQUEST message, the client
+	 * is on a different subnet.  The server MUST set the broadcast bit in
+	 * the DHCPNAK, so that the relay agent will broadcast the DHCPNAK to
+	 * the client, because the client may not have a correct network
+	 * address or subnet mask, and the client may not be answering ARP
+	 * requests."
+	 */
+	if (reply->giaddr) {
+		dport = DHCP_PORT_SERVER;
+		daddr = reply->giaddr;
+		dest_mac = reply->chaddr;
+
+		if (type == DHCP_MESSAGE_TYPE_NAK)
+			reply->flags |= L_CPU_TO_BE16(DHCP_FLAG_BROADCAST);
+	} else {
+		dport = DHCP_PORT_CLIENT;
+
+		if (type == DHCP_MESSAGE_TYPE_NAK) {
+			daddr = 0xffffffff;
+			dest_mac = MAC_BCAST_ADDR;
+		} else if (reply->ciaddr) {
+			daddr = reply->ciaddr;
+			dest_mac = reply->chaddr;
+		} else if (L_BE16_TO_CPU(reply->flags) & DHCP_FLAG_BROADCAST) {
+			daddr = 0xffffffff;
+			dest_mac = MAC_BCAST_ADDR;
+		} else {
+			daddr = reply->yiaddr;
+			dest_mac = reply->chaddr;
+		}
+	}
+
+	if (server->transport->l2_send(server->transport, server->address,
+					DHCP_PORT_SERVER, daddr, dport,
+					dest_mac, reply, len) < 0) {
+		SERVER_DEBUG("Failed to send %s",
+				_dhcp_message_type_to_string(type));
+		return false;
+	}
+
+	return true;
+}
+
 static void add_server_options(struct l_dhcp_server *server,
 				struct dhcp_message_builder *builder)
 {
@@ -491,11 +556,7 @@ static void send_offer(struct l_dhcp_server *server,
 	SERVER_DEBUG("Sending OFFER of "NIPQUAD_FMT " to "MAC,
 			NIPQUAD(reply->yiaddr),	MAC_STR(reply->chaddr));
 
-	if (server->transport->l2_send(server->transport, server->address,
-					DHCP_PORT_SERVER,
-					reply->ciaddr, DHCP_PORT_CLIENT,
-					reply->chaddr, reply, len) < 0)
-		SERVER_DEBUG("Failed to send OFFER");
+	server_message_send(server, reply, len, DHCP_MESSAGE_TYPE_OFFER);
 }
 
 static void send_inform(struct l_dhcp_server *server,
@@ -515,11 +576,7 @@ static void send_inform(struct l_dhcp_server *server,
 
 	_dhcp_message_builder_finalize(&builder, &len);
 
-	if (server->transport->l2_send(server->transport, server->address,
-					DHCP_PORT_SERVER, reply->ciaddr,
-					DHCP_PORT_CLIENT, reply->chaddr,
-					reply, len) < 0)
-		SERVER_DEBUG("Failed to send INFORM");
+	server_message_send(server, reply, len, DHCP_MESSAGE_TYPE_INFORM);
 }
 
 static void send_nak(struct l_dhcp_server *server,
@@ -537,11 +594,7 @@ static void send_nak(struct l_dhcp_server *server,
 
 	_dhcp_message_builder_finalize(&builder, &len);
 
-	if (server->transport->l2_send(server->transport, server->address,
-					DHCP_PORT_SERVER, reply->ciaddr,
-					DHCP_PORT_CLIENT, MAC_BCAST_ADDR,
-					reply, len) < 0)
-		SERVER_DEBUG("Failed to send NACK");
+	server_message_send(server, reply, len, DHCP_MESSAGE_TYPE_NAK);
 }
 
 static void send_ack(struct l_dhcp_server *server,
@@ -574,13 +627,8 @@ static void send_ack(struct l_dhcp_server *server,
 
 	SERVER_DEBUG("Sending ACK to "NIPQUAD_FMT, NIPQUAD(reply->yiaddr));
 
-	if (server->transport->l2_send(server->transport, server->address,
-					DHCP_PORT_SERVER, reply->ciaddr,
-					DHCP_PORT_CLIENT,
-					reply->chaddr, reply, len) < 0) {
-		SERVER_DEBUG("Failed to send ACK");
+	if (!server_message_send(server, reply, len, DHCP_MESSAGE_TYPE_ACK))
 		return;
-	}
 
 	lease = add_lease(server, false, reply->chaddr, reply->yiaddr);
 
-- 
2.30.2

  parent reply	other threads:[~2021-08-02 14:04 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-02 14:04 [PATCH 01/15] dhcp-server: Add "authoritative" mode Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 02/15] dhcp-server: Handle DHCPDECLINE for active leases Andrew Zaborowski
2021-08-02 14:04 ` Andrew Zaborowski [this message]
2021-08-02 14:04 ` [PATCH 04/15] dhcp-server: Look up leases by client identifier option Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 05/15] dhcp-server: Copy client identifier from the client message Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 06/15] dhcp-server: Save lease mac before calling add_lease Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 07/15] dhcp-server: Ensure broadcast address is not selected Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 08/15] dhcp-server: Reuse leases in find_free_or_expired_ip Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 09/15] dhcp-server: Refactor lease lookup Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 10/15] dhcp-server: Allow reactivating expired leases Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 11/15] dhcp: Support RFC4039 Rapid Commit Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 12/15] dhcp-server: " Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 13/15] dhcp-server: Rapid commit enable/disable setter Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 14/15] unit: Stricter checks in unit-dhcp Andrew Zaborowski
2021-08-02 14:04 ` [PATCH 15/15] unit: Test DHCP rapid commit Andrew Zaborowski
2021-08-02 18:15 ` [PATCH 01/15] dhcp-server: Add "authoritative" mode Denis Kenzior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210802140424.170150-3-andrew.zaborowski@intel.com \
    --to=andrew.zaborowski@intel.com \
    --cc=ell@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).