From a18485c8a7b08ee76aecffbb9d72ab4229769ab0 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Mon, 22 Nov 2021 12:43:36 -0500 Subject: [PATCH] dns: send REFUSED is name contains special characters --- src/cache.c | 3 --- src/dns.c | 36 +++++++++++++++++++----------------- src/ns.c | 30 ++++++++++++++++++++++++++---- src/req.c | 13 ------------- src/resource.c | 12 ++++++++++++ src/resource.h | 3 +++ test/hnsd-test.c | 23 +++++++++++++++++++++++ 7 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/cache.c b/src/cache.c index 88a57521..fa2e0b16 100644 --- a/src/cache.c +++ b/src/cache.c @@ -262,9 +262,6 @@ hsk_cache_key_set(hsk_cache_key_t *ck, const char *name, uint16_t type) { if (!hsk_dns_name_verify(name)) return false; - if (hsk_dns_name_dirty(name)) - return false; - int labels = hsk_dns_label_count(name); bool ref = false; diff --git a/src/dns.c b/src/dns.c index f77fe8a6..4dbfc0b7 100644 --- a/src/dns.c +++ b/src/dns.c @@ -725,9 +725,6 @@ hsk_dns_rr_set_name(hsk_dns_rr_t *rr, const char *name) { if (!hsk_dns_name_verify(name)) return false; - if (hsk_dns_name_dirty(name)) - return false; - if (hsk_dns_name_is_fqdn(name)) strcpy(rr->name, name); else @@ -2404,26 +2401,31 @@ hsk_dns_name_alloc( bool hsk_dns_name_dirty(const char *name) { - char *s = (char *)name; + int len = strlen(name); + if (len > HSK_DNS_MAX_LABEL) + return true; - while (*s) { - uint8_t c = (uint8_t)*s; + for (int i = 0; i < len; i++) { + uint8_t c = name[i]; + + if (c >= 0x41 && c <= 0x5a) + c ^= 0x20; switch (c) { - case 0x28 /*(*/: - case 0x29 /*)*/: - case 0x3b /*;*/: - case 0x20 /* */: - case 0x40 /*@*/: - case 0x22 /*"*/: - case 0x5c /*\\*/: - return true; + case 0x5f: /* _ */ + case 0x2d: /* - */ + if (i == 0 || i == len - 1) { + return true; + } else { + continue; + } } - if (c < 0x20 || c > 0x7e) + if (c < 0x30 || + (c > 0x39 && c < 0x61) || + c > 0x7a) { return true; - - s += 1; + } } return false; diff --git a/src/ns.c b/src/ns.c index 1325c590..906b06c2 100644 --- a/src/ns.c +++ b/src/ns.c @@ -297,6 +297,10 @@ hsk_ns_onrecv( const struct sockaddr *addr, uint32_t flags ) { + uint8_t *wire = NULL; + size_t wire_len = 0; + hsk_dns_msg_t *msg = NULL; + hsk_dns_req_t *req = hsk_dns_req_create(data, data_len, addr); if (!req) { @@ -306,10 +310,6 @@ hsk_ns_onrecv( hsk_dns_req_print(req, "ns: "); - uint8_t *wire = NULL; - size_t wire_len = 0; - hsk_dns_msg_t *msg = NULL; - // Hit cache first. msg = hsk_cache_get(&ns->cache, req); @@ -434,6 +434,28 @@ hsk_ns_onrecv( goto done; } + // Send REFUSED if name is dirty + // (contains escaped byte codes or special characters) + if (hsk_dns_name_dirty(req->tld)) { + msg = hsk_resource_to_refused(); + + if (!msg) { + hsk_ns_log(ns, "failed creating refused\n"); + goto fail; + } + + if (!hsk_dns_msg_finalize(&msg, req, ns->ec, ns->key, &wire, &wire_len)) { + hsk_ns_log(ns, "could not reply\n"); + goto done; + } + + hsk_ns_log(ns, "refusing query for msg (%u): %u\n", req->id, wire_len); + + hsk_ns_send(ns, wire, wire_len, addr, true); + + goto done; + } + // Requesting a lookup. if (req->labels > 0) { // Check blacklist. diff --git a/src/req.c b/src/req.c index 062aaa06..cb2f7e8e 100644 --- a/src/req.c +++ b/src/req.c @@ -83,22 +83,9 @@ hsk_dns_req_create( // Grab the first question. hsk_dns_qs_t *qs = msg->qd.items[0]; -#if 0 - if (qs->class != HSK_DNS_IN) - goto fail; - - // Don't allow dirty names. - if (hsk_dns_name_dirty(qs->name)) - goto fail; -#endif - // Check for a TLD. hsk_dns_label_get(qs->name, -1, req->tld); - // Don't allow dirty TLDs. - if (hsk_dns_name_dirty(req->tld)) - goto fail; - // Lowercase. hsk_to_lower(req->tld); diff --git a/src/resource.c b/src/resource.c index 96e2f5fa..41cd5400 100644 --- a/src/resource.c +++ b/src/resource.c @@ -1133,6 +1133,18 @@ hsk_resource_to_servfail(void) { return msg; } +hsk_dns_msg_t * +hsk_resource_to_refused(void) { + hsk_dns_msg_t *msg = hsk_dns_msg_alloc(); + + if (!msg) + return NULL; + + msg->code = HSK_DNS_REFUSED; + + return msg; +} + hsk_dns_msg_t * hsk_resource_to_notimp(void) { hsk_dns_msg_t *msg = hsk_dns_msg_alloc(); diff --git a/src/resource.h b/src/resource.h index 46e73b1f..f7c17319 100644 --- a/src/resource.h +++ b/src/resource.h @@ -88,6 +88,9 @@ hsk_resource_to_nx(void); hsk_dns_msg_t * hsk_resource_to_servfail(void); +hsk_dns_msg_t * +hsk_resource_to_refused(void); + hsk_dns_msg_t * hsk_resource_to_notimp(void); diff --git a/test/hnsd-test.c b/test/hnsd-test.c index 7ec7b071..80782648 100644 --- a/test/hnsd-test.c +++ b/test/hnsd-test.c @@ -60,11 +60,34 @@ test_pointer_to_ip() { assert(family6 == HSK_DNS_AAAA); } +void +test_name_dirty() { + printf("test_name_dirty\n"); + + assert(!hsk_dns_name_dirty("hello")); + assert(!hsk_dns_name_dirty("HELLO")); + assert(!hsk_dns_name_dirty("heLLo")); + assert(!hsk_dns_name_dirty("HeLl0")); + assert(!hsk_dns_name_dirty("hel-lo")); + assert(!hsk_dns_name_dirty("1")); + assert(!hsk_dns_name_dirty("000_000")); + assert(!hsk_dns_name_dirty("this-domain-name-has-sixty-three-octets-taking-max-label-length")); + assert(hsk_dns_name_dirty("hel!lo")); + assert(hsk_dns_name_dirty("-hello")); + assert(hsk_dns_name_dirty("hello_")); + assert(hsk_dns_name_dirty("1@1")); + assert(hsk_dns_name_dirty("x\\000y")); + assert(hsk_dns_name_dirty("H&ELLO")); + assert(hsk_dns_name_dirty("3 3")); + assert(hsk_dns_name_dirty("this-domain-name-has-sixtyfour-octets-exceeding-max-label-length")); +} + int main() { printf("Testing hnsd...\n"); test_base32(); test_pointer_to_ip(); + test_name_dirty(); printf("ok\n");