diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index da1b5a46f65110a32b7b325282b8d5fe390b0ac2..b81d01c61d07bab6d6b4dc9cf13e6c5d60fa4a70 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -147,10 +147,34 @@ static void follow_cname_chain(const knot_dname_t **cname, const knot_rrset_t *r } } +/** @internal Filter ANY or loopback addresses. */ +static bool is_valid_addr(const uint8_t *addr, size_t len) +{ + if (len == sizeof(struct in_addr)) { + /* Filter ANY and 127.0.0.0/8 */ + uint32_t ip_host = ntohl(*(const uint32_t *)(addr)); + if (ip_host == 0 || (ip_host & 0xff000000) == 0x7f000000) { + return false; + } + } else if (len == sizeof(struct in6_addr)) { + struct in6_addr ip6_mask; + memset(&ip6_mask, 0, sizeof(ip6_mask)); + /* All except last byte are zeroed, last byte defines ANY/::1 */ + if (memcmp(addr, ip6_mask.s6_addr, sizeof(ip6_mask.s6_addr) - 1) == 0) { + return (addr[len - 1] > 1); + } + } + return true; +} + static int update_nsaddr(const knot_rrset_t *rr, struct kr_query *query) { if (rr->type == KNOT_RRTYPE_A || rr->type == KNOT_RRTYPE_AAAA) { const knot_rdata_t *rdata = rr->rrs.data; + if (!(query->flags & QUERY_ALLOW_LOCAL) && + !is_valid_addr(knot_rdata_data(rdata), knot_rdata_rdlen(rdata))) { + return KNOT_STATE_CONSUME; /* Ignore invalid addresses */ + } int ret = kr_zonecut_add(&query->zone_cut, rr->owner, rdata); if (ret != 0) { return KNOT_STATE_FAIL; diff --git a/lib/rplan.h b/lib/rplan.h index ccf300a1baf625eb03fb533a100ea00f09b325ef..e936860bec9b78914660da8a96851fc833bfe3cf 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -36,7 +36,8 @@ X(AWAIT_CUT , 1 << 6) /**< Query is waiting for zone cut lookup */ \ X(SAFEMODE , 1 << 7) /**< Don't use fancy stuff (EDNS...) */ \ X(CACHED , 1 << 8) /**< Query response is cached. */ \ - X(EXPIRING , 1 << 9) /**< Query response is cached, but expiring. */ + X(EXPIRING , 1 << 9) /**< Query response is cached, but expiring. */ \ + X(ALLOW_LOCAL, 1 << 10) /**< Allow queries to local or private address ranges. */ /** Query flags */ enum kr_query_flag { diff --git a/lib/zonecut.c b/lib/zonecut.c index 8ca63ebffb2d84af1f2d4f5d2abe815a4b1ee933..536f4102116aa56eec273513e25e07d119797d9c 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -143,29 +143,7 @@ int kr_zonecut_copy(struct kr_zonecut *dst, const struct kr_zonecut *src) return map_walk((map_t *)&src->nsset, copy_addr_set, dst); } -/** @internal Filter ANY or loopback addresses. */ -static bool is_valid_addr(uint8_t *addr, size_t len) -{ - if (len == sizeof(struct in_addr)) { - /* Filter ANY and 127.0.0.0/8 */ - /* temporary workaround for local testing - uint32_t ip_host = ntohl(*(uint32_t *)(addr)); - if (ip_host == 0 || (ip_host & 0xff000000) == 0x7f000000) { - return false; - } - */ - - } else if (len == sizeof(struct in6_addr)) { - struct in6_addr ip6_mask; - memset(&ip6_mask, 0, sizeof(ip6_mask)); - /* All except last byte are zeroed, last byte defines ANY/::1 */ - if (memcmp(addr, ip6_mask.s6_addr, sizeof(ip6_mask.s6_addr) - 1) == 0) { - return (addr[len - 1] > 1); - } - } - return true; -} int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata) { @@ -186,13 +164,9 @@ int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd if (rdata == NULL) { return kr_ok(); } - /* Check for invalid */ + /* Check for duplicates */ uint16_t rdlen = knot_rdata_rdlen(rdata); uint8_t *raw_addr = knot_rdata_data(rdata); - if (!is_valid_addr(raw_addr, rdlen)) { - return kr_error(EILSEQ); - } - /* Check for duplicates */ if (pack_obj_find(pack, raw_addr, rdlen)) { return kr_ok(); } @@ -201,7 +175,7 @@ int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd if (ret != 0) { return kr_error(ENOMEM); } - return pack_obj_push(pack, knot_rdata_data(rdata), rdlen); + return pack_obj_push(pack, raw_addr, rdlen); } int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata) diff --git a/tests/test_integration.py b/tests/test_integration.py index 82b90fc00eaad1c63cd42842939a0e808dfd472b..b1b8adaa01394b0bd8c7a21354fa6b49a1d95a1d 100755 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -205,6 +205,7 @@ def play_object(path): os.write(fd, "modules = {'hints'}\n") os.write(fd, "hints.root({['k.root-servers.net'] = '%s'})\n" % selfaddr) os.write(fd, "option('NO_MINIMIZE', true)\n") + os.write(fd, "option('ALLOW_LOCAL', true)\n") # Permit queries to localhost for k,v in config: # Enable selectively for some tests if k == 'query-minimization' and str2bool(v): diff --git a/tests/test_zonecut.c b/tests/test_zonecut.c index 772de3e99d8f07ddef1c188d706c5e311783a474..7158788429a6cc40a127286a23a499dda08153c8 100644 --- a/tests/test_zonecut.c +++ b/tests/test_zonecut.c @@ -35,40 +35,6 @@ static void test_zonecut_params(void **state) assert_int_not_equal(kr_zonecut_find_cached(NULL, NULL, NULL, NULL, 0), 0); } -#define TEST_IP(cut, ip, expect) { \ - knot_rdata_t rdata[knot_rdata_array_size(sizeof(ip))]; \ - knot_rdata_init(rdata, sizeof(ip), (uint8_t *)&ip, 0); \ - assert_int_equal(kr_zonecut_add(&(cut), (const uint8_t *)"\x02cz", rdata), (expect)); \ -} while (0) - -static void test_zonecut_filter(void **state) -{ - struct kr_zonecut cut; - kr_zonecut_init(&cut, (const uint8_t *)"", NULL); - - /* IPv4 */ - uint32_t ip4 = 0; /* 0.0.0.0 */ - TEST_IP(cut, ip4, kr_error(EILSEQ)); - ip4 = htonl(0x7f000002); /* 127.0.0.2 */ - TEST_IP(cut, ip4, kr_error(EILSEQ)); - ip4 = htonl(0x7fffffff); /* 127.255.255.255 */ - TEST_IP(cut, ip4, kr_error(EILSEQ)); - ip4 = htonl(0xff000001); /* 255.0.0.1 */ - TEST_IP(cut, ip4, 0); - /* IPv6 */ - struct in6_addr ip6; - memset(&ip6, 0, sizeof(ip6)); /* :: */ - TEST_IP(cut, ip6.s6_addr, kr_error(EILSEQ)); - ip6.s6_addr[15] = 0x01; /* ::1 */ - TEST_IP(cut, ip6.s6_addr, kr_error(EILSEQ)); - ip6.s6_addr[15] = 0x02; /* ::2 */ - TEST_IP(cut, ip6.s6_addr, 0); - - kr_zonecut_deinit(&cut); -} - -#undef TEST_IP - static void test_zonecut_copy(void **state) { const knot_dname_t *root = (const uint8_t *)""; @@ -92,7 +58,6 @@ int main(void) { const UnitTest tests[] = { unit_test(test_zonecut_params), - unit_test(test_zonecut_filter), unit_test(test_zonecut_copy) };