]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
Complete AXFR support
authorSimon Kelley <simon@thekelleys.org.uk>
Sun, 9 Dec 2012 17:08:47 +0000 (17:08 +0000)
committerSimon Kelley <simon@thekelleys.org.uk>
Sun, 9 Dec 2012 17:08:47 +0000 (17:08 +0000)
src/auth.c
src/dnsmasq.h
src/lease.c
src/option.c
src/rfc1035.c

index 61ee13536c59982dba1986cb546241594573a358..050fe16db2e9b8ba4dd7707ccb7b66f574fa3bef 100644 (file)
@@ -84,7 +84,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
   struct auth_zone *zone = NULL;
   struct subnet *subnet = NULL;
   char *cut;
-
+  struct mx_srv_record *rec, *move, **up;
+  struct txt_record *txt;
+  struct interface_name *intr;
+  struct naptr *na;
+  struct all_addr addr;
+  struct cname *a;
+  
   if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
     return 0;
   
@@ -99,13 +105,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
     {
       unsigned short flag = 0;
       int found = 0;
-      struct mx_srv_record *rec, *move, **up;
-      struct txt_record *txt;
-      struct interface_name *intr;
-      struct naptr *na;
-      struct all_addr addr;
-      struct cname *a;
-
+  
       /* save pointer to name for copying into answers */
       nameoffset = p - (unsigned char *)header;
 
@@ -345,30 +345,33 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
        flag = F_IPV6;
 #endif
 
-      if (qtype == T_SOA && !cut)
+      if (!cut)
        {
-         soa = 1; /* inhibits auth section */
-         found = 1;
-         log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
-       }
-      
-      if (qtype == T_AXFR && !cut)
-       {
-         soa = 1; /* inhibits auth section */
-         axfr = 1;
-         found = 1;
-         axfroffset = nameoffset;
-         log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
-       }
-      
-      if (qtype == T_NS && !cut)
-       {
-         ns = 1; /* inhibits auth section */
-         found = 1;
-         log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); 
+         nxdomain = 0;
+         
+         if (qtype == T_SOA)
+           {
+             soa = 1; /* inhibits auth section */
+             found = 1;
+             log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
+           }
+         else if (qtype == T_AXFR)
+           {
+             soa = 1; /* inhibits auth section */
+             ns = 1; /* ensure we include NS records! */
+             axfr = 1;
+             found = 1;
+             axfroffset = nameoffset;
+             log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
+           }
+         else if (qtype == T_NS)
+           {
+             ns = 1; /* inhibits auth section */
+             found = 1;
+             log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); 
+           }
        }
       
-      
       if (!option_bool(OPT_DHCP_FQDN) && cut)
        {         
          *cut = 0; /* remove domain part */
@@ -423,7 +426,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
   if (auth)
     {
       char *authname;
-      
+      int newoffset, offset = 0;
+
       if (!subnet)
        authname = zone->domain;
       else
@@ -464,17 +468,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
        }
       
       /* handle NS and SOA in auth section or for explicit queries */
-      if ((anscount != 0 || ns) && 
-         add_resource_record(header, limit, &trunc, 0, &ansp, 
-                             daemon->auth_ttl, NULL, T_NS, C_IN, "d", authname, daemon->authserver))
-       {
-         if (ns) 
-           anscount++;
-         else
-           authcount++;
-       }
-      
-      if ((anscount == 0 || soa) &&
+       newoffset = ansp - (unsigned char *)header;
+       if (((anscount == 0 && !ns) || soa) &&
          add_resource_record(header, limit, &trunc, 0, &ansp, 
                              daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
                              authname, daemon->authserver,  daemon->hostmaster,
@@ -482,14 +477,149 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
                              daemon->soa_retry, daemon->soa_expiry, 
                              daemon->auth_ttl))
        {
+         offset = newoffset;
          if (soa)
            anscount++;
          else
            authcount++;
        }
+      
+      if (anscount != 0 || ns)
+       {
+         struct name_list *secondary;
+         
+         newoffset = ansp - (unsigned char *)header;
+         if (add_resource_record(header, limit, &trunc, -offset, &ansp, 
+                                 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
+           {
+             if (offset == 0) 
+               offset = newoffset;
+             if (ns) 
+               anscount++;
+             else
+               authcount++;
+           }
 
+         if (!subnet)
+           for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
+             if (add_resource_record(header, limit, &trunc, offset, &ansp, 
+                                     daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
+               {
+                 if (ns) 
+                   anscount++;
+                 else
+                   authcount++;
+               }
+       }
+      
       if (axfr)
        {
+         for (rec = daemon->mxnames; rec; rec = rec->next)
+           if (in_zone(zone, rec->name, &cut))
+             {
+               if (cut)
+                  *cut = 0;
+
+               if (rec->issrv)
+                 {
+                   if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+                                           NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
+                                           rec->priority, rec->weight, rec->srvport, rec->target))
+                     
+                     anscount++;
+                 }
+               else
+                 {
+                   if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+                                           NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
+                     anscount++;
+                 }
+               
+               /* restore config data */
+               if (cut)
+                 *cut = '.';
+             }
+             
+         for (txt = daemon->rr; txt; txt = txt->next)
+           if (in_zone(zone, txt->name, &cut))
+             {
+               if (cut)
+                 *cut = 0;
+               
+               if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+                                       NULL, txt->class, C_IN, "t",  cut ? txt->name : NULL, txt->len, txt->txt))
+                 anscount++;
+               
+               /* restore config data */
+               if (cut)
+                 *cut = '.';
+             }
+         
+         for (txt = daemon->txt; txt; txt = txt->next)
+           if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
+             {
+               if (cut)
+                 *cut = 0;
+               
+               if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
+                                       NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
+                 anscount++;
+               
+               /* restore config data */
+               if (cut)
+                 *cut = '.';
+             }
+         
+         for (na = daemon->naptr; na; na = na->next)
+           if (in_zone(zone, na->name, &cut))
+             {
+               if (cut)
+                 *cut = 0;
+               
+               if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, 
+                                       NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
+                                       na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
+                 anscount++;
+               
+               /* restore config data */
+               if (cut)
+                 *cut = '.'; 
+             }
+         
+         for (intr = daemon->int_names; intr; intr = intr->next)
+           if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
+             {
+               if (cut)
+                 *cut = 0;
+               
+               if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+                                       daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))
+                 anscount++;
+               
+               /* restore config data */
+               if (cut)
+                 *cut = '.'; 
+             }
+         
+         for (a = daemon->cnames; a; a = a->next)
+           if (in_zone(zone, a->alias, &cut))
+             {
+               strcpy(name, a->target);
+               if (!strchr(name, '.'))
+                 {
+                   strcat(name, ".");
+                   strcat(name, zone->domain);
+                 }
+               
+               if (cut)
+                 *cut = 0;
+               
+               if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+                                       daemon->auth_ttl, NULL,
+                                       T_CNAME, C_IN, "d",  cut ? a->alias : NULL, name))
+                 anscount++;
+             }
+       
          cache_enumerate(1);
          while ((crecp = cache_enumerate(0)))
            {
@@ -525,20 +655,12 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
                            qtype = T_AAAA;
 #endif
                           if (cut)
-                            {
-                              *cut = 0;
-                              if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
-                                                      daemon->auth_ttl, NULL, qtype, C_IN, 
-                                                      (crecp->flags & F_IPV4) ? "4" : "6", name, &crecp->addr))
-                                anscount++;
-                            }
-                          else
-                            {
-                              if (add_resource_record(header, limit, &trunc, axfroffset, &ansp, 
-                                                      daemon->auth_ttl, NULL, qtype, C_IN, 
-                                                      (crecp->flags & F_IPV4) ? "4" : "6", &crecp->addr))
-                                anscount++;  
-                            }
+                            *cut = 0;
+
+                          if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
+                                                  daemon->auth_ttl, NULL, qtype, C_IN, 
+                                                  (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
+                            anscount++;
                        }
                    }
                }
@@ -555,7 +677,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
        
        }
   
-    }
+}
   
   /* done all questions, set up header and return length of result */
   /* clear authoritative and truncated flags, set QR flag */
index 807a8aadfb7b093052198db0cdd40c792c4c7a98..0d9ab7ef68f500598dcb2658565061e0a78e6c98 100644 (file)
@@ -756,6 +756,7 @@ extern struct daemon {
   char *username, *groupname, *scriptuser;
   char *luascript;
   char *authserver, *authinterface, *hostmaster;
+  struct name_list *secondary_forward_server;
   int group_set, osport;
   char *domain_suffix;
   struct cond_domain *cond_domain;
@@ -901,7 +902,7 @@ size_t resize_packet(struct dns_header *header, size_t plen,
 size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
 int add_resource_record(struct dns_header *header, char *limit, int *truncp,
                        int nameoffset, unsigned char **pp, unsigned long ttl, 
-                       unsigned int *offset, unsigned short type, unsigned short class, char *format, ...);
+                       int *offset, unsigned short type, unsigned short class, char *format, ...);
 unsigned char *skip_questions(struct dns_header *header, size_t plen);
 int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, 
                 char *name, int isExtract, int extrabytes);
index 79824763079bde944be2c9d9c81464e8fc05dd0a..656f006678b375f123fa588336827dcf137eb5fd 100644 (file)
@@ -420,6 +420,9 @@ void lease_update_dns(int force)
 
   if (daemon->port != 0 && (dns_dirty || force))
     {
+      /* force transfer to authoritative secondaries */
+      daemon->soa_sn++;
+      
       cache_unhash_dhcp();
 
       for (lease = leases; lease; lease = lease->next)
index 6a2519c0ee798f86da78c2428bd07f6907bbd202..d32f26450cb82cae426b9e115ad0db6e317c9c33 100644 (file)
@@ -123,8 +123,9 @@ struct myoption {
 #define LOPT_MAXCTTL   312
 #define LOPT_AUTHZONE  313
 #define LOPT_AUTHSERV  314
-#define LOPT_AUTHTTL  315
+#define LOPT_AUTHTTL   315
 #define LOPT_AUTHSOA   316
+#define LOPT_AUTHSFS   317
 
 #ifdef HAVE_GETOPT_LONG
 static const struct option opts[] =  
@@ -255,6 +256,7 @@ static const struct myoption opts[] =
     { "auth-server", 1, 0, LOPT_AUTHSERV },
     { "auth-ttl", 1, 0, LOPT_AUTHTTL },
     { "auth-soa", 1, 0, LOPT_AUTHSOA },
+    { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
     { NULL, 0, 0, 0 }
   };
 
@@ -391,6 +393,7 @@ static struct {
   { LOPT_AUTHZONE, ARG_DUP, "<domain>,<subnet>[,<subnet>]", gettext_noop("Domain to export to global DNS"), NULL },
   { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
   { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL },
+  { LOPT_AUTHSFS, ARG_ONE, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
   { 0, 0, NULL, NULL, NULL }
 }; 
 
@@ -1525,7 +1528,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
            new->next = daemon->dhcp_hosts_file;
            daemon->dhcp_hosts_file = new;
          }
-       else if (option ==  LOPT_DHCP_OPTS)
+       else if (option == LOPT_DHCP_OPTS)
          {
            new->next = daemon->dhcp_opts_file;
            daemon->dhcp_opts_file = new;
@@ -1541,7 +1544,22 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
       daemon->authinterface = opt_string_alloc(comma);
       
       break;
-      
+
+    case LOPT_AUTHSFS: /* --auth-sec-servers */
+      {
+       struct name_list *new;
+
+       do {
+         comma = split(arg);
+         new = safe_malloc(sizeof(struct name_list));
+         new->name = opt_string_alloc(arg);
+         new->next = daemon->secondary_forward_server;
+         daemon->secondary_forward_server = new;
+         arg = comma;
+       } while (arg);
+       break;
+      }
+       
     case LOPT_AUTHZONE: /* --auth-zone */
       {
        struct auth_zone *new;
index 6d5845c20b62550120736fc79e50b7ee3c8a81be..932199b52c1d74705dc9f6d5164984f381958800 100644 (file)
@@ -1186,7 +1186,7 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
 }
 
 int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp, 
-                       unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
+                       unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
 {
   va_list ap;
   unsigned char *sav, *p = *pp;
@@ -1206,7 +1206,9 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
     }
   else
     {
-      p = do_rfc1035_name(p, va_arg(ap, char *));
+      char *name = va_arg(ap, char *);
+      if (name)
+       p = do_rfc1035_name(p, name);
       if (nameoffset < 0)
        {
          PUTSHORT(-nameoffset | 0xc000, p);
@@ -1699,7 +1701,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
                  ans = found = 1;
                  if (!dryrun)
                    {
-                     unsigned int offset;
+                     int offset;
                      log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
                      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
                                              &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
@@ -1737,7 +1739,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
                    found = ans = 1;
                    if (!dryrun)
                      {
-                       unsigned int offset;
+                       int offset;
                        log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
                        if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, 
                                                &offset, T_SRV, C_IN, "sssd",