diff options
Diffstat (limited to 'iterator/iter_priv.c')
-rw-r--r-- | iterator/iter_priv.c | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/iterator/iter_priv.c b/iterator/iter_priv.c index db7dbe5faa65e..572f701f350da 100644 --- a/iterator/iter_priv.c +++ b/iterator/iter_priv.c @@ -208,6 +208,28 @@ size_t priv_get_mem(struct iter_priv* priv) return sizeof(*priv) + regional_get_mem(priv->region); } +/** remove RR from msgparse RRset, return true if rrset is entirely bad */ +static int +remove_rr(const char* str, ldns_buffer* pkt, struct rrset_parse* rrset, + struct rr_parse* prev, struct rr_parse** rr, struct sockaddr_storage* addr, socklen_t addrlen) +{ + if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) { + uint8_t buf[LDNS_MAX_DOMAINLEN+1]; + dname_pkt_copy(pkt, buf, rrset->dname); + log_name_addr(VERB_QUERY, str, buf, addr, addrlen); + } + if(prev) + prev->next = (*rr)->next; + else rrset->rr_first = (*rr)->next; + if(rrset->rr_last == *rr) + rrset->rr_last = prev; + rrset->rr_count --; + rrset->size -= (*rr)->size; + /* rr struct still exists, but is unlinked, so that in the for loop + * the rr->next works fine to continue. */ + return rrset->rr_count == 0; +} + int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt, struct rrset_parse* rrset) { @@ -221,7 +243,7 @@ int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt, } else { /* so its a public name, check the address */ socklen_t len; - struct rr_parse* rr; + struct rr_parse* rr, *prev = NULL; if(rrset->type == LDNS_RR_TYPE_A) { struct sockaddr_storage addr; struct sockaddr_in sa; @@ -232,13 +254,19 @@ int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt, sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); for(rr = rrset->rr_first; rr; rr = rr->next) { if(ldns_read_uint16(rr->ttl_data+4) - != INET_SIZE) + != INET_SIZE) { + prev = rr; continue; + } memmove(&sa.sin_addr, rr->ttl_data+4+2, INET_SIZE); memmove(&addr, &sa, len); - if(priv_lookup_addr(priv, &addr, len)) - return 1; + if(priv_lookup_addr(priv, &addr, len)) { + if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len)) + return 1; + continue; + } + prev = rr; } } else if(rrset->type == LDNS_RR_TYPE_AAAA) { struct sockaddr_storage addr; @@ -249,13 +277,19 @@ int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt, sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); for(rr = rrset->rr_first; rr; rr = rr->next) { if(ldns_read_uint16(rr->ttl_data+4) - != INET6_SIZE) + != INET6_SIZE) { + prev = rr; continue; + } memmove(&sa.sin6_addr, rr->ttl_data+4+2, INET6_SIZE); memmove(&addr, &sa, len); - if(priv_lookup_addr(priv, &addr, len)) - return 1; + if(priv_lookup_addr(priv, &addr, len)) { + if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len)) + return 1; + continue; + } + prev = rr; } } } |