From 6938f3476e01b3fe7979526bc3bd2fc0f9274f27 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sun, 26 Jan 2014 22:47:39 +0000 Subject: [PATCH] Don't mark answers as DNSEC validated if DNS-doctored. --- src/dnsmasq.h | 2 +- src/forward.c | 24 +++++++++++++++--------- src/rfc1035.c | 25 +++++++++++++++---------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 68bf9d7..f8cc969 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1037,7 +1037,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen, unsigned long local_ttl); int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff, time_t now, char **ipsets, int is_sign, int checkrebind, - int no_cache, int secure); + int no_cache, int secure, int *doctored); size_t answer_request(struct dns_header *header, char *limit, size_t qlen, struct in_addr local_addr, struct in_addr local_netmask, time_t now); int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, diff --git a/src/forward.c b/src/forward.c index bec5f95..c047cb4 100644 --- a/src/forward.c +++ b/src/forward.c @@ -556,14 +556,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server if (!is_sign && !option_bool(OPT_DNSSEC_PROXY)) header->hb4 &= ~HB4_AD; -#ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID)) - header->hb4 &= ~HB4_AD; - - if (!(header->hb4 & HB4_CD) && cache_secure) - header->hb4 |= HB4_AD; -#endif - if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN)) return n; @@ -583,9 +575,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server munged = 1; SET_RCODE(header, NXDOMAIN); header->hb3 &= ~HB3_AA; + cache_secure = 0; } else { + int doctored = 0; + if (RCODE(header) == NXDOMAIN && extract_request(header, n, daemon->namebuff, NULL) && check_for_local_domain(daemon->namebuff, now)) @@ -596,13 +591,18 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server munged = 1; header->hb3 |= HB3_AA; SET_RCODE(header, NOERROR); + cache_secure = 0; } - if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure)) + if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored)) { my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff); munged = 1; + cache_secure = 0; } + + if (doctored) + cache_secure = 0; } #ifdef HAVE_DNSSEC @@ -615,6 +615,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server munged = 1; } } + + if (option_bool(OPT_DNSSEC_VALID)) + header->hb4 &= ~HB4_AD; + + if (!(header->hb4 & HB4_CD) && cache_secure) + header->hb4 |= HB4_AD; #endif /* do this after extract_addresses. Ensure NODATA reply and remove diff --git a/src/rfc1035.c b/src/rfc1035.c index 5ae6e1b..850dd8e 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -754,7 +754,7 @@ int private_net(struct in_addr addr, int ban_localhost) ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ; } -static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name) +static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored) { int i, qtype, qclass, rdlen; @@ -799,6 +799,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header * addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr); /* Since we munged the data, the server it came from is no longer authoritative */ header->hb3 &= ~HB3_AA; + *doctored = 1; memcpy(p, &addr, INADDRSZ); break; } @@ -837,7 +838,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header * return p; } -static int find_soa(struct dns_header *header, size_t qlen, char *name) +static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored) { unsigned char *p; int qtype, qclass, rdlen; @@ -846,7 +847,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name) /* first move to NS section and find TTL from any SOA section */ if (!(p = skip_questions(header, qlen)) || - !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name))) + !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored))) return 0; /* bad packet */ for (i = ntohs(header->nscount); i != 0; i--) @@ -881,8 +882,8 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name) return 0; /* bad packet */ } - /* rewrite addresses in additioal section too */ - if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL)) + /* rewrite addresses in additional section too */ + if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored)) return 0; if (!found_soa) @@ -896,7 +897,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name) expired and cleaned out that way. Return 1 if we reject an address because it look like part of dns-rebinding attack. */ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now, - char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure) + char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored) { unsigned char *p, *p1, *endrr, *namep; int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0; @@ -911,10 +912,14 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t cache_start_insert(); /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */ - if (daemon->doctors || option_bool(OPT_LOG)) + if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID)) { searched_soa = 1; - ttl = find_soa(header, qlen, name); + ttl = find_soa(header, qlen, name, doctored); +#ifdef HAVE_DNSSEC + if (*doctored) + secure = 0; +#endif } /* go through the questions. */ @@ -1004,7 +1009,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t if (!searched_soa) { searched_soa = 1; - ttl = find_soa(header, qlen, NULL); + ttl = find_soa(header, qlen, NULL, doctored); } if (ttl) cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag); @@ -1120,7 +1125,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t if (!searched_soa) { searched_soa = 1; - ttl = find_soa(header, qlen, NULL); + ttl = find_soa(header, qlen, NULL, doctored); } /* If there's no SOA to get the TTL from, but there is a CNAME pointing at this, inherit its TTL */