diff --git a/doc/configuration.rst b/doc/configuration.rst index 59bdaca6d8fb83301b6a45710394f419dcaaf6e6..58de4b5b74d98441cc21788ed1e8b5ac01e50766 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -82,21 +82,18 @@ Access control list (ACL) ========================= ACL list specifies which remotes are allowed to send the server a specific -query or do a specific action. A remote can be a single IP address or a -network subnet. Also a TSIG key can be specified:: +request. A remote can be a single IP address or a network subnet. Also a TSIG +key can be specified:: acl: - - id: single_rule - address: 192.168.1.1 # Single IP address - action: [notify, update] # Allow zone notifications and updates zone + - id: address_rule + address: [2001:db8::1, 192.168.2.0/24] # Allowed IP address list + action: [transfer, update] # Allow zone transfers and updates - - id: subnet_rule - address: 192.168.2.0/24 # Network subnet - action: transfer # Allow zone transfers - - - id: deny_rule - address: 192.168.2.100 # Negative match - action: deny # The remote query is denied + - id: deny_rule # Negative match rule + address: 192.168.2.100 + action: transfer + deny: on # The request is denied - id: key_rule key: key1 # Access based just on TSIG key @@ -106,7 +103,7 @@ These rules can then be referenced from a zone :ref:`template_acl`:: zone: - domain: example.com - acl: [single_rule, deny_rule, subnet_rule, key_rule] + acl: [address_rule, deny_rule, key_rule] Slave zone ========== diff --git a/doc/man/knot.conf.5in b/doc/man/knot.conf.5in index 6983e602d96b6a80074e4613ff8292640fdedef2..24ec2b49dc4edb640459569e3d9fbe4972dd0f43 100644 --- a/doc/man/knot.conf.5in +++ b/doc/man/knot.conf.5in @@ -297,7 +297,7 @@ Shared key secret. Default: empty .SH ACL SECTION .sp -Access control list rules definition. +Access control list rule definition. .INDENT 0.0 .INDENT 3.5 .sp @@ -305,9 +305,10 @@ Access control list rules definition. .ft C acl: \- id: STR - address: ADDR[/INT] - key: key_id - action: deny | transfer | notify | update ... + address: ADDR[/INT] ... + key: key_id ... + action: transfer | notify | update ... + deny: BOOL .ft P .fi .UNINDENT @@ -317,13 +318,14 @@ acl: An ACL rule identifier. .SS address .sp -A single IP address or network subnet with the given prefix the query -must match. +An ordered list of IP addresses or network subnets. The query must match +one of them. Empty value means that address match is not required. .sp Default: empty .SS key .sp -A \fI\%reference\fP to the TSIG key the query must match. +An ordered list of \fI\%reference\fPs to TSIG keys. The query must +match one of them. Empty value means that TSIG key is not required. .sp Default: empty .SS action @@ -333,8 +335,6 @@ An ordered list of allowed actions. Possible values: .INDENT 0.0 .IP \(bu 2 -\fBdeny\fP \- Block the matching query -.IP \(bu 2 \fBtransfer\fP \- Allow zone transfer .IP \(bu 2 \fBnotify\fP \- Allow incoming notify @@ -342,7 +342,13 @@ Possible values: \fBupdate\fP \- Allow zone updates .UNINDENT .sp -Default: deny +Default: empty +.SS deny +.sp +Deny if \fI\%address\fP, \fI\%key\fP and +\fI\%action\fP match. +.sp +Default: off .SH CONTROL SECTION .sp Configuration of the server remote control. diff --git a/doc/reference.rst b/doc/reference.rst index 434576edf4bc031d82e312aa25e9fb0f328ad87a..73cbed13dab0821f77230326cf4f374fc01c8935 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -351,15 +351,16 @@ Default: empty ACL section =========== -Access control list rules definition. +Access control list rule definition. :: acl: - id: STR - address: ADDR[/INT] - key: key_id - action: deny | transfer | notify | update ... + address: ADDR[/INT] ... + key: key_id ... + action: transfer | notify | update ... + deny: BOOL .. _acl_id: @@ -373,8 +374,8 @@ An ACL rule identifier. address ------- -A single IP address or network subnet with the given prefix the query -must match. +An ordered list of IP addresses or network subnets. The query must match +one of them. Empty value means that address match is not required. Default: empty @@ -383,7 +384,8 @@ Default: empty key --- -A :ref:`reference<key_id>` to the TSIG key the query must match. +An ordered list of :ref:`reference<key_id>`\ s to TSIG keys. The query must +match one of them. Empty value means that TSIG key is not required. Default: empty @@ -396,12 +398,21 @@ An ordered list of allowed actions. Possible values: -- ``deny`` - Block the matching query - ``transfer`` - Allow zone transfer - ``notify`` - Allow incoming notify - ``update`` - Allow zone updates -Default: deny +Default: empty + +.. _acl_deny: + +deny +---- + +Deny if :ref:`address<acl_address>`, :ref:`key<acl_key>` and +:ref:`action<acl_action>` match. + +Default: off .. _Control section: diff --git a/src/knot/conf/scheme.c b/src/knot/conf/scheme.c index 119f99448a9ac82bc25b42555c8de7667c4e3225..9cf82a4925fe8660067b25f344a6eb4b168462ce 100644 --- a/src/knot/conf/scheme.c +++ b/src/knot/conf/scheme.c @@ -48,10 +48,9 @@ static const lookup_table_t key_algs[] = { }; static const lookup_table_t acl_actions[] = { - { ACL_ACTION_DENY, "deny" }, - { ACL_ACTION_XFER, "transfer" }, - { ACL_ACTION_NOTF, "notify" }, - { ACL_ACTION_DDNS, "update" }, + { ACL_ACTION_NOTIFY, "notify" }, + { ACL_ACTION_TRANSFER, "transfer" }, + { ACL_ACTION_UPDATE, "update" }, { 0, NULL } }; @@ -107,11 +106,12 @@ static const yp_item_t desc_key[] = { }; static const yp_item_t desc_acl[] = { - { C_ID, YP_TSTR, YP_VNONE }, - { C_ADDR, YP_TNET, YP_VNONE }, - { C_KEY, YP_TREF, YP_VREF = { C_KEY }, YP_FNONE, { check_ref } }, - { C_ACTION, YP_TOPT, YP_VOPT = { acl_actions, ACL_ACTION_DENY }, YP_FMULTI }, - { C_COMMENT, YP_TSTR, YP_VNONE }, + { C_ID, YP_TSTR, YP_VNONE }, + { C_ADDR, YP_TNET, YP_VNONE, YP_FMULTI }, + { C_KEY, YP_TREF, YP_VREF = { C_KEY }, YP_FMULTI, { check_ref } }, + { C_ACTION, YP_TOPT, YP_VOPT = { acl_actions, ACL_ACTION_NONE }, YP_FMULTI }, + { C_DENY, YP_TBOOL, YP_VNONE }, + { C_COMMENT, YP_TSTR, YP_VNONE }, { NULL } }; diff --git a/src/knot/conf/scheme.h b/src/knot/conf/scheme.h index 939ba5b170c4da5d6886a9e58f5ab83dd05e5987..d086e17d0f56256d0042b705387b546075643f64 100644 --- a/src/knot/conf/scheme.h +++ b/src/knot/conf/scheme.h @@ -36,6 +36,7 @@ #define C_BG_WORKERS "\x12""background-workers" #define C_COMMENT "\x07""comment" #define C_CTL "\x07""control" +#define C_DENY "\x04""deny" #define C_DISABLE_ANY "\x0B""disable-any" #define C_DOMAIN "\x06""domain" #define C_DNSSEC_ENABLE "\x0D""dnssec-enable" diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c index dcf59a66a1cf857a871fc2d4cacd29c4854f4f81..28b6b02743b106da4fb4a8e308d63b612386416c 100644 --- a/src/knot/nameserver/axfr.c +++ b/src/knot/nameserver/axfr.c @@ -110,7 +110,7 @@ static int axfr_query_check(struct query_data *qdata) { /* Check valid zone, transaction security and contents. */ NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH); - NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_XFER); + NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_TRANSFER); /* Check expiration. */ NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c index f383364a52387ec4ba024e74ae984fc443276391..4cbc1eecf3af0a5a8be524422c865bc45972e97c 100644 --- a/src/knot/nameserver/internet.c +++ b/src/knot/nameserver/internet.c @@ -832,7 +832,7 @@ int internet_query(knot_pkt_t *response, struct query_data *qdata) /* No applicable ACL, refuse transaction security. */ if (knot_pkt_has_tsig(qdata->query)) { /* We have been challenged... */ - NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_XFER); + NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_TRANSFER); /* Reserve space for TSIG. */ knot_pkt_reserve(response, knot_tsig_wire_maxsize(&qdata->sign.tsig_key)); diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c index 42e9b9e286319dde7804b24321d35db97ef11186..08588dd84a816277160ff81c2200446fa49bebd4 100644 --- a/src/knot/nameserver/ixfr.c +++ b/src/knot/nameserver/ixfr.c @@ -212,7 +212,7 @@ static int ixfr_query_check(struct query_data *qdata) NS_NEED_QNAME(qdata, their_soa->owner, KNOT_RCODE_FORMERR); /* Check transcation security and zone contents. */ - NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_XFER); + NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_TRANSFER); NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); /* Check expiration. */ return KNOT_STATE_DONE; diff --git a/src/knot/nameserver/notify.c b/src/knot/nameserver/notify.c index e2a6b2cc39bd07e5375f119a506120ad34be94b9..3155c33bf5c13a6964a094ac79e12ee70eed9e9a 100644 --- a/src/knot/nameserver/notify.c +++ b/src/knot/nameserver/notify.c @@ -54,7 +54,7 @@ static int notify_check_query(struct query_data *qdata) /* Check valid zone, transaction security. */ zone_t *zone = (zone_t *)qdata->zone; NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH); - NS_NEED_AUTH(qdata, zone->name, ACL_ACTION_NOTF); + NS_NEED_AUTH(qdata, zone->name, ACL_ACTION_NOTIFY); return KNOT_STATE_DONE; } diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c index dcb7299add94f124e04846be7b22c5367dfd602f..b2c093df706bea48b60cc3c1b533fb0272cfa675 100644 --- a/src/knot/nameserver/update.c +++ b/src/knot/nameserver/update.c @@ -419,7 +419,7 @@ static void forward_requests(zone_t *zone, list_t *requests) static bool update_tsig_check(struct query_data *qdata, struct knot_request *req) { // Check that ACL is still valid. - if (!process_query_acl_check(qdata->zone->name, ACL_ACTION_DDNS, qdata)) { + if (!process_query_acl_check(qdata->zone->name, ACL_ACTION_UPDATE, qdata)) { UPDATE_LOG(LOG_WARNING, "ACL check failed"); knot_wire_set_rcode(req->resp->wire, qdata->rcode); return false; @@ -529,7 +529,7 @@ int update_query_process(knot_pkt_t *pkt, struct query_data *qdata) /* Need valid transaction security. */ zone_t *zone = (zone_t *)qdata->zone; - NS_NEED_AUTH(qdata, zone->name, ACL_ACTION_DDNS); + NS_NEED_AUTH(qdata, zone->name, ACL_ACTION_UPDATE); /* Check expiration. */ NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); diff --git a/src/knot/updates/acl.c b/src/knot/updates/acl.c index 3894835acc3a0999bf545ec624903545e3a6fd53..e825daf71fb3093cd9221fd07ee702f86f12603a 100644 --- a/src/knot/updates/acl.c +++ b/src/knot/updates/acl.c @@ -96,49 +96,39 @@ bool acl_allowed(conf_val_t *acl, acl_action_t action, } while (acl->code == KNOT_EOK) { - /* Check if the action is allowed. */ - bool match = false, deny = false; - conf_val_t action_val = conf_id_get(conf(), C_ACL, C_ACTION, acl); - while (action_val.code == KNOT_EOK) { - unsigned act = conf_opt(&action_val); - if (act & action) { - match = true; - } - if (act == ACL_ACTION_DENY) { - deny = true; - } - conf_val_next(&action_val); - } - if (!match) { - conf_val_next(acl); - continue; - } + conf_val_t val; - /* Check if the address prefix matches. */ - conf_val_t addr_val = conf_id_get(conf(), C_ACL, C_ADDR, acl); - if (addr_val.code == KNOT_EOK) { + /* Check if the address matches the current acl address list. */ + val = conf_id_get(conf(), C_ACL, C_ADDR, acl); + while (val.code == KNOT_EOK) { unsigned prefix; struct sockaddr_storage ss; - ss = conf_net(&addr_val, &prefix); + ss = conf_net(&val, &prefix); if (!netblock_match(addr, &ss, prefix)) { - conf_val_next(acl); + conf_val_next(&val); continue; } + + break; + } + /* Check for address match or empty list. */ + if (val.code != KNOT_EOK && val.code != KNOT_ENOENT) { + goto next_acl; } - /* Check if the key matches. */ + /* Check if the key matches the current acl key list. */ conf_val_t key_val = conf_id_get(conf(), C_ACL, C_KEY, acl); - if (key_val.code == KNOT_EOK) { + while (key_val.code == KNOT_EOK) { /* No key provided, but required. */ if (tsig->name == NULL) { - conf_val_next(acl); + conf_val_next(&key_val); continue; } /* Compare key names. */ const knot_dname_t *key_name = conf_dname(&key_val); if (knot_dname_cmp(key_name, tsig->name) != 0) { - conf_val_next(acl); + conf_val_next(&key_val); continue; } @@ -146,30 +136,50 @@ bool acl_allowed(conf_val_t *acl, acl_action_t action, conf_val_t alg_val = conf_id_get(conf(), C_KEY, C_ALG, &key_val); if (conf_opt(&alg_val) != tsig->algorithm) { - conf_val_next(acl); + conf_val_next(&key_val); continue; } - /* No key required, but provided. */ - } else if (tsig->name != NULL) { - conf_val_next(acl); - continue; + + break; + } + /* Check for key match or empty list without key provided. */ + if (key_val.code != KNOT_EOK && + !(key_val.code == KNOT_ENOENT && tsig->name == NULL)) { + goto next_acl; } - if (deny) { - conf_val_next(acl); - continue; + /* Check if the action is allowed. */ + val = conf_id_get(conf(), C_ACL, C_ACTION, acl); + while (val.code == KNOT_EOK) { + if (conf_opt(&val) != action) { + conf_val_next(&val); + continue; + } + + break; + } + /* Check for action match. */ + if (val.code != KNOT_EOK) { + goto next_acl; + } + + /* Check if denied. */ + val = conf_id_get(conf(), C_ACL, C_DENY, acl); + if (conf_bool(&val)) { + return false; } - /* Fill the output with tsig secret. */ + /* Fill the output with tsig secret if provided. */ if (tsig->name != NULL) { - conf_val_t secret_val = conf_id_get(conf(), C_KEY, - C_SECRET, &key_val); - conf_data(&secret_val); - tsig->secret.data = (uint8_t *)secret_val.data; - tsig->secret.size = secret_val.len; + val = conf_id_get(conf(), C_KEY, C_SECRET, &key_val); + conf_data(&val); + tsig->secret.data = (uint8_t *)val.data; + tsig->secret.size = val.len; } return true; +next_acl: + conf_val_next(acl); } return false; diff --git a/src/knot/updates/acl.h b/src/knot/updates/acl.h index 041f4d9500bd1855993b6c0629b9bcad7a2eb675..8138a3e1085d183066d7749ab9a6ce4cc2dd55ac 100644 --- a/src/knot/updates/acl.h +++ b/src/knot/updates/acl.h @@ -32,10 +32,10 @@ /*! \brief ACL actions. */ typedef enum { - ACL_ACTION_DENY = 0, - ACL_ACTION_XFER = 1, - ACL_ACTION_NOTF = 2, - ACL_ACTION_DDNS = 3 + ACL_ACTION_NONE = 0, + ACL_ACTION_NOTIFY = 1, + ACL_ACTION_TRANSFER = 2, + ACL_ACTION_UPDATE = 3 } acl_action_t; /*! diff --git a/tests/Makefile.am b/tests/Makefile.am index 0e9aaf5d722da9d4514841ba61b97bcb552286a5..e9ad3756f9f969bfd3f273b4bae173496fba2fa7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -64,6 +64,7 @@ check-local: $(check_PROGRAMS) -L $(top_builddir)/tests/runtests.log \ $(check_PROGRAMS) +acl_SOURCES = acl.c test_conf.h process_query_SOURCES = process_query.c fake_server.h test_conf.h process_answer_SOURCES = process_answer.c fake_server.h test_conf.h CLEANFILES = runtests.log diff --git a/tests/acl.c b/tests/acl.c index 483e711b040c97addf9d926d4a9db0094bb7a852..3e454123a4bbb8bc9ae01b6189e8c25c4004c96e 100644 --- a/tests/acl.c +++ b/tests/acl.c @@ -18,10 +18,10 @@ #include <sys/socket.h> #include <tap/basic.h> +#include "test_conf.h" #include "libknot/libknot.h" #include "libknot/internal/sockaddr.h" #include "knot/updates/acl.h" -#include "knot/conf/conf.h" static void check_sockaddr_set(struct sockaddr_storage *ss, int family, const char *straddr, int port) @@ -30,10 +30,8 @@ static void check_sockaddr_set(struct sockaddr_storage *ss, int family, ok(ret == KNOT_EOK, "set address '%s'", straddr); } -int main(int argc, char *argv[]) +static void test_netblock_match(void) { - plan_lazy(); - int ret; struct sockaddr_storage t = { 0 }; @@ -102,6 +100,142 @@ int main(int argc, char *argv[]) ok(ret == true, "match: ipv6 - last byte, precise prefix"); ret = netblock_match(&t, &ref6, 127); ok(ret == false, "match: ipv6 - last byte, not match"); +} + +#define ZONE "example.zone" +#define KEY1 "key1_md5" +#define KEY2 "key2_md5" +#define KEY3 "key3_sha256" + +static void test_acl_allowed(void) +{ + int ret; + conf_val_t acl; + struct sockaddr_storage addr = { 0 }; + + knot_dname_t *zone_name = knot_dname_from_str_alloc(ZONE); + ok(zone_name != NULL, "create zone 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); + ok(key2_name != NULL, "create "KEY2); + knot_dname_t *key3_name = knot_dname_from_str_alloc(KEY3); + ok(key3_name != NULL, "create "KEY3); + + knot_tsig_key_t key0 = { NULL }; + knot_tsig_key_t key1 = { key1_name, DNSSEC_TSIG_HMAC_MD5 }; + knot_tsig_key_t key2 = { key2_name, DNSSEC_TSIG_HMAC_MD5 }; + knot_tsig_key_t key3 = { key3_name, DNSSEC_TSIG_HMAC_SHA256 }; + + const char *conf_str = + "key:\n" + " - id: "KEY1"\n" + " algorithm: hmac-md5\n" + " secret: Zm9v\n" + " - id: "KEY2"\n" + " algorithm: hmac-md5\n" + " secret: Zm9v\n" + " - id: "KEY3"\n" + " algorithm: hmac-sha256\n" + " secret: Zm8=\n" + "\n" + "acl:\n" + " - id: acl_key_addr\n" + " address: [ 2001::1 ]\n" + " key: [ key1_md5 ]\n" + " action: [ transfer ]\n" + " - id: acl_deny\n" + " address: [ 240.0.0.2 ]\n" + " action: [ notify ]\n" + " deny: on\n" + " - id: acl_multi_addr\n" + " address: [ 192.168.1.1, 240.0.0.0/24 ]\n" + " action: [ notify, update ]\n" + " - id: acl_multi_key\n" + " key: [ key2_md5, key3_sha256 ]\n" + " action: [ notify, update ]\n" + "\n" + "zone:\n" + " - domain: "ZONE"\n" + " acl: [ acl_key_addr, acl_deny, acl_multi_addr, acl_multi_key]"; + + ret = test_conf(conf_str, NULL); + ok(ret == KNOT_EOK, "Prepare configuration"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET6, "2001::1", 0); + ret = acl_allowed(&acl, ACL_ACTION_TRANSFER, &addr, &key1); + ok(ret == true, "Address, key, action match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET6, "2001::2", 0); + ret = acl_allowed(&acl, ACL_ACTION_TRANSFER, &addr, &key1); + ok(ret == false, "Address not match, key, action match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET6, "2001::1", 0); + ret = acl_allowed(&acl, ACL_ACTION_TRANSFER, &addr, &key0); + ok(ret == false, "Address match, no key, action match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET6, "2001::1", 0); + ret = acl_allowed(&acl, ACL_ACTION_TRANSFER, &addr, &key2); + ok(ret == false, "Address match, key not match, action match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET6, "2001::1", 0); + ret = acl_allowed(&acl, ACL_ACTION_NOTIFY, &addr, &key1); + ok(ret == false, "Address, key match, action not match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET, "240.0.0.1", 0); + ret = acl_allowed(&acl, ACL_ACTION_NOTIFY, &addr, &key0); + ok(ret == true, "Second address match, no key, action match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET, "240.0.0.1", 0); + ret = acl_allowed(&acl, ACL_ACTION_NOTIFY, &addr, &key1); + ok(ret == false, "Second address match, extra key, action match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET, "240.0.0.2", 0); + ret = acl_allowed(&acl, ACL_ACTION_NOTIFY, &addr, &key0); + ok(ret == false, "Denied address match, no key, action match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET, "240.0.0.2", 0); + ret = acl_allowed(&acl, ACL_ACTION_UPDATE, &addr, &key0); + ok(ret == true, "Denied address match, no key, action not match"); + + acl = conf_zone_get(conf(), C_ACL, zone_name); + ok(acl.code == KNOT_EOK, "Get zone ACL"); + check_sockaddr_set(&addr, AF_INET, "1.1.1.1", 0); + ret = acl_allowed(&acl, ACL_ACTION_UPDATE, &addr, &key3); + ok(ret == true, "Arbitrary address, second key, action match"); + + conf_free(conf(), false); + knot_dname_free(&zone_name, NULL); + knot_dname_free(&key1_name, NULL); + knot_dname_free(&key2_name, NULL); + knot_dname_free(&key3_name, NULL); +} + +int main(int argc, char *argv[]) +{ + plan_lazy(); + + test_netblock_match(); + + test_acl_allowed(); return 0; }