From: TCY16 Date: Tue, 18 Oct 2022 13:25:47 +0000 (+0200) Subject: intermediate commit X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb85f3435134e65dfe877b391547aa9488657cbc;p=thirdparty%2Funbound.git intermediate commit --- diff --git a/iterator/iterator.c b/iterator/iterator.c index ce4028924..f49632cfb 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -68,6 +68,7 @@ #include "sldns/str2wire.h" #include "sldns/parseutil.h" #include "sldns/sbuffer.h" +#include "daemon/worker.h" /* in msec */ int UNKNOWN_SERVER_NICENESS = 376; @@ -3872,6 +3873,82 @@ process_request(struct module_qstate* qstate, struct iter_qstate* iq, iter_handle(qstate, iq, ie, id); } + + +/** find the bound addr in the list of interfaces */ +static int +get_bound_ip_if(struct outside_network* outnet, + struct sockaddr_storage *bound_addr, socklen_t bound_addrlen, + struct port_if* pif_return) +{ + int i = 0; + struct port_if* pif_list; + int pif_list_len; + + /* Get the list of interfaces and check that that list isn't just the + * "any" address */ + if(addr_is_ip6(bound_addr, bound_addrlen)) { + pif_list = outnet->ip6_ifs; + pif_list_len = outnet->num_ip6; + + // @TODO fix IPv6 + } else { + pif_list = outnet->ip4_ifs; + pif_list_len = outnet->num_ip4; + struct sockaddr_storage addr_any; + socklen_t addr_any_len = 0; + + struct sockaddr_storage addr_fake; + socklen_t addr_fake_len = 0; + + + if (!ipstrtoaddr("0.0.0.0", 0, &addr_any, &addr_any_len)) { + // @TODO do something + } + + if (!ipstrtoaddr("10.10.1.1", 0, &addr_fake, &addr_fake_len)) { + // @TODO do something + } + + log_addr(VERB_DETAIL, "!!!!! outnet->ip4_ifs->addr", &outnet->ip4_ifs->addr, bound_addrlen); + log_addr(VERB_DETAIL, "!!!!! addr_any", &addr_any, addr_any_len); + + /* if we let the kernel decide the IP, fill in + * the previously used */ + if (pif_list_len == 1 && + sockaddr_cmp_addr(&outnet->ip4_ifs->addr, outnet->ip4_ifs->addrlen, + &addr_any, addr_any_len) == 0) { + + /* return the interface from the list, but substitute the + * previously used address */ + memcpy(pif_return, outnet->ip4_ifs, sizeof(struct port_if)); + memcpy(&pif_return->addr, &addr_fake, addr_fake_len); + pif_return->addrlen = addr_fake_len; + + log_addr(VERB_DETAIL, "!!!!! get_bound_ip_if: addr from ip4_ifs == 0.0.0.0, new is:", &pif_return->addr, outnet->ip4_ifs->addrlen); + + return 1; + } + } + + if (pif_list_len == 0) { + return 0; + } + + for (i = 0; i < pif_list_len; i++) { + struct port_if *iface = &pif_list[i]; + + if (iface->addrlen == bound_addrlen && + memcmp(&iface->addr, bound_addr, bound_addrlen)) { + memcpy(pif_return, iface, sizeof(struct port_if)); + + return 1; + } + } + + return 0; +} + /** process authoritative server reply */ static void process_response(struct module_qstate* qstate, struct iter_qstate* iq, @@ -3940,19 +4017,29 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, goto handle_it; } - /* handle the upstream response cookie if enabled*/ + /* handle the upstream response cookie if enabled */ if(qstate->env->cfg->upstream_cookies) { if (edns.opt_list_in && (cookie = edns_list_get_option(edns.opt_list_in, LDNS_EDNS_COOKIE))){ struct sockaddr_storage bound_addr; socklen_t bound_addrlen = sizeof(struct sockaddr); + struct port_if pif; + struct port_if *pif_ptr = &pif; if(getsockname(qstate->reply->c->fd, (struct sockaddr *) &bound_addr, &bound_addrlen) != -1) { log_addr(VERB_DETAIL, "!!!!! iterator:udp socket:", &bound_addr, bound_addrlen); + + if (!(get_bound_ip_if(qstate->env->worker->back, + &bound_addr, bound_addrlen, pif_ptr))) { + bound_addrlen = 0; + } + + log_addr(VERB_DETAIL, "!!!!! iterator:pif addr:", &pif.addr, pif.addrlen); + } else { bound_addrlen = 0; } @@ -3964,8 +4051,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, if (cookie->opt_len == 24 && infra_set_server_cookie(qstate->env->infra_cache, &qstate->reply->addr, qstate->reply->addrlen, - iq->dp->name, iq->dp->namelen, &bound_addr, - bound_addrlen, cookie) >= 0) { + iq->dp->name, iq->dp->namelen, pif_ptr, + cookie) >= 0) { /* log_hex() uses the verbosity levels of verbose() */ log_hex("complete cookie: ", cookie->opt_data, cookie->opt_len); diff --git a/services/cache/infra.c b/services/cache/infra.c index bbcfd414d..f988a61dc 100644 --- a/services/cache/infra.c +++ b/services/cache/infra.c @@ -383,18 +383,25 @@ infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr, return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr); } +/* helper function to fill in random data into the client cookie*/ +void infra_fill_client_cookie_random(struct infra_cache* infra, + uint8_t* data) { + int i; + + for (i = 0; i < 8; i++) { + data[i] = ub_random_max(infra->random_state, 256); + } +} + /** init the data elements */ static void data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, time_t timenow) { - int i; struct infra_data* data; - uint8_t cookie[8] = {0,0,0,0,0,0,0,0}; + uint8_t client_cookie_data[8] = {0,0,0,0,0,0,0,0}; - for (i = 0; i < 8; i++) { - cookie[i] = ub_random_max(infra->random_state, 256); - } + infra_fill_client_cookie_random(infra, client_cookie_data); data = (struct infra_data*)e->data; data->ttl = timenow + infra->host_ttl; @@ -404,7 +411,8 @@ data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, data->probedelay = 0; /* set EDNS cookie to zero, as this also sets the starting state*/ memset(&data->cookie, 0, sizeof(struct edns_cookie)); - memcpy(data->cookie.data.cookie, cookie, 8); + data->cookie.pif.out = NULL; + memcpy(data->cookie.data.cookie, client_cookie_data, 8); data->isdnsseclame = 0; data->rec_lame = 0; data->lame_type_A = 0; @@ -705,41 +713,10 @@ infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, return 1; } -/** find the bound addr in the list of interfaces */ -static int -get_bound_ip_if(struct outside_network* outnet, - struct sockaddr_storage bound_addr, socklen_t bound_addrlen, - struct port_if** pif_return) -{ - int i = 0; - struct port_if* pif_list; - int pif_list_len; - - if(addr_is_ip6(&bound_addr, bound_addrlen)) { - pif_list = outnet->ip6_ifs; - pif_list_len = outnet->num_ip6; - } else { - pif_list = outnet->ip4_ifs; - pif_list_len = outnet->num_ip4; - } - - for (i = 0; i < pif_list_len; i++) { - struct port_if *iface = &pif_list[i]; - - if (iface->addrlen == bound_addrlen && - memcmp(&iface->addr, &bound_addr, bound_addrlen)) { - *pif_return = iface; - return 1; - } - } - return 0; -} - int infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, - time_t timenow, struct outside_network* outnet, struct port_if** pif, - struct edns_cookie* cookie) + time_t timenow, struct edns_cookie* cookie) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, name, namelen, 1); @@ -763,21 +740,11 @@ infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr, data = (struct infra_data*) e->data; - if (data->cookie.state == SERVER_COOKIE_LEARNED) { - // lookup bound interface - log_err("!!!!! infra_get_cookie:bound_addrlen: %d", data->cookie.bound_addrlen); - log_addr(VERB_OPS, "!!!!! infra_get_cookie:bound_addr, len:", &data->cookie.bound_addr, - data->cookie.bound_addrlen); - - if (!(get_bound_ip_if(outnet, data->cookie.bound_addr, - data->cookie.bound_addrlen, pif))) { - log_err("!!!!!!!! creating new cookie for changed interface"); - data_entry_init(infra, e, timenow); - } - } - - // @TODO uggo: data has changed - data = (struct infra_data*) e->data; + // @TODO fix this logic. does the cookie status matter? + /* renew cookie if the address isn't available isn't stored */ + // if (data->cookie->addrlen == 0) { + // infra_fill_client_cookie_random(infra, &data->cookie->data); + // } memcpy(cookie, &data->cookie, sizeof(struct edns_cookie)); @@ -790,10 +757,9 @@ infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr, return 1; } -int +int infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* name, size_t namelen, - struct sockaddr_storage* bound_addr, socklen_t bound_addrlen, + socklen_t addrlen, uint8_t* name, size_t namelen, struct port_if *pif, struct edns_option* cookie) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, @@ -832,8 +798,8 @@ infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr return -1; } - if (!(data->cookie.bound_addrlen == bound_addrlen) && - memcpy(&data->cookie.bound_addr, bound_addr, bound_addrlen)){ + if (!(data->cookie.pif.addrlen == pif->addrlen) && + memcmp(&data->cookie.pif.addr, &pif->addr, pif->addrlen)){ // @TODO do something? this _should_ only happen on reloads? } @@ -872,9 +838,12 @@ infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr /* store the server cookie */ memcpy(data->cookie.data.cookie, cookie->opt_data, 24); data->cookie.state = SERVER_COOKIE_LEARNED; - if (bound_addrlen > 0) { - memcpy(&data->cookie.bound_addr, bound_addr, bound_addrlen); - data->cookie.bound_addrlen = bound_addrlen; + + /* store the inbound interface we receive this cookie on */ + if (pif->addrlen > 0) { + memcpy(&data->cookie.pif, + pif, sizeof(struct port_if)); + data->cookie.pif.addrlen = pif->addrlen; } verbose(VERB_QUERY, "storing received server cookie from upstream"); lock_rw_unlock(&e->lock); diff --git a/services/cache/infra.h b/services/cache/infra.h index 7ef4b0981..07fb74723 100644 --- a/services/cache/infra.h +++ b/services/cache/infra.h @@ -90,8 +90,9 @@ enum edns_cookie_state struct edns_cookie { enum edns_cookie_state state; struct edns_cookie_data data; - struct sockaddr_storage bound_addr; - socklen_t bound_addrlen; + struct port_if pif; + // struct sockaddr_storage bound_addr; + // socklen_t bound_addrlen; }; @@ -375,13 +376,13 @@ int infra_edns_update(struct infra_cache* infra, * @param name: name of zone * @param namelen: length of name * @param timenow: what time it is now. + * @param pif: the interface which contains the outgoing address that we bind to * @param cookie: the cookie that is retrieved from cache on success. * @return: 0 on error, cookie pointer remains unchanged then. */ int infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, - time_t timenow, struct outside_network* outnet, struct port_if** pif, - struct edns_cookie* cookie); + time_t timenow, struct edns_cookie* cookie); /** * Find the cookie entry in the cache and update it with to make a 'complete cookie' @@ -394,16 +395,14 @@ int infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr, * @param name: name of zone * @param namelen: length of name * @param timenow: what time it is now. - * @param bound_addr: the outgoing address that we bind to this cookie - * @param bound_addr: the length of the bound address + * @param pif: the interface which contains the outgoing address that we bind to * @param cookie: the EDNS cookie option we want to store. * @return -1 if the wrong client cookie is found, 0 if the entry isn't found in * the cache and a new one is inserted, 1 if the complete cookie is inserted * or unchanged. */ int infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* name, size_t namelen, - struct sockaddr_storage* bound_addr, socklen_t bound_addrlen, + socklen_t addrlen, uint8_t* name, size_t namelen, struct port_if *pif, struct edns_option* cookie); /** diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 467419b09..bfb701fda 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -630,7 +630,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, && !(errno == EADDRNOTAVAIL && verbosity < 4 && !listen) #endif ) { - log_err_addr("can't bind socket", strerror(errno), + log_err_addr("1can't bind socket", strerror(errno), (struct sockaddr_storage*)addr, addrlen); } #endif /* EADDRINUSE */ @@ -638,7 +638,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, if(WSAGetLastError() != WSAEADDRINUSE && WSAGetLastError() != WSAEADDRNOTAVAIL && !(WSAGetLastError() == WSAEACCES && verbosity < 4 && !listen)) { - log_err_addr("can't bind socket", + log_err_addr("2can't bind socket", wsa_strerror(WSAGetLastError()), (struct sockaddr_storage*)addr, addrlen); } @@ -824,12 +824,12 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, if(addr->ai_family==AF_INET6 && errno==EINVAL) *noproto = 1; else { - log_err_addr("can't bind socket", strerror(errno), + log_err_addr("3can't bind socket", strerror(errno), (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); } #else - log_err_addr("can't bind socket", + log_err_addr("4can't bind socket", wsa_strerror(WSAGetLastError()), (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); diff --git a/services/outside_network.c b/services/outside_network.c index 6954065ba..a5f00b340 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -1407,6 +1407,11 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error, struct pending* p; verbose(VERB_ALGO, "answer cb"); + + log_err("!!!!! outnet_udp_cb: HERE, error: %d", error); + + // @TODO this is the function where we find the failed kernel call + if(error != NETEVENT_NOERROR) { verbose(VERB_QUERY, "outnetudp got udp error %d", error); return 0; @@ -1939,6 +1944,9 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, int port, int* inuse, struct ub_randstate* rnd, int dscp) { int fd, noproto; + + log_err("!!!!! udp_sockport: HERE!"); + if(addr_is_ip6(addr, addrlen)) { int freebind = 0; struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; @@ -2032,6 +2040,7 @@ select_ifport(struct outside_network* outnet, struct pending* pend, "outgoing interfaces of that family"); return 0; } + log_assert(outnet->unused_fds); tries = 0; while(1) { @@ -2069,7 +2078,7 @@ select_ifport(struct outside_network* outnet, struct pending* pend, } } - log_err("!!!!! pif->inuse: %d, pif->maxout: %d", pif->inuse, pif->maxout); + log_err("!!!!! select_ifport:pif->inuse: %d, pif->maxout: %d", pif->inuse, pif->maxout); /* try to open new port, if fails, loop to try again */ log_assert(pif->inuse < pif->maxout); @@ -2080,6 +2089,7 @@ select_ifport(struct outside_network* outnet, struct pending* pend, fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, portno, &inuse, outnet->rnd, outnet->ip_dscp); if(fd == -1 && !inuse) { + log_err("!!!! select_ifport:nonrecoverable error making socket"); /* nonrecoverable error making socket */ return 0; } @@ -2616,7 +2626,17 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, sq->status = serviced_initial; sq->retry = 0; sq->to_be_deleted = 0; - sq->bound_interface = bound_interface; + if (bound_interface != NULL) { + sq->bound_interface = regional_alloc_init(region, + bound_interface, sizeof(struct port_if)); + if (!sq->bound_interface) { + alloc_reg_release(alloc, region); + free(sq); + return NULL; + } + } else { + sq->bound_interface = NULL; + } sq->padding_block_size = pad_queries_block_size; #ifdef UNBOUND_DEBUG ins = @@ -3377,7 +3397,7 @@ outnet_serviced_query(struct outside_network* outnet, struct edns_option* backed_up_opt_list = qstate->edns_opts_back_out; struct edns_option* per_upstream_opt_list = NULL; time_t timenow = 0; - struct port_if* pif; + struct port_if* pif = NULL; /* If we have an already populated EDNS option list make a copy since * we may now add upstream specific EDNS options. */ @@ -3416,12 +3436,18 @@ outnet_serviced_query(struct outside_network* outnet, if (env->cfg->upstream_cookies && infra_get_cookie(env->infra_cache, addr, addrlen, zone, zonelen, - *env->now, outnet, &pif, &cookie)) { + *env->now, &cookie)) { if (cookie.state == SERVER_COOKIE_LEARNED) { /* We known the complete cookie, so we attach it */ edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE, 24, cookie.data.cookie, region); + + if (cookie.pif.addrlen > 0) { + pif = &cookie.pif; + + log_addr(VERB_DETAIL, "!!!!! outnet_serviced_query:pif addr:", &cookie.pif.addr, cookie.pif.addrlen); + } } else if (cookie.state == SERVER_COOKIE_UNKNOWN) { /* We know just client cookie, so we attach it */ edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE, diff --git a/services/outside_network.h b/services/outside_network.h index 14d11b9b6..37162117d 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -527,7 +527,7 @@ struct serviced_query { struct comm_timer* timer; /** true if serviced_query is currently doing net I/O and may block */ int busy; - /** Interface bound to the EDNS cookie @TODO fix this */ + /** interface bound to the EDNS cookie @TODO fix this */ struct port_if* bound_interface; };