From 3fcddb8cb0a02bdac5fd972fdd69fece43108293 Mon Sep 17 00:00:00 2001 From: Yuri Schaeffer Date: Thu, 14 Feb 2013 15:38:07 +0000 Subject: [PATCH] Implicit declaration -> strange crashes Improved parsing ednsdata Improved mesh state selection git-svn-id: file:///svn/unbound/branches/edns-subnet@2844 be551aaa-1e26-0410-a405-d3ace91eadb9 --- edns-subnet/subnetmod.c | 1 + services/mesh.c | 59 ++++++++++++++++++++++++++++++----------- util/data/msgparse.c | 13 ++++----- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/edns-subnet/subnetmod.c b/edns-subnet/subnetmod.c index 54e0e4982..acaf115fc 100644 --- a/edns-subnet/subnetmod.c +++ b/edns-subnet/subnetmod.c @@ -46,6 +46,7 @@ #include "edns-subnet/edns-subnet.h" #include "services/mesh.h" #include "util/module.h" +#include "util/regional.h" /** fill in message structure */ static struct subnet_qstate* diff --git a/services/mesh.c b/services/mesh.c index 04df7ac5f..d85b04eb0 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -124,11 +124,46 @@ timeval_smaller(const struct timeval* x, const struct timeval* y) #endif } +#ifdef CLIENT_SUBNET +/** Returns a==b: 0, ab: negative */ +int subnet_compare(struct edns_data *a, struct edns_data *b) +{ + if (!a) { + if (b) return 1; + return 0; + } else { + if (!b) return -1; + /* crude way: + * return memcmp(b, a, sizeof(struct edns_data)); */ + + if ( a->edns_present && !b->edns_present) return -1; + if (!a->edns_present && !b->edns_present) return 0; + if (!a->edns_present && b->edns_present) return 1; + + if ( a->subnet_validdata && !b->subnet_validdata) return -1; + if (!a->subnet_validdata && !b->subnet_validdata) return 0; + if (!a->subnet_validdata && b->subnet_validdata) return 1; + + if (a->subnet_addr_fam != b->subnet_addr_fam) { + return b->subnet_addr_fam - a->subnet_addr_fam; + } + if (a->subnet_source_mask != b->subnet_source_mask) { + return b->subnet_source_mask - a->subnet_source_mask; + } + return memcmp(b->subnet_addr, a->subnet_addr, INET6_SIZE); + + } +} +#endif + int mesh_state_compare(const void* ap, const void* bp) { struct mesh_state* a = (struct mesh_state*)ap; struct mesh_state* b = (struct mesh_state*)bp; +#ifdef CLIENT_SUBNET + int r; +#endif if(ap == bp) return 0; @@ -147,6 +182,10 @@ mesh_state_compare(const void* ap, const void* bp) if(!(a->s.query_flags&BIT_CD) && (b->s.query_flags&BIT_CD)) return 1; +#ifdef CLIENT_SUBNET + r = subnet_compare(a->s.edns_from_client, b->s.edns_from_client); + if (r != 0) return r; +#endif return query_info_compare(&a->s.qinfo, &b->s.qinfo); } @@ -311,21 +350,6 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, return; } } -#ifdef CLIENT_SUBNET - /* See if both the found mesh and the query have the same subnet - * option set. If not forget about mesh_state and create a new one */ - if(s) { - struct edns_data* medns = s->s.edns_from_client; - if ( !(edns->edns_present && edns->subnet_validdata) || - !(medns && medns->edns_present && medns->subnet_validdata) || - edns->subnet_addr_fam != medns->subnet_addr_fam || - edns->subnet_source_mask != medns->subnet_source_mask || - memcmp(edns->subnet_addr, medns->subnet_addr, INET6_SIZE) != 0) - { - s = NULL; - } - } -#endif /* see if it already exists, if not, create one */ if(!s) { #ifdef UNBOUND_DEBUG @@ -1015,7 +1039,10 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh, key.s.is_priming = prime; key.s.qinfo = *qinfo; key.s.query_flags = qflags; - +#ifdef CLIENT_SUBNET + key.s.edns_from_client = NULL; +#endif + result = (struct mesh_state*)rbtree_search(&mesh->all, &key); return result; } diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 580e82d26..3d34b25ad 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -941,20 +941,21 @@ parse_ednsdata(uint8_t* data, struct edns_data* edns) edns->subnet_validdata = 0; /* Parse EDNS data field */ 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[2 + opt_start]); - opt_len = ldns_read_uint16(&data[4 + opt_start]); + 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_opc == EDNSSUBNET_OPCODE) { 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]; + 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); @@ -1022,7 +1023,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns) 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]); -#ifdef CLIENT_SUBNET +#ifdef CLIENT_SUBNET parse_ednsdata(found->rr_last->ttl_data + 4, edns); #endif /* ignore rdata and rrsigs */ -- 2.47.2