]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Parse EDNS data on incoming queries and incoming replies.
authorYuri Schaeffer <yuri@nlnetlabs.nl>
Mon, 17 Sep 2012 13:31:39 +0000 (13:31 +0000)
committerYuri Schaeffer <yuri@nlnetlabs.nl>
Mon, 17 Sep 2012 13:31:39 +0000 (13:31 +0000)
git-svn-id: file:///svn/unbound/branches/edns-subnet@2761 be551aaa-1e26-0410-a405-d3ace91eadb9

13 files changed:
daemon/worker.c
libunbound/libworker.c
services/localzone.c
services/mesh.c
services/mesh.h
services/outside_network.c
services/outside_network.h
testcode/fake_event.c
testcode/streamtcp.c
util/data/msgencode.c
util/data/msgparse.c
util/data/msgparse.h
validator/autotrust.c

index 82dfb93fec182e029e492df652363216b8d35213..67ffebc3f6960a127e691dc99b8aee2465c2a5cb 100644 (file)
@@ -475,7 +475,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
                        edns->udp_size = EDNS_ADVERTISED_SIZE;
                        edns->ext_rcode = 0;
                        edns->bits &= EDNS_DO;
-                       edns->subnet_option_add = 0;
+                       edns->subnet_option = 0;
                        error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
                                &msg->qinfo, id, flags, edns);
                        regional_free_all(worker->scratchpad);
@@ -504,7 +504,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
        edns->udp_size = EDNS_ADVERTISED_SIZE;
        edns->ext_rcode = 0;
        edns->bits &= EDNS_DO;
-       edns->subnet_option_add = 0;
+       edns->subnet_option = 0;
        msg->rep->flags |= BIT_QR|BIT_RA;
        if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags, 
                repinfo->c->buffer, 0, 1, worker->scratchpad,
@@ -563,7 +563,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
                edns->udp_size = EDNS_ADVERTISED_SIZE;
                edns->ext_rcode = 0;
                edns->bits &= EDNS_DO;
-               edns->subnet_option_add = 0;
+               edns->subnet_option = 0;
                error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
                        qinfo, id, flags, edns);
                rrset_array_unlock_touch(worker->env.rrset_cache, 
@@ -595,7 +595,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
        edns->udp_size = EDNS_ADVERTISED_SIZE;
        edns->ext_rcode = 0;
        edns->bits &= EDNS_DO;
-       edns->subnet_option_add = 0;
+       edns->subnet_option = 0;
        if(!reply_info_answer_encode(qinfo, rep, id, flags, 
                repinfo->c->buffer, timenow, 1, worker->scratchpad,
                udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
@@ -669,7 +669,7 @@ chaos_replystr(ldns_buffer* pkt, const char* str, struct edns_data* edns)
        edns->edns_version = EDNS_ADVERTISED_VERSION;
        edns->udp_size = EDNS_ADVERTISED_SIZE;
        edns->bits &= EDNS_DO;
-       edns->subnet_option_add = 0;
+       edns->subnet_option = 0;
        attach_edns_record(pkt, edns);
 }
 
@@ -821,7 +821,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                edns.edns_version = EDNS_ADVERTISED_VERSION;
                edns.udp_size = EDNS_ADVERTISED_SIZE;
                edns.bits &= EDNS_DO;
-               edns.subnet_option_add = 0;
+               edns.subnet_option = 0;
                verbose(VERB_ALGO, "query with bad edns version.");
                log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
                error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
index 5d8c40bcfa66dab67827fdfcfe70683cf44086f2..b50af944e5e8585fc2a559f56df108c94625038b 100644 (file)
@@ -531,7 +531,7 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
        edns->ext_rcode = 0;
        edns->edns_version = 0;
        edns->bits = EDNS_DO;
-       edns->subnet_option_add = 0; 
+       edns->subnet_option = 0; 
        if(ldns_buffer_capacity(w->back->udp_buff) < 65535)
                edns->udp_size = (uint16_t)ldns_buffer_capacity(
                        w->back->udp_buff);
@@ -725,8 +725,7 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
        if(!e->qsent) {
                return NULL;
        }
-       if(e->qstate->mesh_info->reply_list)
-               e->qsent->client = &e->qstate->mesh_info->reply_list->query_reply;
+       e->qsent->mesh_info = e->qstate->mesh_info;
        return e;
 }
 
index 6a166e257e19763ee2e800e1fc185975aca2599e..b8ef26aca1fd16e4fc63b486d032f2492ab30d7c 100644 (file)
@@ -1010,7 +1010,7 @@ local_encode(struct query_info* qinfo, struct edns_data* edns,
        edns->udp_size = EDNS_ADVERTISED_SIZE;
        edns->ext_rcode = 0;
        edns->bits &= EDNS_DO;
-       edns->subnet_option_add = 0;
+       edns->subnet_option = 0;
        if(!reply_info_answer_encode(qinfo, &rep, 
                *(uint16_t*)ldns_buffer_begin(buf),
                ldns_buffer_read_u16_at(buf, 2),
index fdbdc6e5d95c127875b3a61d75c9ed88d6aa79e0..c041b2584c4a2fcf95b7ce4c685d894507800fce 100644 (file)
@@ -791,7 +791,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
                r->edns.udp_size = EDNS_ADVERTISED_SIZE;
                r->edns.ext_rcode = 0;
                r->edns.bits &= EDNS_DO;
-               r->edns.subnet_option_add = 0;
+               r->edns.subnet_option = 0;
                if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid, 
                        r->qflags, r->buf, 0, 1, 
                        m->s.env->scratch, udp_size, &r->edns, 
@@ -863,7 +863,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
                r->edns.udp_size = EDNS_ADVERTISED_SIZE;
                r->edns.ext_rcode = 0;
                r->edns.bits &= EDNS_DO;
-               r->edns.subnet_option_add = 0;
+               r->edns.subnet_option = 0;
                m->s.qinfo.qname = r->qname;
                if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid, 
                        r->qflags, r->query_reply.c->buffer, 0, 1, 
index 5f109779a4d2371ab8e65eec77c2c1823cdd069a..8291fc4bbe0a0562b4efa93ba214dc7f6e1abea6 100644 (file)
@@ -182,6 +182,12 @@ struct mesh_state {
 
        /** true if replies have been sent out (at end for alignment) */
        uint8_t replies_sent;
+       
+       /* YBS */
+       int             subnet_option_expect;
+       uint16_t        subnet_addr_fam;
+       uint8_t         subnet_source_mask;
+       uint8_t         subnet_addr[16];
 };
 
 /**
index 10c25a897b32d47d32612b967987302dae0a64ac..3da40d9dcf2bad8368b531406c086eb674e0b88d 100644 (file)
@@ -1209,7 +1209,7 @@ serviced_create(struct outside_network* outnet, ldns_buffer* buff, int dnssec,
        sq->status = serviced_initial;
        sq->retry = 0;
        sq->to_be_deleted = 0;
-       sq->client = NULL;
+       sq->mesh_info = NULL;
 #ifdef UNBOUND_DEBUG
        ins = 
 #endif
@@ -1333,10 +1333,11 @@ serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns)
                edns.edns_version = EDNS_ADVERTISED_VERSION;
                /* If this query has an interested client and the upstream
                 * target is in the whitelist, add the edns subnet option. */
-               edns.subnet_option_add = sq->client && upstream_lookup(
-                       sq->outnet->edns_subnet_upstreams, &sq->addr, sq->addrlen);
-               if(edns.subnet_option_add) {
-                       ss = &sq->client->addr;
+               edns.subnet_option = sq->mesh_info->reply_list && 
+                       upstream_lookup(sq->outnet->edns_subnet_upstreams, 
+                       &sq->addr, sq->addrlen);
+               if(edns.subnet_option) {
+                       ss = &sq->mesh_info->reply_list->query_reply.addr;
                        if(((struct sockaddr_in*)ss)->sin_family == AF_INET) {
                                edns.subnet_addr_fam = IANA_ADDRFAM_IP4;
                                sinaddr = &((struct sockaddr_in*)ss)->sin_addr;
@@ -1355,6 +1356,11 @@ serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns)
                        }
 #endif
                        edns.subnet_scope_mask = 0;
+                       //YBS add addr,fam,mask to mesh.
+                       sq->mesh_info->subnet_option_expect = 1;
+                       sq->mesh_info->subnet_addr_fam = edns.subnet_addr_fam;
+                       sq->mesh_info->subnet_source_mask = edns.subnet_source_mask;
+                       memcpy(sq->mesh_info->subnet_addr, (uint8_t *)sinaddr, INET6_SIZE);
                }
                if(sq->status == serviced_query_UDP_EDNS_FRAG) {
                        if(addr_is_ip6(&sq->addr, sq->addrlen)) {
@@ -1825,7 +1831,6 @@ outnet_serviced_query(struct outside_network* outnet,
 {
        struct serviced_query* sq;
        struct service_callback* cb;
-       struct mesh_reply* reply_list;
        serviced_gen_query(buff, qname, qnamelen, qtype, qclass, flags);
        sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen);
        /* duplicate entries are inclded in the callback list, because
@@ -1844,10 +1849,8 @@ outnet_serviced_query(struct outside_network* outnet,
                }
                /* Is this a client initiated query? Make clients available
                 * to serviced query. */
-               reply_list = ((struct outbound_entry*)callback_arg)
-                                               ->qstate->mesh_info->reply_list;
-               if(reply_list)
-                       sq->client = &reply_list->query_reply;
+               sq->mesh_info = ((struct outbound_entry*)callback_arg)
+                                               ->qstate->mesh_info;
                
                /* perform first network action */
                if(outnet->do_udp && !(tcp_upstream || ssl_upstream)) {
index 74208441b411fb4cc9b2a08e0951d480af4aa5bb..b781015d5901a47230f5ab1e904d9faada0031e3 100644 (file)
@@ -356,7 +356,7 @@ struct serviced_query {
        /** the UDP or TCP query that is pending, see status which */
        void* pending;
        /** Clients initiating lookup. Not owned by serviced_query */
-       struct comm_reply *client;
+       struct mesh_state *mesh_info;
 };
 
 /**
index baa9bb66252c5631b0e93995b756d9091aa6a973..f0ca60251e43b8c26738701993ef75d56d06a0e4 100644 (file)
@@ -1100,9 +1100,9 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
                memcpy(&pend->addr, (struct sockaddr_storage*)&target_addr, 
                        sizeof(struct sockaddr_storage));
                pend->addrlen = 16;
-               edns.subnet_option_add = pend->client && upstream_lookup(
+               edns.subnet_option = pend->client && upstream_lookup(
                        outnet->edns_subnet_upstreams, &pend->addr, pend->addrlen);
-               if(edns.subnet_option_add) {
+               if(edns.subnet_option) {
                        ss = &pend->client->addr;
                        if(((struct sockaddr_in*)ss)->sin_family == AF_INET) {
                                edns.subnet_addr_fam = IANA_ADDRFAM_IP4;
index de123ed4dea3f22733815cf52992c7c79e37ec1f..cb7a5d1bec78297ad95cabe40fd4c099730db301 100644 (file)
@@ -141,7 +141,7 @@ write_q(int fd, int udp, SSL* ssl, ldns_buffer* buf, uint16_t id,
                edns.edns_present = 1;
                edns.bits = EDNS_DO;
                edns.udp_size = 4096;
-               edns.subnet_option_add = 0; 
+               edns.subnet_option = 0; 
                attach_edns_record(buf, &edns);
        }
 
index 97fe83f7561469b8312d0040094b0cf42f035c5f..5b386a1e1f72395707b245cca17e7a71dbd2dd18 100644 (file)
@@ -746,7 +746,7 @@ attach_edns_record(ldns_buffer* pkt, struct edns_data* edns)
        ldns_buffer_write_u8(pkt, edns->edns_version);
        ldns_buffer_write_u16(pkt, edns->bits);
        /* Add edns-subnet option to record */
-       if(edns->subnet_option_add) {
+       if(edns->subnet_option) {
                assert(edns->subnet_addr_fam == IANA_ADDRFAM_IP4 || 
                        edns->subnet_addr_fam == IANA_ADDRFAM_IP6);
                assert(edns->subnet_addr_fam != IANA_ADDRFAM_IP4 || 
@@ -863,7 +863,7 @@ error_encode(ldns_buffer* buf, int r, struct query_info* qinfo,
                es.udp_size = EDNS_ADVERTISED_SIZE;
                es.ext_rcode = 0;
                es.bits &= EDNS_DO;
-               es.subnet_option_add = 0;
+               es.subnet_option = 0;
                if(ldns_buffer_limit(buf) + calc_edns_field_size(&es) >
                        edns->udp_size)
                        return;
index e5f00551b1f5c289c538dbedbf0f3cd8f1083796..7be61f88627696f9fd12b3b76d59b40207a311a1 100644 (file)
@@ -43,6 +43,7 @@
 #include "util/data/packed_rrset.h"
 #include "util/storage/lookup3.h"
 #include "util/regional.h"
+#include "util/net_help.h"
 
 /** smart comparison of (compressed, valid) dnames from packet */
 static int
@@ -930,6 +931,40 @@ parse_packet(ldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
        return 0;
 }
 
+void
+parse_ednsdata(uint8_t* data, struct edns_data* edns)
+{
+       int edns_datalen, opt_opc, opt_len, opt_start;
+       edns->subnet_option = 0;
+       /* Parse EDNS data field */
+       edns_datalen = ldns_read_uint16(data);
+       if(edns_datalen < 4) return;
+       /* iterate trough all options */
+       opt_start = 0;
+       while(opt_start + 4 <= edns_datalen) { /* opcode + len must fit */
+               opt_opc = ldns_read_uint16(&data[2 + opt_start]);
+               opt_len = ldns_read_uint16(&data[4 + opt_start]);
+               /* Option does not fit in remaining data */
+               if(opt_start + 4 + opt_len > edns_datalen) return;
+               opt_start += 4;
+               if(opt_opc == EDNS_SUBNET_OPC) {
+                       if(opt_len < 4) break;
+                       edns->subnet_addr_fam = ldns_read_uint16(data + 2 + opt_start);
+                       edns->subnet_source_mask = data[4 + opt_start];
+                       edns->subnet_scope_mask = data[5 + opt_start];
+                       /* remaing bytes indicate address */
+                       if(opt_len - 4 > INET6_SIZE || opt_len == 0) break;
+                       memset(edns->subnet_addr, 0, INET6_SIZE);
+                       memcpy(edns->subnet_addr, data + 6 + opt_start, opt_len - 4);
+                       edns->subnet_option = 1;
+                       break;
+               } else { /* Unknown opcode */
+                       verbose(VERB_QUERY, "Unknow EDNS option %x", opt_opc);
+               }
+               opt_start += opt_len;
+       }
+}
+
 int 
 parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
 {
@@ -979,12 +1014,11 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
        
        /* take the data ! */
        edns->edns_present = 1;
+       edns->udp_size = ntohs(found->rrset_class);
        edns->ext_rcode = found->rr_last->ttl_data[0];
        edns->edns_version = found->rr_last->ttl_data[1];
        edns->bits = ldns_read_uint16(&found->rr_last->ttl_data[2]);
-       edns->udp_size = ntohs(found->rrset_class);
-       edns->subnet_option_add = 0; //YBS do some actual parsing here
-       /* ignore rdata and rrsigs */
+       parse_ednsdata(found->rr_last->ttl_data + 4, edns);
        return 0;
 }
 
@@ -1015,6 +1049,6 @@ parse_edns_from_pkt(ldns_buffer* pkt, struct edns_data* edns)
        edns->ext_rcode = ldns_buffer_read_u8(pkt); /* ttl used for bits */
        edns->edns_version = ldns_buffer_read_u8(pkt);
        edns->bits = ldns_buffer_read_u16(pkt);
-       /* ignore rdata and rrsigs */
+       parse_ednsdata(ldns_buffer_current(pkt), edns);
        return 0;
 }
index b0c665e2a3b6e49fb98c9d1a817851a55fb0dc2f..606880dbeb8b464e589edc7e9a24ff44d68915f3 100644 (file)
@@ -211,7 +211,7 @@ struct edns_data {
        uint16_t bits;
        /** UDP reassembly size. */
        uint16_t udp_size;
-       int             subnet_option_add;
+       int             subnet_option; /*YBS*/
        uint16_t        subnet_addr_fam;
        uint8_t         subnet_source_mask;
        uint8_t         subnet_scope_mask;
index 149f3f889b1ec4749400d13c010d8dfd34bf412f..0e1988e56fc7dcc9a897e6dd4d0d670080f39d7c 100644 (file)
@@ -2133,7 +2133,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
        edns.ext_rcode = 0;
        edns.edns_version = 0;
        edns.bits = EDNS_DO;
-       edns.subnet_option_add = 0; 
+       edns.subnet_option = 0; 
        if(ldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)ldns_buffer_capacity(buf);
        else    edns.udp_size = 65535;