authzone, handle probe return packets.

git-svn-id: file:///svn/unbound/trunk@4384 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2017-10-20 14:43:51 +00:00
parent eb0f3256d9
commit 15d892c62d
4 changed files with 129 additions and 4 deletions

View 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 \

View 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;
}
}

View 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 */

View 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();
}