diff options
Diffstat (limited to 'contrib/unbound/services/rpz.c')
-rw-r--r-- | contrib/unbound/services/rpz.c | 303 |
1 files changed, 252 insertions, 51 deletions
diff --git a/contrib/unbound/services/rpz.c b/contrib/unbound/services/rpz.c index 322e9d1393c4..18d76c07bff3 100644 --- a/contrib/unbound/services/rpz.c +++ b/contrib/unbound/services/rpz.c @@ -526,13 +526,13 @@ rpz_create(struct config_auth* p) size_t nmlen = sizeof(nm); if(!p->rpz_cname) { - log_err("RPZ override with cname action found, but no " + log_err("rpz: override with cname action found, but no " "rpz-cname-override configured"); goto err; } if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) { - log_err("cannot parse RPZ cname override: %s", + log_err("rpz: cannot parse cname override: %s", p->rpz_cname); goto err; } @@ -614,7 +614,7 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname, return; /* no need to log these types as unsupported */ } dname_str(dname, str); - verbose(VERB_ALGO, "RPZ: qname trigger, %s skipping unsupported action: %s", + verbose(VERB_ALGO, "rpz: qname trigger, %s skipping unsupported action: %s", str, rpz_action_to_string(a)); free(dname); return; @@ -999,7 +999,7 @@ rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, rpz_action_to_respip_action(a) == respip_invalid) { char str[255+1]; dname_str(dname, str); - verbose(VERB_ALGO, "RPZ: respip trigger, %s skipping unsupported action: %s", + verbose(VERB_ALGO, "rpz: respip trigger, %s skipping unsupported action: %s", str, rpz_action_to_string(a)); return 0; } @@ -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); } @@ -1392,11 +1576,13 @@ log_rpz_apply(char* trigger, uint8_t* dname, struct addr_tree_node* addrnode, dnamestr[0]=0; } if(repinfo) { - addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); - port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port); + addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip)); + port = ntohs(((struct sockaddr_in*)&repinfo->client_addr)->sin_port); } else if(ms && ms->mesh_info && ms->mesh_info->reply_list) { - addr_to_str(&ms->mesh_info->reply_list->query_reply.addr, ms->mesh_info->reply_list->query_reply.addrlen, ip, sizeof(ip)); - port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.addr)->sin_port); + addr_to_str(&ms->mesh_info->reply_list->query_reply.client_addr, + ms->mesh_info->reply_list->query_reply.client_addrlen, + ip, sizeof(ip)); + port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.client_addr)->sin_port); } else { ip[0]=0; port = 0; @@ -1468,7 +1654,9 @@ rpz_resolve_client_action_and_zone(struct auth_zones* az, struct query_info* qin } z = rpz_find_zone(r->local_zones, qinfo->qname, qinfo->qname_len, qinfo->qclass, 0, 0, 0); - node = rpz_ipbased_trigger_lookup(r->client_set, &repinfo->addr, repinfo->addrlen, "clientip"); + node = rpz_ipbased_trigger_lookup(r->client_set, + &repinfo->client_addr, repinfo->client_addrlen, + "clientip"); if((z || node) && r->action_override == RPZ_DISABLED_ACTION) { if(r->log) log_rpz_apply((node?"clientip":"qname"), @@ -1559,19 +1747,6 @@ rpz_local_encode(struct module_env* env, struct query_info* qinfo, return 1; } -static struct local_rrset* -rpz_find_synthesized_rrset(int 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, @@ -1707,7 +1882,8 @@ rpz_synthesize_nodata(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms, 0, /* ns */ 0, /* ar */ 0, /* total */ - sec_status_insecure); + sec_status_insecure, + LDNS_EDE_NONE); if(msg->rep) msg->rep->authoritative = 1; if(!rpz_add_soa(msg->rep, ms, az)) @@ -1736,7 +1912,8 @@ rpz_synthesize_nxdomain(struct rpz* r, struct module_qstate* ms, 0, /* ns */ 0, /* ar */ 0, /* total */ - sec_status_insecure); + sec_status_insecure, + LDNS_EDE_NONE); if(msg->rep) msg->rep->authoritative = 1; if(!rpz_add_soa(msg->rep, ms, az)) @@ -1766,7 +1943,8 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs 0, /* ns */ 0, /* ar */ 1, /* total */ - sec_status_insecure); + sec_status_insecure, + LDNS_EDE_NONE); if(new_reply_info == NULL) { log_err("out of memory"); return NULL; @@ -1984,7 +2162,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r, case RPZ_TCP_ONLY_ACTION: /* basically a passthru here but the tcp-only will be * honored before the query gets sent. */ - ms->respip_action_info->action = respip_truncate; + ms->tcp_required = 1; ret = NULL; break; case RPZ_DROP_ACTION: @@ -1997,6 +2175,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r, break; case RPZ_PASSTHRU_ACTION: ret = NULL; + ms->rpz_passthru = 1; break; default: verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", @@ -2038,7 +2217,7 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r, case RPZ_TCP_ONLY_ACTION: /* basically a passthru here but the tcp-only will be * honored before the query gets sent. */ - ms->respip_action_info->action = respip_truncate; + ms->tcp_required = 1; ret = NULL; break; case RPZ_DROP_ACTION: @@ -2051,6 +2230,7 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r, break; case RPZ_PASSTHRU_ACTION: ret = NULL; + ms->rpz_passthru = 1; break; default: verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", @@ -2114,6 +2294,11 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate* struct local_zone* z = NULL; struct matched_delegation_point match = {0}; + if(ms->rpz_passthru) { + verbose(VERB_ALGO, "query is rpz_passthru, no further processing"); + return NULL; + } + if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; } az = ms->env->auth_zones; @@ -2155,18 +2340,16 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate* lock_rw_unlock(&az->rpz_lock); - if(raddr == NULL && z == NULL) { return NULL; } - else if(raddr != NULL) { + if(raddr == NULL && z == NULL) + return NULL; + + if(raddr != NULL) { if(z) { lock_rw_unlock(&z->lock); } return rpz_apply_nsip_trigger(ms, r, raddr, a); - } else if(z != NULL) { - if(raddr) { - lock_rw_unlock(&raddr->lock); - } - return rpz_apply_nsdname_trigger(ms, r, z, &match, a); - } else { return NULL; } + } + return rpz_apply_nsdname_trigger(ms, r, z, &match, a); } struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, @@ -2179,6 +2362,11 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, enum localzone_type lzt; struct dns_msg* ret = NULL; + if(ms->rpz_passthru) { + verbose(VERB_ALGO, "query is rpz_passthru, no further processing"); + return NULL; + } + if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; } az = ms->env->auth_zones; @@ -2240,7 +2428,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, case RPZ_TCP_ONLY_ACTION: /* basically a passthru here but the tcp-only will be * honored before the query gets sent. */ - ms->respip_action_info->action = respip_truncate; + ms->tcp_required = 1; ret = NULL; break; case RPZ_DROP_ACTION: @@ -2253,12 +2441,17 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, break; case RPZ_PASSTHRU_ACTION: ret = NULL; + ms->rpz_passthru = 1; break; default: verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'", rpz_action_to_string(localzone_type_to_rpz_action(lzt))); ret = NULL; } + if(r->log) + log_rpz_apply("qname", (z?z->name:NULL), NULL, + localzone_type_to_rpz_action(lzt), + &is->qchase, NULL, ms, r->log_name); lock_rw_unlock(&z->lock); lock_rw_unlock(&a->lock); return ret; @@ -2270,7 +2463,8 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env, uint8_t* taglist, size_t taglen, struct ub_server_stats* stats, sldns_buffer* buf, struct regional* temp, /* output parameters */ - struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out) + struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out, + int* passthru) { int ret = 0; enum rpz_action client_action; @@ -2278,7 +2472,9 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env, az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out); client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action); - + if(client_action == RPZ_PASSTHRU_ACTION) { + *passthru = 1; + } if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION && client_action != RPZ_PASSTHRU_ACTION)) { if(client_action == RPZ_PASSTHRU_ACTION @@ -2323,7 +2519,7 @@ int rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env, struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist, - size_t taglen, struct ub_server_stats* stats) + size_t taglen, struct ub_server_stats* stats, int* passthru) { struct rpz* r = NULL; struct auth_zone* a = NULL; @@ -2332,7 +2528,8 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env, enum localzone_type lzt; int clientip_trigger = rpz_apply_maybe_clientip_trigger(az, env, qinfo, - edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r); + edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r, + passthru); if(clientip_trigger >= 0) { if(a) { lock_rw_unlock(&a->lock); @@ -2357,6 +2554,10 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env, } else { lzt = rpz_action_to_localzone_type(r->action_override); } + if(r->action_override == RPZ_PASSTHRU_ACTION || + lzt == local_zone_always_transparent /* RPZ_PASSTHRU_ACTION */) { + *passthru = 1; + } if(verbosity >= VERB_ALGO) { char nm[255+1], zn[255+1]; |