From: Denis Kenzior <denkenz@gmail.com>
To: ell@lists.01.org
Subject: Re: [PATCH 1/8] dhcp-server: Add "authoritative" mode
Date: Wed, 28 Jul 2021 10:42:40 -0500 [thread overview]
Message-ID: <fc2fc4b7-8892-81fb-1658-33fa79ab33dc@gmail.com> (raw)
In-Reply-To: <20210723182331.135123-1-andrew.zaborowski@intel.com>
[-- Attachment #1: Type: text/plain, Size: 9204 bytes --]
Hi Andrew,
On 7/23/21 1:23 PM, Andrew Zaborowski wrote:
> An authoritative DHCP server basically assumes that there are no other
> DHCP servers on the network and replies to DHCPREQUEST messages
> requesting IPs from outside of its subnet or with a wrong server ID
> value. This speeds up connections from clients who try to use IP
> leases they have cached from other networks and who start their IP
> configuration by trying DHCPREQUESTs for those leases.
>
> The term is not defined in the DHCP standard but is used by various
> implementations. Default to authoritative being true. When set to
> false, handle a DHCPREQUEST message directed at other servers by taking
> it as meaning the client is declining our own lease offer as mandated
> by RFC 2131 on page 16.
>
> Refactor the checks in DHCPREQUEST handling quoting parts of the RFC.
> The new checks are stricter and I'm not preserving some of the checks
> that didn't seem justified, for example in the
> "if (server_id_opt || !lease) ... send_nak()" block it didn't seem to
> make sense to only reply to clients who have no lease (offered or
> active) and ignore those who do have a lease with a different IP
> address, the opposite would make more sense.
It seems like this is supposed to be handling the init-reboot, bound, renewing,
rebinding states where server_id isn't present...?
> ---
> ell/dhcp-server.c | 109 ++++++++++++++++++++++++++++++++++++++++------
> ell/dhcp.h | 2 +
> ell/ell.sym | 1 +
> 3 files changed, 98 insertions(+), 14 deletions(-)
>
> diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
> index bae0f10..6415872 100644
> --- a/ell/dhcp-server.c
> +++ b/ell/dhcp-server.c
> @@ -87,6 +87,8 @@ struct l_dhcp_server {
> struct dhcp_transport *transport;
>
> struct l_acd *acd;
> +
> + bool authoritative : 1;
> };
>
> #define MAC "%02x:%02x:%02x:%02x:%02x:%02x"
> @@ -615,9 +617,6 @@ static void listener_event(const void *data, size_t len, void *user_data)
> if (l == 4)
> server_id_opt = l_get_u32(v);
>
> - if (server->address != server_id_opt)
> - return;
> -
> break;
> case L_DHCP_OPTION_REQUESTED_IP_ADDRESS:
> if (l == 4)
> @@ -640,6 +639,9 @@ static void listener_event(const void *data, size_t len, void *user_data)
> SERVER_DEBUG("Received DISCOVER, requested IP "NIPQUAD_FMT,
> NIPQUAD(requested_ip_opt));
>
> + if (server_id_opt && server_id_opt != server->address)
> + break;
> +
So strictly speaking, according to DHCPDISCOVER from the client shouldn't even
have this option...
> send_offer(server, message, lease, requested_ip_opt);
>
> break;
> @@ -647,27 +649,92 @@ static void listener_event(const void *data, size_t len, void *user_data)
> SERVER_DEBUG("Received REQUEST, requested IP "NIPQUAD_FMT,
> NIPQUAD(requested_ip_opt));
>
> - if (requested_ip_opt == 0) {
> - requested_ip_opt = message->ciaddr;
> - if (requested_ip_opt == 0)
> + /*
> + * RFC2131 Section 3.5: "Those servers not selected by the
> + * DHCPREQUEST message use the message as notification that
> + * the client has declined that server's offer."
> + */
> + if (server_id_opt && server_id_opt != server->address) {
> + if (server->authoritative) {
> + send_nak(server, message);
> break;
So you send a NAK here if server_id_opt is provided and doesn't match...
> - }
> + }
>
> - if (lease && requested_ip_opt == lease->address) {
> - send_ack(server, message, lease->address);
> + if (!lease || !lease->offering)
> + break;
> +
> + remove_lease(server, lease);
> break;
> }
>
> - if (server_id_opt || !lease) {
> - send_nak(server, message);
> + /*
> + * RFC2131 Section 3.5: "If the selected server is unable to
> + * satisfy the DHCPREQUEST message (...), the server SHOULD
> + * respond with a DHCPNAK message."
> + *
> + * But:
> + * 4.3.2: "If the DHCP server has no record of this client,
> + * then it MUST remain silent (...)"
> + */
> + if (!lease) {
> + if (server_id_opt == server->address ||
> + server->authoritative)
So why check server->authoritative here? It seems like you can only get to this
point if the server_id_opt is provided and matches, or not provided at all. The
'server_id_opt ==' part also seems unsafe for those cases where server_id isn't
provided at all...?
> + send_nak(server, message);
> +
> break;
> }
> +
> + /*
> + * 4.3.2: "If the DHCPREQUEST message contains a 'server
> + * identifier' option, the message is in response to a
> + * DHCPOFFER message. Otherwise, the message is a request
> + * to verify or extend an existing lease."
> + */
> + if (server_id_opt == server->address) {
Same here, checking server_id_opt seems unsafe?
> + /*
> + * Allow either no 'requested IP address' option or
> + * a value identical with the one we offered because
> + * the spec is unclear on whether it is to be
> + * included:
> + *
> + * Section 4.3.2: "DHCPREQUEST generated during
> + * SELECTING state: (...) 'requested IP address' MUST
> + * be filled in with the yiaddr value from the chosen
> + * DHCPOFFER."
> + *
> + * but section 3.5 suggests only in the INIT-REBOOT
> + * state: "The 'requested IP address' option is to be
> + * filled in only in a DHCPREQUEST message when the
> + * client is verifying network parameters obtained
> + * previously."
> + */
> + if (!lease->offering ||
> + (requested_ip_opt &&
> + requested_ip_opt != lease->address)) {
> + send_nak(server, message);
> + break;
> + }
> + } else {
> + /*
> + * 3.5: "If a server receives a DHCPREQUEST message
> + * with an invalid 'requested IP address', the server
> + * SHOULD respond to the client with a DHCPNAK message"
> + */
> + if (lease->offering ||
> + (requested_ip_opt &&
> + requested_ip_opt != lease->address)) {
> + send_nak(server, message);
> + break;
> + }
> + }
> +
> + send_ack(server, message, lease->address);
> break;
> case DHCP_MESSAGE_TYPE_DECLINE:
> SERVER_DEBUG("Received DECLINE");
>
> - if (!server_id_opt || !requested_ip_opt || !lease ||
> - !lease->offering)
> + if (server_id_opt != server->address || !requested_ip_opt ||
> + !lease || !lease->offering)
This also seems unsafe? server_id must be present, but you're not checking this
here?
> break;
>
> if (requested_ip_opt == lease->address)
> @@ -677,7 +744,8 @@ static void listener_event(const void *data, size_t len, void *user_data)
> case DHCP_MESSAGE_TYPE_RELEASE:
> SERVER_DEBUG("Received RELEASE");
>
> - if (!server_id_opt || !lease || lease->offering)
> + if (server_id_opt != server->address || !lease ||
> + lease->offering)
Or here?
> break;
>
> if (message->ciaddr == lease->address)
> @@ -687,6 +755,9 @@ static void listener_event(const void *data, size_t len, void *user_data)
> case DHCP_MESSAGE_TYPE_INFORM:
> SERVER_DEBUG("Received INFORM");
>
> + if (server_id_opt && server_id_opt != server->address)
> + break;
> +
> send_inform(server, message);
> break;
> }
> @@ -732,6 +803,7 @@ LIB_EXPORT struct l_dhcp_server *l_dhcp_server_new(int ifindex)
> server->expired_list = l_queue_new();
>
> server->started = false;
> + server->authoritative = true;
>
> server->lease_seconds = DEFAULT_DHCP_LEASE_SEC;
> server->max_expired = MAX_EXPIRED_LEASES;
> @@ -1053,6 +1125,15 @@ failed:
> return false;
> }
>
> +LIB_EXPORT void l_dhcp_server_set_authoritative(struct l_dhcp_server *server,
> + bool authoritative)
> +{
> + if (unlikely(!server))
> + return;
> +
> + server->authoritative = authoritative;
> +}
> +
> LIB_EXPORT struct l_dhcp_lease *l_dhcp_server_discover(
> struct l_dhcp_server *server,
> uint32_t requested_ip_opt,
> diff --git a/ell/dhcp.h b/ell/dhcp.h
> index 2804c78..830cbb1 100644
> --- a/ell/dhcp.h
> +++ b/ell/dhcp.h
> @@ -141,6 +141,8 @@ bool l_dhcp_server_set_ip_address(struct l_dhcp_server *server,
> bool l_dhcp_server_set_netmask(struct l_dhcp_server *server, const char *mask);
> bool l_dhcp_server_set_gateway(struct l_dhcp_server *server, const char *ip);
> bool l_dhcp_server_set_dns(struct l_dhcp_server *server, char **dns);
> +void l_dhcp_server_set_authoritative(struct l_dhcp_server *server,
> + bool authoritative);
>
> struct l_dhcp_lease *l_dhcp_server_discover(struct l_dhcp_server *server,
> uint32_t requested_ip_opt,
> diff --git a/ell/ell.sym b/ell/ell.sym
> index 4d41448..3be10dc 100644
> --- a/ell/ell.sym
> +++ b/ell/ell.sym
> @@ -259,6 +259,7 @@ global:
> l_dhcp_server_set_netmask;
> l_dhcp_server_set_gateway;
> l_dhcp_server_set_dns;
> + l_dhcp_server_set_authoritative;
> l_dhcp_server_discover;
> l_dhcp_server_request;
> l_dhcp_server_decline;
>
Regards,
-Denis
next prev parent reply other threads:[~2021-07-28 15:42 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-23 18:23 [PATCH 1/8] dhcp-server: Add "authoritative" mode Andrew Zaborowski
2021-07-23 18:23 ` [PATCH 2/8] dhcp-server: Handle DHCPDECLINE for active leases Andrew Zaborowski
2021-07-23 18:23 ` [PATCH 3/8] dhcp-server: Respect client's broadcast flag Andrew Zaborowski
2021-07-28 15:47 ` Denis Kenzior
2021-07-28 17:57 ` Andrew Zaborowski
2021-07-23 18:23 ` [PATCH 4/8] dhcp-lease: Check duplicate options in _dhcp_lease_parse_options Andrew Zaborowski
2021-07-28 15:50 ` Denis Kenzior
2021-07-23 18:23 ` [PATCH 5/8] dhcp-server: Look up leases by client identifier option Andrew Zaborowski
2021-07-23 18:23 ` [PATCH 6/8] dhcp-server: Copy client identifier from the client message Andrew Zaborowski
2021-07-23 18:23 ` [PATCH 7/8] dhcp-server: Support RFC4039 Rapid Commit Andrew Zaborowski
2021-07-23 18:23 ` [PATCH 8/8] dhcp: " Andrew Zaborowski
2021-07-28 15:42 ` Denis Kenzior [this message]
2021-07-28 17:51 ` [PATCH 1/8] dhcp-server: Add "authoritative" mode Andrew Zaborowski
2021-07-28 18:39 ` Denis Kenzior
2021-07-28 19:29 ` Andrew Zaborowski
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=fc2fc4b7-8892-81fb-1658-33fa79ab33dc@gmail.com \
--to=denkenz@gmail.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).