Commit 394ff492 authored by Simon Kelley's avatar Simon Kelley

Allow control characters in names in the cache, handle when logging.

parent 1e153945
...@@ -1399,6 +1399,19 @@ int cache_make_stat(struct txt_record *t) ...@@ -1399,6 +1399,19 @@ int cache_make_stat(struct txt_record *t)
return 1; 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 "<name unprintable>";
return name;
}
void dump_cache(time_t now) void dump_cache(time_t now)
{ {
struct server *serv, *serv1; struct server *serv, *serv1;
...@@ -1452,9 +1465,9 @@ void dump_cache(time_t now) ...@@ -1452,9 +1465,9 @@ void dump_cache(time_t now)
*a = 0; *a = 0;
if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
n = "<Root>"; n = "<Root>";
p += sprintf(p, "%-30.30s ", n); p += sprintf(p, "%-30.30s ", sanitise(n));
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) 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 #ifdef HAVE_DNSSEC
else if (cache->flags & F_DS) else if (cache->flags & F_DS)
{ {
...@@ -1587,6 +1600,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg) ...@@ -1587,6 +1600,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
if (!option_bool(OPT_LOG)) if (!option_bool(OPT_LOG))
return; return;
name = sanitise(name);
if (addr) if (addr)
{ {
if (flags & F_KEYTAG) if (flags & F_KEYTAG)
......
...@@ -552,7 +552,7 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, ...@@ -552,7 +552,7 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
(*desc)++; (*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 */ /* domain-name, canonicalise */
return to_wire(buff); return to_wire(buff);
else else
...@@ -811,7 +811,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -811,7 +811,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
GETLONG(sig_inception, p); GETLONG(sig_inception, p);
GETSHORT(key_tag, 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; return STAT_BOGUS;
/* RFC 4035 5.3.1 says that the Signer's Name field MUST equal /* 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 ...@@ -866,7 +866,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
u16 len, *dp; u16 len, *dp;
p = rrset[i]; p = rrset[i];
if (!extract_name(header, plen, &p, name, 2, 10)) if (!extract_name(header, plen, &p, name, 1, 10))
return STAT_BOGUS; return STAT_BOGUS;
name_start = name; name_start = name;
...@@ -923,7 +923,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -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 */ /* namebuff used for workspace above, restore to leave unchanged on exit */
p = (unsigned char*)(rrset[0]); p = (unsigned char*)(rrset[0]);
extract_name(header, plen, &p, name, 2, 0); extract_name(header, plen, &p, name, 1, 0);
if (key) if (key)
{ {
...@@ -963,7 +963,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch ...@@ -963,7 +963,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
struct all_addr a; struct all_addr a;
if (ntohs(header->qdcount) != 1 || if (ntohs(header->qdcount) != 1 ||
!extract_name(header, plen, &p, name, 2, 4)) !extract_name(header, plen, &p, name, 1, 4))
return STAT_BOGUS; return STAT_BOGUS;
GETSHORT(qtype, p); GETSHORT(qtype, p);
...@@ -1202,7 +1202,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char ...@@ -1202,7 +1202,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
val = STAT_BOGUS; val = STAT_BOGUS;
p = (unsigned char *)(header+1); 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 */ p += 4; /* qtype, qclass */
if (!(p = skip_section(p, ntohs(header->ancount), header, plen))) 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 ...@@ -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++) for (i = 0; i < nsec_count; i++)
{ {
p = nsecs[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; return STAT_BOGUS;
p += 8; /* class, type, TTL */ p += 8; /* class, type, TTL */
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
psave = p; psave = p;
if (!extract_name(header, plen, &p, workspace2, 2, 10)) if (!extract_name(header, plen, &p, workspace2, 1, 10))
return STAT_BOGUS; return STAT_BOGUS;
rc = hostname_cmp(workspace1, name); rc = hostname_cmp(workspace1, name);
...@@ -1553,7 +1553,7 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige ...@@ -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++) for (i = 0; i < nsec_count; i++)
if ((p = nsecs[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))) !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
return 0; return 0;
...@@ -1730,7 +1730,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns ...@@ -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++) for (i = 0; i < nsec_count; i++)
if ((p = nsecs[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))) !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
return STAT_BOGUS; return STAT_BOGUS;
...@@ -1796,7 +1796,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -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); 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; return STAT_BOGUS;
GETSHORT(qtype, p1); GETSHORT(qtype, p1);
...@@ -1836,7 +1836,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -1836,7 +1836,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
qname = p1; qname = p1;
/* looped CNAMES */ /* 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; return STAT_BOGUS;
p1 = ans_start; p1 = ans_start;
...@@ -1857,7 +1857,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -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++) 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 */ return STAT_BOGUS; /* bad packet */
GETSHORT(type1, p1); GETSHORT(type1, p1);
...@@ -2039,7 +2039,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -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. */ an unsigned zone. Return STAT_NO_SIG to cause this to be proved. */
/* Get name of missing answer */ /* 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; return STAT_BOGUS;
if (nsec_type == T_NSEC) if (nsec_type == T_NSEC)
...@@ -2061,7 +2061,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char ...@@ -2061,7 +2061,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
int cname_count = CNAME_CHAIN; int cname_count = CNAME_CHAIN;
/* Get question */ /* Get question */
if (!extract_name(header, plen, &p, name, 2, 4)) if (!extract_name(header, plen, &p, name, 1, 4))
return STAT_BOGUS; return STAT_BOGUS;
p +=2; /* type */ p +=2; /* type */
...@@ -2102,7 +2102,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char ...@@ -2102,7 +2102,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
/* Loop down CNAME chain/ */ /* Loop down CNAME chain/ */
if (!cname_count-- || if (!cname_count-- ||
!extract_name(header, plen, &p, name, 2, 0) || !extract_name(header, plen, &p, name, 1, 0) ||
!(p = skip_questions(header, plen))) !(p = skip_questions(header, plen)))
return STAT_BOGUS; return STAT_BOGUS;
...@@ -2419,7 +2419,7 @@ unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name ...@@ -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--) 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 */ break; /* bad packet */
len = to_wire(name); len = to_wire(name);
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "dnsmasq.h" #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, int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes) char *name, int isExtract, int extrabytes)
{ {
...@@ -87,7 +86,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, ...@@ -87,7 +86,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
if ((l & 0x3f) != 1) if ((l & 0x3f) != 1)
return 0; /* we only understand bitstrings */ return 0; /* we only understand bitstrings */
if (isExtract != 1) if (!isExtract)
return 0; /* Cannot compare bitsrings */ return 0; /* Cannot compare bitsrings */
count = *p++; count = *p++;
...@@ -129,8 +128,8 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, ...@@ -129,8 +128,8 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
if (isExtract) if (isExtract)
{ {
unsigned char c = *p; unsigned char c = *p;
if ((isExtract == 2 || (isascii(c) && !iscntrl(c))) && c != '.') if (c != 0 && c != '.')
*cp++ = *p; *cp++ = c;
else else
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment