Blame SOURCES/dnsmasq-2.81-tag-filtering-of-dhcp-host-directives.patch

c1823a
From dd04a0d90d2fca66b5f91952ae7286c5de1714f1 Mon Sep 17 00:00:00 2001
c1823a
From: Simon Kelley <simon@thekelleys.org.uk>
c1823a
Date: Fri, 7 Feb 2020 21:05:54 +0000
c1823a
Subject: [PATCH] Add tag filtering of dhcp-host directives.
c1823a
c1823a
(cherry picked from commit 52ec7836139e7a11374971905e5ac0d2d02e32c0)
c1823a
c1823a
Conflicts:
c1823a
	CHANGELOG
c1823a
	src/rfc3315.c
c1823a
---
c1823a
 man/dnsmasq.8     |  5 ++++-
c1823a
 src/dhcp-common.c | 42 ++++++++++++++++++++++++++++++++----------
c1823a
 src/dnsmasq.h     |  4 +++-
c1823a
 src/lease.c       |  2 +-
c1823a
 src/option.c      | 14 ++++++--------
c1823a
 src/rfc2131.c     |  6 +++---
c1823a
 src/rfc3315.c     | 49 ++++++++++++++++++++++---------------------------
c1823a
 7 files changed, 71 insertions(+), 51 deletions(-)
c1823a
c1823a
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
c1823a
index 2c9d9f6..a59b06f 100644
c1823a
--- a/man/dnsmasq.8
c1823a
+++ b/man/dnsmasq.8
c1823a
@@ -953,7 +953,7 @@ is also included, as described in RFC-3775 section 7.3.
c1823a
 tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
c1823a
 
c1823a
 .TP
c1823a
-.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
c1823a
+.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
c1823a
 Specify per host parameters for the DHCP server. This allows a machine
c1823a
 with a particular hardware address to be always allocated the same
c1823a
 hostname, IP address and lease time. A hostname specified like this
c1823a
@@ -1038,6 +1038,9 @@ ignore requests from unknown machines using
c1823a
 .B --dhcp-ignore=tag:!known
c1823a
 If the host matches only a dhcp-host directive which cannot
c1823a
 be used because it specifies an address on different subnet, the tag "known-othernet" is set.
c1823a
+
c1823a
+The tag:<tag> construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones.
c1823a
+
c1823a
 Ethernet addresses (but not client-ids) may have
c1823a
 wildcard bytes, so for example 
c1823a
 .B --dhcp-host=00:20:e0:3b:13:*,ignore 
c1823a
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
c1823a
index 5d437dd..71e9e5b 100644
c1823a
--- a/src/dhcp-common.c
c1823a
+++ b/src/dhcp-common.c
c1823a
@@ -304,11 +304,12 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
c1823a
   return 0;
c1823a
 }
c1823a
 
c1823a
-struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
-				struct dhcp_context *context,
c1823a
-				unsigned char *clid, int clid_len,
c1823a
-				unsigned char *hwaddr, int hw_len, 
c1823a
-				int hw_type, char *hostname)
c1823a
+static struct dhcp_config *find_config_match(struct dhcp_config *configs,
c1823a
+					     struct dhcp_context *context,
c1823a
+					     unsigned char *clid, int clid_len,
c1823a
+					     unsigned char *hwaddr, int hw_len, 
c1823a
+					     int hw_type, char *hostname,
c1823a
+					     struct dhcp_netid *tags, int tag_not_needed)
c1823a
 {
c1823a
   int count, new;
c1823a
   struct dhcp_config *config, *candidate; 
c1823a
@@ -320,7 +321,9 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
 	{
c1823a
 	  if (config->clid_len == clid_len && 
c1823a
 	      memcmp(config->clid, clid, clid_len) == 0 &&
c1823a
-	      is_config_in_context(context, config))
c1823a
+	      is_config_in_context(context, config) &&
c1823a
+	      match_netid(config->filter, tags, tag_not_needed))
c1823a
+	    
c1823a
 	    return config;
c1823a
 	  
c1823a
 	  /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
c1823a
@@ -328,7 +331,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
 	     see lease_update_from_configs() */
c1823a
 	  if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1  &&
c1823a
 	      memcmp(config->clid, clid+1, clid_len-1) == 0 &&
c1823a
-	      is_config_in_context(context, config))
c1823a
+	      is_config_in_context(context, config) &&
c1823a
+	      match_netid(config->filter, tags, tag_not_needed))
c1823a
 	    return config;
c1823a
 	}
c1823a
   
c1823a
@@ -336,14 +340,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
   if (hwaddr)
c1823a
     for (config = configs; config; config = config->next)
c1823a
       if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
c1823a
-	  is_config_in_context(context, config))
c1823a
+	  is_config_in_context(context, config) &&
c1823a
+	  match_netid(config->filter, tags, tag_not_needed))
c1823a
 	return config;
c1823a
   
c1823a
   if (hostname && context)
c1823a
     for (config = configs; config; config = config->next)
c1823a
       if ((config->flags & CONFIG_NAME) && 
c1823a
 	  hostname_isequal(config->hostname, hostname) &&
c1823a
-	  is_config_in_context(context, config))
c1823a
+	  is_config_in_context(context, config) &&
c1823a
+	  match_netid(config->filter, tags, tag_not_needed))
c1823a
 	return config;
c1823a
 
c1823a
   
c1823a
@@ -352,7 +358,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
 
c1823a
   /* use match with fewest wildcard octets */
c1823a
   for (candidate = NULL, count = 0, config = configs; config; config = config->next)
c1823a
-    if (is_config_in_context(context, config))
c1823a
+    if (is_config_in_context(context, config) &&
c1823a
+	match_netid(config->filter, tags, tag_not_needed))
c1823a
       for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
c1823a
 	if (conf_addr->wildcard_mask != 0 &&
c1823a
 	    conf_addr->hwaddr_len == hw_len &&	
c1823a
@@ -366,6 +373,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
   return candidate;
c1823a
 }
c1823a
 
c1823a
+/* Find tagged configs first. */
c1823a
+struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
+				struct dhcp_context *context,
c1823a
+				unsigned char *clid, int clid_len,
c1823a
+				unsigned char *hwaddr, int hw_len, 
c1823a
+				int hw_type, char *hostname, struct dhcp_netid *tags)
c1823a
+{
c1823a
+  struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
c1823a
+
c1823a
+  if (!ret)
c1823a
+    ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
c1823a
+
c1823a
+  return ret;
c1823a
+}
c1823a
+
c1823a
 void dhcp_update_configs(struct dhcp_config *configs)
c1823a
 {
c1823a
   /* Some people like to keep all static IP addresses in /etc/hosts.
c1823a
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
c1823a
index 9437226..055a0d1 100644
c1823a
--- a/src/dnsmasq.h
c1823a
+++ b/src/dnsmasq.h
c1823a
@@ -749,6 +749,7 @@ struct dhcp_config {
c1823a
   unsigned char *clid;   /* clientid */
c1823a
   char *hostname, *domain;
c1823a
   struct dhcp_netid_list *netid;
c1823a
+  struct dhcp_netid *filter;
c1823a
 #ifdef HAVE_DHCP6
c1823a
   struct addrlist *addr6;
c1823a
 #endif
c1823a
@@ -1514,7 +1515,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
c1823a
 				struct dhcp_context *context,
c1823a
 				unsigned char *clid, int clid_len,
c1823a
 				unsigned char *hwaddr, int hw_len, 
c1823a
-				int hw_type, char *hostname);
c1823a
+				int hw_type, char *hostname,
c1823a
+				struct dhcp_netid *filter);
c1823a
 int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
c1823a
 #ifdef HAVE_LINUX_NETWORK
c1823a
 char *whichdevice(void);
c1823a
diff --git a/src/lease.c b/src/lease.c
c1823a
index 5c33df7..00c82f6 100644
c1823a
--- a/src/lease.c
c1823a
+++ b/src/lease.c
c1823a
@@ -222,7 +222,7 @@ void lease_update_from_configs(void)
c1823a
     if (lease->flags & (LEASE_TA | LEASE_NA))
c1823a
       continue;
c1823a
     else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, 
c1823a
-				   lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && 
c1823a
+				   lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL, NULL)) && 
c1823a
 	     (config->flags & CONFIG_NAME) &&
c1823a
 	     (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
c1823a
       lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
c1823a
diff --git a/src/option.c b/src/option.c
c1823a
index ea70ee3..88cd2ab 100644
c1823a
--- a/src/option.c
c1823a
+++ b/src/option.c
c1823a
@@ -953,8 +953,7 @@ static char *set_prefix(char *arg)
c1823a
    return arg;
c1823a
 }
c1823a
 
c1823a
-static struct dhcp_netid *
c1823a
-dhcp_netid_create(const char *net, struct dhcp_netid *next)
c1823a
+static struct dhcp_netid *dhcp_netid_create(const char *net, struct dhcp_netid *next)
c1823a
 {
c1823a
   struct dhcp_netid *tt;
c1823a
   tt = opt_malloc(sizeof (struct dhcp_netid));
c1823a
@@ -1019,7 +1018,8 @@ static void dhcp_config_free(struct dhcp_config *config)
c1823a
         }
c1823a
       
c1823a
       dhcp_netid_list_free(config->netid);
c1823a
-
c1823a
+      dhcp_netid_free(config->filter);
c1823a
+      
c1823a
       if (config->flags & CONFIG_CLID)
c1823a
         free(config->clid);
c1823a
 
c1823a
@@ -3167,6 +3167,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
c1823a
 	new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
c1823a
 	new->hwaddr = NULL;
c1823a
 	new->netid = NULL;
c1823a
+	new->filter = NULL;
c1823a
 	new->clid = NULL;
c1823a
 	new->addr6 = NULL;
c1823a
 
c1823a
@@ -3215,11 +3216,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
c1823a
 		    newlist->list = dhcp_netid_create(arg+4, NULL);
c1823a
 		  }
c1823a
 		else if (strstr(arg, "tag:") == arg)
c1823a
-		  {
c1823a
-		    
c1823a
-		    dhcp_config_free(new);
c1823a
-		    ret_err(_("cannot match tags in --dhcp-host"));
c1823a
-		  }
c1823a
+		  new->filter = dhcp_netid_create(arg+4, new->filter);
c1823a
+		  
c1823a
 #ifdef HAVE_DHCP6
c1823a
 		else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
c1823a
 		  {
c1823a
diff --git a/src/rfc2131.c b/src/rfc2131.c
c1823a
index 997575a..a741f9f 100644
c1823a
--- a/src/rfc2131.c
c1823a
+++ b/src/rfc2131.c
c1823a
@@ -479,7 +479,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
c1823a
   mess->op = BOOTREPLY;
c1823a
   
c1823a
   config = find_config(daemon->dhcp_conf, context, clid, clid_len, 
c1823a
-		       mess->chaddr, mess->hlen, mess->htype, NULL);
c1823a
+		       mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid));
c1823a
 
c1823a
   /* set "known" tag for known hosts */
c1823a
   if (config)
c1823a
@@ -489,7 +489,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
c1823a
       netid = &known_id;
c1823a
     }
c1823a
   else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len, 
c1823a
-		       mess->chaddr, mess->hlen, mess->htype, NULL))
c1823a
+		       mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid)))
c1823a
     {
c1823a
       known_id.net = "known-othernet";
c1823a
       known_id.next = netid;
c1823a
@@ -725,7 +725,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
c1823a
 		 to avoid impersonation by name. */
c1823a
 	      struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
c1823a
 						    mess->chaddr, mess->hlen, 
c1823a
-						    mess->htype, hostname);
c1823a
+						    mess->htype, hostname, run_tag_if(netid));
c1823a
 	      if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
c1823a
 		{
c1823a
 		  config = new;
c1823a
diff --git a/src/rfc3315.c b/src/rfc3315.c
c1823a
index ee58b57..a0067e9 100644
c1823a
--- a/src/rfc3315.c
c1823a
+++ b/src/rfc3315.c
c1823a
@@ -486,35 +486,29 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
c1823a
 	 }
c1823a
     }	 
c1823a
   
c1823a
-  if (state->clid)
c1823a
+  if (state->clid &&
c1823a
+      (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len,
c1823a
+			    state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags))) &&
c1823a
+      have_config(config, CONFIG_NAME))
c1823a
     {
c1823a
-      config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);
c1823a
-      
c1823a
-      if (have_config(config, CONFIG_NAME))
c1823a
-	{
c1823a
-	  state->hostname = config->hostname;
c1823a
-	  state->domain = config->domain;
c1823a
-	  state->hostname_auth = 1;
c1823a
-	}
c1823a
-      else if (state->client_hostname)
c1823a
-	{
c1823a
-	  state->domain = strip_hostname(state->client_hostname);
c1823a
+      state->hostname = config->hostname;
c1823a
+      state->domain = config->domain;
c1823a
+      state->hostname_auth = 1;
c1823a
+    }
c1823a
+  else if (state->client_hostname)
c1823a
+    {
c1823a
+      state->domain = strip_hostname(state->client_hostname);
c1823a
 	  
c1823a
-	  if (strlen(state->client_hostname) != 0)
c1823a
-	    {
c1823a
-	      state->hostname = state->client_hostname;
c1823a
-	      if (!config)
c1823a
-		{
c1823a
-		  /* Search again now we have a hostname. 
c1823a
-		     Only accept configs without CLID here, (it won't match)
c1823a
-		     to avoid impersonation by name. */
c1823a
-		  struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
c1823a
-		  if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
c1823a
-		    config = new;
c1823a
-		}
c1823a
-	    }
c1823a
+      if (strlen(state->client_hostname) != 0)
c1823a
+	{
c1823a
+	  /* Search again now we have a hostname. 
c1823a
+	     Only accept configs without CLID here, (it won't match)
c1823a
+	     to avoid impersonation by name. */
c1823a
+	  struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, run_tag_if(state->tags));
c1823a
+	  if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
c1823a
+	    config = new;
c1823a
 	}
c1823a
-    }
c1823a
+     }
c1823a
 
c1823a
   if (config)
c1823a
     {
c1823a
@@ -535,7 +529,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
c1823a
 	ignore = 1;
c1823a
     }
c1823a
   else if (state->clid &&
c1823a
-	   find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
c1823a
+	   find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len,
c1823a
+		       state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags)))
c1823a
     {
c1823a
       known_id.net = "known-othernet";
c1823a
       known_id.next = state->tags;
c1823a
-- 
c1823a
1.8.3.1
c1823a