]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
acl: apply deny rule without tsig to queries with tsig present
authorDaniel Salzman <daniel.salzman@nic.cz>
Mon, 6 Sep 2021 14:11:11 +0000 (16:11 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Tue, 7 Sep 2021 13:39:28 +0000 (15:39 +0200)
src/knot/updates/acl.c
tests/knot/test_acl.c

index 21dd74b1897fea1d12a2611474c5b7b8c6f1e4f5..4335e90573cc48c85cf9df65a2192e07abf9b0d2 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -156,7 +156,7 @@ static bool update_match(conf_t *conf, conf_val_t *acl, knot_dname_t *key_name,
 
 static bool check_addr_key(conf_t *conf, conf_val_t *addr_val, conf_val_t *key_val,
                            bool remote, const struct sockaddr_storage *addr,
-                           const knot_tsig_key_t *tsig)
+                           const knot_tsig_key_t *tsig, bool deny)
 {
        /* Check if the address matches the acl address list or remote addresses. */
        if (addr_val->code != KNOT_ENOENT) {
@@ -201,9 +201,17 @@ static bool check_addr_key(conf_t *conf, conf_val_t *addr_val, conf_val_t *key_v
                        conf_val_next(key_val);
                }
        }
-       /* Check for key match or empty list without key provided. */
-       if (key_val->code != KNOT_EOK &&
-           !(key_val->code == KNOT_ENOENT && tsig->name == NULL)) {
+       switch (key_val->code) {
+       case KNOT_EOK:
+               // Key match.
+               break;
+       case KNOT_ENOENT:
+               // Empty list without key provided or denied.
+               if (tsig->name == NULL || deny) {
+                       break;
+               }
+               // FALLTHROUGH
+       default:
                return false;
        }
 
@@ -221,13 +229,15 @@ bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
        while (acl->code == KNOT_EOK) {
                conf_val_t rmt_val = conf_id_get(conf, C_ACL, C_RMT, acl);
                bool remote = (rmt_val.code == KNOT_EOK);
+               conf_val_t deny_val = conf_id_get(conf, C_ACL, C_DENY, acl);
+               bool deny = conf_bool(&deny_val);
 
                /* Check if a remote matches given address and key. */
                conf_val_t addr_val, key_val;
                while (rmt_val.code == KNOT_EOK) {
                        addr_val = conf_id_get(conf, C_RMT, C_ADDR, &rmt_val);
                        key_val = conf_id_get(conf, C_RMT, C_KEY, &rmt_val);
-                       if (check_addr_key(conf, &addr_val, &key_val, remote, addr, tsig)) {
+                       if (check_addr_key(conf, &addr_val, &key_val, remote, addr, tsig, deny)) {
                                break;
                        }
                        conf_val_next(&rmt_val);
@@ -239,7 +249,7 @@ bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
                if (!remote) {
                        addr_val = conf_id_get(conf, C_ACL, C_ADDR, acl);
                        key_val = conf_id_get(conf, C_ACL, C_KEY, acl);
-                       if (!check_addr_key(conf, &addr_val, &key_val, remote, addr, tsig)) {
+                       if (!check_addr_key(conf, &addr_val, &key_val, remote, addr, tsig, deny)) {
                                goto next_acl;
                        }
                }
@@ -272,14 +282,13 @@ bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
                }
 
                /* Check if denied. */
-               conf_val_t val = conf_id_get(conf, C_ACL, C_DENY, acl);
-               if (conf_bool(&val)) {
+               if (deny) {
                        return false;
                }
 
                /* Fill the output with tsig secret if provided. */
                if (tsig->name != NULL) {
-                       val = conf_id_get(conf, C_KEY, C_SECRET, &key_val);
+                       conf_val_t val = conf_id_get(conf, C_KEY, C_SECRET, &key_val);
                        tsig->secret.data = (uint8_t *)conf_bin(&val, &tsig->secret.size);
                }
 
index 43b020bcdec35f7df2a245ad53d7ade53adb8158..ae409211b423d29733e4234d0b3052ce461af226 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
 #include "contrib/sockaddr.h"
 
 #define ZONE   "example.zone"
+#define ZONE2  "example2.zone"
 #define KEY1   "key1_md5"
 #define KEY2   "key2_md5"
 #define KEY3   "key3_sha256"
@@ -69,6 +70,8 @@ static void test_acl_allowed(void)
 
        knot_dname_t *zone_name = knot_dname_from_str_alloc(ZONE);
        ok(zone_name != NULL, "create zone dname");
+       knot_dname_t *zone2_name = knot_dname_from_str_alloc(ZONE2);
+       ok(zone2_name != NULL, "create zone2 dname");
        knot_dname_t *key1_name = knot_dname_from_str_alloc(KEY1);
        ok(key1_name != NULL, "create "KEY1);
        knot_dname_t *key2_name = knot_dname_from_str_alloc(KEY2);
@@ -121,6 +124,13 @@ static void test_acl_allowed(void)
                "  - id: acl_range_addr\n"
                "    address: [ 100.0.0.0-100.0.0.5, ::0-::5 ]\n"
                "    action: [ transfer ]\n"
+               "  - id: acl_deny_no_action_no_key\n"
+               "    address: [ 240.0.0.4 ]\n"
+               "    deny: on\n"
+               "  - id: acl_notify_key\n"
+               "    address: [ 240.0.0.0/24 ]\n"
+               "    key: "KEY1"\n"
+               "    action: [ notify ]\n"
                "  - id: acl_update_key\n"
                "    key: "KEY1"\n"
                "    update-owner: key\n"
@@ -138,6 +148,8 @@ static void test_acl_allowed(void)
                "    acl: [ acl_key_addr, acl_deny, acl_no_action_deny ]\n"
                "    acl: [ acl_multi_addr, acl_multi_key ]\n"
                "    acl: [ acl_range_addr ]\n"
+               "  - domain: "ZONE2"\n"
+               "    acl: [ acl_deny_no_action_no_key, acl_notify_key ]\n"
                "  - domain: "KEY1"\n"
                "    acl: acl_update_key\n"
                "  - domain: "KEY2"\n"
@@ -230,6 +242,18 @@ static void test_acl_allowed(void)
        ret = acl_allowed(conf(), &acl, ACL_ACTION_TRANSFER, &addr, &key0, zone_name, NULL);
        ok(ret == true, "IPv6 address from range, no key, action match");
 
+       acl = conf_zone_get(conf(), C_ACL, zone2_name);
+       ok(acl.code == KNOT_EOK, "Get zone2 ACL");
+       check_sockaddr_set(&addr, AF_INET, "240.0.0.4", 0);
+       ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key1, zone2_name, NULL);
+       ok(ret == false, "Address, key, action, denied");
+
+       acl = conf_zone_get(conf(), C_ACL, zone2_name);
+       ok(acl.code == KNOT_EOK, "Get zone2 ACL");
+       check_sockaddr_set(&addr, AF_INET, "240.0.0.1", 0);
+       ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key1, zone2_name, NULL);
+       ok(ret == true, "Address, key, action, match");
+
        knot_rrset_t A;
        knot_rrset_init(&A, key1_name, KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600);
        knot_rrset_add_rdata(&A, (uint8_t *)"\x00\x00\x00\x00", 4, NULL);
@@ -273,6 +297,7 @@ static void test_acl_allowed(void)
 
        conf_free(conf());
        knot_dname_free(zone_name, NULL);
+       knot_dname_free(zone2_name, NULL);
        knot_dname_free(key1_name, NULL);
        knot_dname_free(key2_name, NULL);
        knot_dname_free(key3_name, NULL);