Commit 6516b705 authored by Marek Vavrusa's avatar Marek Vavrusa

ACL finally searches for exact address/key combination.

parent 69311aae
......@@ -26,6 +26,7 @@
#include "common/errcode.h"
#include "common/acl.h"
#include "libknot/util/endian.h"
#include "libknot/tsig.h"
static inline uint32_t ipv4_chunk(const sockaddr_t *a)
{
......@@ -81,7 +82,7 @@ static uint32_t acl_fill_mask32(short nbits)
return htonl(r);
}
static int acl_compare(const sockaddr_t *a1, const sockaddr_t *a2)
static int addr_match(const sockaddr_t *a1, const sockaddr_t *a2)
{
int ret = 0;
uint32_t mask = 0xffffffff;
......@@ -141,55 +142,26 @@ void acl_delete(acl_t **acl)
*acl = 0;
}
int acl_insert(acl_t *acl, const sockaddr_t *addr, void *val)
int acl_insert(acl_t *acl, const sockaddr_t *addr, knot_tsig_key_t *key)
{
if (acl == NULL || addr == NULL) {
return KNOT_EINVAL;
}
/* Create new match. */
acl_match_t *key = malloc(sizeof(acl_match_t));
if (key == NULL) {
acl_match_t *match = malloc(sizeof(acl_match_t));
if (match == NULL) {
return KNOT_ENOMEM;
}
memcpy(&key->addr, addr, sizeof(sockaddr_t));
key->val = val;
/* Sort by prefix length.
* This way the longest prefix match always goes first.
*/
if (EMPTY_LIST(*acl)) {
add_head(acl, &key->n);
} else {
bool inserted = false;
acl_match_t *cur = NULL, *prev = NULL;
WALK_LIST(cur, *acl) {
/* Next node prefix is equal/shorter than current key.
* This means we need to insert before the next node.
*/
if (cur->addr.prefix < addr->prefix) {
if (prev == NULL) { /* First node. */
add_head(acl, &key->n);
} else {
insert_node(&key->n, &prev->n);
}
inserted = true;
break;
}
prev = cur;
}
/* Didn't find any better fit, insert at the end. */
if (!inserted) {
add_tail(acl, &key->n);
}
}
memcpy(&match->addr, addr, sizeof(sockaddr_t));
match->key = key;
add_tail(acl, &match->n);
return KNOT_EOK;
}
acl_match_t* acl_find(acl_t *acl, const sockaddr_t *addr)
acl_match_t* acl_find(acl_t *acl, const sockaddr_t *addr, const knot_dname_t *key_name)
{
if (acl == NULL || addr == NULL) {
return NULL;
......@@ -197,11 +169,19 @@ acl_match_t* acl_find(acl_t *acl, const sockaddr_t *addr)
acl_match_t *cur = NULL;
WALK_LIST(cur, *acl) {
/* Since the list is sorted by prefix length, the first match
* is guaranteed to be longest prefix match (most precise).
*/
if (acl_compare(&cur->addr, addr) == 0) {
return cur;
if (addr_match(&cur->addr, addr) == 0) {
/* NOKEY entry. */
if (cur->key == NULL) {
if (key_name == NULL) {
return cur;
}
/* NOKEY entry, but key provided. */
continue;
}
/* Key name match. */
if (knot_dname_is_equal(cur->key->name, key_name)) {
return cur;
}
}
}
......
......@@ -32,6 +32,10 @@
#include "common/lists.h"
#include "common/sockaddr.h"
#include "common/mempattern.h"
#include "libknot/tsig.h"
struct knot_tsig_key;
/*! \brief ACL structure. */
typedef list_t acl_t;
......@@ -40,7 +44,7 @@ typedef list_t acl_t;
typedef struct acl_match {
node_t n;
sockaddr_t addr; /*!< \brief Address for comparison. */
void *val; /*!< \brief Associated value (or NULL). */
struct knot_tsig_key *key; /*!< \brief TSIG key. */
} acl_match_t;
/*!
......@@ -69,7 +73,7 @@ void acl_delete(acl_t **acl);
* \retval KNOT_EINVAL
* \retval KNOT_ENOMEM
*/
int acl_insert(acl_t *acl, const sockaddr_t *addr, void *val);
int acl_insert(acl_t *acl, const sockaddr_t *addr, knot_tsig_key_t *key);
/*!
* \brief Match address against ACL.
......@@ -80,7 +84,7 @@ int acl_insert(acl_t *acl, const sockaddr_t *addr, void *val);
* \retval Matching rule instance if found.
* \retval NULL if it didn't find a match.
*/
acl_match_t* acl_find(acl_t *acl, const sockaddr_t *addr);
acl_match_t* acl_find(acl_t *acl, const sockaddr_t *addr, const knot_dname_t *key_name);
/*!
* \brief Truncate ACL.
......
......@@ -439,7 +439,7 @@ static int conf_process(conf_t *conf)
sockaddr_init(&addr, -1);
sockaddr_set(&addr, i->family, i->address, 0);
sockaddr_setprefix(&addr, i->prefix);
acl_insert(conf->ctl.acl, &addr, i);
acl_insert(conf->ctl.acl, &addr, i->key);
}
return ret;
......
......@@ -649,11 +649,15 @@ int remote_process(server_t *s, conf_iface_t *ctl_if, int r,
sockaddr_tostr(&a, straddr, sizeof(straddr));
int rport = sockaddr_portnum(&a);
knot_tsig_key_t *tsig_key = NULL;
const knot_dname_t *tsig_name = NULL;
if (pkt->tsig_rr) {
tsig_name = pkt->tsig_rr->owner;
}
acl_match_t *m = NULL;
knot_rcode_t ts_rc = 0;
uint16_t ts_trc = 0;
uint64_t ts_tmsigned = 0;
if ((m = acl_find(conf()->ctl.acl, &a)) == NULL) {
if ((m = acl_find(conf()->ctl.acl, &a, tsig_name)) == NULL) {
knot_pkt_free(&pkt);
log_server_warning("Denied remote control for '%s@%d' "
"(doesn't match ACL).\n",
......@@ -661,8 +665,8 @@ int remote_process(server_t *s, conf_iface_t *ctl_if, int r,
remote_senderr(c, buf, wire_len);
socket_close(c);
return KNOT_EACCES;
} else if (m->val) {
tsig_key = ((conf_iface_t *)m->val)->key;
} else {
tsig_key = m->key;
}
/* Check TSIG. */
......
......@@ -26,7 +26,7 @@
int main(int argc, char *argv[])
{
plan(19);
plan(18);
// 1. Create an ACL
acl_match_t *match = NULL;
......@@ -60,27 +60,27 @@ int main(int argc, char *argv[])
// 7. Attempt to match unmatching address
sockaddr_t unmatch_v4;
sockaddr_set(&unmatch_v4, AF_INET, "10.10.10.10", 24424);
match = acl_find(acl, &unmatch_v4);
match = acl_find(acl, &unmatch_v4, NULL);
ok(match == NULL, "acl: matching non-existing address");
// 8. Attempt to match unmatching IPv6 address
sockaddr_t unmatch_v6;
sockaddr_set(&unmatch_v6, AF_INET6, "2001:db8::1428:57ab", 24424);
match = acl_find(acl, &unmatch_v6);
match = acl_find(acl, &unmatch_v6, NULL);
ok(match == NULL, "acl: matching non-existing IPv6 address");
// 9. Attempt to match matching address
match = acl_find(acl, &test_v4);
match = acl_find(acl, &test_v4, NULL);
ok(match != NULL, "acl: matching existing address");
// 10. Attempt to match matching address
match = acl_find(acl, &test_v6);
match = acl_find(acl, &test_v6, NULL);
ok(match != NULL, "acl: matching existing IPv6 address");
// 11. Attempt to match matching 'any port' address
sockaddr_t match_v4a;
sockaddr_set(&match_v4a, AF_INET, "20.20.20.20", 24424);
match = acl_find(acl, &match_v4a);
match = acl_find(acl, &match_v4a, NULL);
ok(match != NULL, "acl: matching existing IPv4 'any port' address");
// 12. Attempt to match matching address without matching port
......@@ -94,7 +94,7 @@ int main(int argc, char *argv[])
// lives_ok({
acl_delete(0);
acl_insert(0, 0, NULL);
acl_find(0, 0);
acl_find(0, 0, NULL);
acl_truncate(0);
// }, "acl: won't crash with NULL parameters");
ok(1, "acl: won't crash with NULL parameters");
......@@ -105,12 +105,12 @@ int main(int argc, char *argv[])
sockaddr_setprefix(&match_pf4, 24);
acl_insert(acl, &match_pf4, NULL);
sockaddr_set(&test_pf4, AF_INET, "192.168.1.20", 0);
match = acl_find(acl, &test_pf4);
match = acl_find(acl, &test_pf4, NULL);
ok(match != NULL, "acl: searching address in matching prefix /24");
// 15. Attempt to search non-matching subnet
sockaddr_set(&test_pf4, AF_INET, "192.168.2.20", 0);
match = acl_find(acl, &test_pf4);
match = acl_find(acl, &test_pf4, NULL);
ok(match == NULL, "acl: searching address in non-matching prefix /24");
// 16. Attempt to match v6 subnet
......@@ -119,25 +119,15 @@ int main(int argc, char *argv[])
sockaddr_setprefix(&match_pf6, 120);
acl_insert(acl, &match_pf6, NULL);
sockaddr_set(&test_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:AB03", 0);
match = acl_find(acl, &test_pf6);
match = acl_find(acl, &test_pf6, NULL);
ok(match != NULL, "acl: searching v6 address in matching prefix /120");
// 17. Attempt to search non-matching subnet
sockaddr_set(&test_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:CCCC", 0);
match = acl_find(acl, &test_pf6);
match = acl_find(acl, &test_pf6, NULL);
ok(match == NULL, "acl: searching v6 address in non-matching prefix /120");
// 18. Add preferred node
sockaddr_set(&test_pf4, AF_INET, "192.168.0.0", 0);
sockaddr_setprefix(&test_pf4, 16);
acl_insert(acl, &test_pf4, NULL);
sockaddr_set(&match_pf4, AF_INET, "192.168.1.20", 0);
void *sval = (void*)0x1234;
acl_insert(acl, &match_pf4, sval);
match = acl_find(acl, &match_pf4);
ok(match && match->val == sval, "acl: search for preferred node");
// 19. Scenario after truncating
// 18. Scenario after truncating
acl_truncate(acl);
sockaddr_set(&test_pf6, AF_INET6, "2001:a1b0:e11e:50d1::3:300", 0);
acl_insert(acl, &test_pf6, NULL);
......@@ -146,7 +136,7 @@ int main(int argc, char *argv[])
sockaddr_set(&test_pf4, AF_INET, "82.87.48.136", 0);
acl_insert(acl, &test_pf4, NULL);
sockaddr_set(&match_pf4, AF_INET, "82.87.48.136", 12345);
match = acl_find(acl, &match_pf4);
match = acl_find(acl, &match_pf4, NULL);
ok(match != NULL, "acl: scenario after truncating");
acl_delete(&acl);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment