#include "sldns/str2wire.h"
#include "sldns/parseutil.h"
#include "sldns/sbuffer.h"
+#include "daemon/worker.h"
/* in msec */
int UNKNOWN_SERVER_NICENESS = 376;
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,
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;
}
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);
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;
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;
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);
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));
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,
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?
}
/* 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);
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;
};
* @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'
* @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);
/**
&& !(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 */
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);
}
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);
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;
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;
"outgoing interfaces of that family");
return 0;
}
+
log_assert(outnet->unused_fds);
tries = 0;
while(1) {
}
}
- 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);
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;
}
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 =
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. */
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,
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;
};