mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-22 09:44:56 +02:00
intermediate commit
This commit is contained in:
+90
-3
@@ -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);
|
||||
|
||||
Vendored
+30
-61
@@ -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);
|
||||
|
||||
Vendored
+7
-8
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user