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.42.0


_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to