Blame SOURCES/dnsmasq-2.66-dhcp-match-now-work-with-BOOTP.patch

cab8d5
From 86e92f998379d219e10517dfa2c42f544ba164ce Mon Sep 17 00:00:00 2001
cab8d5
From: Simon Kelley <simon@thekelleys.org.uk>
cab8d5
Date: Tue, 23 Apr 2013 11:31:39 +0100
cab8d5
Subject: [PATCH] --dhcp-match et al now work with BOOTP as well as DHCP.
cab8d5
cab8d5
---
cab8d5
 CHANGELOG     |   4 ++
cab8d5
 src/rfc2131.c | 227 +++++++++++++++++++++++++++++-----------------------------
cab8d5
 2 files changed, 117 insertions(+), 114 deletions(-)
cab8d5
cab8d5
diff --git a/CHANGELOG b/CHANGELOG
cab8d5
index 268b64d..0a34b64 100644
cab8d5
--- a/CHANGELOG
cab8d5
+++ b/CHANGELOG
cab8d5
@@ -11,6 +11,10 @@ version 2.67
cab8d5
 	    lease-time only if it's specifically requested
cab8d5
 	    (maintaining standards) and the dhcp_lease_time utility
cab8d5
 	    has been taught to ask for it (restoring functionality). 
cab8d5
+
cab8d5
+	    Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
cab8d5
+	    to work with BOOTP and well as DHCP. Thanks to Peter
cab8d5
+	    Korsgaard for spotting the problem. 
cab8d5
 	
cab8d5
 
cab8d5
 version 2.66
cab8d5
diff --git a/src/rfc2131.c b/src/rfc2131.c
cab8d5
index 013a446..54e444b 100644
cab8d5
--- a/src/rfc2131.c
cab8d5
+++ b/src/rfc2131.c
cab8d5
@@ -355,6 +355,117 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
cab8d5
 		      ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
cab8d5
 	}
cab8d5
     }
cab8d5
+  
cab8d5
+  /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
cab8d5
+     Otherwise assume the option is an array, and look for a matching element. 
cab8d5
+     If no data given, existance of the option is enough. This code handles 
cab8d5
+     rfc3925 V-I classes too. */
cab8d5
+  for (o = daemon->dhcp_match; o; o = o->next)
cab8d5
+    {
cab8d5
+      unsigned int len, elen, match = 0;
cab8d5
+      size_t offset, o2;
cab8d5
+
cab8d5
+      if (o->flags & DHOPT_RFC3925)
cab8d5
+	{
cab8d5
+	  if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
cab8d5
+	    continue;
cab8d5
+	  
cab8d5
+	  for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
cab8d5
+	    {
cab8d5
+	      len = option_uint(opt, offset + 4 , 1);
cab8d5
+	      /* Need to take care that bad data can't run us off the end of the packet */
cab8d5
+	      if ((offset + len + 5 <= (option_len(opt))) &&
cab8d5
+		  (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
cab8d5
+		for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
cab8d5
+		  { 
cab8d5
+		    elen = option_uint(opt, o2, 1);
cab8d5
+		    if ((o2 + elen + 1 <= option_len(opt)) &&
cab8d5
+			(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
cab8d5
+		      break;
cab8d5
+		  }
cab8d5
+	      if (match) 
cab8d5
+		break;
cab8d5
+	    }	  
cab8d5
+	}
cab8d5
+      else
cab8d5
+	{
cab8d5
+	  if (!(opt = option_find(mess, sz, o->opt, 1)))
cab8d5
+	    continue;
cab8d5
+	  
cab8d5
+	  match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
cab8d5
+	} 
cab8d5
+
cab8d5
+      if (match)
cab8d5
+	{
cab8d5
+	  o->netid->next = netid;
cab8d5
+	  netid = o->netid;
cab8d5
+	}
cab8d5
+    }
cab8d5
+	
cab8d5
+  /* user-class options are, according to RFC3004, supposed to contain
cab8d5
+     a set of counted strings. Here we check that this is so (by seeing
cab8d5
+     if the counts are consistent with the overall option length) and if
cab8d5
+     so zero the counts so that we don't get spurious matches between 
cab8d5
+     the vendor string and the counts. If the lengths don't add up, we
cab8d5
+     assume that the option is a single string and non RFC3004 compliant 
cab8d5
+     and just do the substring match. dhclient provides these broken options.
cab8d5
+     The code, later, which sends user-class data to the lease-change script
cab8d5
+     relies on the transformation done here.
cab8d5
+  */
cab8d5
+
cab8d5
+  if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
cab8d5
+    {
cab8d5
+      unsigned char *ucp = option_ptr(opt, 0);
cab8d5
+      int tmp, j;
cab8d5
+      for (j = 0; j < option_len(opt); j += ucp[j] + 1);
cab8d5
+      if (j == option_len(opt))
cab8d5
+	for (j = 0; j < option_len(opt); j = tmp)
cab8d5
+	  {
cab8d5
+	    tmp = j + ucp[j] + 1;
cab8d5
+	    ucp[j] = 0;
cab8d5
+	  }
cab8d5
+    }
cab8d5
+    
cab8d5
+  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
cab8d5
+    {
cab8d5
+      int mopt;
cab8d5
+      
cab8d5
+      if (vendor->match_type == MATCH_VENDOR)
cab8d5
+	mopt = OPTION_VENDOR_ID;
cab8d5
+      else if (vendor->match_type == MATCH_USER)
cab8d5
+	mopt = OPTION_USER_CLASS; 
cab8d5
+      else
cab8d5
+	continue;
cab8d5
+
cab8d5
+      if ((opt = option_find(mess, sz, mopt, 1)))
cab8d5
+	{
cab8d5
+	  int i;
cab8d5
+	  for (i = 0; i <= (option_len(opt) - vendor->len); i++)
cab8d5
+	    if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
cab8d5
+	      {
cab8d5
+		vendor->netid.next = netid;
cab8d5
+		netid = &vendor->netid;
cab8d5
+		break;
cab8d5
+	      }
cab8d5
+	}
cab8d5
+    }
cab8d5
+
cab8d5
+  /* mark vendor-encapsulated options which match the client-supplied vendor class,
cab8d5
+     save client-supplied vendor class */
cab8d5
+  if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
cab8d5
+    {
cab8d5
+      memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
cab8d5
+      vendor_class_len = option_len(opt);
cab8d5
+    }
cab8d5
+  match_vendor_opts(opt, daemon->dhcp_opts);
cab8d5
+  
cab8d5
+  if (option_bool(OPT_LOG_OPTS))
cab8d5
+    {
cab8d5
+      if (sanitise(opt, daemon->namebuff))
cab8d5
+	my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
cab8d5
+      if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
cab8d5
+	my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
cab8d5
+    }
cab8d5
 
cab8d5
   mess->op = BOOTREPLY;
cab8d5
   
cab8d5
@@ -494,9 +605,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
cab8d5
 	      lease_set_interface(lease, int_index, now);
cab8d5
 	      
cab8d5
 	      clear_packet(mess, end);
cab8d5
-	      match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
cab8d5
 	      do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 
cab8d5
-			 netid, subnet_addr, 0, 0, -1, NULL, 0, now);
cab8d5
+			 netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
cab8d5
 	    }
cab8d5
 	}
cab8d5
       
cab8d5
@@ -623,119 +733,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
cab8d5
 	}
cab8d5
     }
cab8d5
   
cab8d5
-  /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
cab8d5
-     Otherwise assume the option is an array, and look for a matching element. 
cab8d5
-     If no data given, existance of the option is enough. This code handles 
cab8d5
-     rfc3925 V-I classes too. */
cab8d5
-  for (o = daemon->dhcp_match; o; o = o->next)
cab8d5
-    {
cab8d5
-      unsigned int len, elen, match = 0;
cab8d5
-      size_t offset, o2;
cab8d5
-
cab8d5
-      if (o->flags & DHOPT_RFC3925)
cab8d5
-	{
cab8d5
-	  if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
cab8d5
-	    continue;
cab8d5
-	  
cab8d5
-	  for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
cab8d5
-	    {
cab8d5
-	      len = option_uint(opt, offset + 4 , 1);
cab8d5
-	      /* Need to take care that bad data can't run us off the end of the packet */
cab8d5
-	      if ((offset + len + 5 <= (option_len(opt))) &&
cab8d5
-		  (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
cab8d5
-		for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
cab8d5
-		  { 
cab8d5
-		    elen = option_uint(opt, o2, 1);
cab8d5
-		    if ((o2 + elen + 1 <= option_len(opt)) &&
cab8d5
-			(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
cab8d5
-		      break;
cab8d5
-		  }
cab8d5
-	      if (match) 
cab8d5
-		break;
cab8d5
-	    }	  
cab8d5
-	}
cab8d5
-      else
cab8d5
-	{
cab8d5
-	  if (!(opt = option_find(mess, sz, o->opt, 1)))
cab8d5
-	    continue;
cab8d5
-	  
cab8d5
-	  match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
cab8d5
-	} 
cab8d5
-
cab8d5
-      if (match)
cab8d5
-	{
cab8d5
-	  o->netid->next = netid;
cab8d5
-	  netid = o->netid;
cab8d5
-	}
cab8d5
-    }
cab8d5
-	
cab8d5
-  /* user-class options are, according to RFC3004, supposed to contain
cab8d5
-     a set of counted strings. Here we check that this is so (by seeing
cab8d5
-     if the counts are consistent with the overall option length) and if
cab8d5
-     so zero the counts so that we don't get spurious matches between 
cab8d5
-     the vendor string and the counts. If the lengths don't add up, we
cab8d5
-     assume that the option is a single string and non RFC3004 compliant 
cab8d5
-     and just do the substring match. dhclient provides these broken options.
cab8d5
-     The code, later, which sends user-class data to the lease-change script
cab8d5
-     relies on the transformation done here.
cab8d5
-  */
cab8d5
-
cab8d5
-  if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
cab8d5
-    {
cab8d5
-      unsigned char *ucp = option_ptr(opt, 0);
cab8d5
-      int tmp, j;
cab8d5
-      for (j = 0; j < option_len(opt); j += ucp[j] + 1);
cab8d5
-      if (j == option_len(opt))
cab8d5
-	for (j = 0; j < option_len(opt); j = tmp)
cab8d5
-	  {
cab8d5
-	    tmp = j + ucp[j] + 1;
cab8d5
-	    ucp[j] = 0;
cab8d5
-	  }
cab8d5
-    }
cab8d5
-    
cab8d5
-  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
cab8d5
-    {
cab8d5
-      int mopt;
cab8d5
-      
cab8d5
-      if (vendor->match_type == MATCH_VENDOR)
cab8d5
-	mopt = OPTION_VENDOR_ID;
cab8d5
-      else if (vendor->match_type == MATCH_USER)
cab8d5
-	mopt = OPTION_USER_CLASS; 
cab8d5
-      else
cab8d5
-	continue;
cab8d5
-
cab8d5
-      if ((opt = option_find(mess, sz, mopt, 1)))
cab8d5
-	{
cab8d5
-	  int i;
cab8d5
-	  for (i = 0; i <= (option_len(opt) - vendor->len); i++)
cab8d5
-	    if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
cab8d5
-	      {
cab8d5
-		vendor->netid.next = netid;
cab8d5
-		netid = &vendor->netid;
cab8d5
-		break;
cab8d5
-	      }
cab8d5
-	}
cab8d5
-    }
cab8d5
-
cab8d5
-  /* mark vendor-encapsulated options which match the client-supplied vendor class,
cab8d5
-     save client-supplied vendor class */
cab8d5
-  if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
cab8d5
-    {
cab8d5
-      memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
cab8d5
-      vendor_class_len = option_len(opt);
cab8d5
-    }
cab8d5
-  match_vendor_opts(opt, daemon->dhcp_opts);
cab8d5
-  
cab8d5
-  if (option_bool(OPT_LOG_OPTS))
cab8d5
-    {
cab8d5
-      if (sanitise(opt, daemon->namebuff))
cab8d5
-	my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
cab8d5
-      if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
cab8d5
-	my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
cab8d5
-    }
cab8d5
-
cab8d5
   tagif_netid = run_tag_if(netid);
cab8d5
-
cab8d5
+  
cab8d5
   /* if all the netids in the ignore list are present, ignore this client */
cab8d5
   for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
cab8d5
     if (match_netid(id_list->list, tagif_netid, 0))
cab8d5
-- 
cab8d5
1.8.1.4
cab8d5