From: Marek Skrobacki via Dnsmasq-discuss <dnsmasq-discuss@lists.thekelleys.org.uk>
If the DHCP server is running inside a container or behind a load balancer, the DHCPREQUEST arriving at dnsmasq for processing may have a Server ID (option 54) configured with an IP address that is not assigned to the local interface. In this case, dnsmasq will check if the 'Server Identifier Override' option was set in the incoming packet. - If it was not set, the packet is dropped. - If it was set, dnsmasq evaluates the Server ID against the value provided in 'Server ID Override' suboption 11, as outlined in RFC5107. In both cases, there is no match against the 'backend' IP address configured on the interface. This results in the DHCPNAK being returned with the 'wrong server' message. The --dhcp-allowed-srvids option allows turning off this security mechanism for specific address(es). When enabled, the incoming DHCPREQUEST is evaluated against the provided value(s) instead of the addresses configured on the local interfaces. Signed-off-by: Marek Skrobacki <skro...@skrobul.com> --- man/dnsmasq.8 | 20 ++++++++++++++++++++ src/dnsmasq.h | 2 ++ src/option.c | 15 +++++++++++++++ src/rfc2131.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 32bdeff..d05ffc4 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -2026,6 +2026,26 @@ form is used, there must be a route to all of the addresses configured on the in The two-address form of shared-network is also usable with a DHCP relay: the first address is the address of the relay and the second, as before, specifies an extra subnet which addresses may be allocated from. +.TP +.B --dhcp-allowed-srvids[=<ip addr>] +(IPv4 Only) If the DHCP server is running inside a container or behind a load balancer, the +DHCPREQUEST arriving at dnsmasq for processing may have a Server ID (option 54) +configured with an IP address that is not assigned to the local interface. In +this case, dnsmasq will check if the 'Server Identifier Override' option was +set in the incoming packet. +.IP +If it was not set, the packet is dropped. +.IP +If it was set, dnsmasq evaluates the Server ID against the value provided in \'Server ID Override\' suboption +11, as outlined in RFC5107. +.IP +In both cases, there is no match against the \'backend\' IP address configured on the interface. +This results in the DHCPNAK being returned with the \'wrong server\' message. +.IP +The \fB\-\-dhcp\-allowed\-srvids\fP option allows turning off this security +mechanism for specific address(es). When enabled, the incoming DHCPREQUEST is +evaluated against the provided value(s) instead of the addresses configured on +the local interfaces. .TP .B \-s, --domain=<domain>[[,<address range>[,local]]|<interface>] diff --git a/src/dnsmasq.h b/src/dnsmasq.h index e455c3f..6f52e3e 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1206,11 +1206,13 @@ extern struct daemon { struct pxe_service *pxe_services; struct tag_if *tag_if; struct addr_list *override_relays; + struct addr_list *allowed_srvids; struct dhcp_relay *relay4, *relay6; struct delay_config *delay_conf; int override; int enable_pxe; int doing_ra, doing_dhcp6; + int allowing_custom_srvids; struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names; struct dhcp_netid_list *force_broadcast, *bootp_dynamic; struct hostsfile *dhcp_hosts_file, *dhcp_opts_file; diff --git a/src/option.c b/src/option.c index f4ff7c0..eafcf54 100644 --- a/src/option.c +++ b/src/option.c @@ -192,6 +192,7 @@ struct myoption { #define LOPT_NO_DHCP4 383 #define LOPT_MAX_PROCS 384 #define LOPT_DNSSEC_LIMITS 385 +#define LOPT_DHCP_AL_SVID 386 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -388,6 +389,7 @@ static const struct myoption opts[] = { "use-stale-cache", 2, 0 , LOPT_STALE_CACHE }, { "no-ident", 0, 0, LOPT_NO_IDENT }, { "max-tcp-connections", 1, 0, LOPT_MAX_PROCS }, + { "dhcp-allowed-srvids", 1, 0, LOPT_DHCP_AL_SVID }, { NULL, 0, 0, 0 } }; @@ -591,6 +593,7 @@ static struct { { LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL }, { LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL }, { LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL }, + { LOPT_DHCP_AL_SVID, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Allow these ServerIDs"), NULL }, { 0, 0, NULL, NULL, NULL } }; @@ -4720,6 +4723,18 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma break; } + case LOPT_DHCP_AL_SVID: + daemon->allowing_custom_srvids = 1; + while (arg) { + struct addr_list *new = opt_malloc(sizeof(struct addr_list)); + comma = split(arg); + if (!(inet_pton(AF_INET, arg, &new->addr) > 0)) + ret_err_free(_("bad dhcp-allowed-srvids address"), new); + new->next = daemon->allowed_srvids; + daemon->allowed_srvids = new; + arg = comma; + } + break; #endif diff --git a/src/rfc2131.c b/src/rfc2131.c index 68834ea..fd24654 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -1202,8 +1202,22 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, if (override.s_addr != 0) { - if (option_addr(opt).s_addr != override.s_addr) - return 0; + if (option_addr(opt).s_addr != override.s_addr) { + if (daemon->allowing_custom_srvids) { + struct addr_list *l; + for (l = daemon->allowed_srvids; l; l = l->next) + if (l->addr.s_addr == option_addr(opt).s_addr) { + inet_ntop(AF_INET, &l->addr.s_addr, daemon->addrbuff, ADDRSTRLEN); + my_syslog(MS_DHCP | LOG_DEBUG, _("ServerID %s is explicitly allowed."), + daemon->addrbuff); + break; + } + if (!l) + return 0; + } + else + return 0; + } } else { @@ -1230,12 +1244,28 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, override = intr->addr.in.sin_addr; else { - /* In auth mode, a REQUEST sent to the wrong server - should be faulted, so that the client establishes - communication with us, otherwise, silently ignore. */ - if (!option_bool(OPT_AUTHORITATIVE)) - return 0; - message = _("wrong server-ID"); + if (daemon->allowing_custom_srvids) { + my_syslog(MS_DHCP | LOG_DEBUG, _("checking allowed custom serverids")); + struct addr_list *l; + for (l = daemon->allowed_srvids; l; l = l->next) + if (l->addr.s_addr == option_addr(opt).s_addr) + break; + if (l) { + inet_ntop(AF_INET, &l->addr.s_addr, daemon->addrbuff, ADDRSTRLEN); + my_syslog(MS_DHCP | LOG_DEBUG, _("ServerID %s is explicitly allowed."), + daemon->addrbuff); + override = option_addr(opt); + } + else + { + /* In auth mode, a REQUEST sent to the wrong server + should be faulted, so that the client establishes + communication with us, otherwise, silently ignore. */ + if (!option_bool(OPT_AUTHORITATIVE)) + return 0; + message = _("wrong server-ID"); + } + } } } } -- 2.30.2 _______________________________________________ Dnsmasq-discuss mailing list Dnsmasq-discuss@lists.thekelleys.org.uk https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss