summaryrefslogtreecommitdiff
path: root/iterator/iter_priv.c
diff options
context:
space:
mode:
Diffstat (limited to 'iterator/iter_priv.c')
-rw-r--r--iterator/iter_priv.c48
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;
}
}
}