From ab194ed7ca433e4e2e8b2ec338bfa4e6aa886a4b Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Tue, 1 Jan 2019 01:35:30 +0000
Subject: [PATCH 20/32] Futher address union tidying.

Pass DNSKEY and DS data into cache_insert via the address argument,
now these data types are included in struct all_addr.

Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
---
 src/cache.c   | 116 ++++++++++++++++----------------------------------
 src/dnsmasq.h |  26 +++++------
 src/dnssec.c  |  53 +++++++++++------------
 3 files changed, 73 insertions(+), 122 deletions(-)

--- a/src/cache.c
+++ b/src/cache.c
@@ -202,9 +202,9 @@ static void cache_hash(struct crec *crec
 static void cache_blockdata_free(struct crec *crecp)
 {
   if (crecp->flags & F_DNSKEY)
-    blockdata_free(crecp->addr.key.keydata);
+    blockdata_free(crecp->addr.addr.addr.key.keydata);
   else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
-    blockdata_free(crecp->addr.ds.keydata);
+    blockdata_free(crecp->addr.addr.addr.ds.keydata);
 }
 #endif
 
@@ -659,33 +659,22 @@ void cache_end_insert(void)
 	      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
 	      read_write(daemon->pipe_to_parent, (unsigned  char *)&flags, sizeof(flags), 0);
 
-	      if (flags & (F_IPV4 | F_IPV6))
+	      if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
 		read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
 #ifdef HAVE_DNSSEC
-	      else if (flags & F_DNSKEY)
+	      if (flags & F_DNSKEY)
 		{
 		  read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
-		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.algo, sizeof(new_chain->addr.key.algo), 0);
-		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keytag, sizeof(new_chain->addr.key.keytag), 0);
-		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.flags, sizeof(new_chain->addr.key.flags), 0);
-		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keylen, sizeof(new_chain->addr.key.keylen), 0);
-		  blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
+		  blockdata_write(new_chain->addr.addr.addr.key.keydata, new_chain->addr.addr.addr.key.keylen, daemon->pipe_to_parent);
 		}
 	      else if (flags & F_DS)
 		{
 		  read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
 		  /* A negative DS entry is possible and has no data, obviously. */
 		  if (!(flags & F_NEG))
-		    {
-		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.algo, sizeof(new_chain->addr.ds.algo), 0);
-		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keytag, sizeof(new_chain->addr.ds.keytag), 0);
-		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.digest, sizeof(new_chain->addr.ds.digest), 0);
-		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keylen, sizeof(new_chain->addr.ds.keylen), 0);
-		      blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
-		    }
+		    blockdata_write(new_chain->addr.addr.addr.ds.keydata, new_chain->addr.addr.addr.ds.keylen, daemon->pipe_to_parent);
 		}
 #endif
-	      
 	    }
 	}
       
@@ -736,11 +725,30 @@ int cache_recv_insert(time_t now, int fd
 
       ttl = difftime(ttd, now);
       
-      if (flags & (F_IPV4 | F_IPV6))
+      if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
 	{
+	  unsigned short class = C_IN;
+
 	  if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
 	    return 0;
-	  crecp = really_insert(daemon->namebuff, &addr, C_IN, now, ttl, flags);
+	  
+#ifdef HAVE_DNSSEC
+	   if (flags & F_DNSKEY)
+	     {
+	       if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
+		   !(addr.addr.key.keydata = blockdata_read(fd, addr.addr.key.keylen)))
+		 return 0;
+	     }
+	   else  if (flags & F_DS)
+	     {
+	        if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
+		   (flags & F_NEG) ||
+		    !(addr.addr.key.keydata = blockdata_read(fd, addr.addr.key.keylen)))
+		  return 0;
+	     }
+#endif
+	       
+	  crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
 	}
       else if (flags & F_CNAME)
 	{
@@ -764,58 +772,6 @@ int cache_recv_insert(time_t now, int fd
 		}
 	    }
 	}
-#ifdef HAVE_DNSSEC
-      else if (flags & (F_DNSKEY | F_DS))
-	{
-	  unsigned short class, keylen, keyflags, keytag;
-	  unsigned char algo, digest;
-	  struct blockdata *keydata;
-	  
-	  if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1))
-	    return 0;
-	 
-	  crecp = really_insert(daemon->namebuff, NULL, class, now, ttl, flags);
-	    
-	  if (flags & F_DNSKEY)
-	    {
-	      if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) ||
-		  !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) ||
-		  !read_write(fd, (unsigned char *)&keyflags, sizeof(keyflags), 1) ||
-		  !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) ||
-		  !(keydata = blockdata_read(fd, keylen)))
-		return 0;
-	    }
-	  else if (!(flags & F_NEG))
-	    {
-	      if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) ||
-		  !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) ||
-		  !read_write(fd, (unsigned char *)&digest, sizeof(digest), 1) ||
-		  !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) ||
-		  !(keydata = blockdata_read(fd, keylen)))
-		return 0;
-	    }
-
-	  if (crecp)
-	    {
-	       if (flags & F_DNSKEY)
-		 {
-		   crecp->addr.key.algo = algo;
-		   crecp->addr.key.keytag = keytag;
-		   crecp->addr.key.flags = flags;
-		   crecp->addr.key.keylen = keylen;
-		   crecp->addr.key.keydata = keydata;
-		 }
-	       else if (!(flags & F_NEG))
-		 {
-		   crecp->addr.ds.algo = algo;
-		   crecp->addr.ds.keytag = keytag;
-		   crecp->addr.ds.digest = digest;
-		   crecp->addr.ds.keylen = keylen;
-		   crecp->addr.ds.keydata = keydata;
-		 }
-	    }
-	}
-#endif
     }
 }
 	
@@ -1290,15 +1246,15 @@ void cache_reload(void)
 #ifdef HAVE_DNSSEC
   for (ds = daemon->ds; ds; ds = ds->next)
     if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
-	(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
+	(cache->addr.addr.addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
       {
 	cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
 	cache->ttd = daemon->local_ttl;
 	cache->name.namep = ds->name;
-	cache->addr.ds.keylen = ds->digestlen;
-	cache->addr.ds.algo = ds->algo;
-	cache->addr.ds.keytag = ds->keytag;
-	cache->addr.ds.digest = ds->digest_type;
+	cache->addr.addr.addr.ds.keylen = ds->digestlen;
+	cache->addr.addr.addr.ds.algo = ds->algo;
+	cache->addr.addr.addr.ds.keytag = ds->keytag;
+	cache->addr.addr.addr.ds.digest = ds->digest_type;
 	cache->uid = ds->class;
 	cache_hash(cache);
 	make_non_terminals(cache);
@@ -1775,12 +1731,12 @@ void dump_cache(time_t now)
 	    else if (cache->flags & F_DS)
 	      {
 		if (!(cache->flags & F_NEG))
-		  sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
-			  cache->addr.ds.algo, cache->addr.ds.digest);
+		  sprintf(a, "%5u %3u %3u", cache->addr.addr.addr.ds.keytag,
+			  cache->addr.addr.addr.ds.algo, cache->addr.addr.addr.ds.digest);
 	      }
 	    else if (cache->flags & F_DNSKEY)
-	      sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
-		      cache->addr.key.algo, cache->addr.key.flags);
+	      sprintf(a, "%5u %3u %3u", cache->addr.addr.addr.key.keytag,
+		      cache->addr.addr.addr.key.algo, cache->addr.addr.addr.key.flags);
 #endif
 	    else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
 	      { 
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -277,14 +277,21 @@ struct all_addr {
   union {
     struct in_addr addr4;
     struct in6_addr addr6;
+    struct {
+      struct blockdata *keydata;
+      unsigned short keylen, flags, keytag;
+      unsigned char algo;
+    } key; 
+    struct {
+      struct blockdata *keydata;
+      unsigned short keylen, keytag;
+      unsigned char algo;
+      unsigned char digest; 
+    } ds;
     /* for log_query */
     struct {
       unsigned short keytag, algo, digest, rcode;
     } log;
-    /* for cache_insert of DNSKEY, DS */
-    struct {
-      unsigned short class, type;
-    } dnssec;      
   } addr;
 };
 
@@ -414,17 +421,6 @@ struct crec {
       } target;
       unsigned int uid; /* 0 if union is interface-name */
     } cname;
-    struct {
-      struct blockdata *keydata;
-      unsigned short keylen, flags, keytag;
-      unsigned char algo;
-    } key; 
-    struct {
-      struct blockdata *keydata;
-      unsigned short keylen, keytag;
-      unsigned char algo;
-      unsigned char digest; 
-    } ds; 
   } addr;
   time_t ttd; /* time to die */
   /* used as class if DNSKEY/DS, index to source for F_HOSTS */
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -628,10 +628,10 @@ static int validate_rrset(time_t now, st
 	{
 	  /* iterate through all possible keys 4035 5.3.1 */
 	  for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
-	    if (crecp->addr.key.algo == algo && 
-		crecp->addr.key.keytag == key_tag &&
+	    if (crecp->addr.addr.addr.key.algo == algo && 
+		crecp->addr.addr.addr.key.keytag == key_tag &&
 		crecp->uid == (unsigned int)class &&
-		verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
+		verify(crecp->addr.addr.addr.key.keydata, crecp->addr.addr.addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
 	      return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
 	}
     }
@@ -728,10 +728,10 @@ int dnssec_validate_by_ds(time_t now, st
 	  const struct nettle_hash *hash;
 	  int sigcnt, rrcnt;
 
-	  if (recp1->addr.ds.algo == algo && 
-	      recp1->addr.ds.keytag == keytag &&
+	  if (recp1->addr.addr.addr.ds.algo == algo && 
+	      recp1->addr.addr.addr.ds.keytag == keytag &&
 	      recp1->uid == (unsigned int)class &&
-	      (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
+	      (hash = hash_find(ds_digest_name(recp1->addr.addr.addr.ds.digest))) &&
 	      hash_init(hash, &ctx, &digest))
 	    
 	    {
@@ -746,9 +746,9 @@ int dnssec_validate_by_ds(time_t now, st
 	      from_wire(name);
 	      
 	      if (!(recp1->flags & F_NEG) &&
-		  recp1->addr.ds.keylen == (int)hash->digest_size &&
-		  (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
-		  memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
+		  recp1->addr.addr.addr.ds.keylen == (int)hash->digest_size &&
+		  (ds_digest = blockdata_retrieve(recp1->addr.addr.addr.ds.keydata, recp1->addr.addr.addr.ds.keylen, NULL)) &&
+		  memcmp(ds_digest, digest, recp1->addr.addr.addr.ds.keylen) == 0 &&
 		  explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
 		  sigcnt != 0 && rrcnt != 0 &&
 		  validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname, 
@@ -800,7 +800,13 @@ int dnssec_validate_by_ds(time_t now, st
 		  
 		  if ((key = blockdata_alloc((char*)p, rdlen - 4)))
 		    {
-		      if (!(recp1 = cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
+		      a.addr.key.keylen = rdlen - 4;
+		      a.addr.key.keydata = key;
+		      a.addr.key.algo = algo;
+		      a.addr.key.keytag = keytag;
+		      a.addr.key.flags = flags;
+		      
+		      if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK))
 			{
 			  blockdata_free(key);
 			  return STAT_BOGUS;
@@ -813,12 +819,6 @@ int dnssec_validate_by_ds(time_t now, st
 			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
 			  else
 			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
-			  
-			  recp1->addr.key.keylen = rdlen - 4;
-			  recp1->addr.key.keydata = key;
-			  recp1->addr.key.algo = algo;
-			  recp1->addr.key.keytag = keytag;
-			  recp1->addr.key.flags = flags;
 			}
 		    }
 		}
@@ -915,8 +915,7 @@ int dnssec_validate_ds(time_t now, struc
 	      int algo, digest, keytag;
 	      unsigned char *psave = p;
 	      struct blockdata *key;
-	      struct crec *crecp;
-
+	   
 	      if (rdlen < 4)
 		return STAT_BOGUS; /* bad packet */
 	      
@@ -926,7 +925,13 @@ int dnssec_validate_ds(time_t now, struc
 	      
 	      if ((key = blockdata_alloc((char*)p, rdlen - 4)))
 		{
-		  if (!(crecp = cache_insert(name, NULL, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
+		  a.addr.ds.digest = digest;
+		  a.addr.ds.keydata = key;
+		  a.addr.ds.algo = algo;
+		  a.addr.ds.keytag = keytag;
+		  a.addr.ds.keylen = rdlen - 4;
+
+		  if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
 		    {
 		      blockdata_free(key);
 		      return STAT_BOGUS;
@@ -940,12 +945,6 @@ int dnssec_validate_ds(time_t now, struc
 			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
 		      else
 			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
-		      
-		      crecp->addr.ds.digest = digest;
-		      crecp->addr.ds.keydata = key;
-		      crecp->addr.ds.algo = algo;
-		      crecp->addr.ds.keytag = keytag;
-		      crecp->addr.ds.keylen = rdlen - 4; 
 		    } 
 		}
 	      
@@ -1711,8 +1710,8 @@ static int zone_status(char *name, int c
 	  do 
 	    {
 	      if (crecp->uid == (unsigned int)class &&
-		  ds_digest_name(crecp->addr.ds.digest) &&
-		  algo_digest_name(crecp->addr.ds.algo))
+		  ds_digest_name(crecp->addr.addr.addr.ds.digest) &&
+		  algo_digest_name(crecp->addr.addr.addr.ds.algo))
 		break;
 	    }
 	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
