]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Make sure we set unused addr bytes to zero
authorYuri Schaeffer <yuri@nlnetlabs.nl>
Mon, 18 Feb 2013 16:23:43 +0000 (16:23 +0000)
committerYuri Schaeffer <yuri@nlnetlabs.nl>
Mon, 18 Feb 2013 16:23:43 +0000 (16:23 +0000)
Improve structure

git-svn-id: file:///svn/unbound/branches/edns-subnet@2846 be551aaa-1e26-0410-a405-d3ace91eadb9

edns-subnet/edns-subnet.c
edns-subnet/edns-subnet.h
edns-subnet/subnetmod.c
edns-subnet/subnetmod.h
services/mesh.c
services/outside_network.c
services/outside_network.h
util/data/msgencode.c
util/data/msgparse.c

index fdfecc71ccecdec6c6dc0ffc89c43ebdba784438..cc3d6311575fa785d17e21ea2b531028d7217b35 100644 (file)
@@ -55,6 +55,25 @@ uint16_t EDNSSUBNET_OPCODE = 0x50fa;
 uint8_t EDNSSUBNET_MAX_SUBNET_IP4 = 24;
 uint8_t EDNSSUBNET_MAX_SUBNET_IP6 = 64;
 
+int
+copy_clear(uint8_t* dst, int dstlen, uint8_t* src, int srclen, int n)
+{
+       int intpart = n / 8;  /* bytes */
+       int fracpart = n % 8; /* bits */
+       int written = intpart;
+       if (intpart > dstlen || intpart > srclen)
+               return 1;
+       if (fracpart && (intpart+1 > dstlen || intpart+1 > srclen))
+               return 1;
+       memcpy(dst, src, intpart);
+       if (fracpart) {
+               dst[intpart] = src[intpart] & ~(0xFF >> fracpart);
+               written++;
+       }
+       memset(dst + written, 0, dstlen - written);
+       return 0;
+}
+
 struct ednssubnet_upstream* 
 upstream_create(void)
 {
index 969e6e805fc69cb921201358968c9d570a33b85f..b052fdea734b78ed47c0e7b65be4d49c566a5567 100644 (file)
@@ -57,6 +57,11 @@ extern uint16_t EDNSSUBNET_OPCODE;
 extern uint8_t EDNSSUBNET_MAX_SUBNET_IP4;
 extern uint8_t EDNSSUBNET_MAX_SUBNET_IP6;
 
+/** copy the first n BITS from src to dst iff both src and dst 
+ * are large enough, return 0 on succes */
+int
+copy_clear(uint8_t* dst, int dstlen, uint8_t* src, int srclen, int n);
+
 /**
  * ednssubnet_upstream structure
  */
index acaf115fc6a4588e4673095f03b889dc8e240fc5..d2571eb1250ed114255fd985fae635f55a047104 100644 (file)
 #include "util/module.h"
 #include "util/regional.h"
 
-/** fill in message structure */
-static struct subnet_qstate*
-sub_new_getmsg(struct module_qstate* qstate, struct subnet_qstate* snq)
-{
-       return snq;
-}
-
-/** allocate new subnet query state */
-static struct subnet_qstate*
-sub_new(struct module_qstate* qstate, int id)
-{
-       struct subnet_qstate* snq = (struct subnet_qstate*)regional_alloc(
-               qstate->region, sizeof(*snq));
-       log_assert(!qstate->minfo[id]);
-       if(!snq)
-               return NULL;
-       memset(snq, 0, sizeof(*snq));
-       qstate->minfo[id] = snq;
-       return sub_new_getmsg(qstate, snq);
-}
-
 int subnetmod_init(struct module_env* env, int id)
 {
        return 1;
@@ -78,7 +57,8 @@ void subnetmod_deinit(struct module_env* env, int id)
 {
 }
 
-void subnetmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super)
+void subnetmod_inform_super(struct module_qstate* qstate, int id, 
+       struct module_qstate* super)
 {
 }
 
@@ -91,6 +71,69 @@ void cp_edns_bad_response(struct edns_data* target, struct edns_data* source)
        target->subnet_validdata = 1;
 }
 
+enum module_ext_state eval_response(struct module_qstate* qstate)
+{
+       if (!qstate->edns_out.subnet_sent) {
+               if (qstate->edns_in.subnet_validdata)
+                       verbose(VERB_QUERY, "subnet: received spurious data");
+               if (qstate->edns_out.subnet_downstream) {
+                       /* Copy question back to client */
+                       qstate->edns_to_client = &qstate->edns_in;
+                       cp_edns_bad_response(qstate->edns_to_client, 
+                                                               qstate->edns_from_client);
+               }
+               return module_finished;
+       }
+       
+       /* subnet sent but nothing came back */
+       if (!qstate->edns_in.subnet_validdata) {
+               /** The authority indicated no support for vandergaast. As a
+                * consequence the answer ended up in the regular cache. It
+                * is still usefull to put it in the vandergaast cache for 
+                * when a client explicitly asks for subnet specific answer. */
+               verbose(VERB_QUERY, "subnet: Authority indicates no support");
+               // TODO PUT IT IN OUR SPECIAL CACHE
+               if (qstate->edns_out.subnet_downstream) {
+                       qstate->edns_to_client = &qstate->edns_in;
+                       cp_edns_bad_response(qstate->edns_to_client, 
+                                                               qstate->edns_from_client);
+               }
+               return module_finished;
+       }
+       
+       /** Being here means We asked for and got a subnet specific answer.
+        * Also the answer from the authority is not yet cached anywhere. */
+       
+       /* can we accept response? */
+       size_t sn_octs, remainder;
+       sn_octs = qstate->edns_out.subnet_source_mask / 8;
+       assert(sn_octs <= INET6_SIZE); /* Enforced by msgparse */
+       remainder = 8 - (size_t)(qstate->edns_out.subnet_source_mask % 8);
+       if(qstate->edns_out.subnet_addr_fam != qstate->edns_in.subnet_addr_fam ||
+               qstate->edns_out.subnet_source_mask != qstate->edns_in.subnet_source_mask ||
+               memcmp(qstate->edns_out.subnet_addr, qstate->edns_in.subnet_addr, sn_octs) != 0 ||
+               (qstate->edns_out.subnet_addr[sn_octs]^qstate->edns_in.subnet_addr[sn_octs])>>remainder) {
+               /* we can not, restart query without option */
+               verbose(VERB_QUERY, "subnet: forged data");
+               qstate->edns_out.subnet_validdata = 0;
+               qstate->edns_out.subnet_sent = 0;
+               return module_wait_module;
+       }
+       
+       /* TODO PUT IT IN OUR SPECIAL CACHE */
+       
+       if (qstate->edns_out.subnet_downstream) {
+               /* Client wants to see the answer, echo option back
+                * and adjust the scope. */
+               qstate->edns_to_client = qstate->edns_from_client;
+               verbose(VERB_QUERY, "subnet: attach");
+               qstate->edns_to_client->subnet_scope_mask = 
+                       qstate->edns_in.subnet_scope_mask;
+       }
+       verbose(VERB_QUERY, "subnet: done");
+       return module_finished;
+}
+
 void subnetmod_operate(struct module_qstate* qstate, enum module_ev event, 
        int id, struct outbound_entry* ATTR_UNUSED(outbound))
 {
@@ -98,19 +141,16 @@ void subnetmod_operate(struct module_qstate* qstate, enum module_ev event,
        void* cachehit;
        int max_mask;
 #endif
-       struct edns_data* edns_from_client; //from client
+       struct edns_data* edns_from_client;
        struct subnet_env* sne = (struct subnet_env*)qstate->env->modinfo[id];
        struct subnet_qstate* snq = (struct subnet_qstate*)qstate->minfo[id];
        
        verbose(VERB_QUERY, "subnet[module %d] operate: extstate:%s "
                "event:%s", id, strextstate(qstate->ext_state[id]), 
                strmodulevent(event));
-       log_query_info(VERB_QUERY, "subnet operate: query",
-               &qstate->qinfo);
-       /* This query is new for us */
-       if(event == module_event_new || 
-               (event == module_event_pass && snq == NULL)) {
-               snq = sub_new(qstate, id);
+       log_query_info(VERB_QUERY, "subnet operate: query", &qstate->qinfo);
+
+       if(event == module_event_new) {
                edns_from_client = qstate->edns_from_client;
                
                if(!edns_from_client || !edns_from_client->subnet_validdata) {
@@ -184,58 +224,7 @@ void subnetmod_operate(struct module_qstate* qstate, enum module_ev event,
        if(event == module_event_moddone) {
                verbose(VERB_QUERY, "subnet: done");
                qstate->edns_to_client = NULL;
-               if (!qstate->edns_out.subnet_sent) {
-                       verbose(VERB_QUERY, "subnet: did not sent");
-                       if (qstate->edns_in.subnet_validdata) {
-                               verbose(VERB_QUERY, "subnet: received spurious data");
-                       }
-                       if (qstate->edns_out.subnet_downstream) {
-                               verbose(VERB_QUERY, "subnet: client shows interest");
-                               qstate->edns_to_client = &qstate->edns_in;
-                               cp_edns_bad_response(qstate->edns_to_client, 
-                                                                       qstate->edns_from_client);
-                       }
-               } else {
-                       verbose(VERB_QUERY, "subnet: did sent");
-                       /* subnet sent but nothing came back */
-                       if (!qstate->edns_in.subnet_validdata) {
-                               verbose(VERB_QUERY, "subnet: missing data");
-                               // TODO PUT IT IN OUR SPECIAL CACHE
-                               if (qstate->edns_out.subnet_downstream) {
-                                       qstate->edns_to_client = &qstate->edns_in;
-                                       cp_edns_bad_response(qstate->edns_to_client, 
-                                                                               qstate->edns_from_client);
-                               }
-                       } else {
-                               verbose(VERB_QUERY, "subnet: is not cached");
-                               /* can we accept response? */
-                               size_t sn_octs, remainder;
-                               sn_octs = qstate->edns_out.subnet_source_mask / 8;
-                               /* should be enforced by msgparse */
-                               assert(sn_octs <= INET6_SIZE);
-                               remainder = 8 - (size_t)(qstate->edns_out.subnet_source_mask % 8);
-                               if(qstate->edns_out.subnet_addr_fam != qstate->edns_in.subnet_addr_fam ||
-                                       qstate->edns_out.subnet_source_mask != qstate->edns_in.subnet_source_mask ||
-                                       memcmp(qstate->edns_out.subnet_addr, qstate->edns_in.subnet_addr, sn_octs) != 0 ||
-                                       (qstate->edns_out.subnet_addr[sn_octs]^qstate->edns_in.subnet_addr[sn_octs])>>remainder) {
-                                       /* we can not, restart query without option */
-                                       verbose(VERB_QUERY, "subnet: forged data");
-                                       qstate->edns_out.subnet_validdata = 0;
-                                       qstate->edns_out.subnet_sent = 0;
-                                       qstate->ext_state[id] = module_wait_module;
-                                       return;
-                               }
-                               verbose(VERB_QUERY, "subnet: now cache it");
-                               /* TODO PUT IT IN OUR SPECIAL CACHE */
-                               if (qstate->edns_out.subnet_downstream) {
-                                       qstate->edns_to_client = qstate->edns_from_client;
-                                       verbose(VERB_QUERY, "subnet: attach");
-                                       qstate->edns_to_client->subnet_scope_mask = 
-                                               qstate->edns_in.subnet_scope_mask;
-                               }
-                       }
-               }
-               qstate->ext_state[id] = module_finished;
+               qstate->ext_state[id] = eval_response(qstate);
                return;
        }
        /* We are being revisited */
index 229959327aed3d7d7c6554524c811980396fd4b8..be9179f4a9b59b9029ad0fd63747501cf8672903 100644 (file)
@@ -51,16 +51,6 @@ struct subnet_env {
        
 };
 
-/**
- * Per query state for the subnet module.
- */
-struct subnet_qstate {
-       /** 
-        * State of the subnet module.
-        */
-       struct edns_data edns;
-};
-
 /**
  * Get the module function block.
  * @return: function block with function pointers to module methods.
index d85b04eb0fce8605de82df6f7868598bc1b69d07..c71c1a1f99e357b9f9befbc34777c8edabf541da 100644 (file)
@@ -394,6 +394,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
        } else {
                struct sockaddr_storage *ss;
                void* sinaddr;
+               edns->subnet_validdata = 0;
                edns->subnet_downstream = 0;
                /* Construct subnet option from original query */
                ss = &s->reply_list->query_reply.addr;
@@ -401,16 +402,22 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
                        edns->subnet_source_mask = EDNSSUBNET_MAX_SUBNET_IP4;
                        edns->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP4;
                        sinaddr = &((struct sockaddr_in*)ss)->sin_addr;
-                       memcpy(edns->subnet_addr, (uint8_t *)sinaddr, INET_SIZE);
-                       edns->subnet_validdata = 1;
+                       if (!copy_clear(
+                                       edns->subnet_addr, INET6_SIZE, (uint8_t *)sinaddr, 
+                                       INET_SIZE, EDNSSUBNET_MAX_SUBNET_IP4)) {
+                               edns->subnet_validdata = 1;
+                       }
                }
 #ifdef INET6
                else {
                        edns->subnet_source_mask = EDNSSUBNET_MAX_SUBNET_IP6;
                        edns->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP6;
                        sinaddr = &((struct sockaddr_in6*)ss)->sin6_addr;
-                       memcpy(edns->subnet_addr, (uint8_t *)sinaddr, INET6_SIZE);
-                       edns->subnet_validdata = 1;
+                       if (!copy_clear(
+                                       edns->subnet_addr, INET6_SIZE, (uint8_t *)sinaddr, 
+                                       INET6_SIZE, EDNSSUBNET_MAX_SUBNET_IP4)) {
+                               edns->subnet_validdata = 1;
+                       }
                }
 #else
                else {
index 4ba9efed48b18b1ece2f4c9f83dca4fa82882815..3fa9f3d7d39a64b39a020404e5a7ef9072827d14 100644 (file)
@@ -557,7 +557,6 @@ static int setup_if(struct port_if* pif, const char* addrstr,
        return 1;
 }
 
-#ifdef CLIENT_SUBNET
 struct outside_network* 
 outside_network_create(struct comm_base *base, size_t bufsize, 
        size_t num_ports, char** ifs, int num_ifs, int do_ip4, 
@@ -565,17 +564,11 @@ outside_network_create(struct comm_base *base, size_t bufsize,
        struct ub_randstate* rnd, int use_caps_for_id, int* availports, 
        int numavailports, size_t unwanted_threshold,
        void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
-       void* sslctx, struct ednssubnet_upstream* edns_subnet_upstreams)
-#else
-struct outside_network* 
-outside_network_create(struct comm_base *base, size_t bufsize, 
-       size_t num_ports, char** ifs, int num_ifs, int do_ip4, 
-       int do_ip6, size_t num_tcp, struct infra_cache* infra,
-       struct ub_randstate* rnd, int use_caps_for_id, int* availports, 
-       int numavailports, size_t unwanted_threshold,
-       void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
-       void* sslctx)
+       void* sslctx
+#ifdef CLIENT_SUBNET
+       , struct ednssubnet_upstream* edns_subnet_upstreams
 #endif
+       )
 {
        struct outside_network* outnet = (struct outside_network*)
                calloc(1, sizeof(struct outside_network));
index 9001c89ba26b1011dc621db3a885c6a238eef975..bbe6feff2bf591b143b425c6875e57ec1629061b 100644 (file)
@@ -362,7 +362,7 @@ struct serviced_query {
 #endif
 };
 
-#ifdef CLIENT_SUBNET
+
 /**
  * Create outside_network structure with N udp ports.
  * @param base: the communication base to use for event handling.
@@ -393,40 +393,12 @@ struct outside_network* outside_network_create(struct comm_base* base,
        struct ub_randstate* rnd, int use_caps_for_id, int* availports, 
        int numavailports, size_t unwanted_threshold,
        void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
-       void* sslctx, struct ednssubnet_upstream* edns_subnet_upstreams);
-#else
-/**
- * Create outside_network structure with N udp ports.
- * @param base: the communication base to use for event handling.
- * @param bufsize: size for network buffers.
- * @param num_ports: number of udp ports to open per interface.
- * @param ifs: interface names (or NULL for default interface).
- *    These interfaces must be able to access all authoritative servers.
- * @param num_ifs: number of names in array ifs.
- * @param do_ip4: service IP4.
- * @param do_ip6: service IP6.
- * @param num_tcp: number of outgoing tcp buffers to preallocate.
- * @param infra: pointer to infra cached used for serviced queries.
- * @param rnd: stored to create random numbers for serviced queries.
- * @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
- * @param availports: array of available ports. 
- * @param numavailports: number of available ports in array.
- * @param unwanted_threshold: when to take defensive action.
- * @param unwanted_action: the action to take.
- * @param unwanted_param: user parameter to action.
- * @param do_udp: if udp is done.
- * @param sslctx: context to create outgoing connections with (if enabled).
- * @return: the new structure (with no pending answers) or NULL on error.
- */
-
-struct outside_network* outside_network_create(struct comm_base* base,
-       size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
-       int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra, 
-       struct ub_randstate* rnd, int use_caps_for_id, int* availports, 
-       int numavailports, size_t unwanted_threshold,
-       void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
-       void* sslctx);
+       void* sslctx
+#ifdef CLIENT_SUBNET
+       , struct ednssubnet_upstream* edns_subnet_upstreams
 #endif
+);
+
 /**
  * Delete outside_network structure.
  * @param outnet: object to delete.
index d45f2f1a3c8a2744a99e913d231f234a9ed0c7b4..45e6db17a701d8aa8e3ba96d42c0da77027e131b 100644 (file)
@@ -763,6 +763,7 @@ attach_edns_record(ldns_buffer* pkt, struct edns_data* edns)
                sn_octs = edns->subnet_source_mask / 8;
                sn_octs_remainder = (size_t)((edns->subnet_source_mask % 8)>0?1:0);
                
+               assert(sn_octs + sn_octs_remainder <= INET6_SIZE);
                assert(ldns_buffer_available(pkt, sn_octs + sn_octs_remainder + 4 + 6));
                
                ldns_buffer_write_u16(pkt, sn_octs + sn_octs_remainder + 4 + 4); /* rdatalen */
index 3d34b25ad9442093e04e02a18424fff374fa8905..7477e588d0df06517542ea16c5874bb5ea7609c3 100644 (file)
@@ -934,6 +934,34 @@ parse_packet(ldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
 }
 
 #ifdef CLIENT_SUBNET
+
+void parse_subnet_option(uint8_t* data, struct edns_data* edns, int opt_len)
+{
+       if(opt_len < 4) return; /* try next */
+
+       edns->subnet_addr_fam = ldns_read_uint16(data);
+       edns->subnet_source_mask = data[2];
+       edns->subnet_scope_mask = data[3];
+       /* remaing bytes indicate address */
+       
+       /* validate input*/
+       if(opt_len - 4 > INET6_SIZE || opt_len == 0) return;
+       if (edns->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) {
+               if (edns->subnet_source_mask > 32 || edns->subnet_scope_mask > 32)
+                       return;
+       } else if (edns->subnet_addr_fam != EDNSSUBNET_ADDRFAM_IP6) {
+               if (edns->subnet_source_mask > 128 || edns->subnet_scope_mask > 128)
+                       return;
+       } else return;
+       
+       
+       if (copy_clear(edns->subnet_addr, INET6_SIZE, data + 6, 
+                       opt_len - 4, edns->subnet_source_mask))
+               return;
+
+       edns->subnet_validdata = 1;
+}
+
 void
 parse_ednsdata(uint8_t* data, struct edns_data* edns)
 {
@@ -943,29 +971,20 @@ parse_ednsdata(uint8_t* data, struct edns_data* edns)
        edns_datalen = ldns_read_uint16(data);
        data += 2;
        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[opt_start]);
                opt_len = ldns_read_uint16(&data[2 + opt_start]);
                /* Option does not fit in remaining data */
-               if(opt_start + 4 + opt_len > edns_datalen) return;
-               opt_start += 4;
+               if(opt_start + 4 + opt_len > edns_datalen) break;
+               
                if(opt_opc == EDNSSUBNET_OPCODE) {
-                       if(opt_len < 4) break;
-                       edns->subnet_addr_fam = ldns_read_uint16(data + opt_start);
-                       edns->subnet_source_mask = data[2 + opt_start];
-                       edns->subnet_scope_mask = data[3 + 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_validdata = 1;
-                       break;
+                       parse_subnet_option(data + opt_start + 4, edns, opt_len);
                } else { /* Unknown opcode */
                        verbose(VERB_QUERY, "Unknow EDNS option %x", opt_opc);
                }
-               opt_start += opt_len;
+               
+               opt_start += opt_len + 4;
        }
 }
 #endif