]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- and also generic edns options for upstream messages (and replies).
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 31 May 2016 16:55:22 +0000 (16:55 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 31 May 2016 16:55:22 +0000 (16:55 +0000)
  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

15 files changed:
daemon/worker.c
doc/Changelog
iterator/iterator.c
libunbound/libworker.c
libunbound/worker.h
services/mesh.c
services/outside_network.c
services/outside_network.h
smallapp/worker_cb.c
testcode/fake_event.c
util/data/msgreply.c
util/data/msgreply.h
util/fptr_wlist.c
util/fptr_wlist.h
util/module.h

index b08474fb1e873193083f84ace4d9a27e3558e33b..84c004ed6364d08fe2fa1b760993976e4d2b66c6 100644 (file)
@@ -1370,8 +1370,9 @@ worker_delete(struct worker* worker)
 struct outbound_entry*
 worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
        uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec,
-       int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
-       uint8_t* zone, size_t zonelen, struct module_qstate* q)
+       int nocaps, struct edns_option* opt_list,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, struct module_qstate* q)
 {
        struct worker* worker = q->env->worker;
        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->qsent = outnet_serviced_query(worker->back, qname,
                qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps,
-               q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
-               addrlen, zone, zonelen, worker_handle_service_reply, e,
+               q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, opt_list,
+               addr, addrlen, zone, zonelen, worker_handle_service_reply, e,
                worker->back->udp_buff);
        if(!e->qsent) {
                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), 
        uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 
        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),
        size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
 {
index 6293ce7aa0fddb4c0f6ffb31b124f9d08d957182..a6bce071cc34e4e10b87866baf9c9d79e787c84f 100644 (file)
@@ -3,6 +3,10 @@
          network service account, from Mario Turschmann.
        - compat strsep implementation.
        - 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
        - Fix time in case answer comes from cache in ub_resolve_event().
index bcce7e6fc272ad73639cd67c4f19e15025d1c6d2..139cae4bae0acb2966b67e33967754f14cf0abb7 100644 (file)
@@ -1786,6 +1786,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
        int tf_policy;
        struct delegpt_addr* target;
        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 
         * 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,
                &iq->qinfo_out)||target->attempts==1)?0:BIT_CD), 
                iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
-               ie, iq), &target->addr, target->addrlen, iq->dp->name,
-               iq->dp->namelen, qstate);
+               ie, iq), opt_list, &target->addr, target->addrlen,
+               iq->dp->name, iq->dp->namelen, qstate);
        if(!outq) {
                log_addr(VERB_DETAIL, "error sending query to auth server", 
                        &target->addr, target->addrlen);
index 8129f8c013fb74f77e88bfc97366f02d74f72b06..3065bede48142237da558cbbb2747f93e012aa06 100644 (file)
@@ -822,9 +822,9 @@ void libworker_alloc_cleanup(void* arg)
 
 struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
         uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
-       int want_dnssec, int nocaps, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen,
-       struct module_qstate* q)
+       int want_dnssec, int nocaps, struct edns_option* opt_list,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, struct module_qstate* q)
 {
        struct libworker* w = (struct libworker*)q->env->worker;
        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->qsent = outnet_serviced_query(w->back, qname,
                qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps,
-               q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
-               addrlen, zone, zonelen, libworker_handle_service_reply, e,
-               w->back->udp_buff);
+               q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, opt_list,
+               addr, addrlen, zone, zonelen, libworker_handle_service_reply,
+               e, w->back->udp_buff);
        if(!e->qsent) {
                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), 
        uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 
        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),
        size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
 {
index a531501994af26434eef55c1de40c5cf1ec513ee..b8d8dd88a8d96c194ac13be283d4f97d9e310908 100644 (file)
@@ -48,6 +48,7 @@ struct comm_reply;
 struct comm_point;
 struct module_qstate;
 struct tube;
+struct edns_option;
 
 /**
  * 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 want_dnssec: signatures needed.
  * @param nocaps: ignore capsforid(if in config), do not perturb qname.
+ * @param opt_list: EDNS options on outgoing packet.
  * @param addr: where to.
  * @param addrlen: length of addr.
  * @param zone: delegation point name.
@@ -69,9 +71,9 @@ struct tube;
  */
 struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
         uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
-       int want_dnssec, int nocaps, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen,
-       struct module_qstate* q);
+       int want_dnssec, int nocaps, struct edns_option* opt_list,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, struct module_qstate* q);
 
 /** process incoming replies from the network */
 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 want_dnssec: signatures needed.
  * @param nocaps: ignore capsforid(if in config), do not perturb qname.
+ * @param opt_list: EDNS options on outgoing packet.
  * @param addr: where to.
  * @param addrlen: length of addr.
  * @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, 
        uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 
-       int want_dnssec, int nocaps, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen,
-       struct module_qstate* q);
+       int want_dnssec, int nocaps, struct edns_option* opt_list,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, struct module_qstate* q);
 
 /** 
  * process control messages from the main thread. Frees the control 
index 2df5ad62f716575b51a9dc9aef77da460b2ed405..8f74cbe822b0aa3bb6fffa1c219fe59411f03265 100644 (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.bits == r->edns.bits && 
                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(prev->query_reply.c->buffer != r->query_reply.c->buffer)
                        sldns_buffer_copy(r->query_reply.c->buffer, 
index 56f46f42eecd2cf472cf97ba9f3ee7e783f61554..d9e34f46999de97e042dcb29a16900a8d9c55d71 100644 (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)
                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);
 }
 
@@ -757,6 +759,7 @@ serviced_node_del(rbnode_t* node, void* ATTR_UNUSED(arg))
        struct service_callback* p = sq->cblist, *np;
        free(sq->qbuf);
        free(sq->zone);
+       edns_opt_list_free(sq->opt_list);
        while(p) {
                np = p->next;
                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 */
 static struct serviced_query*
 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;
        key.node.key = &key;
@@ -1229,6 +1233,7 @@ lookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        memcpy(&key.addr, addr, addrlen);
        key.addrlen = addrlen;
        key.outnet = outnet;
+       key.opt_list = opt_list;
        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,
        int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream,
        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));
 #ifdef UNBOUND_DEBUG
@@ -1267,6 +1272,16 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        sq->ssl_upstream = ssl_upstream;
        memcpy(&sq->addr, addr, 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->cblist = 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.ext_rcode = 0;
                edns.edns_version = EDNS_ADVERTISED_VERSION;
-               /* insert EDNS options here for upstream messages,
-                * stored from sq */
-               edns.opt_list = NULL;
+               edns.opt_list = sq->opt_list;
                if(sq->status == serviced_query_UDP_EDNS_FRAG) {
                        if(addr_is_ip6(&sq->addr, sq->addrlen)) {
                                if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE)
@@ -1919,15 +1932,15 @@ struct serviced_query*
 outnet_serviced_query(struct outside_network* outnet,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
-       int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen,
-       comm_point_callback_t* callback, void* callback_arg,
+       int tcp_upstream, int ssl_upstream, struct edns_option* opt_list,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
        sldns_buffer* buff)
 {
        struct serviced_query* sq;
        struct service_callback* cb;
        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
         * there is a counterpart registration by our caller that needs to
         * be doubly-removed (with callbacks perhaps). */
@@ -1937,7 +1950,7 @@ outnet_serviced_query(struct outside_network* outnet,
                /* make new serviced query entry */
                sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps,
                        tcp_upstream, ssl_upstream, addr, addrlen, zone,
-                       zonelen, (int)qtype);
+                       zonelen, (int)qtype, opt_list);
                if(!sq) {
                        free(cb);
                        return NULL;
index 36f798d3b419ab2ddd2c9869c41b4c0dbf356076..9a3270ee19a6de49a5859ffe62ea937c85ac741b 100644 (file)
@@ -58,6 +58,7 @@ struct port_if;
 struct sldns_buffer;
 struct serviced_query;
 struct dt_env;
+struct edns_option;
 
 /**
  * Send queries to outside servers and wait for answers from servers.
@@ -367,6 +368,8 @@ struct serviced_query {
        int last_rtt;
        /** do we know edns probe status already, for UDP_EDNS queries */
        int edns_lame_known;
+       /** edns options to use for sending upstream packet */
+       struct edns_option* opt_list;
        /** outside network this is part of */
        struct outside_network* outnet;
        /** 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 tcp_upstream: use TCP 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_arg: user argument to callback function.
  * @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,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
-       int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen,
-       comm_point_callback_t* callback, void* callback_arg,
+       int tcp_upstream, int ssl_upstream, struct edns_option* opt_list,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
        struct sldns_buffer* buff);
 
 /**
index 8193bec1b4d8a2372b068a6542943bdbcce1f57b..6ed95ac0107c1f5962dc0e1a202fd0dd7a67e603 100644 (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), 
        uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 
        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),
        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), 
        uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 
        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),
        size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
 {
index d50f8b03cc2e9b551c5f7d211c91fcba86f2b777..1578b7ddca2faa3b6170db5d01c1008efde844bc 100644 (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,
        uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec),
        int ATTR_UNUSED(nocaps), int ATTR_UNUSED(tcp_upstream),
-       int ATTR_UNUSED(ssl_upstream), struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen,
-       comm_point_callback_t* callback, void* callback_arg,
+       int ATTR_UNUSED(ssl_upstream), struct edns_option* opt_list,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
        sldns_buffer* ATTR_UNUSED(buff))
 {
        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.udp_size = EDNS_ADVERTISED_SIZE;
                edns.bits = 0;
-               edns.opt_list = NULL;
+               edns.opt_list = opt_list;
                if(dnssec)
                        edns.bits = EDNS_DO;
                attach_edns_record(pend->buffer, &edns);
index 4cfc37d7142c07ba88c3e87838bc5fdc32ca3256..f8a24918dcad552056943a68a14d70b5f02cc35b 100644 (file)
@@ -923,22 +923,89 @@ struct edns_option* edns_opt_copy_region(struct edns_option* list,
        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)
+{
+       if(!p && !q) return 0;
+       if(!p) return -1;
+       if(!q) return 1;
+       log_assert(p && q);
+       if(p->opt_code != q->opt_code)
+               return (int)q->opt_code - (int)p->opt_code;
+       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;
+}
+
+int edns_opt_list_compare(struct edns_option* p, struct edns_option* q)
 {
+       int r;
        while(p && q) {
-               /* compare elements */
-               if(p->opt_code != q->opt_code ||
-                       p->opt_len != q->opt_len)
-                       return 0;
-               if(p->opt_len > 0 && q->opt_len > 0) {
-                       if(memcmp(p->opt_data, q->opt_data, p->opt_len) != 0)
-                               return 0;
-               }
-
+               r = edns_opt_compare(p, q);
+               if(r != 0)
+                       return r;
                p = p->next;
                q = q->next;
        }
-       if(p || q)
-               return 0; /* uneven length lists */
-       return 1;
+       if(p || q) {
+               /* uneven length lists */
+               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;
 }
index 32a822706a7b686df2aa22d640e4178d3aad96fb..b542b75e697086a5982a9fe6188103ce13e9db11 100644 (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,
        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.
  * 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);
 
 /**
- * See if edns option lists are equal, also order and contents of options.
+ * Copy edns option list allocated with malloc
+ */
+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_equal(struct edns_option* p, struct edns_option* q);
+int edns_opt_list_compare(struct edns_option* p, struct edns_option* q);
 
 #endif /* UTIL_DATA_MSGREPLY_H */
index 63d0b8b6fe7573a3484b3522b061c26c8dd45f57..80a23f20361bdf4aa3209a1480bf2b00cc1ad4c1 100644 (file)
@@ -267,8 +267,8 @@ int
 fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
         uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
         uint16_t flags, int dnssec, int want_dnssec, int nocaps,
-       struct sockaddr_storage* addr, socklen_t addrlen, 
-       uint8_t* zone, size_t zonelen,
+       struct edns_option* opt_list, struct sockaddr_storage* addr,
+       socklen_t addrlen, uint8_t* zone, size_t zonelen,
        struct module_qstate* q))
 {
        if(fptr == &worker_send_query) return 1;
index 10de5d8167726851531a74703e389a9b066b35fb..98ca21bb9671f713a300817436c98111093db33c 100644 (file)
@@ -212,7 +212,7 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr);
 int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, 
        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,
        struct module_qstate* q));
 
index b9dde36e2f3ce445f3588b8a26ba2281dff59a7a..c3ce8a40eda260b3c44d68848bc439afcc3f7d25 100644 (file)
@@ -214,6 +214,8 @@ struct module_env {
         *      EDNS, the answer is likely to be useless for this domain.
         * @param nocaps: do not use caps_for_id, use the qname as given.
         *      (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 addrlen: length of addr.
         * @param zone: delegation point name.
@@ -226,9 +228,9 @@ struct module_env {
         */
        struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen, 
                uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 
-               int want_dnssec, int nocaps, struct sockaddr_storage* addr, 
-               socklen_t addrlen, uint8_t* zone, size_t zonelen,
-               struct module_qstate* q);
+               int want_dnssec, int nocaps, struct edns_option* opt_list,
+               struct sockaddr_storage* addr, socklen_t addrlen,
+               uint8_t* zone, size_t zonelen, struct module_qstate* q);
 
        /**
         * Detach-subqueries.