diff options
| author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-09-10 16:32:55 +0000 |
|---|---|---|
| committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-09-10 16:32:55 +0000 |
| commit | dcaa814d350c5ee7deb2164502a24f2f698b9799 (patch) | |
| tree | 9cb62373e6c424da021043a171564ced3bb19501 /services | |
| parent | 4aea2433fa04a7a86c8972869bd021b7a3622dc8 (diff) | |
Notes
Diffstat (limited to 'services')
| -rw-r--r-- | services/authzone.c | 124 | ||||
| -rw-r--r-- | services/authzone.h | 20 | ||||
| -rw-r--r-- | services/cache/dns.c | 6 | ||||
| -rw-r--r-- | services/cache/dns.h | 12 | ||||
| -rw-r--r-- | services/cache/infra.c | 36 | ||||
| -rw-r--r-- | services/cache/rrset.c | 4 | ||||
| -rw-r--r-- | services/listen_dnsport.c | 15 | ||||
| -rw-r--r-- | services/listen_dnsport.h | 10 | ||||
| -rw-r--r-- | services/localzone.c | 128 | ||||
| -rw-r--r-- | services/mesh.c | 54 | ||||
| -rw-r--r-- | services/mesh.h | 10 | ||||
| -rw-r--r-- | services/outside_network.c | 66 |
12 files changed, 336 insertions, 149 deletions
diff --git a/services/authzone.c b/services/authzone.c index f1ca2a2b0552..fe56c9f81b65 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -185,11 +185,13 @@ msg_ttl(struct dns_msg* msg) if(msg->rep->rrset_count == 1) { msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[0]); msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; } else if(get_rrset_ttl(msg->rep->rrsets[msg->rep->rrset_count-1]) < msg->rep->ttl) { msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[ msg->rep->rrset_count-1]); msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; } } @@ -1014,7 +1016,8 @@ rrset_moveover_rrsigs(struct auth_data* node, uint16_t rr_type, } /* copy base values */ memcpy(sigd, sigold, sizeof(struct packed_rrset_data)); - sigd->rrsig_count -= sigs; + /* in sigd the RRSIGs are stored in the base of the RR, in count */ + sigd->count -= sigs; /* setup rr_len */ sigd->rr_len = (size_t*)((uint8_t*)sigd + sizeof(struct packed_rrset_data)); @@ -2284,6 +2287,7 @@ az_add_negative_soa(struct auth_zone* z, struct regional* region, d->rr_ttl[0] = (time_t)minimum; msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[0]); msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; return 1; } @@ -3168,8 +3172,8 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo, /** encode auth answer */ static void auth_answer_encode(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - struct dns_msg* msg) + struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, + struct regional* temp, struct dns_msg* msg) { uint16_t udpsize; udpsize = edns->udp_size; @@ -3179,7 +3183,7 @@ auth_answer_encode(struct query_info* qinfo, struct module_env* env, edns->bits &= EDNS_DO; if(!inplace_cb_reply_local_call(env, qinfo, NULL, msg->rep, - (int)FLAGS_GET_RCODE(msg->rep->flags), edns, temp) + (int)FLAGS_GET_RCODE(msg->rep->flags), edns, repinfo, temp) || !reply_info_answer_encode(qinfo, msg->rep, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), @@ -3194,8 +3198,8 @@ auth_answer_encode(struct query_info* qinfo, struct module_env* env, /** encode auth error answer */ static void auth_error_encode(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - int rcode) + struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, + struct regional* temp, int rcode) { edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; @@ -3203,7 +3207,7 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env, edns->bits &= EDNS_DO; if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, - rcode, edns, temp)) + rcode, edns, repinfo, temp)) edns->opt_list = NULL; error_encode(buf, rcode|BIT_AA, qinfo, *(uint16_t*)sldns_buffer_begin(buf), @@ -3211,8 +3215,8 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env, } int auth_zones_answer(struct auth_zones* az, struct module_env* env, - struct query_info* qinfo, struct edns_data* edns, struct sldns_buffer* buf, - struct regional* temp) + struct query_info* qinfo, struct edns_data* edns, + struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp) { struct dns_msg* msg = NULL; struct auth_zone* z; @@ -3260,9 +3264,9 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env, /* encode answer */ if(!r) - auth_error_encode(qinfo, env, edns, buf, temp, + auth_error_encode(qinfo, env, edns, repinfo, buf, temp, LDNS_RCODE_SERVFAIL); - else auth_answer_encode(qinfo, env, edns, buf, temp, msg); + else auth_answer_encode(qinfo, env, edns, repinfo, buf, temp, msg); return 1; } @@ -3470,6 +3474,23 @@ int auth_zones_notify(struct auth_zones* az, struct module_env* env, return 1; } +int auth_zones_startprobesequence(struct auth_zones* az, + struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t dclass) +{ + struct auth_xfer* xfr; + lock_rw_rdlock(&az->lock); + xfr = auth_xfer_find(az, nm, nmlen, dclass); + if(!xfr) { + lock_rw_unlock(&az->lock); + return 0; + } + lock_basic_lock(&xfr->lock); + lock_rw_unlock(&az->lock); + + xfr_process_notify(xfr, env, 0, 0, NULL); + return 1; +} + /** set a zone expired */ static void auth_xfer_set_expired(struct auth_xfer* xfr, struct module_env* env, @@ -5073,7 +5094,8 @@ xfr_transfer_nexttarget_or_end(struct auth_xfer* xfr, struct module_env* env) xfr_transfer_disown(xfr); /* pick up the nextprobe task and wait */ - xfr_set_timeout(xfr, env, 1, 0); + if(xfr->task_nextprobe->worker == NULL) + xfr_set_timeout(xfr, env, 1, 0); lock_basic_unlock(&xfr->lock); } @@ -5132,7 +5154,8 @@ xfr_master_add_addrs(struct auth_master* m, struct ub_packed_rrset_key* rrset, /** callback for task_transfer lookup of host name, of A or AAAA */ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus)) + enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), + int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -5530,7 +5553,8 @@ process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env) return; } else { /* pick up the nextprobe task and wait (normail wait time) */ - xfr_set_timeout(xfr, env, 0, 0); + if(xfr->task_nextprobe->worker == NULL) + xfr_set_timeout(xfr, env, 0, 0); } lock_basic_unlock(&xfr->lock); return; @@ -5871,29 +5895,35 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err, return 0; } + /* other tasks are running, we don't do this anymore */ + xfr_probe_disown(xfr); + 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; } 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) - xfr_set_timeout(xfr, env, 0, 0); + verbose(VERB_ALGO, "auth_zone master reports unchanged soa serial"); + /* we if cannot find updates amongst the + * masters, this means we then have a new lease + * on the zone */ + xfr->task_probe->have_new_lease = 1; + } + } else { + if(verbosity >= VERB_ALGO) { + char buf[256]; + dname_str(xfr->name, buf); + verbose(VERB_ALGO, "auth zone %s: bad reply to soa probe", buf); } - /* other tasks are running, we don't do this anymore */ - xfr_probe_disown(xfr); - 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; } - } - if(verbosity >= VERB_ALGO) { - char buf[256]; - dname_str(xfr->name, buf); - verbose(VERB_ALGO, "auth zone %s: soa probe failed", buf); + } else { + if(verbosity >= VERB_ALGO) { + char buf[256]; + dname_str(xfr->name, buf); + verbose(VERB_ALGO, "auth zone %s: soa probe failed", buf); + } } - /* failed lookup */ + /* failed lookup or not an update */ /* delete commpoint so a new one is created, with a fresh port nr */ comm_point_delete(xfr->task_probe->cp); xfr->task_probe->cp = NULL; @@ -5996,7 +6026,8 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) /* only wanted lookups for copy, stop probe and start wait */ xfr->task_probe->only_lookup = 0; xfr_probe_disown(xfr); - xfr_set_timeout(xfr, env, 0, 0); + if(xfr->task_nextprobe->worker == NULL) + xfr_set_timeout(xfr, env, 0, 0); lock_basic_unlock(&xfr->lock); return; } @@ -6012,18 +6043,31 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) xfr_probe_nextmaster(xfr); } - /* we failed to send this as well, move to the wait task, - * use the shorter retry timeout */ - xfr_probe_disown(xfr); + /* done with probe sequence, wait */ + if(xfr->task_probe->have_new_lease) { + /* if zone not updated, start the wait timer again */ + verbose(VERB_ALGO, "auth_zone unchanged, new lease, wait"); + xfr_probe_disown(xfr); + if(xfr->have_zone) + xfr->lease_time = *env->now; + if(xfr->task_nextprobe->worker == NULL) + xfr_set_timeout(xfr, env, 0, 0); + } else { + /* we failed to send this as well, move to the wait task, + * use the shorter retry timeout */ + xfr_probe_disown(xfr); + /* pick up the nextprobe task and wait */ + if(xfr->task_nextprobe->worker == NULL) + xfr_set_timeout(xfr, env, 1, 0); + } - /* pick up the nextprobe task and wait */ - xfr_set_timeout(xfr, env, 1, 0); lock_basic_unlock(&xfr->lock); } /** callback for task_probe lookup of host name, of A or AAAA */ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus)) + enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), + int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -6151,6 +6195,8 @@ xfr_start_probe(struct auth_xfer* xfr, struct module_env* env, xfr->task_probe->cp = NULL; /* start the task */ + /* have not seen a new lease yet, this scan */ + xfr->task_probe->have_new_lease = 0; /* if this was a timeout, no specific first master to scan */ /* otherwise, spec is nonNULL the notified master, scan * first and also transfer first from it */ diff --git a/services/authzone.h b/services/authzone.h index 4e06c0654d99..8c636eaa446c 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -309,6 +309,9 @@ struct auth_probe { /** we only want to do lookups for making config work (for notify), * don't proceed with UDP SOA probe queries */ int only_lookup; + /** we have seen a new lease this scan, because one of the masters + * replied with the current SOA serial version */ + int have_new_lease; /** once notified, or the timeout has been reached. a scan starts. */ /** the scan specific target (notify source), or NULL if none */ @@ -509,12 +512,13 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo, * @param qinfo: query info (parsed). * @param edns: edns info (parsed). * @param buf: buffer with query ID and flags, also for reply. + * @param repinfo: reply information for a communication point. * @param temp: temporary storage region. * @return false if not answered */ int auth_zones_answer(struct auth_zones* az, struct module_env* env, - struct query_info* qinfo, struct edns_data* edns, struct sldns_buffer* buf, - struct regional* temp); + struct query_info* qinfo, struct edns_data* edns, + struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp); /** * Find the auth zone that is above the given qname. @@ -588,6 +592,12 @@ int auth_zones_notify(struct auth_zones* az, struct module_env* env, * returns 0 if no soa record in the notify */ int auth_zone_parse_notify_serial(struct sldns_buffer* pkt, uint32_t *serial); +/** for the zone and if not already going, starts the probe sequence. + * false if zone cannot be found. This is like a notify arrived and was + * accepted for that zone. */ +int auth_zones_startprobesequence(struct auth_zones* az, + struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t dclass); + /** read auth zone from zonefile. caller must lock zone. false on failure */ int auth_zone_read_zonefile(struct auth_zone* z); @@ -637,10 +647,12 @@ int auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err, void auth_xfer_probe_timer_callback(void* arg); /** mesh callback for task_probe on lookup of host names */ void auth_xfer_probe_lookup_callback(void* arg, int rcode, - struct sldns_buffer* buf, enum sec_status sec, char* why_bogus); + struct sldns_buffer* buf, enum sec_status sec, char* why_bogus, + int was_ratelimited); /** mesh callback for task_transfer on lookup of host names */ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, - struct sldns_buffer* buf, enum sec_status sec, char* why_bogus); + struct sldns_buffer* buf, enum sec_status sec, char* why_bogus, + int was_ratelimited); /* * Compares two 32-bit serial numbers as defined in RFC1982. Returns diff --git a/services/cache/dns.c b/services/cache/dns.c index 35adc35b57ee..01c9a8c5c10a 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -109,7 +109,7 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now, } /** delete message from message cache */ -static void +void msg_cache_remove(struct module_env* env, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags) { @@ -547,6 +547,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, if(r->prefetch_ttl > now) msg->rep->prefetch_ttl = r->prefetch_ttl - now; else msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; msg->rep->security = r->security; msg->rep->an_numrrsets = r->an_numrrsets; msg->rep->ns_numrrsets = r->ns_numrrsets; @@ -601,6 +602,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region, msg->rep->qdcount = 1; msg->rep->ttl = d->ttl - now; msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; msg->rep->security = sec_status_unchecked; msg->rep->an_numrrsets = 1; msg->rep->ns_numrrsets = 0; @@ -638,6 +640,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region, msg->rep->qdcount = 1; msg->rep->ttl = d->ttl - now; msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; msg->rep->security = sec_status_unchecked; msg->rep->an_numrrsets = 1; msg->rep->ns_numrrsets = 0; @@ -696,6 +699,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region, newd->rr_ttl[0] = newd->ttl; msg->rep->ttl = newd->ttl; msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(newd->ttl); + msg->rep->serve_expired_ttl = newd->ttl + SERVE_EXPIRED_TTL; sldns_write_uint16(newd->rr_data[0], newlen); memmove(newd->rr_data[0] + sizeof(uint16_t), newname, newlen); msg->rep->an_numrrsets ++; diff --git a/services/cache/dns.h b/services/cache/dns.h index 78f81e799522..19d0d9f992d1 100644 --- a/services/cache/dns.h +++ b/services/cache/dns.h @@ -238,4 +238,16 @@ struct msgreply_entry* msg_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, time_t now, int wr); +/** + * Remove entry from the message cache. For unwanted entries. + * @param env: with message cache. + * @param qname: query name, in wireformat + * @param qnamelen: length of qname, including terminating 0. + * @param qtype: query type, host order. + * @param qclass: query class, host order. + * @param flags: flags + */ +void msg_cache_remove(struct module_env* env, uint8_t* qname, size_t qnamelen, + uint16_t qtype, uint16_t qclass, uint16_t flags); + #endif /* SERVICES_CACHE_DNS_H */ diff --git a/services/cache/infra.c b/services/cache/infra.c index f4320306daa2..6f8fea6ad826 100644 --- a/services/cache/infra.c +++ b/services/cache/infra.c @@ -215,6 +215,18 @@ static int infra_ratelimit_cfg_insert(struct infra_cache* infra, return 1; } +/** setup domain limits tree (0 on failure) */ +static int +setup_domain_limits(struct infra_cache* infra, struct config_file* cfg) +{ + name_tree_init(&infra->domain_limits); + if(!infra_ratelimit_cfg_insert(infra, cfg)) { + return 0; + } + name_tree_init_parents(&infra->domain_limits); + return 1; +} + struct infra_cache* infra_create(struct config_file* cfg) { @@ -230,7 +242,6 @@ infra_create(struct config_file* cfg) return NULL; } infra->host_ttl = cfg->host_ttl; - name_tree_init(&infra->domain_limits); infra_dp_ratelimit = cfg->ratelimit; infra->domain_rates = slabhash_create(cfg->ratelimit_slabs, INFRA_HOST_STARTSIZE, cfg->ratelimit_size, @@ -241,11 +252,10 @@ infra_create(struct config_file* cfg) return NULL; } /* insert config data into ratelimits */ - if(!infra_ratelimit_cfg_insert(infra, cfg)) { + if(!setup_domain_limits(infra, cfg)) { infra_delete(infra); return NULL; } - name_tree_init_parents(&infra->domain_limits); infra_ip_ratelimit = cfg->ip_ratelimit; infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs, INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc, @@ -285,12 +295,28 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg) if(!infra) return infra_create(cfg); infra->host_ttl = cfg->host_ttl; + infra_dp_ratelimit = cfg->ratelimit; + infra_ip_ratelimit = cfg->ip_ratelimit; maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+ sizeof(struct infra_data)+INFRA_BYTES_NAME); - if(maxmem != slabhash_get_size(infra->hosts) || - cfg->infra_cache_slabs != infra->hosts->size) { + /* divide cachesize by slabs and multiply by slabs, because if the + * cachesize is not an even multiple of slabs, that is the resulting + * size of the slabhash */ + if(!slabhash_is_size(infra->hosts, maxmem, cfg->infra_cache_slabs) || + !slabhash_is_size(infra->domain_rates, cfg->ratelimit_size, + cfg->ratelimit_slabs) || + !slabhash_is_size(infra->client_ip_rates, cfg->ip_ratelimit_size, + cfg->ip_ratelimit_slabs)) { infra_delete(infra); infra = infra_create(cfg); + } else { + /* reapply domain limits */ + traverse_postorder(&infra->domain_limits, domain_limit_free, + NULL); + if(!setup_domain_limits(infra, cfg)) { + infra_delete(infra); + return NULL; + } } return infra; } diff --git a/services/cache/rrset.c b/services/cache/rrset.c index 26c1aeb91c62..8c0251bcb939 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -81,8 +81,8 @@ void rrset_cache_delete(struct rrset_cache* r) struct rrset_cache* rrset_cache_adjust(struct rrset_cache *r, struct config_file* cfg, struct alloc_cache* alloc) { - if(!r || !cfg || cfg->rrset_cache_slabs != r->table.size || - cfg->rrset_cache_size != slabhash_get_size(&r->table)) + if(!r || !cfg || !slabhash_is_size(&r->table, cfg->rrset_cache_size, + cfg->rrset_cache_slabs)) { rrset_cache_delete(r); r = rrset_cache_create(cfg, alloc); diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 248cad3665b0..458bf6f513f2 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -564,7 +564,8 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, /* detect freebsd jail with no ipv6 permission */ if(family==AF_INET6 && errno==EINVAL) *noproto = 1; - else if(errno != EADDRINUSE) { + else if(errno != EADDRINUSE && + !(errno == EACCES && verbosity < 4 && !listen)) { log_err_addr("can't bind socket", strerror(errno), (struct sockaddr_storage*)addr, addrlen); } @@ -572,7 +573,8 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, close(s); #else /* USE_WINSOCK */ if(WSAGetLastError() != WSAEADDRINUSE && - WSAGetLastError() != WSAEADDRNOTAVAIL) { + WSAGetLastError() != WSAEADDRNOTAVAIL && + !(WSAGetLastError() == WSAEACCES && verbosity < 4 && !listen)) { log_err_addr("can't bind socket", wsa_strerror(WSAGetLastError()), (struct sockaddr_storage*)addr, addrlen); @@ -1216,7 +1218,8 @@ listen_cp_insert(struct comm_point* c, struct listen_dnsport* front) struct listen_dnsport* listen_create(struct comm_base* base, struct listen_port* ports, - size_t bufsize, int tcp_accept_count, void* sslctx, + size_t bufsize, int tcp_accept_count, int tcp_idle_timeout, + struct tcl_list* tcp_conn_limit, void* sslctx, struct dt_env* dtenv, comm_point_callback_type* cb, void *cb_arg) { struct listen_dnsport* front = (struct listen_dnsport*) @@ -1243,10 +1246,12 @@ listen_create(struct comm_base* base, struct listen_port* ports, else if(ports->ftype == listen_type_tcp || ports->ftype == listen_type_tcp_dnscrypt) cp = comm_point_create_tcp(base, ports->fd, - tcp_accept_count, bufsize, cb, cb_arg); + tcp_accept_count, tcp_idle_timeout, + tcp_conn_limit, bufsize, cb, cb_arg); else if(ports->ftype == listen_type_ssl) { cp = comm_point_create_tcp(base, ports->fd, - tcp_accept_count, bufsize, cb, cb_arg); + tcp_accept_count, tcp_idle_timeout, + tcp_conn_limit, bufsize, cb, cb_arg); cp->ssl = sslctx; } else if(ports->ftype == listen_type_udpancil || ports->ftype == listen_type_udpancil_dnscrypt) diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index fac0f7970924..46b432d4b934 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -47,6 +47,7 @@ struct listen_list; struct config_file; struct addrinfo; struct sldns_buffer; +struct tcl_list; /** * Listening for queries structure. @@ -137,6 +138,8 @@ void listening_ports_free(struct listen_port* list); * @param bufsize: size of datagram buffer. * @param tcp_accept_count: max number of simultaneous TCP connections * from clients. + * @param tcp_idle_timeout: idle timeout for TCP connections in msec. + * @param tcp_conn_limit: TCP connection limit info. * @param sslctx: nonNULL if ssl context. * @param dtenv: nonNULL if dnstap enabled. * @param cb: callback function when a request arrives. It is passed @@ -145,9 +148,10 @@ void listening_ports_free(struct listen_port* list); * @return: the malloced listening structure, ready for use. NULL on error. */ struct listen_dnsport* listen_create(struct comm_base* base, - struct listen_port* ports, size_t bufsize, int tcp_accept_count, - void* sslctx, struct dt_env *dtenv, comm_point_callback_type* cb, - void* cb_arg); + struct listen_port* ports, size_t bufsize, + int tcp_accept_count, int tcp_idle_timeout, + struct tcl_list* tcp_conn_limit, void* sslctx, + struct dt_env *dtenv, comm_point_callback_type* cb, void* cb_arg); /** * delete the listening structure diff --git a/services/localzone.c b/services/localzone.c index 0f608170c850..902a29f21d48 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1146,8 +1146,9 @@ void local_zones_print(struct local_zones* zones) /** encode answer consisting of 1 rrset */ static int local_encode(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - struct ub_packed_rrset_key* rrset, int ansec, int rcode) + struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, + struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec, + int rcode) { struct reply_info rep; uint16_t udpsize; @@ -1165,23 +1166,22 @@ local_encode(struct query_info* qinfo, struct module_env* env, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, temp) - || !reply_info_answer_encode(qinfo, &rep, - *(uint16_t*)sldns_buffer_begin(buf), - sldns_buffer_read_u16_at(buf, 2), - buf, 0, 0, temp, udpsize, edns, - (int)(edns->bits&EDNS_DO), 0)) + if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, + repinfo, temp) || !reply_info_answer_encode(qinfo, &rep, + *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), + buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) { error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); + } return 1; } /** encode local error answer */ static void local_error_encode(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - int rcode, int r) + struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, + struct regional* temp, int rcode, int r) { edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; @@ -1189,7 +1189,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env, edns->bits &= EDNS_DO; if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, - rcode, edns, temp)) + rcode, edns, repinfo, temp)) edns->opt_list = NULL; error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); @@ -1310,7 +1310,8 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list, /** answer local data match */ static int local_data_answer(struct local_zone* z, struct module_env* env, - struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, + struct query_info* qinfo, struct edns_data* edns, + struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, int labs, struct local_data** ldp, enum localzone_type lz_type, int tag, struct config_strlist** tag_datas, size_t tag_datas_size, char** tagname, int num_tags) @@ -1339,7 +1340,7 @@ local_data_answer(struct local_zone* z, struct module_env* env, * chain. */ if(qinfo->local_alias) return 1; - return local_encode(qinfo, env, edns, buf, temp, + return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1, LDNS_RCODE_NOERROR); } } @@ -1374,29 +1375,60 @@ local_data_answer(struct local_zone* z, struct module_env* env, struct ub_packed_rrset_key r = *lr->rrset; r.rk.dname = qinfo->qname; r.rk.dname_len = qinfo->qname_len; - return local_encode(qinfo, env, edns, buf, temp, &r, 1, + return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1, LDNS_RCODE_NOERROR); } - return local_encode(qinfo, env, edns, buf, temp, lr->rrset, 1, + return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1, LDNS_RCODE_NOERROR); } +/** + * See if the local zone does not cover the name, eg. the name is not + * in the zone and the zone is transparent */ +static int +local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo, + int labs) +{ + struct local_data key; + struct local_data* ld = NULL; + struct local_rrset* lr = NULL; + if(z->type == local_zone_always_transparent) + return 1; + if(z->type != local_zone_transparent + && z->type != local_zone_typetransparent + && z->type != local_zone_inform) + return 0; + key.node.key = &key; + key.name = qinfo->qname; + key.namelen = qinfo->qname_len; + key.namelabs = labs; + ld = (struct local_data*)rbtree_search(&z->data, &key.node); + if(z->type == local_zone_transparent || z->type == local_zone_inform) + return (ld == NULL); + if(ld) + lr = local_data_find_type(ld, qinfo->qtype, 1); + /* local_zone_typetransparent */ + return (lr == NULL); +} + /** - * answer in case where no exact match is found - * @param z: zone for query - * @param env: module environment - * @param qinfo: query - * @param edns: edns from query + * Answer in case where no exact match is found. + * @param z: zone for query. + * @param env: module environment. + * @param qinfo: query. + * @param edns: edns from query. + * @param repinfo: source address for checks. may be NULL. * @param buf: buffer for answer. - * @param temp: temp region for encoding + * @param temp: temp region for encoding. * @param ld: local data, if NULL, no such name exists in localdata. - * @param lz_type: type of the local zone + * @param lz_type: type of the local zone. * @return 1 if a reply is to be sent, 0 if not. */ static int lz_zone_answer(struct local_zone* z, struct module_env* env, - struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, - struct regional* temp, struct local_data* ld, enum localzone_type lz_type) + struct query_info* qinfo, struct edns_data* edns, + struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, + struct local_data* ld, enum localzone_type lz_type) { if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) { /** no reply at all, signal caller by clearing buffer. */ @@ -1405,7 +1437,7 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, return 1; } else if(lz_type == local_zone_refuse || lz_type == local_zone_always_refuse) { - local_error_encode(qinfo, env, edns, buf, temp, + local_error_encode(qinfo, env, edns, repinfo, buf, temp, LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA)); return 1; } else if(lz_type == local_zone_static || @@ -1421,9 +1453,9 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, int rcode = (ld || lz_type == local_zone_redirect)? LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; if(z->soa) - return local_encode(qinfo, env, edns, buf, temp, + return local_encode(qinfo, env, edns, repinfo, buf, temp, z->soa, 0, rcode); - local_error_encode(qinfo, env, edns, buf, temp, rcode, + local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode, (rcode|BIT_AA)); return 1; } else if(lz_type == local_zone_typetransparent @@ -1438,9 +1470,9 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, if(ld && ld->rrsets) { int rcode = LDNS_RCODE_NOERROR; if(z->soa) - return local_encode(qinfo, env, edns, buf, temp, + return local_encode(qinfo, env, edns, repinfo, buf, temp, z->soa, 0, rcode); - local_error_encode(qinfo, env, edns, buf, temp, rcode, + local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode, (rcode|BIT_AA)); return 1; } @@ -1459,7 +1491,7 @@ lz_inform_print(struct local_zone* z, struct query_info* qinfo, uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port); dname_str(z->name, zname); addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); - snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip, + snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip, (unsigned)port); log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); } @@ -1543,10 +1575,6 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, (z = local_zones_lookup(view->local_zones, qinfo->qname, qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype))) { - if(z->type != local_zone_noview) - verbose(VERB_ALGO, - "using localzone from view: %s", - view->name); lock_rw_rdlock(&z->lock); lzt = z->type; } @@ -1554,10 +1582,24 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, lock_rw_unlock(&z->lock); z = NULL; } + if(z && (lzt == local_zone_transparent || + lzt == local_zone_typetransparent || + lzt == local_zone_inform || + lzt == local_zone_always_transparent) && + local_zone_does_not_cover(z, qinfo, labs)) { + lock_rw_unlock(&z->lock); + z = NULL; + } if(view->local_zones && !z && !view->isfirst){ lock_rw_unlock(&view->lock); return 0; } + if(z && verbosity >= VERB_ALGO) { + char zname[255+1]; + dname_str(z->name, zname); + verbose(VERB_ALGO, "using localzone %s %s from view %s", + zname, local_zone_type2str(lzt), view->name); + } lock_rw_unlock(&view->lock); } if(!z) { @@ -1570,27 +1612,33 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, return 0; } lock_rw_rdlock(&z->lock); - lzt = lz_type(taglist, taglen, z->taglist, z->taglen, tagactions, tagactionssize, z->type, repinfo, z->override_tree, &tag, tagname, num_tags); lock_rw_unlock(&zones->lock); + if(z && verbosity >= VERB_ALGO) { + char zname[255+1]; + dname_str(z->name, zname); + verbose(VERB_ALGO, "using localzone %s %s", zname, + local_zone_type2str(lzt)); + } } - if((lzt == local_zone_inform || lzt == local_zone_inform_deny) - && repinfo) + if((env->cfg->log_local_actions || + lzt == local_zone_inform || lzt == local_zone_inform_deny) + && repinfo) lz_inform_print(z, qinfo, repinfo); if(lzt != local_zone_always_refuse && lzt != local_zone_always_transparent && lzt != local_zone_always_nxdomain - && local_data_answer(z, env, qinfo, edns, buf, temp, labs, &ld, lzt, - tag, tag_datas, tag_datas_size, tagname, num_tags)) { + && local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs, + &ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) { lock_rw_unlock(&z->lock); /* We should tell the caller that encode is deferred if we found * a local alias. */ return !qinfo->local_alias; } - r = lz_zone_answer(z, env, qinfo, edns, buf, temp, ld, lzt); + r = lz_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt); lock_rw_unlock(&z->lock); return r && !qinfo->local_alias; /* see above */ } diff --git a/services/mesh.c b/services/mesh.c index 41aba74ab260..c6bb9ef2bc63 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -55,6 +55,7 @@ #include "util/fptr_wlist.h" #include "util/alloc.h" #include "util/config_file.h" +#include "util/edns.h" #include "sldns/sbuffer.h" #include "sldns/wire2str.h" #include "services/localzone.h" @@ -385,7 +386,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, if(!s) { log_err("mesh_state_create: out of memory; SERVFAIL"); if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, - LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch)) + LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch)) edns->opt_list = NULL; error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); @@ -401,7 +402,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, if(!s->s.edns_opts_front_in) { log_err("mesh_state_create: out of memory; SERVFAIL"); if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, - NULL, LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch)) + NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch)) edns->opt_list = NULL; error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); @@ -429,7 +430,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) { log_err("mesh_new_client: out of memory; SERVFAIL"); if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s, - NULL, LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch)) + NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch)) edns->opt_list = NULL; error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); @@ -631,8 +632,8 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, mesh_run(mesh, e->qstate->mesh_info, event, e); } -struct mesh_state* -mesh_state_create(struct module_env* env, struct query_info* qinfo, +struct mesh_state* +mesh_state_create(struct module_env* env, struct query_info* qinfo, struct respip_client_info* cinfo, uint16_t qflags, int prime, int valrec) { @@ -693,6 +694,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo, mstate->s.no_cache_lookup = 0; mstate->s.no_cache_store = 0; mstate->s.need_refetch = 0; + mstate->s.was_ratelimited = 0; /* init modules */ for(i=0; i<env->mesh->mods.num; i++) { @@ -740,7 +742,7 @@ mesh_state_cleanup(struct mesh_state* mstate) mstate->cb_list = cb->next; fptr_ok(fptr_whitelist_mesh_cb(cb->cb)); (*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL, - sec_status_unchecked, NULL); + sec_status_unchecked, NULL, 0); mesh->num_reply_addrs--; } } @@ -968,7 +970,8 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, { int secure; char* reason = NULL; - /* bogus messages are not made into servfail, sec_status passed + int was_ratelimited = m->s.was_ratelimited; + /* bogus messages are not made into servfail, sec_status passed * to the callback function */ if(rep && rep->security == sec_status_secure) secure = 1; @@ -977,22 +980,23 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, rcode = LDNS_RCODE_SERVFAIL; if(!rcode && (rep->security == sec_status_bogus || rep->security == sec_status_secure_sentinel_fail)) { - if(!(reason = errinf_to_str(&m->s))) + if(!(reason = errinf_to_str_bogus(&m->s))) rcode = LDNS_RCODE_SERVFAIL; } /* send the reply */ if(rcode) { if(rcode == LDNS_RCODE_SERVFAIL) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, - rep, rcode, &r->edns, m->s.region)) + rep, rcode, &r->edns, NULL, m->s.region)) r->edns.opt_list = NULL; } else { if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, - &r->edns, m->s.region)) + &r->edns, NULL, m->s.region)) r->edns.opt_list = NULL; } fptr_ok(fptr_whitelist_mesh_cb(r->cb)); - (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL); + (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL, + was_ratelimited); } else { size_t udp_size = r->edns.udp_size; sldns_buffer_clear(r->buf); @@ -1002,7 +1006,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, r->edns.bits &= EDNS_DO; if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, - LDNS_RCODE_NOERROR, &r->edns, m->s.region) || + LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) || !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, r->qflags, r->buf, 0, 1, m->s.env->scratch, udp_size, &r->edns, @@ -1010,11 +1014,11 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf, - sec_status_unchecked, NULL); + sec_status_unchecked, NULL, 0); } else { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf, - rep->security, reason); + rep->security, reason, was_ratelimited); } } free(reason); @@ -1080,11 +1084,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, m->s.qinfo.local_alias = r->local_alias; if(rcode == LDNS_RCODE_SERVFAIL) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, - rep, rcode, &r->edns, m->s.region)) + rep, rcode, &r->edns, NULL, m->s.region)) r->edns.opt_list = NULL; } else { if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, - &r->edns, m->s.region)) + &r->edns, NULL, m->s.region)) r->edns.opt_list = NULL; } error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo, @@ -1099,14 +1103,17 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, - LDNS_RCODE_NOERROR, &r->edns, m->s.region) || + LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) || + !apply_edns_options(&r->edns, &edns_bak, + m->s.env->cfg, r->query_reply.c, + m->s.region) || !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, r->qflags, r->query_reply.c->buffer, 0, 1, m->s.env->scratch, udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO), secure)) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, - rep, LDNS_RCODE_SERVFAIL, &r->edns, m->s.region)) + rep, LDNS_RCODE_SERVFAIL, &r->edns, NULL, m->s.region)) r->edns.opt_list = NULL; error_encode(r->query_reply.c->buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, @@ -1148,6 +1155,15 @@ void mesh_query_done(struct mesh_state* mstate) struct mesh_cb* c; struct reply_info* rep = (mstate->s.return_msg? mstate->s.return_msg->rep:NULL); + if((mstate->s.return_rcode == LDNS_RCODE_SERVFAIL || + (rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) + && mstate->s.env->cfg->log_servfail + && !mstate->s.env->cfg->val_log_squelch) { + char* err = errinf_to_str_servfail(&mstate->s); + if(err) + log_err("%s", err); + free(err); + } for(r = mstate->reply_list; r; r = r->next) { /* if a response-ip address block has been stored the * information should be logged for each client. */ @@ -1197,6 +1213,8 @@ void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate) mesh->mods.mod[ref->s->s.curmod]->inform_super)); (*mesh->mods.mod[ref->s->s.curmod]->inform_super)(&mstate->s, ref->s->s.curmod, &ref->s->s); + /* copy state that is always relevant to super */ + copy_state_to_super(&mstate->s, ref->s->s.curmod, &ref->s->s); } } diff --git a/services/mesh.h b/services/mesh.h index 67749accb35a..b4ce03e7e2a0 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -223,10 +223,11 @@ struct mesh_reply { /** * Mesh result callback func. - * called as func(cb_arg, rcode, buffer_with_reply, security, why_bogus); + * called as func(cb_arg, rcode, buffer_with_reply, security, why_bogus, + * was_ratelimited); */ -typedef void (*mesh_cb_func_type)(void*, int, struct sldns_buffer*, enum sec_status, - char*); +typedef void (*mesh_cb_func_type)(void* cb_arg, int rcode, struct sldns_buffer*, + enum sec_status, char* why_bogus, int was_ratelimited); /** * Callback to result routine @@ -242,9 +243,8 @@ struct mesh_cb { uint16_t qflags; /** buffer for reply */ struct sldns_buffer* buf; - /** callback routine for results. if rcode != 0 buf has message. - * called as cb(cb_arg, rcode, buf, sec_state); + * called as cb(cb_arg, rcode, buf, sec_state, why_bogus, was_ratelimited); */ mesh_cb_func_type cb; /** user arg for callback */ diff --git a/services/outside_network.c b/services/outside_network.c index 5700ef8a95e5..87c88349b3f8 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -48,6 +48,7 @@ #include "services/outside_network.h" #include "services/listen_dnsport.h" #include "services/cache/infra.h" +#include "iterator/iterator.h" #include "util/data/msgparse.h" #include "util/data/msgreply.h" #include "util/data/msgencode.h" @@ -1036,6 +1037,8 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, int freebind = 0; struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; sa.sin6_port = (in_port_t)htons((uint16_t)port); + sa.sin6_flowinfo = 0; + sa.sin6_scope_id = 0; if(pfxlen != 0) { freebind = 1; sai6_putrandom(&sa, pfxlen, rnd); @@ -1882,7 +1885,7 @@ serviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff) sq->last_sent_time = *sq->outnet->now_tv; if(sq->tcp_upstream || sq->ssl_upstream) { timeout = rtt; - if(rtt >= 376 && rtt < TCP_AUTH_QUERY_TIMEOUT) + if(rtt >= UNKNOWN_SERVER_NICENESS && rtt < TCP_AUTH_QUERY_TIMEOUT) timeout = TCP_AUTH_QUERY_TIMEOUT; } else { timeout = TCP_AUTH_QUERY_TIMEOUT; @@ -2190,39 +2193,48 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, { struct sockaddr_storage* addr; socklen_t addrlen; - int i; - int try; - - /* select interface */ - if(addr_is_ip6(to_addr, to_addrlen)) { - if(outnet->num_ip6 == 0) { - char to[64]; - addr_to_str(to_addr, to_addrlen, to, sizeof(to)); - verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing interfaces, for %s", to); - return -1; - } - i = ub_random_max(outnet->rnd, outnet->num_ip6); - addr = &outnet->ip6_ifs[i].addr; - addrlen = outnet->ip6_ifs[i].addrlen; - } else { - if(outnet->num_ip4 == 0) { - char to[64]; - addr_to_str(to_addr, to_addrlen, to, sizeof(to)); - verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing interfaces, for %s", to); - return -1; - } - i = ub_random_max(outnet->rnd, outnet->num_ip4); - addr = &outnet->ip4_ifs[i].addr; - addrlen = outnet->ip4_ifs[i].addrlen; - } + int i, try, pnum; + struct port_if* pif; /* create fd */ for(try = 0; try<1000; try++) { + int port = 0; int freebind = 0; int noproto = 0; int inuse = 0; - int port = ub_random(outnet->rnd)&0xffff; int fd = -1; + + /* select interface */ + if(addr_is_ip6(to_addr, to_addrlen)) { + if(outnet->num_ip6 == 0) { + char to[64]; + addr_to_str(to_addr, to_addrlen, to, sizeof(to)); + verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing interfaces, for %s", to); + return -1; + } + i = ub_random_max(outnet->rnd, outnet->num_ip6); + pif = &outnet->ip6_ifs[i]; + } else { + if(outnet->num_ip4 == 0) { + char to[64]; + addr_to_str(to_addr, to_addrlen, to, sizeof(to)); + verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing interfaces, for %s", to); + return -1; + } + i = ub_random_max(outnet->rnd, outnet->num_ip4); + pif = &outnet->ip4_ifs[i]; + } + addr = &pif->addr; + addrlen = pif->addrlen; + pnum = ub_random_max(outnet->rnd, pif->avail_total); + if(pnum < pif->inuse) { + /* port already open */ + port = pif->out[pnum]->number; + } else { + /* unused ports in start part of array */ + port = pif->avail_ports[pnum - pif->inuse]; + } + if(addr_is_ip6(to_addr, to_addrlen)) { struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; sa.sin6_port = (in_port_t)htons((uint16_t)port); |
