Blame SOURCES/dnsmasq-2.80-unaligned-addresses-in-DHCPv6-packet.patch

8e0267
From 653481c6ebf46dcadb5a017085325d956dd04a28 Mon Sep 17 00:00:00 2001
8e0267
From: Simon Kelley <simon@thekelleys.org.uk>
8e0267
Date: Tue, 21 Aug 2018 22:06:36 +0100
8e0267
Subject: [PATCH] Properly deal with unaligned addresses in DHCPv6 packets.
8e0267
8e0267
Thanks to Vladislav Grishenko for spotting this.
8e0267
8e0267
(cherry picked from commit 97f876b64c22b2b18412e2e3d8506ee33e42db7c)
8e0267
8e0267
Conflicts:
8e0267
	src/rfc3315.c
8e0267
---
8e0267
 src/rfc1035.c |   2 +-
8e0267
 src/rfc3315.c | 101 ++++++++++++++++++++++++++++++++++------------------------
8e0267
 2 files changed, 61 insertions(+), 42 deletions(-)
8e0267
8e0267
diff --git a/src/rfc1035.c b/src/rfc1035.c
8e0267
index 6b3bb27..ee5f7a0 100644
8e0267
--- a/src/rfc1035.c
8e0267
+++ b/src/rfc1035.c
8e0267
@@ -1376,7 +1376,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
8e0267
 		    if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
8e0267
 					    daemon->local_ttl, NULL,
8e0267
 					    t->class, C_IN, "t", t->len, t->txt))
8e0267
-		      anscount ++;
8e0267
+		      anscount++;
8e0267
 		  }
8e0267
 	      }
8e0267
 		
8e0267
diff --git a/src/rfc3315.c b/src/rfc3315.c
8e0267
index 21fcd9b..ee1cf17 100644
8e0267
--- a/src/rfc3315.c
8e0267
+++ b/src/rfc3315.c
8e0267
@@ -639,9 +639,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 	    int plain_range = 1;
8e0267
 	    u32 lease_time;
8e0267
 	    struct dhcp_lease *ltmp;
8e0267
-	    struct in6_addr *req_addr;
8e0267
-	    struct in6_addr addr;
8e0267
-
8e0267
+	    struct in6_addr req_addr, addr;
8e0267
+	    
8e0267
 	    if (!check_ia(state, opt, &ia_end, &ia_option))
8e0267
 	      continue;
8e0267
 	    
8e0267
@@ -709,9 +708,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 
8e0267
 	    for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
8e0267
 	      {
8e0267
-		req_addr = opt6_ptr(ia_option, 0);
8e0267
+		/* worry about alignment here. */
8e0267
+		memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
8e0267
 				
8e0267
-		if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
8e0267
+		if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
8e0267
 		  {
8e0267
 		    lease_time = c->lease_time;
8e0267
 		    /* If the client asks for an address on the same network as a configured address, 
8e0267
@@ -719,14 +719,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		       addresses automatic. */
8e0267
 		    if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
8e0267
 		      {
8e0267
-			req_addr = &addr;
8e0267
+			req_addr = addr;
8e0267
 			mark_config_used(c, &addr);
8e0267
 			if (have_config(config, CONFIG_TIME))
8e0267
 			  lease_time = config->lease_time;
8e0267
 		      }
8e0267
-		    else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
8e0267
+		    else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
8e0267
 		      continue; /* not an address we're allowed */
8e0267
-		    else if (!check_address(state, req_addr))
8e0267
+		    else if (!check_address(state, &req_addr))
8e0267
 		      continue; /* address leased elsewhere */
8e0267
 		    
8e0267
 		    /* add address to output packet */
8e0267
@@ -734,8 +734,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		    if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
8e0267
 		      state->send_prefix_class = prefix_class_from_context(c);
8e0267
 #endif		    
8e0267
-		    add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
8e0267
-		    mark_context_used(state, req_addr);
8e0267
+		    add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
8e0267
+		    mark_context_used(state, &req_addr);
8e0267
 		    get_context_tag(state, c);
8e0267
 		    address_assigned = 1;
8e0267
 		  }
8e0267
@@ -768,15 +768,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 	    ltmp = NULL;
8e0267
 	    while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
8e0267
 	      {
8e0267
-		req_addr = &ltmp->addr6;
8e0267
-		if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
8e0267
+		req_addr = ltmp->addr6;
8e0267
+		if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
8e0267
 		  {
8e0267
 #ifdef OPTION6_PREFIX_CLASS
8e0267
 		    if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
8e0267
 		      state->send_prefix_class = prefix_class_from_context(c);
8e0267
 #endif
8e0267
-		    add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now);
8e0267
-		    mark_context_used(state, req_addr);
8e0267
+		    add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
8e0267
+		    mark_context_used(state, &req_addr);
8e0267
 		    get_context_tag(state, c);
8e0267
 		    address_assigned = 1;
8e0267
 		  }
8e0267
@@ -892,16 +892,19 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 	      
8e0267
 	    for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
8e0267
 	      {
8e0267
-		struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
8e0267
+		struct in6_addr req_addr;
8e0267
 		struct dhcp_context *dynamic, *c;
8e0267
 		unsigned int lease_time;
8e0267
 		struct in6_addr addr;
8e0267
 		int config_ok = 0;
8e0267
+
8e0267
+		/* align. */
8e0267
+		memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
8e0267
 		
8e0267
-		if ((c = address6_valid(state->context, req_addr, tagif, 1)))
8e0267
-		  config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
8e0267
+		if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
8e0267
+		  config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr);
8e0267
 		
8e0267
-		if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
8e0267
+		if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
8e0267
 		  {
8e0267
 		    if (!dynamic && !config_ok)
8e0267
 		      {
8e0267
@@ -911,7 +914,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 			put_opt6_string(_("address unavailable"));
8e0267
 			end_opt6(o1);
8e0267
 		      }
8e0267
-		    else if (!check_address(state, req_addr))
8e0267
+		    else if (!check_address(state, &req_addr))
8e0267
 		      {
8e0267
 			/* Address leased to another DUID/IAID */
8e0267
 			o1 = new_opt6(OPTION6_STATUS_CODE);
8e0267
@@ -933,7 +936,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 			if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
8e0267
 			  state->send_prefix_class = prefix_class_from_context(c);
8e0267
 #endif
8e0267
-			add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now);
8e0267
+			add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
8e0267
 			get_context_tag(state, dynamic);
8e0267
 			address_assigned = 1;
8e0267
 		      }
8e0267
@@ -996,15 +999,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 	    for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
8e0267
 	      {
8e0267
 		struct dhcp_lease *lease = NULL;
8e0267
-		struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
8e0267
+		struct in6_addr req_addr;
8e0267
 		unsigned int preferred_time =  opt6_uint(ia_option, 16, 4);
8e0267
 		unsigned int valid_time =  opt6_uint(ia_option, 20, 4);
8e0267
 		char *message = NULL;
8e0267
 		struct dhcp_context *this_context;
8e0267
+
8e0267
+		memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); 
8e0267
 		
8e0267
 		if (!(lease = lease6_find(state->clid, state->clid_len,
8e0267
 					  state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, 
8e0267
-					  state->iaid, req_addr)))
8e0267
+					  state->iaid, &req_addr)))
8e0267
 		  {
8e0267
 		    /* If the server cannot find a client entry for the IA the server
8e0267
 		       returns the IA containing no addresses with a Status Code option set
8e0267
@@ -1012,7 +1017,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		    save_counter(iacntr);
8e0267
 		    t1cntr = 0;
8e0267
 		    
8e0267
-		    log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
8e0267
+		    log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
8e0267
 		    
8e0267
 		    o1 = new_opt6(OPTION6_STATUS_CODE);
8e0267
 		    put_opt6_short(DHCP6NOBINDING);
8e0267
@@ -1024,15 +1029,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		  }
8e0267
 		
8e0267
 		
8e0267
-		if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
8e0267
-		    (this_context = address6_valid(state->context, req_addr, tagif, 1)))
8e0267
+		if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
8e0267
+		    (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
8e0267
 		  {
8e0267
 		    struct in6_addr addr;
8e0267
 		    unsigned int lease_time;
8e0267
 
8e0267
 		    get_context_tag(state, this_context);
8e0267
 		    
8e0267
-		    if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
8e0267
+		    if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
8e0267
 		      lease_time = config->lease_time;
8e0267
 		    else 
8e0267
 		      lease_time = this_context->lease_time;
8e0267
@@ -1045,7 +1050,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		      lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
8e0267
 		    if (state->ia_type == OPTION6_IA_NA && state->hostname)
8e0267
 		      {
8e0267
-			char *addr_domain = get_domain6(req_addr);
8e0267
+			char *addr_domain = get_domain6(&req_addr);
8e0267
 			if (!state->send_domain)
8e0267
 			  state->send_domain = addr_domain;
8e0267
 			lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain); 
8e0267
@@ -1063,12 +1068,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		  } 
8e0267
 
8e0267
 		if (message && (message != state->hostname))
8e0267
-		  log6_packet(state, "DHCPREPLY", req_addr, message);	
8e0267
+		  log6_packet(state, "DHCPREPLY", &req_addr, message);	
8e0267
 		else
8e0267
-		  log6_quiet(state, "DHCPREPLY", req_addr, message);
8e0267
+		  log6_quiet(state, "DHCPREPLY", &req_addr, message);
8e0267
 	
8e0267
 		o1 =  new_opt6(OPTION6_IAADDR);
8e0267
-		put_opt6(req_addr, sizeof(*req_addr));
8e0267
+		put_opt6(&req_addr, sizeof(req_addr));
8e0267
 		put_opt6_long(preferred_time);
8e0267
 		put_opt6_long(valid_time);
8e0267
 		end_opt6(o1);
8e0267
@@ -1100,19 +1105,23 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		 ia_option;
8e0267
 		 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
8e0267
 	      {
8e0267
-		struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
8e0267
+		struct in6_addr req_addr;
8e0267
+
8e0267
+		/* alignment */
8e0267
+		memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
8e0267
 		
8e0267
-		if (!address6_valid(state->context, req_addr, tagif, 1))
8e0267
+		if (!address6_valid(state->context, &req_addr, tagif, 1))
8e0267
 		  {
8e0267
 		    o1 = new_opt6(OPTION6_STATUS_CODE);
8e0267
 		    put_opt6_short(DHCP6NOTONLINK);
8e0267
 		    put_opt6_string(_("confirm failed"));
8e0267
 		    end_opt6(o1);
8e0267
+		    log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
8e0267
 		    return 1;
8e0267
 		  }
8e0267
 
8e0267
 		good_addr = 1;
8e0267
-		log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
8e0267
+		log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
8e0267
 	      }
8e0267
 	  }	 
8e0267
 	
8e0267
@@ -1171,9 +1180,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
8e0267
 	      {
8e0267
 		struct dhcp_lease *lease;
8e0267
-		
8e0267
+		struct in6_addr addr;
8e0267
+
8e0267
+		/* align */
8e0267
+		memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
8e0267
 		if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
8e0267
-					 state->iaid, opt6_ptr(ia_option, 0))))
8e0267
+					 state->iaid, &addr)))
8e0267
 		  lease_prune(lease, now);
8e0267
 		else
8e0267
 		  {
8e0267
@@ -1233,12 +1245,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
8e0267
 	      {
8e0267
 		struct dhcp_lease *lease;
8e0267
-		struct in6_addr *addrp = opt6_ptr(ia_option, 0);
8e0267
+		struct in6_addr addr;
8e0267
 
8e0267
-		if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
8e0267
+		/* align */
8e0267
+		memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
8e0267
+
8e0267
+		if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
8e0267
 		  {
8e0267
 		    prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
8e0267
-		    inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
8e0267
+		    inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
8e0267
 		    my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), 
8e0267
 			      daemon->addrbuff, daemon->dhcp_buff3);
8e0267
 		    config->flags |= CONFIG_DECLINED;
8e0267
@@ -1250,7 +1265,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		    context_tmp->addr_epoch++;
8e0267
 		
8e0267
 		if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
8e0267
-					 state->iaid, opt6_ptr(ia_option, 0))))
8e0267
+					 state->iaid, &addr)))
8e0267
 		  lease_prune(lease, now);
8e0267
 		else
8e0267
 		  {
8e0267
@@ -1267,7 +1282,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
8e0267
 		      }
8e0267
 		    
8e0267
 		    o1 = new_opt6(OPTION6_IAADDR);
8e0267
-		    put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
8e0267
+		    put_opt6(&addr, IN6ADDRSZ);
8e0267
 		    put_opt6_long(0);
8e0267
 		    put_opt6_long(0);
8e0267
 		    end_opt6(o1);
8e0267
@@ -1935,7 +1950,11 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
8e0267
 	}
8e0267
       else if (type == OPTION6_IAADDR)
8e0267
 	{
8e0267
-	  inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
8e0267
+	  struct in6_addr addr;
8e0267
+
8e0267
+	  /* align */
8e0267
+	  memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
8e0267
+	  inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
8e0267
 	  sprintf(daemon->namebuff, "%s PL=%u VL=%u", 
8e0267
 		  daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
8e0267
 	  optname = "iaaddr";
8e0267
-- 
8e0267
1.8.3.1
8e0267