- Fix RPZ removal of client-ip, nsip, nsdname triggers from IXFR.

This commit is contained in:
W.C.A. Wijngaards 2023-05-19 14:38:41 +02:00
parent a07ccbae9a
commit da78c42f88
5 changed files with 458 additions and 33 deletions

View File

@ -1,3 +1,6 @@
19 May 2023: Wouter
- Fix RPZ removal of client-ip, nsip, nsdname triggers from IXFR.
16 May 2023: Wouter
- Fix #888: [FR] Use kernel timestamps for dnstap.
- Fix to print debug log for ancillary data with correct IP address.

View File

@ -1306,8 +1306,8 @@ az_remove_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
auth_data_delete(node);
}
if(z->rpz) {
rpz_remove_rr(z->rpz, z->namelen, dname, dname_len, rr_type,
rr_class, rdata, rdatalen);
rpz_remove_rr(z->rpz, z->name, z->namelen, dname, dname_len,
rr_type, rr_class, rdata, rdatalen);
}
return 1;
}

View File

@ -1188,6 +1188,22 @@ rpz_find_zone(struct local_zones* zones, uint8_t* qname, size_t qname_len, uint1
return z;
}
/** Find entry for RR type in the list of rrsets for the clientip. */
static struct local_rrset*
rpz_find_synthesized_rrset(uint16_t qtype,
struct clientip_synthesized_rr* data)
{
struct local_rrset* cursor = data->data;
while( cursor != NULL) {
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
if(htons(qtype) == packed_rrset->type) {
return cursor;
}
cursor = cursor->next;
}
return NULL;
}
/**
* Remove RR from RPZ's local-data
* @param z: local-zone for RPZ, holding write lock
@ -1270,15 +1286,15 @@ rpz_rrset_delete_rr(struct resp_addr* raddr, uint16_t rr_type, uint8_t* rdata,
}
/** Remove RR from RPZ's local-zone */
/** Remove RR from rpz localzones structure */
static void
rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
enum rpz_action a, uint16_t rr_type, uint16_t rr_class,
uint8_t* rdatawl, size_t rdatalen)
rpz_remove_local_zones_trigger(struct local_zones* zones, uint8_t* dname,
size_t dnamelen, enum rpz_action a, uint16_t rr_type,
uint16_t rr_class, uint8_t* rdatawl, size_t rdatalen)
{
struct local_zone* z;
int delete_zone = 1;
z = rpz_find_zone(r->local_zones, dname, dnamelen, rr_class,
z = rpz_find_zone(zones, dname, dnamelen, rr_class,
1 /* only exact */, 1 /* wr lock */, 1 /* keep lock*/);
if(!z) {
verbose(VERB_ALGO, "rpz: cannot remove RR from IXFR, "
@ -1290,15 +1306,24 @@ rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
dnamelen, rr_type, rdatawl, rdatalen);
else if(a != localzone_type_to_rpz_action(z->type)) {
lock_rw_unlock(&z->lock);
lock_rw_unlock(&r->local_zones->lock);
lock_rw_unlock(&zones->lock);
return;
}
lock_rw_unlock(&z->lock);
if(delete_zone) {
local_zones_del_zone(r->local_zones, z);
local_zones_del_zone(zones, z);
}
lock_rw_unlock(&r->local_zones->lock);
return;
lock_rw_unlock(&zones->lock);
}
/** Remove RR from RPZ's local-zone */
static void
rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
enum rpz_action a, uint16_t rr_type, uint16_t rr_class,
uint8_t* rdatawl, size_t rdatalen)
{
rpz_remove_local_zones_trigger(r->local_zones, dname, dnamelen,
a, rr_type, rr_class, rdatawl, rdatalen);
}
static void
@ -1335,15 +1360,159 @@ rpz_remove_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
lock_rw_unlock(&r->respip_set->lock);
}
/** find and remove type from list of local_rrset entries*/
static void
del_local_rrset_from_list(struct local_rrset** list_head, uint16_t dtype)
{
struct local_rrset* prev=NULL, *p=*list_head;
while(p && ntohs(p->rrset->rk.type) != dtype) {
prev = p;
p = p->next;
}
if(!p)
return; /* rrset type not found */
/* unlink it */
if(prev) prev->next = p->next;
else *list_head = p->next;
/* no memory recycling for zone deletions ... */
}
/** Delete client-ip trigger RR from its RRset and perhaps also the rrset
* from the linked list. Returns if the local data is empty and the node can
* be deleted too, or not. */
static int rpz_remove_clientip_rr(struct clientip_synthesized_rr* node,
uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
{
struct local_rrset* rrset;
struct packed_rrset_data* d;
size_t index;
rrset = rpz_find_synthesized_rrset(rr_type, node);
if(rrset == NULL)
return 0; /* type not found, ignore */
d = (struct packed_rrset_data*)rrset->rrset->entry.data;
if(!packed_rrset_find_rr(d, rdatawl, rdatalen, &index))
return 0; /* RR not found, ignore */
if(d->count == 1) {
/* regional alloc'd */
/* delete the type entry from the list */
del_local_rrset_from_list(&node->data, rr_type);
/* if the list is empty, the node can be removed too */
if(node->data == NULL)
return 1;
} else if (d->count > 1) {
if(!local_rrset_remove_rr(d, index))
return 0;
}
return 0;
}
/** remove trigger RR from clientip_syntheized set tree. */
static void
rpz_clientip_remove_trigger_rr(struct clientip_synthesized_rrset* set,
struct sockaddr_storage* addr, socklen_t addrlen, int net,
enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
{
struct clientip_synthesized_rr* node;
int delete_node = 1;
lock_rw_wrlock(&set->lock);
node = (struct clientip_synthesized_rr*)addr_tree_find(&set->entries,
addr, addrlen, net);
if(node == NULL) {
/* netblock not found */
verbose(VERB_ALGO, "rpz: cannot remove RR from IXFR, "
"RPZ address, netblock not found");
lock_rw_unlock(&set->lock);
return;
}
lock_rw_wrlock(&node->lock);
if(a == RPZ_LOCAL_DATA_ACTION) {
/* remove RR, signal whether entry can be removed */
delete_node = rpz_remove_clientip_rr(node, rr_type, rdatawl,
rdatalen);
} else if(a != node->action) {
/* ignore the RR with different action specification */
delete_node = 0;
}
if(delete_node) {
rbtree_delete(&set->entries, node->node.node.key);
}
lock_rw_unlock(&set->lock);
lock_rw_unlock(&node->lock);
if(delete_node) {
lock_rw_destroy(&node->lock);
}
}
/** Remove clientip trigger RR from RPZ. */
static void
rpz_remove_clientip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
{
struct sockaddr_storage addr;
socklen_t addrlen;
int net, af;
if(a == RPZ_INVALID_ACTION)
return;
if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af))
return;
rpz_clientip_remove_trigger_rr(r->client_set, &addr, addrlen, net,
a, rr_type, rdatawl, rdatalen);
}
/** Remove nsip trigger RR from RPZ. */
static void
rpz_remove_nsip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
{
struct sockaddr_storage addr;
socklen_t addrlen;
int net, af;
if(a == RPZ_INVALID_ACTION)
return;
if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af))
return;
rpz_clientip_remove_trigger_rr(r->ns_set, &addr, addrlen, net,
a, rr_type, rdatawl, rdatalen);
}
/** Remove nsdname trigger RR from RPZ. */
static void
rpz_remove_nsdname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
enum rpz_action a, uint16_t rr_type, uint16_t rr_class,
uint8_t* rdatawl, size_t rdatalen)
{
uint8_t* dname_stripped = NULL;
size_t dnamelen_stripped = 0;
if(a == RPZ_INVALID_ACTION)
return;
if(!rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped,
&dnamelen_stripped))
return;
rpz_remove_local_zones_trigger(r->nsdname_zones, dname_stripped,
dnamelen_stripped, a, rr_type, rr_class, rdatawl, rdatalen);
free(dname_stripped);
}
void
rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, size_t dnamelen,
uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl, size_t rdatalen)
rpz_remove_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl,
size_t rdatalen)
{
size_t policydnamelen;
enum rpz_trigger t;
enum rpz_action a;
uint8_t* policydname;
if(rpz_type_ignored(rr_type)) {
/* this rpz action is not valid, eg. this is the SOA or NS RR */
return;
}
if(!dname_subdomain_c(dname, azname)) {
/* not subdomain of the RPZ zone. */
return;
}
if(!(policydname = calloc(1, LDNS_MAX_DOMAINLEN + 1)))
return;
@ -1358,13 +1527,28 @@ rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, size_t dnamelen,
return;
}
t = rpz_dname_to_trigger(policydname, policydnamelen);
if(t == RPZ_INVALID_TRIGGER) {
/* skipping invalid trigger */
free(policydname);
return;
}
if(t == RPZ_QNAME_TRIGGER) {
rpz_remove_qname_trigger(r, policydname, policydnamelen, a,
rr_type, rr_class, rdatawl, rdatalen);
} else if(t == RPZ_RESPONSE_IP_TRIGGER) {
rpz_remove_response_ip_trigger(r, policydname, policydnamelen,
a, rr_type, rdatawl, rdatalen);
} else if(t == RPZ_CLIENT_IP_TRIGGER) {
rpz_remove_clientip_trigger(r, policydname, policydnamelen, a,
rr_type, rdatawl, rdatalen);
} else if(t == RPZ_NSIP_TRIGGER) {
rpz_remove_nsip_trigger(r, policydname, policydnamelen, a,
rr_type, rdatawl, rdatalen);
} else if(t == RPZ_NSDNAME_TRIGGER) {
rpz_remove_nsdname_trigger(r, policydname, policydnamelen, a,
rr_type, rr_class, rdatawl, rdatalen);
}
/* else it was an unsupported trigger, also skipped. */
free(policydname);
}
@ -1563,21 +1747,6 @@ rpz_local_encode(struct module_env* env, struct query_info* qinfo,
return 1;
}
static struct local_rrset*
rpz_find_synthesized_rrset(uint16_t qtype,
struct clientip_synthesized_rr* data)
{
struct local_rrset* cursor = data->data;
while( cursor != NULL) {
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
if(htons(qtype) == packed_rrset->type) {
return cursor;
}
cursor = cursor->next;
}
return NULL;
}
/** allocate SOA record ubrrsetkey in region */
static struct ub_packed_rrset_key*
make_soa_ubrrset(struct auth_zone* auth_zone, struct auth_rrset* soa,

View File

@ -152,6 +152,7 @@ int rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dna
/**
* Delete policy matching RR, used for IXFR.
* @param r: the rpz to add the policy to.
* @param azname: dname of the auth-zone
* @param aznamelen: the length of the auth-zone name
* @param dname: dname of the RR
* @param dnamelen: length of the dname
@ -160,9 +161,9 @@ int rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dna
* @param rdatawl: rdata of the RR, prepended with the rdata size
* @param rdatalen: length if the RR, including the prepended rdata size
*/
void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl,
size_t rdatalen);
void rpz_remove_rr(struct rpz* r, uint8_t* azname, size_t aznamelen,
uint8_t* dname, size_t dnamelen, uint16_t rr_type, uint16_t rr_class,
uint8_t* rdatawl, size_t rdatalen);
/**
* Walk over the RPZ zones to find and apply a QNAME trigger policy.

256
testdata/rpz_ixfr.rpl vendored
View File

@ -4,6 +4,7 @@ server:
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
rrset-roundrobin: no
access-control: 192.0.0.0/8 allow
rpz:
name: "rpz.example.com."
@ -22,6 +23,11 @@ d.rpz.example.com. IN CNAME .
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.3
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.4
32.4.123.0.10.rpz-ip.rpz.example.com. CNAME .
; also test client-ip, and remove it later with an IXFR.
24.0.5.0.192.rpz-client-ip A 127.0.0.5
24.0.6.0.192.rpz-client-ip CNAME *.
32.41.30.20.10.rpz-nsip A 127.0.0.1
ns.gotham.com.rpz-nsdname A 127.0.0.1
TEMPFILE_END
stub-zone:
@ -97,6 +103,42 @@ SECTION ANSWER
d.rpz-ip. IN A 10.0.123.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
a.a. IN A
SECTION ANSWER
a.a. IN A 10.0.123.5
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
foo.com. IN NS
SECTION ANSWER
SECTION AUTHORITY
foo.com. 10 IN NS ns.foo.com.
SECTION ADDITIONAL
ns.foo.com. 10 IN A 10.20.30.41
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.com. IN NS
SECTION ANSWER
SECTION AUTHORITY
gotham.com. 10 IN NS ns.gotham.com.
SECTION ADDITIONAL
ns.gotham.com. 10 IN A 10.20.30.42
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
@ -124,6 +166,10 @@ d.rpz.example.com. IN CNAME .
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.3
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.4
32.4.123.0.10.rpz-ip.rpz.example.com. CNAME .
24.0.5.0.192.rpz-client-ip.rpz.example.com. A 127.0.0.5
24.0.6.0.192.rpz-client-ip.rpz.example.com. CNAME *.
32.41.30.20.10.rpz-nsip.rpz.example.com. A 127.0.0.1
ns.gotham.com.rpz-nsdname.rpz.example.com. A 127.0.0.1
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600
b.rpz.example.com. TXT "hello from RPZ"
c.rpz.example.com. TXT "hello from RPZ"
@ -136,6 +182,78 @@ ENTRY_END
RANGE_END
; ns.foo.com
RANGE_BEGIN 0 100
ADDRESS 10.20.30.41
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
ns.foo.com. IN A
SECTION ANSWER
ns.foo.com. 10 IN A 10.20.30.41
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
ns.foo.com. IN AAAA
SECTION ANSWER
SECTION AUTHORITY
foo.com. 10 IN SOA ns.foo.com. root.foo.com. 1 2 3 4 10
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
www.foo.com. IN A
SECTION ANSWER
www.foo.com. 10 IN A 10.20.30.42
ENTRY_END
RANGE_END
; ns.gotham.com
RANGE_BEGIN 0 100
ADDRESS 10.20.30.42
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
ns.gotham.com. IN A
SECTION ANSWER
ns.gotham.com. 10 IN A 10.20.30.42
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
ns.gotham.com. IN AAAA
SECTION ANSWER
SECTION AUTHORITY
gotham.com. 10 IN SOA ns.gotham.com. root.gotham.com. 1 2 3 4 10
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
www.gotham.com. IN A
SECTION ANSWER
www.gotham.com. 10 IN A 10.20.30.43
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
@ -244,7 +362,6 @@ SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 15 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
@ -253,7 +370,74 @@ SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 16 TIME_PASSES ELAPSE 1
STEP 16 QUERY ADDRESS 192.0.5.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN A
ENTRY_END
STEP 17 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
a.a. IN A
SECTION ANSWER
a.a. IN A 127.0.0.5
ENTRY_END
STEP 18 QUERY ADDRESS 192.0.6.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN A
ENTRY_END
STEP 19 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
a.a. IN A
SECTION ANSWER
ENTRY_END
STEP 20 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.foo.com. IN A
ENTRY_END
STEP 21 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
www.foo.com. IN A
SECTION ANSWER
www.foo.com. IN A 127.0.0.1
ENTRY_END
STEP 22 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.gotham.com. IN A
ENTRY_END
STEP 23 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
www.gotham.com. IN A
SECTION ANSWER
www.gotham.com. IN A 127.0.0.1
ENTRY_END
STEP 24 TIME_PASSES ELAPSE 1
STEP 30 TIME_PASSES ELAPSE 3600
STEP 40 TRAFFIC
@ -376,4 +560,72 @@ SECTION ANSWER
d.rpz-ip. IN A 10.0.123.4
ENTRY_END
STEP 64 QUERY ADDRESS 192.0.5.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN A
ENTRY_END
STEP 65 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a.a. IN A
SECTION ANSWER
a.a. IN A 10.0.123.5
ENTRY_END
STEP 66 QUERY ADDRESS 192.0.6.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN A
ENTRY_END
STEP 67 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a.a. IN A
SECTION ANSWER
a.a. IN A 10.0.123.5
ENTRY_END
STEP 68 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.foo.com. IN A
ENTRY_END
STEP 69 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.foo.com. IN A
SECTION ANSWER
www.foo.com. 10 IN A 10.20.30.42
ENTRY_END
STEP 70 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.gotham.com. IN A
ENTRY_END
STEP 71 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.gotham.com. IN A
SECTION ANSWER
www.gotham.com. 10 IN A 10.20.30.43
ENTRY_END
SCENARIO_END