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 */
+ 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)
{
if (!cut || !ns) {
if (rdata == NULL) {
return kr_ok();
}
- /* Check for duplicates */
+ /* Check for invalid */
uint16_t rdlen = knot_rdata_rdlen(rdata);
- if (pack_obj_find(pack, knot_rdata_data(rdata), rdlen)) {
+ 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();
}
/* Push new address */
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <netinet/in.h>
+
#include "tests/test.h"
#include "lib/zonecut.h"
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 *)"";
{
const UnitTest tests[] = {
unit_test(test_zonecut_params),
+ unit_test(test_zonecut_filter),
unit_test(test_zonecut_copy)
};
ENTRY_BEGIN
MATCH opcode qtype qname
-ADJUST copy_id
-REPLY QR NOERROR
+ADJUST copy_id copy_query
+REPLY QR NXDOMAIN
SECTION QUESTION
-a.gtld-servers.net. IN AAAA
-SECTION ANSWER
+a.gtld-servers.net. IN AAAA
+SECTION AUTHORITY
+. SOA bla bla 1 2 3 4 5
ENTRY_END
ENTRY_BEGIN
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id copy_query
+REPLY QR SERVFAIL
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION AUTHORITY
+com. SOA bla bla 1 2 3 4 5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id copy_query
+REPLY QR SERVFAIL
+SECTION QUESTION
+ns2.example.com. IN AAAA
+SECTION AUTHORITY
+com. SOA bla bla 1 2 3 4 5
+ENTRY_END
+
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
ns.example.com. IN A 127.255.255.255
ns2.example.com. IN A 127.0.0.2
ENTRY_END
+
RANGE_END
; ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
+
+RANGE_END
+
+; ns.example.com trap
+RANGE_BEGIN 0 100
+ ADDRESS 127.255.255.255
+RANGE_END
+
+; ns.example.com trap
+RANGE_BEGIN 0 100
+ ADDRESS 127.0.0.2
RANGE_END
STEP 1 QUERY