From: Wouter Wijngaards Date: Thu, 1 Feb 2018 10:38:05 +0000 (+0000) Subject: auth zone test, udp and tcp answered from unit test X-Git-Tag: release-1.7.0rc1~77 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6a0b5aa8e32c8307307ab4af1c2e6a661a4ce462;p=thirdparty%2Funbound.git auth zone test, udp and tcp answered from unit test git-svn-id: file:///svn/unbound/trunk@4484 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/services/authzone.c b/services/authzone.c index 6efe2e1f8..b53f2bc58 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -3554,20 +3554,12 @@ check_packet_ok(sldns_buffer* pkt, uint16_t qtype, struct auth_xfer* xfr, 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) + if(!xfr->have_zone) return 1; /* no zone, anything is better */ - if(zone_expired) + if(xfr->zone_expired) return 1; /* expired, the sent serial is better than expired data */ - if(compare_serial(zserial, serial) < 0) + if(compare_serial(xfr->serial, serial) < 0) return 1; /* our serial is smaller than the sent serial, the data is newer, fetch it */ return 0; @@ -4711,10 +4703,12 @@ auth_xfer_probe_timer_callback(void* arg) struct module_env* env; log_assert(xfr->task_probe); env = xfr->task_probe->env; + lock_basic_lock(&xfr->lock); if(xfr->task_probe->timeout <= AUTH_PROBE_TIMEOUT_STOP) { /* try again with bigger timeout */ if(xfr_probe_send_probe(xfr, env, xfr->task_probe->timeout*2)) { + lock_basic_unlock(&xfr->lock); return; } } @@ -4750,19 +4744,28 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err, if(check_packet_ok(c->buffer, LDNS_RR_TYPE_SOA, xfr, &serial)) { /* successful lookup */ + if(verbosity >= VERB_ALGO) { + char buf[256]; + dname_str(xfr->name, buf); + verbose(VERB_ALGO, "auth zone %s: soa probe " + "serial is %u", buf, (unsigned)serial); + } /* see if this serial indicates that the zone has * to be updated */ if(xfr_serial_means_update(xfr, serial)) { /* if updated, start the transfer task, if needed */ + verbose(VERB_ALGO, "auth_zone updated, start transfer"); if(xfr->task_transfer->worker == NULL) { xfr_probe_disown(xfr); xfr_start_transfer(xfr, env, xfr_probe_current_master(xfr)); + lock_basic_unlock(&xfr->lock); return 0; } } else { /* if zone not updated, start the wait timer again */ + verbose(VERB_ALGO, "auth_zone unchanged, new lease, wait"); if(xfr->have_zone) xfr->lease_time = *env->now; if(xfr->task_nextprobe->worker == NULL) @@ -4776,6 +4779,11 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err, return 0; } } + if(verbosity >= VERB_ALGO) { + char buf[256]; + dname_str(xfr->name, buf); + verbose(VERB_ALGO, "auth zone %s: soa probe failed", buf); + } /* failed lookup */ /* delete commpoint so a new one is created, with a fresh port nr */ @@ -4875,7 +4883,6 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) xfr_probe_nextmaster(xfr); } - lock_basic_lock(&xfr->lock); /* we failed to send this as well, move to the wait task, * use the shorter retry timeout */ xfr_probe_disown(xfr); diff --git a/sldns/wire2str.c b/sldns/wire2str.c index 861b7648a..832239f9b 100644 --- a/sldns/wire2str.c +++ b/sldns/wire2str.c @@ -255,6 +255,12 @@ int sldns_wire2str_rr_buf(uint8_t* d, size_t dlen, char* s, size_t slen) return sldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0); } +int sldns_wire2str_rrquestion_buf(uint8_t* d, size_t dlen, char* s, size_t slen) +{ + /* use arguments as temporary variables */ + return sldns_wire2str_rrquestion_scan(&d, &dlen, &s, &slen, NULL, 0); +} + int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str, size_t str_len, uint16_t rrtype) { diff --git a/sldns/wire2str.h b/sldns/wire2str.h index aac13c548..a64f58072 100644 --- a/sldns/wire2str.h +++ b/sldns/wire2str.h @@ -358,6 +358,22 @@ int sldns_wire2str_edns_option_code_print(char** str, size_t* str_len, int sldns_wire2str_rr_buf(uint8_t* rr, size_t rr_len, char* str, size_t str_len); +/** + * Convert question RR to string presentation format, on one line. User buffer. + * @param rr: wireformat RR data + * @param rr_len: length of the rr wire data. + * @param str: the string buffer to write to. + * If you pass NULL as the str, the return value of the function is + * the str_len you need for the entire packet. It does not include + * the 0 byte at the end. + * @param str_len: the size of the string buffer. If more is needed, it'll + * silently truncate the output to fit in the buffer. + * @return the number of characters for this element, excluding zerobyte. + * Is larger or equal than str_len if output was truncated. + */ +int sldns_wire2str_rrquestion_buf(uint8_t* rr, size_t rr_len, char* str, + size_t str_len); + /** * 3597 printout of an RR in unknown rr format. * There are more format and comment options available for printout diff --git a/testcode/fake_event.c b/testcode/fake_event.c index e999896ec..f5481c22d 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -67,6 +67,27 @@ struct worker; struct daemon_remote; +/** unique code to check that fake_commpoint is that structure */ +#define FAKE_COMMPOINT_TYPECODE 97347923 +/** fake commpoint, stores information */ +struct fake_commpoint { + /** typecode */ + int typecode; + /** if this is a udp outgoing type of commpoint */ + int type_udp_out; + /** if this is a tcp outgoing tcp of commpoint */ + int type_tcp_out; + + /** the callback, stored for usage */ + comm_point_callback_type* cb; + /** the callback userarg, stored for usage */ + void* cb_arg; + /** runtime ptr */ + struct replay_runtime* runtime; + /** the pending entry for this commpoint (if any) */ + struct fake_pending* pending; +}; + /** Global variable: the scenario. Saved here for when event_init is done. */ static struct replay_scenario* saved_scenario = NULL; @@ -247,7 +268,6 @@ pending_matches_range(struct replay_runtime* runtime, struct fake_pending* p = runtime->pending_list; /* slow, O(N*N), but it works as advertised with weird matching */ while(p) { - log_info("check of pending"); if(pending_find_match(runtime, entry, p)) { *pend = p; return 1; @@ -1168,7 +1188,11 @@ struct comm_point* comm_point_create_local(struct comm_base* ATTR_UNUSED(base), comm_point_callback_type* ATTR_UNUSED(callback), void* ATTR_UNUSED(callback_arg)) { - return calloc(1, 1); + struct fake_commpoint* fc = (struct fake_commpoint*)calloc(1, + sizeof(*fc)); + if(!fc) return NULL; + fc->typecode = FAKE_COMMPOINT_TYPECODE; + return (struct comm_point*)fc; } struct comm_point* comm_point_create_raw(struct comm_base* ATTR_UNUSED(base), @@ -1177,7 +1201,11 @@ struct comm_point* comm_point_create_raw(struct comm_base* ATTR_UNUSED(base), void* ATTR_UNUSED(callback_arg)) { /* no pipe comm possible */ - return calloc(1, 1); + struct fake_commpoint* fc = (struct fake_commpoint*)calloc(1, + sizeof(*fc)); + if(!fc) return NULL; + fc->typecode = FAKE_COMMPOINT_TYPECODE; + return (struct comm_point*)fc; } void comm_point_start_listening(struct comm_point* ATTR_UNUSED(c), @@ -1194,6 +1222,13 @@ void comm_point_stop_listening(struct comm_point* ATTR_UNUSED(c)) /* only cmd com _local gets deleted */ void comm_point_delete(struct comm_point* c) { + struct fake_commpoint* fc = (struct fake_commpoint*)c; + if(c == NULL) return; + log_assert(fc->typecode == FAKE_COMMPOINT_TYPECODE); + if(fc->type_tcp_out) { + /* remove tcp pending, so no more callbacks to it */ + pending_list_delete(fc->runtime, fc->pending); + } free(c); } @@ -1437,6 +1472,7 @@ struct comm_point* comm_point_create_udp(struct comm_base *ATTR_UNUSED(base), comm_point_callback_type* ATTR_UNUSED(callback), void* ATTR_UNUSED(callback_arg)) { + log_assert(0); return NULL; } @@ -1445,21 +1481,27 @@ struct comm_point* comm_point_create_tcp_out(struct comm_base* comm_point_callback_type* ATTR_UNUSED(callback), void* ATTR_UNUSED(callback_arg)) { + log_assert(0); return NULL; } struct comm_point* outnet_comm_point_for_udp(struct outside_network* outnet, comm_point_callback_type* cb, void* cb_arg, - struct sockaddr_storage* to_addr, socklen_t to_addrlen) + struct sockaddr_storage* ATTR_UNUSED(to_addr), + socklen_t ATTR_UNUSED(to_addrlen)) { + struct replay_runtime* runtime = (struct replay_runtime*) + outnet->base; + struct fake_commpoint* fc = (struct fake_commpoint*)calloc(1, + sizeof(*fc)); + if(!fc) return NULL; + fc->typecode = FAKE_COMMPOINT_TYPECODE; + fc->type_udp_out = 1; + fc->cb = cb; + fc->cb_arg = cb_arg; + fc->runtime = runtime; /* used by authzone transfers */ - (void)outnet; - (void)cb; - (void)cb_arg; - (void)to_addr; - (void)to_addrlen; - /* TODO */ - return NULL; + return (struct comm_point*)fc; } struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet, @@ -1467,35 +1509,144 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet, struct sockaddr_storage* to_addr, socklen_t to_addrlen, struct sldns_buffer* query, int timeout) { + struct replay_runtime* runtime = (struct replay_runtime*) + outnet->base; + struct fake_commpoint* fc = (struct fake_commpoint*)calloc(1, + sizeof(*fc)); + struct fake_pending* pend = (struct fake_pending*)calloc(1, + sizeof(struct fake_pending)); + if(!fc || !pend) { + free(fc); + free(pend); + return NULL; + } + fc->typecode = FAKE_COMMPOINT_TYPECODE; + fc->type_tcp_out = 1; + fc->cb = cb; + fc->cb_arg = cb_arg; + fc->runtime = runtime; + fc->pending = pend; + /* used by authzone transfers */ - (void)outnet; - (void)cb; - (void)cb_arg; - (void)to_addr; - (void)to_addrlen; - (void)query; - (void)timeout; - /* TODO */ - return NULL; + /* create pending item */ + pend->buffer = sldns_buffer_new(sldns_buffer_limit(query)+10); + if(!pend->buffer) { + free(fc); + free(pend); + return NULL; + } + sldns_buffer_copy(pend->buffer, query); + memcpy(&pend->addr, to_addr, to_addrlen); + pend->addrlen = to_addrlen; + pend->zone = NULL; + pend->zonelen = 0; + if(LDNS_QDCOUNT(sldns_buffer_begin(query)) > 0) { + char buf[512]; + char addrbuf[128]; + (void)sldns_wire2str_rrquestion_buf(sldns_buffer_at(query, LDNS_HEADER_SIZE), sldns_buffer_limit(query)-LDNS_HEADER_SIZE, buf, sizeof(buf)); + addr_to_str((struct sockaddr_storage*)to_addr, to_addrlen, + addrbuf, sizeof(addrbuf)); + if(verbosity >= VERB_ALGO) { + if(buf[0] != 0) buf[strlen(buf)-1] = 0; /* del newline*/ + log_info("tcp to %s: %s", addrbuf, buf); + } + log_assert(sldns_buffer_limit(query)-LDNS_HEADER_SIZE >= 2); + pend->qtype = (int)sldns_buffer_read_u16_at(query, + LDNS_HEADER_SIZE+ + dname_valid(sldns_buffer_at(query, LDNS_HEADER_SIZE), + sldns_buffer_limit(query)-LDNS_HEADER_SIZE)); + } + pend->callback = cb; + pend->cb_arg = cb_arg; + pend->timeout = timeout; + pend->transport = transport_tcp; + pend->pkt = NULL; + pend->runtime = runtime; + pend->serviced = 0; + pend->pkt_len = sldns_buffer_limit(pend->buffer); + pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len); + if(!pend->pkt) fatal_exit("out of memory"); + + log_info("testbound: created fake pending for tcp_out"); + + /* add to list */ + pend->next = runtime->pending_list; + runtime->pending_list = pend; + + return (struct comm_point*)fc; } -int comm_point_send_udp_msg(struct comm_point *ATTR_UNUSED(c), - sldns_buffer* ATTR_UNUSED(packet), struct sockaddr* ATTR_UNUSED(addr), - socklen_t ATTR_UNUSED(addrlen)) +int comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet, + struct sockaddr* addr, socklen_t addrlen) { - /* could create a test framework; and intercept eg. authzone probes */ - return 0; + struct fake_commpoint* fc = (struct fake_commpoint*)c; + struct replay_runtime* runtime = fc->runtime; + struct fake_pending* pend = (struct fake_pending*)calloc(1, + sizeof(struct fake_pending)); + if(!pend) { + log_err("malloc failure"); + return 0; + } + fc->pending = pend; + /* used by authzone transfers */ + /* create pending item */ + pend->buffer = sldns_buffer_new(sldns_buffer_limit(packet) + 10); + if(!pend->buffer) { + free(pend); + return 0; + } + sldns_buffer_copy(pend->buffer, packet); + memcpy(&pend->addr, addr, addrlen); + pend->addrlen = addrlen; + pend->zone = NULL; + pend->zonelen = 0; + if(LDNS_QDCOUNT(sldns_buffer_begin(packet)) > 0) { + char buf[512]; + char addrbuf[128]; + (void)sldns_wire2str_rrquestion_buf(sldns_buffer_at(packet, LDNS_HEADER_SIZE), sldns_buffer_limit(packet)-LDNS_HEADER_SIZE, buf, sizeof(buf)); + addr_to_str((struct sockaddr_storage*)addr, addrlen, + addrbuf, sizeof(addrbuf)); + if(verbosity >= VERB_ALGO) { + if(buf[0] != 0) buf[strlen(buf)-1] = 0; /* del newline*/ + log_info("udp to %s: %s", addrbuf, buf); + } + log_assert(sldns_buffer_limit(packet)-LDNS_HEADER_SIZE >= 2); + pend->qtype = (int)sldns_buffer_read_u16_at(packet, + LDNS_HEADER_SIZE+ + dname_valid(sldns_buffer_at(packet, LDNS_HEADER_SIZE), + sldns_buffer_limit(packet)-LDNS_HEADER_SIZE)); + } + pend->callback = fc->cb; + pend->cb_arg = fc->cb_arg; + pend->timeout = UDP_AUTH_QUERY_TIMEOUT; + pend->transport = transport_udp; + pend->pkt = NULL; + pend->runtime = runtime; + pend->serviced = 0; + pend->pkt_len = sldns_buffer_limit(pend->buffer); + pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len); + if(!pend->pkt) fatal_exit("out of memory"); + + log_info("testbound: created fake pending for send_udp_msg"); + + /* add to list */ + pend->next = runtime->pending_list; + runtime->pending_list = pend; + + return 1; } int outnet_get_tcp_fd(struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(tcp_mss)) { + log_assert(0); return -1; } int outnet_tcp_connect(int ATTR_UNUSED(s), struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen)) { + log_assert(0); return 0; } diff --git a/testcode/testpkts.c b/testcode/testpkts.c index e1a7768ab..401f8afd1 100644 --- a/testcode/testpkts.c +++ b/testcode/testpkts.c @@ -572,6 +572,10 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate, } else if(str_keyword(&parse, "ADJUST")) { adjustline(parse, current, cur_reply); } else if(str_keyword(&parse, "EXTRA_PACKET")) { + cur_reply->reply_pkt = memdup(pktbuf, pktlen); + cur_reply->reply_len = pktlen; + if(!cur_reply->reply_pkt) + error("out of memory"); cur_reply = entry_add_reply(current); } else if(str_keyword(&parse, "SECTION")) { if(str_keyword(&parse, "QUESTION")) @@ -1558,10 +1562,10 @@ adjust_packet(struct entry* match, uint8_t** answer_pkt, size_t *answer_len, return; } /* copy the ID */ - if(match->copy_id && reslen >= 2) - res[1] = orig[1]; - if(match->copy_id && reslen >= 1) - res[0] = orig[0]; + if(match->copy_id && reslen >= 2 && query_len >= 2) + res[1] = query_pkt[1]; + if(match->copy_id && reslen >= 1 && query_len >= 1) + res[0] = query_pkt[0]; if(match->copy_ednsdata_assume_clientsubnet) { /** Assume there is only one EDNS option, which is ECS. diff --git a/testdata/auth_xfr.rpl b/testdata/auth_xfr.rpl index 60b85668e..b1610202c 100644 --- a/testdata/auth_xfr.rpl +++ b/testdata/auth_xfr.rpl @@ -152,6 +152,35 @@ www.example.com. IN A SECTION ANSWER www.example.com. IN A 10.20.30.40 ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN SOA +SECTION ANSWER +; serial, refresh, retry, expire, minimum +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.com. IN AXFR +SECTION ANSWER +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +example.com. IN NS ns.example.net. +EXTRA_PACKET +REPLY QR AA NOERROR +SECTION QUESTION +example.com. IN AXFR +SECTION ANSWER +www.example.com. IN A 1.2.3.4 +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +ENTRY_END RANGE_END STEP 1 QUERY @@ -172,5 +201,6 @@ SECTION ANSWER ENTRY_END STEP 30 TIME_PASSES ELAPSE 10 +STEP 40 TRAFFIC SCENARIO_END