From 394ff492da6af5da7e7d356be9586683bc5fc011 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sun, 29 Mar 2015 22:17:14 +0100 Subject: Allow control characters in names in the cache, handle when logging. --- src/cache.c | 19 +++++++++++++++++-- src/dnssec.c | 34 +++++++++++++++++----------------- src/rfc1035.c | 7 +++---- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/cache.c b/src/cache.c index c95624c..873c577 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1399,6 +1399,19 @@ int cache_make_stat(struct txt_record *t) return 1; } +/* There can be names in the cache containing control chars, don't + mess up logging or open security holes. */ +static char *sanitise(char *name) +{ + unsigned char *r; + for (r = (unsigned char *)name; *r; r++) + if (!isprint((int)*r)) + return ""; + + return name; +} + + void dump_cache(time_t now) { struct server *serv, *serv1; @@ -1452,9 +1465,9 @@ void dump_cache(time_t now) *a = 0; if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) n = ""; - p += sprintf(p, "%-30.30s ", n); + p += sprintf(p, "%-30.30s ", sanitise(n)); if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) - a = cache_get_cname_target(cache); + a = sanitise(cache_get_cname_target(cache)); #ifdef HAVE_DNSSEC else if (cache->flags & F_DS) { @@ -1587,6 +1600,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg) if (!option_bool(OPT_LOG)) return; + name = sanitise(name); + if (addr) { if (flags & F_KEYTAG) diff --git a/src/dnssec.c b/src/dnssec.c index 8bd5294..14bae7e 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -552,7 +552,7 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, (*desc)++; - if (d == 0 && extract_name(header, plen, p, buff, 2, 0)) + if (d == 0 && extract_name(header, plen, p, buff, 1, 0)) /* domain-name, canonicalise */ return to_wire(buff); else @@ -811,7 +811,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in GETLONG(sig_inception, p); GETSHORT(key_tag, p); - if (!extract_name(header, plen, &p, keyname, 2, 0)) + if (!extract_name(header, plen, &p, keyname, 1, 0)) return STAT_BOGUS; /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal @@ -866,7 +866,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in u16 len, *dp; p = rrset[i]; - if (!extract_name(header, plen, &p, name, 2, 10)) + if (!extract_name(header, plen, &p, name, 1, 10)) return STAT_BOGUS; name_start = name; @@ -923,7 +923,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in /* namebuff used for workspace above, restore to leave unchanged on exit */ p = (unsigned char*)(rrset[0]); - extract_name(header, plen, &p, name, 2, 0); + extract_name(header, plen, &p, name, 1, 0); if (key) { @@ -963,7 +963,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch struct all_addr a; if (ntohs(header->qdcount) != 1 || - !extract_name(header, plen, &p, name, 2, 4)) + !extract_name(header, plen, &p, name, 1, 4)) return STAT_BOGUS; GETSHORT(qtype, p); @@ -1202,7 +1202,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char val = STAT_BOGUS; p = (unsigned char *)(header+1); - extract_name(header, plen, &p, name, 2, 4); + extract_name(header, plen, &p, name, 1, 4); p += 4; /* qtype, qclass */ if (!(p = skip_section(p, ntohs(header->ancount), header, plen))) @@ -1419,12 +1419,12 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi for (i = 0; i < nsec_count; i++) { p = nsecs[i]; - if (!extract_name(header, plen, &p, workspace1, 2, 10)) + if (!extract_name(header, plen, &p, workspace1, 1, 10)) return STAT_BOGUS; p += 8; /* class, type, TTL */ GETSHORT(rdlen, p); psave = p; - if (!extract_name(header, plen, &p, workspace2, 2, 10)) + if (!extract_name(header, plen, &p, workspace2, 1, 10)) return STAT_BOGUS; rc = hostname_cmp(workspace1, name); @@ -1553,7 +1553,7 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige for (i = 0; i < nsec_count; i++) if ((p = nsecs[i])) { - if (!extract_name(header, plen, &p, workspace1, 2, 0) || + if (!extract_name(header, plen, &p, workspace1, 1, 0) || !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2))) return 0; @@ -1730,7 +1730,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns for (i = 0; i < nsec_count; i++) if ((p = nsecs[i])) { - if (!extract_name(header, plen, &p, workspace1, 2, 0) || + if (!extract_name(header, plen, &p, workspace1, 1, 0) || !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2))) return STAT_BOGUS; @@ -1796,7 +1796,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch qname = p1 = (unsigned char *)(header+1); - if (!extract_name(header, plen, &p1, name, 2, 4)) + if (!extract_name(header, plen, &p1, name, 1, 4)) return STAT_BOGUS; GETSHORT(qtype, p1); @@ -1836,7 +1836,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch qname = p1; /* looped CNAMES */ - if (!cname_count-- || !extract_name(header, plen, &p1, name, 2, 0)) + if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0)) return STAT_BOGUS; p1 = ans_start; @@ -1857,7 +1857,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++) { - if (!extract_name(header, plen, &p1, name, 2, 10)) + if (!extract_name(header, plen, &p1, name, 1, 10)) return STAT_BOGUS; /* bad packet */ GETSHORT(type1, p1); @@ -2039,7 +2039,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch an unsigned zone. Return STAT_NO_SIG to cause this to be proved. */ /* Get name of missing answer */ - if (!extract_name(header, plen, &qname, name, 2, 0)) + if (!extract_name(header, plen, &qname, name, 1, 0)) return STAT_BOGUS; if (nsec_type == T_NSEC) @@ -2061,7 +2061,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char int cname_count = CNAME_CHAIN; /* Get question */ - if (!extract_name(header, plen, &p, name, 2, 4)) + if (!extract_name(header, plen, &p, name, 1, 4)) return STAT_BOGUS; p +=2; /* type */ @@ -2102,7 +2102,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char /* Loop down CNAME chain/ */ if (!cname_count-- || - !extract_name(header, plen, &p, name, 2, 0) || + !extract_name(header, plen, &p, name, 1, 0) || !(p = skip_questions(header, plen))) return STAT_BOGUS; @@ -2419,7 +2419,7 @@ unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name for (q = ntohs(header->qdcount); q != 0; q--) { - if (!extract_name(header, plen, &p, name, 2, 4)) + if (!extract_name(header, plen, &p, name, 1, 4)) break; /* bad packet */ len = to_wire(name); diff --git a/src/rfc1035.c b/src/rfc1035.c index 10832a3..7a07b0c 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -16,7 +16,6 @@ #include "dnsmasq.h" -/* isExtract == 2 -> DNSSEC mode, no bitstrings, no ascii checks. */ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, char *name, int isExtract, int extrabytes) { @@ -87,7 +86,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, if ((l & 0x3f) != 1) return 0; /* we only understand bitstrings */ - if (isExtract != 1) + if (!isExtract) return 0; /* Cannot compare bitsrings */ count = *p++; @@ -129,8 +128,8 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, if (isExtract) { unsigned char c = *p; - if ((isExtract == 2 || (isascii(c) && !iscntrl(c))) && c != '.') - *cp++ = *p; + if (c != 0 && c != '.') + *cp++ = c; else return 0; } -- cgit v1.2.1