diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2014-02-06 14:45:17 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2014-02-06 14:45:17 +0000 |
commit | 610e782a29958aa2e3d6f0955cb01dab2016e4f6 (patch) | |
tree | d33b232575a96902c46d31f514abea433af1e586 | |
parent | 854cf269072900447e13f768a3c9d1af59a303f4 (diff) | |
download | dnsmasq-610e782a29958aa2e3d6f0955cb01dab2016e4f6.tar.gz |
Fix stack-smashing crash in DNSSEC. Thanks to Henk Jan Agteresch.
-rw-r--r-- | src/cache.c | 45 | ||||
-rw-r--r-- | src/dnsmasq.h | 2 | ||||
-rw-r--r-- | src/dnssec.c | 4 | ||||
-rw-r--r-- | src/forward.c | 9 | ||||
-rw-r--r-- | src/rfc1035.c | 6 |
5 files changed, 44 insertions, 22 deletions
diff --git a/src/cache.c b/src/cache.c index 19a5d61..66b52d2 100644 --- a/src/cache.c +++ b/src/cache.c @@ -55,7 +55,9 @@ static const struct { { 41, "OPT" }, { 43, "DS" }, { 46, "RRSIG" }, + { 47, "NSEC" }, { 48, "DNSKEY" }, + { 50, "NSEC3" }, { 249, "TKEY" }, { 250, "TSIG" }, { 251, "IXFR" }, @@ -1301,12 +1303,10 @@ void dump_cache(time_t now) { if (cache->flags & F_DNSKEY) { - char tp[20]; /* RRSIG */ - querystr("", tp, cache->addr.sig.type_covered); a = daemon->addrbuff; sprintf(a, "%5u %3u %s", cache->addr.sig.keytag, - cache->addr.sig.algo, tp); + cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered)); } else { @@ -1382,14 +1382,45 @@ char *record_source(int index) return "<unknown>"; } -void querystr(char *desc, char *str, unsigned short type) +char *querystr(char *desc, unsigned short type) { unsigned int i; - - sprintf(str, "%s[type=%d]", desc, type); + int len = 10; /* strlen("type=xxxxx") */ + const char *types = NULL; + static char *buff = NULL; + static int bufflen = 0; + for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++) if (typestr[i].type == type) - sprintf(str,"%s[%s]", desc, typestr[i].name); + { + types = typestr[i].name; + len = strlen(types); + break; + } + + len += 3; /* braces, terminator */ + len += strlen(desc); + + if (!buff || bufflen < len) + { + if (buff) + free(buff); + else if (len < 20) + len = 20; + + buff = whine_malloc(len); + bufflen = len; + } + + if (buff) + { + if (types) + sprintf(buff, "%s[%s]", desc, types); + else + sprintf(buff, "%s[type=%d]", desc, type); + } + + return buff ? buff : ""; } void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 58a4fe2..a84ac36 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -991,7 +991,7 @@ extern struct daemon { void cache_init(void); void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg); char *record_source(int index); -void querystr(char *desc, char *str, unsigned short type); +char *querystr(char *desc, unsigned short type); struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, time_t now, unsigned int prot); diff --git a/src/dnssec.c b/src/dnssec.c index 7a69528..8263b3e 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -1387,9 +1387,7 @@ int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen) size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr) { unsigned char *p; - char types[20]; - - querystr("dnssec-query", types, type); + char *types = querystr("dnssec-query", type); if (addr->sa.sa_family == AF_INET) log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types); diff --git a/src/forward.c b/src/forward.c index ed853a3..073b2c9 100644 --- a/src/forward.c +++ b/src/forward.c @@ -1117,13 +1117,11 @@ void receive_query(struct listener *listen, time_t now) if (extract_request(header, (size_t)n, daemon->namebuff, &type)) { - char types[20]; #ifdef HAVE_AUTH struct auth_zone *zone; #endif - - querystr(auth_dns ? "auth" : "query", types, type); - + char *types = querystr(auth_dns ? "auth" : "query", type); + if (listen->family == AF_INET) log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, (struct all_addr *)&source_addr.in.sin_addr, types); @@ -1290,11 +1288,10 @@ unsigned char *tcp_request(int confd, time_t now, if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype))) { - char types[20]; #ifdef HAVE_AUTH struct auth_zone *zone; #endif - querystr(auth_dns ? "auth" : "query", types, qtype); + char *types = querystr(auth_dns ? "auth" : "query", qtype); if (peer_addr.sa.sa_family == AF_INET) log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, diff --git a/src/rfc1035.c b/src/rfc1035.c index 26cda15..ac8c4ae 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1628,11 +1628,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL))) { if (qtype == T_RRSIG) - { - char types[20]; - querystr("rrsig", types, crecp->addr.sig.type_covered); - log_query(F_RRNAME, name, NULL, types); - } + log_query(F_RRNAME, name, NULL, querystr("rrsig", crecp->addr.sig.type_covered)); if ((keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)) && add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, |