- and also generic edns options for upstream messages (and replies).

after parse use edns_opt_find(edns.opt_list, LDNS_EDNS_NSID),
  to insert use edns_opt_append(edns, region, code, len, bindata) on
  the opt_list passed to send_query, or in edns_opt_inplace_reply.


git-svn-id: file:///svn/unbound/trunk@3742 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2016-05-31 16:55:22 +00:00
parent 3904c2be9a
commit 031caba9c0
15 changed files with 186 additions and 61 deletions

View file

@ -1370,8 +1370,9 @@ worker_delete(struct worker* worker)
struct outbound_entry* struct outbound_entry*
worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec, uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec,
int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, int nocaps, struct edns_option* opt_list,
uint8_t* zone, size_t zonelen, struct module_qstate* q) struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
size_t zonelen, struct module_qstate* q)
{ {
struct worker* worker = q->env->worker; struct worker* worker = q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc( struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@ -1381,8 +1382,8 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
e->qstate = q; e->qstate = q;
e->qsent = outnet_serviced_query(worker->back, qname, e->qsent = outnet_serviced_query(worker->back, qname,
qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps,
q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, opt_list,
addrlen, zone, zonelen, worker_handle_service_reply, e, addr, addrlen, zone, zonelen, worker_handle_service_reply, e,
worker->back->udp_buff); worker->back->udp_buff);
if(!e->qsent) { if(!e->qsent) {
return NULL; return NULL;
@ -1427,7 +1428,8 @@ struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname),
size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list),
struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
{ {

View file

@ -3,6 +3,10 @@
network service account, from Mario Turschmann. network service account, from Mario Turschmann.
- compat strsep implementation. - compat strsep implementation.
- generic edns option parse and store code. - generic edns option parse and store code.
- and also generic edns options for upstream messages (and replies).
after parse use edns_opt_find(edns.opt_list, LDNS_EDNS_NSID),
to insert use edns_opt_append(edns, region, code, len, bindata) on
the opt_list passed to send_query, or in edns_opt_inplace_reply.
30 May 2016: Wouter 30 May 2016: Wouter
- Fix time in case answer comes from cache in ub_resolve_event(). - Fix time in case answer comes from cache in ub_resolve_event().

View file

@ -1786,6 +1786,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
int tf_policy; int tf_policy;
struct delegpt_addr* target; struct delegpt_addr* target;
struct outbound_entry* outq; struct outbound_entry* outq;
/* EDNS options to set on outgoing packet */
struct edns_option* opt_list = NULL;
/* NOTE: a request will encounter this state for each target it /* NOTE: a request will encounter this state for each target it
* needs to send a query to. That is, at least one per referral, * needs to send a query to. That is, at least one per referral,
@ -2103,8 +2105,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
!qstate->blacklist&&(!iter_indicates_dnssec_fwd(qstate->env, !qstate->blacklist&&(!iter_indicates_dnssec_fwd(qstate->env,
&iq->qinfo_out)||target->attempts==1)?0:BIT_CD), &iq->qinfo_out)||target->attempts==1)?0:BIT_CD),
iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted( iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
ie, iq), &target->addr, target->addrlen, iq->dp->name, ie, iq), opt_list, &target->addr, target->addrlen,
iq->dp->namelen, qstate); iq->dp->name, iq->dp->namelen, qstate);
if(!outq) { if(!outq) {
log_addr(VERB_DETAIL, "error sending query to auth server", log_addr(VERB_DETAIL, "error sending query to auth server",
&target->addr, target->addrlen); &target->addr, target->addrlen);

View file

@ -822,9 +822,9 @@ void libworker_alloc_cleanup(void* arg)
struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, struct sockaddr_storage* addr, int want_dnssec, int nocaps, struct edns_option* opt_list,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
struct module_qstate* q) size_t zonelen, struct module_qstate* q)
{ {
struct libworker* w = (struct libworker*)q->env->worker; struct libworker* w = (struct libworker*)q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc( struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@ -834,9 +834,9 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
e->qstate = q; e->qstate = q;
e->qsent = outnet_serviced_query(w->back, qname, e->qsent = outnet_serviced_query(w->back, qname,
qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps,
q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, opt_list,
addrlen, zone, zonelen, libworker_handle_service_reply, e, addr, addrlen, zone, zonelen, libworker_handle_service_reply,
w->back->udp_buff); e, w->back->udp_buff);
if(!e->qsent) { if(!e->qsent) {
return NULL; return NULL;
} }
@ -955,7 +955,8 @@ struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list),
struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
{ {

View file

@ -48,6 +48,7 @@ struct comm_reply;
struct comm_point; struct comm_point;
struct module_qstate; struct module_qstate;
struct tube; struct tube;
struct edns_option;
/** /**
* Worker service routine to send serviced queries to authoritative servers. * Worker service routine to send serviced queries to authoritative servers.
@ -59,6 +60,7 @@ struct tube;
* @param dnssec: if set, EDNS record will have DO bit set. * @param dnssec: if set, EDNS record will have DO bit set.
* @param want_dnssec: signatures needed. * @param want_dnssec: signatures needed.
* @param nocaps: ignore capsforid(if in config), do not perturb qname. * @param nocaps: ignore capsforid(if in config), do not perturb qname.
* @param opt_list: EDNS options on outgoing packet.
* @param addr: where to. * @param addr: where to.
* @param addrlen: length of addr. * @param addrlen: length of addr.
* @param zone: delegation point name. * @param zone: delegation point name.
@ -69,9 +71,9 @@ struct tube;
*/ */
struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, struct sockaddr_storage* addr, int want_dnssec, int nocaps, struct edns_option* opt_list,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
struct module_qstate* q); size_t zonelen, struct module_qstate* q);
/** process incoming replies from the network */ /** process incoming replies from the network */
int libworker_handle_reply(struct comm_point* c, void* arg, int error, int libworker_handle_reply(struct comm_point* c, void* arg, int error,
@ -114,6 +116,7 @@ void worker_sighandler(int sig, void* arg);
* @param dnssec: if set, EDNS record will have DO bit set. * @param dnssec: if set, EDNS record will have DO bit set.
* @param want_dnssec: signatures needed. * @param want_dnssec: signatures needed.
* @param nocaps: ignore capsforid(if in config), do not perturb qname. * @param nocaps: ignore capsforid(if in config), do not perturb qname.
* @param opt_list: EDNS options on outgoing packet.
* @param addr: where to. * @param addr: where to.
* @param addrlen: length of addr. * @param addrlen: length of addr.
* @param zone: wireformat dname of the zone. * @param zone: wireformat dname of the zone.
@ -124,9 +127,9 @@ void worker_sighandler(int sig, void* arg);
*/ */
struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen, struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, struct sockaddr_storage* addr, int want_dnssec, int nocaps, struct edns_option* opt_list,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
struct module_qstate* q); size_t zonelen, struct module_qstate* q);
/** /**
* process control messages from the main thread. Frees the control * process control messages from the main thread. Frees the control

View file

@ -865,7 +865,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
prev->edns.edns_present == r->edns.edns_present && prev->edns.edns_present == r->edns.edns_present &&
prev->edns.bits == r->edns.bits && prev->edns.bits == r->edns.bits &&
prev->edns.udp_size == r->edns.udp_size && prev->edns.udp_size == r->edns.udp_size &&
edns_opt_list_equal(prev->edns.opt_list, r->edns.opt_list)) { edns_opt_list_compare(prev->edns.opt_list, r->edns.opt_list)
== 0) {
/* if the previous reply is identical to this one, fix ID */ /* if the previous reply is identical to this one, fix ID */
if(prev->query_reply.c->buffer != r->query_reply.c->buffer) if(prev->query_reply.c->buffer != r->query_reply.c->buffer)
sldns_buffer_copy(r->query_reply.c->buffer, sldns_buffer_copy(r->query_reply.c->buffer,

View file

@ -122,6 +122,8 @@ serviced_cmp(const void* key1, const void* key2)
} }
if((r = query_dname_compare(q1->qbuf+10, q2->qbuf+10)) != 0) if((r = query_dname_compare(q1->qbuf+10, q2->qbuf+10)) != 0)
return r; return r;
if((r = edns_opt_list_compare(q1->opt_list, q2->opt_list)) != 0)
return r;
return sockaddr_cmp(&q1->addr, q1->addrlen, &q2->addr, q2->addrlen); return sockaddr_cmp(&q1->addr, q1->addrlen, &q2->addr, q2->addrlen);
} }
@ -757,6 +759,7 @@ serviced_node_del(rbnode_t* node, void* ATTR_UNUSED(arg))
struct service_callback* p = sq->cblist, *np; struct service_callback* p = sq->cblist, *np;
free(sq->qbuf); free(sq->qbuf);
free(sq->zone); free(sq->zone);
edns_opt_list_free(sq->opt_list);
while(p) { while(p) {
np = p->next; np = p->next;
free(p); free(p);
@ -1219,7 +1222,8 @@ serviced_gen_query(sldns_buffer* buff, uint8_t* qname, size_t qnamelen,
/** lookup serviced query in serviced query rbtree */ /** lookup serviced query in serviced query rbtree */
static struct serviced_query* static struct serviced_query*
lookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec, lookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
struct sockaddr_storage* addr, socklen_t addrlen) struct sockaddr_storage* addr, socklen_t addrlen,
struct edns_option* opt_list)
{ {
struct serviced_query key; struct serviced_query key;
key.node.key = &key; key.node.key = &key;
@ -1229,6 +1233,7 @@ lookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
memcpy(&key.addr, addr, addrlen); memcpy(&key.addr, addr, addrlen);
key.addrlen = addrlen; key.addrlen = addrlen;
key.outnet = outnet; key.outnet = outnet;
key.opt_list = opt_list;
return (struct serviced_query*)rbtree_search(outnet->serviced, &key); return (struct serviced_query*)rbtree_search(outnet->serviced, &key);
} }
@ -1237,7 +1242,7 @@ static struct serviced_query*
serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream, int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
size_t zonelen, int qtype) size_t zonelen, int qtype, struct edns_option* opt_list)
{ {
struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq)); struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
#ifdef UNBOUND_DEBUG #ifdef UNBOUND_DEBUG
@ -1267,6 +1272,16 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
sq->ssl_upstream = ssl_upstream; sq->ssl_upstream = ssl_upstream;
memcpy(&sq->addr, addr, addrlen); memcpy(&sq->addr, addr, addrlen);
sq->addrlen = addrlen; sq->addrlen = addrlen;
sq->opt_list = NULL;
if(opt_list) {
sq->opt_list = edns_opt_copy_alloc(opt_list);
if(!sq->opt_list) {
free(sq->zone);
free(sq->qbuf);
free(sq);
return NULL;
}
}
sq->outnet = outnet; sq->outnet = outnet;
sq->cblist = NULL; sq->cblist = NULL;
sq->pending = NULL; sq->pending = NULL;
@ -1394,9 +1409,7 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
edns.edns_present = 1; edns.edns_present = 1;
edns.ext_rcode = 0; edns.ext_rcode = 0;
edns.edns_version = EDNS_ADVERTISED_VERSION; edns.edns_version = EDNS_ADVERTISED_VERSION;
/* insert EDNS options here for upstream messages, edns.opt_list = sq->opt_list;
* stored from sq */
edns.opt_list = NULL;
if(sq->status == serviced_query_UDP_EDNS_FRAG) { if(sq->status == serviced_query_UDP_EDNS_FRAG) {
if(addr_is_ip6(&sq->addr, sq->addrlen)) { if(addr_is_ip6(&sq->addr, sq->addrlen)) {
if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE) if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE)
@ -1919,15 +1932,15 @@ struct serviced_query*
outnet_serviced_query(struct outside_network* outnet, outnet_serviced_query(struct outside_network* outnet,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, int want_dnssec, int nocaps, uint16_t flags, int dnssec, int want_dnssec, int nocaps,
int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr, int tcp_upstream, int ssl_upstream, struct edns_option* opt_list,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
comm_point_callback_t* callback, void* callback_arg, size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
sldns_buffer* buff) sldns_buffer* buff)
{ {
struct serviced_query* sq; struct serviced_query* sq;
struct service_callback* cb; struct service_callback* cb;
serviced_gen_query(buff, qname, qnamelen, qtype, qclass, flags); serviced_gen_query(buff, qname, qnamelen, qtype, qclass, flags);
sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen); sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen, opt_list);
/* duplicate entries are included in the callback list, because /* duplicate entries are included in the callback list, because
* there is a counterpart registration by our caller that needs to * there is a counterpart registration by our caller that needs to
* be doubly-removed (with callbacks perhaps). */ * be doubly-removed (with callbacks perhaps). */
@ -1937,7 +1950,7 @@ outnet_serviced_query(struct outside_network* outnet,
/* make new serviced query entry */ /* make new serviced query entry */
sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps, sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps,
tcp_upstream, ssl_upstream, addr, addrlen, zone, tcp_upstream, ssl_upstream, addr, addrlen, zone,
zonelen, (int)qtype); zonelen, (int)qtype, opt_list);
if(!sq) { if(!sq) {
free(cb); free(cb);
return NULL; return NULL;

View file

@ -58,6 +58,7 @@ struct port_if;
struct sldns_buffer; struct sldns_buffer;
struct serviced_query; struct serviced_query;
struct dt_env; struct dt_env;
struct edns_option;
/** /**
* Send queries to outside servers and wait for answers from servers. * Send queries to outside servers and wait for answers from servers.
@ -367,6 +368,8 @@ struct serviced_query {
int last_rtt; int last_rtt;
/** do we know edns probe status already, for UDP_EDNS queries */ /** do we know edns probe status already, for UDP_EDNS queries */
int edns_lame_known; int edns_lame_known;
/** edns options to use for sending upstream packet */
struct edns_option* opt_list;
/** outside network this is part of */ /** outside network this is part of */
struct outside_network* outnet; struct outside_network* outnet;
/** list of interested parties that need callback on results. */ /** list of interested parties that need callback on results. */
@ -477,6 +480,8 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
* @param nocaps: ignore use_caps_for_id and use unperturbed qname. * @param nocaps: ignore use_caps_for_id and use unperturbed qname.
* @param tcp_upstream: use TCP for upstream queries. * @param tcp_upstream: use TCP for upstream queries.
* @param ssl_upstream: use SSL for upstream queries. * @param ssl_upstream: use SSL for upstream queries.
* @param opt_list: pass edns option list (deep copied into serviced query)
* these options are set on the outgoing packets.
* @param callback: callback function. * @param callback: callback function.
* @param callback_arg: user argument to callback function. * @param callback_arg: user argument to callback function.
* @param addr: to which server to send the query. * @param addr: to which server to send the query.
@ -492,9 +497,9 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
struct serviced_query* outnet_serviced_query(struct outside_network* outnet, struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, int want_dnssec, int nocaps, uint16_t flags, int dnssec, int want_dnssec, int nocaps,
int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr, int tcp_upstream, int ssl_upstream, struct edns_option* opt_list,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
comm_point_callback_t* callback, void* callback_arg, size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
struct sldns_buffer* buff); struct sldns_buffer* buff);
/** /**

View file

@ -103,7 +103,8 @@ struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list),
struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
{ {
@ -135,7 +136,8 @@ struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname),
size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list),
struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
{ {

View file

@ -1039,9 +1039,9 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec), uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(nocaps), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), struct sockaddr_storage* addr, int ATTR_UNUSED(ssl_upstream), struct edns_option* opt_list,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
comm_point_callback_t* callback, void* callback_arg, size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
sldns_buffer* ATTR_UNUSED(buff)) sldns_buffer* ATTR_UNUSED(buff))
{ {
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
@ -1077,7 +1077,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
edns.edns_version = EDNS_ADVERTISED_VERSION; edns.edns_version = EDNS_ADVERTISED_VERSION;
edns.udp_size = EDNS_ADVERTISED_SIZE; edns.udp_size = EDNS_ADVERTISED_SIZE;
edns.bits = 0; edns.bits = 0;
edns.opt_list = NULL; edns.opt_list = opt_list;
if(dnssec) if(dnssec)
edns.bits = EDNS_DO; edns.bits = EDNS_DO;
attach_edns_record(pend->buffer, &edns); attach_edns_record(pend->buffer, &edns);

View file

@ -923,22 +923,89 @@ struct edns_option* edns_opt_copy_region(struct edns_option* list,
return result; return result;
} }
int edns_opt_list_equal(struct edns_option* p, struct edns_option* q) int edns_opt_compare(struct edns_option* p, struct edns_option* q)
{ {
while(p && q) { if(!p && !q) return 0;
/* compare elements */ if(!p) return -1;
if(p->opt_code != q->opt_code || if(!q) return 1;
p->opt_len != q->opt_len) log_assert(p && q);
return 0; if(p->opt_code != q->opt_code)
if(p->opt_len > 0 && q->opt_len > 0) { return (int)q->opt_code - (int)p->opt_code;
if(memcmp(p->opt_data, q->opt_data, p->opt_len) != 0) if(p->opt_len != q->opt_len)
return (int)q->opt_len - (int)p->opt_len;
if(p->opt_len != 0)
return memcmp(p->opt_data, q->opt_data, p->opt_len);
return 0; return 0;
} }
int edns_opt_list_compare(struct edns_option* p, struct edns_option* q)
{
int r;
while(p && q) {
r = edns_opt_compare(p, q);
if(r != 0)
return r;
p = p->next; p = p->next;
q = q->next; q = q->next;
} }
if(p || q) if(p || q) {
return 0; /* uneven length lists */ /* uneven length lists */
return 1; if(p) return 1;
if(q) return -1;
}
return 0;
}
void edns_opt_list_free(struct edns_option* list)
{
struct edns_option* n;
while(list) {
free(list->opt_data);
n = list->next;
free(list);
list = n;
}
}
struct edns_option* edns_opt_copy_alloc(struct edns_option* list)
{
struct edns_option* result = NULL, *cur = NULL, *s;
while(list) {
/* copy edns option structure */
s = memdup(list, sizeof(*list));
if(!s) {
edns_opt_list_free(result);
return NULL;
}
s->next = NULL;
/* copy option data */
if(s->opt_data) {
s->opt_data = memdup(s->opt_data, s->opt_len);
if(!s->opt_data) {
edns_opt_list_free(result);
return NULL;
}
}
/* link into list */
if(cur)
cur->next = s;
else result = s;
cur = s;
/* examine next element */
list = list->next;
}
return result;
}
struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code)
{
struct edns_option* p;
for(p=list; p; p=p->next) {
if(p->opt_code == code)
return p;
}
return NULL;
} }

View file

@ -443,6 +443,14 @@ void log_query_info(enum verbosity_value v, const char* str,
int edns_opt_append(struct edns_data* edns, struct regional* region, int edns_opt_append(struct edns_data* edns, struct regional* region,
uint16_t code, size_t len, uint8_t* data); uint16_t code, size_t len, uint8_t* data);
/**
* Find edns option in edns list
* @param list: list of edns options (eg. edns.opt_list)
* @param code: opt code to find.
* @return NULL or the edns_option element.
*/
struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code);
/** /**
* Transform edns data structure from query structure into reply structure. * Transform edns data structure from query structure into reply structure.
* In place transform, for errors and cache replies. * In place transform, for errors and cache replies.
@ -462,8 +470,23 @@ struct edns_option* edns_opt_copy_region(struct edns_option* list,
struct regional* region); struct regional* region);
/** /**
* See if edns option lists are equal, also order and contents of options. * Copy edns option list allocated with malloc
*/ */
int edns_opt_list_equal(struct edns_option* p, struct edns_option* q); struct edns_option* edns_opt_copy_alloc(struct edns_option* list);
/**
* Free edns option list allocated with malloc
*/
void edns_opt_list_free(struct edns_option* list);
/**
* Compare an edns option. (not entire list). Also compares contents.
*/
int edns_opt_compare(struct edns_option* p, struct edns_option* q);
/**
* Compare edns option lists, also the order and contents of edns-options.
*/
int edns_opt_list_compare(struct edns_option* p, struct edns_option* q);
#endif /* UTIL_DATA_MSGREPLY_H */ #endif /* UTIL_DATA_MSGREPLY_H */

View file

@ -267,8 +267,8 @@ int
fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)( fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, int want_dnssec, int nocaps, uint16_t flags, int dnssec, int want_dnssec, int nocaps,
struct sockaddr_storage* addr, socklen_t addrlen, struct edns_option* opt_list, struct sockaddr_storage* addr,
uint8_t* zone, size_t zonelen, socklen_t addrlen, uint8_t* zone, size_t zonelen,
struct module_qstate* q)) struct module_qstate* q))
{ {
if(fptr == &worker_send_query) return 1; if(fptr == &worker_send_query) return 1;

View file

@ -212,7 +212,7 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr);
int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)( int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, int want_dnssec, int nocaps, uint16_t flags, int dnssec, int want_dnssec, int nocaps,
struct sockaddr_storage* addr, socklen_t addrlen, struct edns_option*, struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* zone, size_t zonelen, uint8_t* zone, size_t zonelen,
struct module_qstate* q)); struct module_qstate* q));

View file

@ -214,6 +214,8 @@ struct module_env {
* EDNS, the answer is likely to be useless for this domain. * EDNS, the answer is likely to be useless for this domain.
* @param nocaps: do not use caps_for_id, use the qname as given. * @param nocaps: do not use caps_for_id, use the qname as given.
* (ignored if caps_for_id is disabled). * (ignored if caps_for_id is disabled).
* @param opt_list: set these EDNS options on the outgoing packet.
* or NULL if none (the list is deep-copied).
* @param addr: where to. * @param addr: where to.
* @param addrlen: length of addr. * @param addrlen: length of addr.
* @param zone: delegation point name. * @param zone: delegation point name.
@ -226,9 +228,9 @@ struct module_env {
*/ */
struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen, struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, struct sockaddr_storage* addr, int want_dnssec, int nocaps, struct edns_option* opt_list,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q); uint8_t* zone, size_t zonelen, struct module_qstate* q);
/** /**
* Detach-subqueries. * Detach-subqueries.