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
}
-/** 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, "
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
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;
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);
}
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,
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."
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:
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
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"
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
d.rpz-ip. IN A
ENTRY_END
-
STEP 15 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
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
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