]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
authzone, handle probe return packets.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 20 Oct 2017 14:43:51 +0000 (14:43 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 20 Oct 2017 14:43:51 +0000 (14:43 +0000)
git-svn-id: file:///svn/unbound/trunk@4384 be551aaa-1e26-0410-a405-d3ace91eadb9

Makefile.in
services/authzone.c
services/authzone.h
testcode/unitauth.c

index ab9ba39122eb64ef85419bdbe9c07655dc054709..c009f06346f6dd0cedf81fa1607038f25d14ee24 100644 (file)
@@ -827,7 +827,9 @@ authzone.lo authzone.o: $(srcdir)/services/authzone.c config.h $(srcdir)/service
  $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgencode.h \
  $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
   $(srcdir)/dnscrypt/cert.h $(srcdir)/util/config_file.h \
- $(srcdir)/util/module.h $(srcdir)/services/cache/dns.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/str2wire.h \
+ $(srcdir)/util/module.h $(srcdir)/util/random.h $(srcdir)/services/cache/dns.h \
+ $(srcdir)/services/outside_network.h  \
+ $(srcdir)/services/listen_dnsport.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/str2wire.h \
  $(srcdir)/sldns/wire2str.h $(srcdir)/sldns/parseutil.h $(srcdir)/validator/val_nsec3.h \
  $(srcdir)/validator/val_secalgo.h
 fptr_wlist.lo fptr_wlist.o: $(srcdir)/util/fptr_wlist.c config.h $(srcdir)/util/fptr_wlist.h \
index 061c305d4c8764af9316907a589eeb6b137879e8..20318438e1b74c294ffea8ad3d3868994b5d3574 100644 (file)
@@ -2918,7 +2918,7 @@ check_packet_ok(sldns_buffer* pkt, uint16_t qtype, struct auth_xfer* xfr,
        uint32_t* serial)
 {
        uint16_t id;
-       /* TODO parse to see if packet worked, valid reply */
+       /* parse to see if packet worked, valid reply */
 
        /* check serial number of SOA */
        if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE)
@@ -2994,6 +2994,65 @@ check_packet_ok(sldns_buffer* pkt, uint16_t qtype, struct auth_xfer* xfr,
        return 1;
 }
 
+/** see if the serial means the zone has to be updated, i.e. the serial
+ * is newer than the zone serial, or we have no zone */
+static int
+xfr_serial_means_update(struct auth_xfer* xfr, uint32_t serial)
+{
+       uint32_t zserial;
+       int have_zone, zone_expired;
+       lock_basic_lock(&xfr->lock);
+       zserial = xfr->serial;
+       have_zone = xfr->have_zone;
+       zone_expired = xfr->zone_expired;
+       lock_basic_unlock(&xfr->lock);
+
+       if(!have_zone)
+               return 1; /* no zone, anything is better */
+       if(zone_expired)
+               return 1; /* expired, the sent serial is better than expired
+                       data */
+       if(compare_serial(zserial, serial) < 0)
+               return 1; /* our serial is smaller than the sent serial,
+                       the data is newer, fetch it */
+       return 0;
+}
+
+/** find master (from notify or probe) in list of masters */
+static struct auth_master*
+find_master_by_host(struct auth_master* list, char* host)
+{
+       struct auth_master* p;
+       for(p=list; p; p=p->next) {
+               if(strcmp(p->host, host) == 0)
+                       return p;
+       }
+       return NULL;
+}
+
+/** start transfer task by this worker , xfr is locked. */
+static void
+xfr_start_transfer(struct auth_xfer* xfr, struct module_env* env,
+       struct auth_master* master)
+{
+       log_assert(xfr->task_transfer != NULL);
+       log_assert(xfr->task_transfer->worker == NULL);
+       log_assert(xfr->task_transfer->chunks_first == NULL);
+       log_assert(xfr->task_transfer->chunks_last == NULL);
+       xfr->task_transfer->worker = env->worker;
+       xfr->task_transfer->env = env;
+       
+       /* init transfer process */
+       /* find that master in the transfer's list of masters? */
+       xfr->task_transfer->scan_specific = find_master_by_host(
+               xfr->task_transfer->masters, master->host);
+       if(xfr->task_transfer->scan_specific)
+               xfr->task_transfer->scan_target = NULL;
+       else    xfr->task_transfer->scan_target = xfr->task_transfer->masters;
+
+       /* TODO initiate TCP, and set timeout on it */
+}
+
 /** callback for task_probe udp packets */
 int
 auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
@@ -3010,11 +3069,28 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
        /* TODO */
 
        if(err == NETEVENT_NOERROR) {
-               uint32_t serial;
+               uint32_t serial = 0;
                if(check_packet_ok(c->buffer, LDNS_RR_TYPE_SOA, xfr,
                        &serial)) {
                        /* successful lookup */
-                       /* TODO */
+                       /* see if this serial indicates that the zone has
+                        * to be updated */
+                       lock_basic_lock(&xfr->lock);
+                       if(xfr_serial_means_update(xfr, serial)) {
+                               /* if updated, start the transfer task, if needed */
+                               if(xfr->task_transfer->worker == NULL) {
+                                       xfr_start_transfer(xfr, env, 
+                                               (xfr->task_probe->scan_specific?xfr->task_probe->scan_specific:xfr->task_probe->scan_target));
+                               }
+                       } else {
+                               /* if zone not updated, start the wait timer again */
+                               if(xfr->task_nextprobe->worker == NULL)
+                                       xfr_set_timeout(xfr, env, 0);
+                       }
+                       lock_basic_unlock(&xfr->lock);
+                       /* return, we don't sent a reply to this udp packet,
+                        * and we setup the tasks to do next */
+                       return 0;
                }
        }
        
@@ -3044,6 +3120,9 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env)
        if(!master) master = xfr->task_probe->scan_target;
        if(!master) return 0;
 
+       /* TODO: use mesh_new_callback to probe for non-addr hosts,
+        * and then wait for them to be looked up (in cache, or query) */
+
        /* create packet */
        xfr_create_probe_packet(xfr, env, env->scratch_buffer, 1);
        if(!xfr->task_probe->cp) {
@@ -3353,3 +3432,18 @@ xfer_set_masters(struct auth_master** list, struct config_auth* c)
        }
        return 1;
 }
+
+#define SERIAL_BITS      32
+int
+compare_serial(uint32_t a, uint32_t b)
+{
+        const uint32_t cutoff = ((uint32_t) 1 << (SERIAL_BITS - 1));
+
+        if (a == b) {
+                return 0;
+        } else if ((a < b && b - a < cutoff) || (a > b && a - b > cutoff)) {
+                return -1;
+        } else {
+                return 1;
+        }
+}
index c724a9a1ee67e355c2d6026302f44a60d46d08ab..f2de82893c252351728199fdd5ad155d1f20b18a 100644 (file)
@@ -306,6 +306,8 @@ struct auth_probe {
 struct auth_transfer {
        /* Worker pointer. NULL means unowned. */
        struct worker* worker;
+       /* module env for this task */
+       struct module_env* env;
 
        /** xfer data that has been transferred, the data is applied
         * once the transfer has completed correctly */
@@ -497,4 +499,12 @@ void auth_xfer_timer(void* arg);
 int auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
         struct comm_reply* repinfo);
 
+/*
+ * Compares two 32-bit serial numbers as defined in RFC1982.  Returns
+ * <0 if a < b, 0 if a == b, and >0 if a > b.  The result is undefined
+ * if a != b but neither is greater or smaller (see RFC1982 section
+ * 3.2.).
+ */
+int compare_serial(uint32_t a, uint32_t b);
+
 #endif /* SERVICES_AUTHZONE_H */
index f6c022aa03d702fc178b71920cefc7b4e85c393a..6ca0be9d8d25788a86ba8152ba2563104248d19a 100644 (file)
@@ -831,6 +831,24 @@ check_queries(const char* name, const char* zone, struct q_ans* queries)
        auth_zones_delete(az);
 }
 
+/** Test authzone compare_serial */
+static void
+authzone_compare_serial(void)
+{
+       if(vbmp) printf("Testing compare_serial\n");
+       unit_assert(compare_serial(0, 1) < 0);
+       unit_assert(compare_serial(1, 0) > 0);
+       unit_assert(compare_serial(0, 0) == 0);
+       unit_assert(compare_serial(1, 1) == 0);
+       unit_assert(compare_serial(0xf0000000, 0xf0000000) == 0);
+       unit_assert(compare_serial(0, 0xf0000000) > 0);
+       unit_assert(compare_serial(0xf0000000, 0) < 0);
+       unit_assert(compare_serial(0xf0000000, 0xf0000001) < 0);
+       unit_assert(compare_serial(0xf0000002, 0xf0000001) > 0);
+       unit_assert(compare_serial(0x70000000, 0x80000000) < 0);
+       unit_assert(compare_serial(0x90000000, 0x70000000) > 0);
+}
+
 /** Test authzone read from file */
 static void
 authzone_read_test(void)
@@ -853,6 +871,7 @@ authzone_test(void)
 {
        unit_show_feature("authzone");
        atexit(tmpfilecleanup);
+       authzone_compare_serial();
        authzone_read_test();
        authzone_query_test();
 }