for(a = az->rpz_first; a; a = a->rpz_az_next) {
lock_rw_rdlock(&a->lock);
r = a->rpz;
- if(!r->disabled && (!r->taglist || taglist_intersect(r->taglist,
- r->taglistlen, taglist, taglen))) {
- z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len,
- qinfo->qclass, 0, 0, 0);
- if(z && r->action_override == RPZ_DISABLED_ACTION) {
- if(r->log)
- log_rpz_apply(z->name,
- r->action_override,
- qinfo, repinfo, r->log_name);
- /* TODO only register stats when stats_extended?
- * */
- stats->rpz_action[r->action_override]++;
- lock_rw_unlock(&z->lock);
- z = NULL;
++ if(r->disabled) {
++ lock_rw_unlock(&a->lock);
++ continue;
++ }
+ if(r->taglist && !taglist_intersect(r->taglist,
+ r->taglistlen, taglist, taglen)) {
+ lock_rw_unlock(&a->lock);
+ continue;
+ }
+ 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);
+ if(z && r->action_override == RPZ_DISABLED_ACTION) {
+ if(r->log)
+ log_rpz_apply(z->name,
+ r->action_override,
+ qinfo, repinfo, r->log_name);
+ /* TODO only register stats when stats_extended? */
+ stats->rpz_action[r->action_override]++;
+ lock_rw_unlock(&z->lock);
+ z = NULL;
+ }
+ if(z) {
+ break;
+ } else {
+ if(node != NULL) {
+ lock_rw_unlock(&node->lock);
+ node = NULL;
}
- if(z)
- break;
}
- lock_rw_unlock(&a->lock); /* not found in this auth_zone */
+ /* not found in this auth_zone */
+ lock_rw_unlock(&a->lock);
}
+
lock_rw_unlock(&az->rpz_lock);
- if(!z)
- return 0; /* not holding auth_zone.lock anymore */
- log_assert(r);
- if(r->action_override == RPZ_NO_OVERRIDE_ACTION)
- lzt = z->type;
- else
- lzt = rpz_action_to_localzone_type(r->action_override);
+ *r_out = r;
+ *a_out = a;
+ *z_out = z;
+
+ return node;
+ }
+
+ static inline int
+ rpz_is_udp_query(struct comm_reply* repinfo) {
+ return repinfo != NULL
+ ? (repinfo->c != NULL
+ ? repinfo->c->type == comm_udp
+ : 0)
+ : 0;
+ }
+
+ /** encode answer consisting of 1 rrset */
+ static int
+ rpz_local_encode(struct query_info* qinfo,struct edns_data* edns, sldns_buffer* buf,
+ struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec, int rcode)
+ {
+ struct reply_info rep;
+ uint16_t udpsize;
+
+ memset(&rep, 0, sizeof(rep));
+ rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
+ rep.qdcount = 1;
+ rep.rrset_count = ansec;
+ if(ansec > 0) {
+ rep.an_numrrsets = 1;
+ rep.rrsets = &rrset;
+ rep.ttl = ((struct packed_rrset_data*)rrset->entry.data)->rr_ttl[0];
+ }
+
+ udpsize = edns->udp_size;
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->ext_rcode = 0;
+ edns->bits &= EDNS_DO;
+ //!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,repinfo, temp) ||
+ if(!reply_info_answer_encode(qinfo, &rep,
+ *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
+ buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
+ error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
+ *(uint16_t*)sldns_buffer_begin(buf),
+ sldns_buffer_read_u16_at(buf, 2), edns);
+ }
+
+ 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;
+ }
+
+ static void
+ rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr,
+ struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
+ struct regional* temp)
+ {
+ struct local_rrset* rrset;
+ enum rpz_action action = RPZ_INVALID_ACTION;
+ struct ub_packed_rrset_key* rp = NULL;
+ int rcode = LDNS_RCODE_NOERROR|BIT_AA;
+ int rrset_count = 1;
+
+ verbose(VERB_ALGO, "rpz: apply client ip trigger: found=%d action=%s",
+ raddr != NULL, rpz_action_to_string(action));
+
+ /* prepare synthesized answer for client */
+
+ action = raddr->action;
+ if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL ) {
+ verbose(VERB_ALGO, "rpz: bug: local-data action but no local data");
+ return;
+ }
+
+ /* check query type / rr type */
+
+ rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: unable to find local-data for query");
+ rrset_count = 0;
+ goto nodata;
+ }
+
+ rp = respip_copy_rrset(rrset->rrset, temp);
+ if(!rp) {
+ verbose(VERB_ALGO, "rpz: local data action: out of memory");
+ return;
+ }
+
+ rp->rk.flags |= PACKED_RRSET_FIXEDTTL;
+ rp->rk.dname = qinfo->qname;
+ rp->rk.dname_len = qinfo->qname_len;
+ nodata:
+ rpz_local_encode(qinfo, edns, buf, temp, rp, rrset_count, rcode);
+ }
+
+ static inline struct dns_msg*
+ rpz_dns_msg_new(struct regional* region)
+ {
+ struct dns_msg* msg =
+ (struct dns_msg*)regional_alloc(region,
+ sizeof(struct dns_msg));
+ if(msg == NULL) { return NULL; }
+ memset(msg, 0, sizeof(struct dns_msg));
+
+ return msg;
+ }
+
+ static inline struct dns_msg*
+ rpz_synthesize_nodata(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms)
+ {
+ struct dns_msg* msg = rpz_dns_msg_new(ms->region);
+ if(msg == NULL) { return msg; }
+ msg->qinfo = ms->qinfo;
+ msg->rep = construct_reply_info_base(ms->region,
+ LDNS_RCODE_NOERROR | BIT_RD | BIT_QR | BIT_AA | BIT_RA,
+ 1, //qd
+ 0, //ttl
+ 0, //prettl
+ 0, //expttl
+ 0, //an
+ 0, //ns
+ 0, //ar
+ 0, //total
+ sec_status_secure);
+ return msg;
+ }
+
+ static inline struct dns_msg*
+ rpz_synthesize_nxdomain(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms)
+ {
+ struct dns_msg* msg = rpz_dns_msg_new(ms->region);
+ if(msg == NULL) { return msg; }
+ msg->qinfo = ms->qinfo;
+ msg->rep = construct_reply_info_base(ms->region,
+ LDNS_RCODE_NXDOMAIN | BIT_RD | BIT_QR | BIT_AA | BIT_RA,
+ 1, //qd
+ 0, //ttl
+ 0, //prettl
+ 0, //expttl
+ 0, //an
+ 0, //ns
+ 0, //ar
+ 0, //total
+ sec_status_secure);
+ return msg;
+ }
+
+ static inline struct dns_msg*
+ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms,
+ struct local_rrset* rrset)
+ {
+ struct dns_msg* msg = NULL;
+ struct query_info* qi = &ms->qinfo;
+ struct reply_info* new_reply_info;
+ struct ub_packed_rrset_key* rp;
+
+
+ msg = rpz_dns_msg_new(ms->region);
+ if(msg == NULL) { return NULL; }
+
+ // XXX: use ttl etc from rpz zone?
+ new_reply_info = construct_reply_info_base(ms->region,
+ LDNS_RCODE_NOERROR | BIT_RD | BIT_QR | BIT_AA | BIT_RA,
+ 1, //qd
+ 0, //ttl
+ 0, //prettl
+ 0, //expttl
+ 1, //an
+ 0, //ns
+ 0, //ar
+ 1, //total
+ sec_status_secure);
+ if(new_reply_info == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ rp = respip_copy_rrset(rrset->rrset, ms->region);
+ if(rp == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ rp->rk.dname = qi->qname;
+ rp->rk.dname_len = qi->qname_len;
+ new_reply_info->rrsets[0] = rp;
+ msg->rep = new_reply_info;
+ return msg;
+ }
+
+ static inline struct dns_msg*
+ rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms,
+ struct clientip_synthesized_rr* data)
+ {
+ struct query_info* qi = &ms->qinfo;
+ struct local_rrset* rrset;
+
+ rrset = rpz_find_synthesized_rrset(qi->qtype, data);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: nsip: no matching local data found");
+ return NULL;
+ }
+
+ return rpz_synthesize_localdata_from_rrset(r, ms, rrset);
+ }
+
+ // copy'n'paste from localzone.c
+ static struct local_rrset*
+ local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
+ {
+ struct local_rrset* p;
+ type = htons(type);
+ for(p = data->rrsets; p; p = p->next) {
+ verbose(VERB_ALGO, "type=%d (%d)", type, p->rrset->rk.type);
+ if(p->rrset->rk.type == type)
+ return p;
+ if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
+ return p;
+ }
+ return NULL;
+ }
+
+ // based on localzone.c:local_data_answer()
+ static inline struct dns_msg*
+ rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
+ struct local_zone* z, struct matched_delegation_point const* match)
+ {
+ struct local_data key;
+ struct local_data* ld;
+ struct local_rrset* rrset;
+
+ if(match->dname == NULL) { return NULL; }
+
+ key.node.key = &key;
+ key.name = match->dname;
+ key.namelen = match->dname_len;
+ key.namelabs = dname_count_labels(match->dname);
+
+ rpz_log_dname("nsdname local data", key.name, key.namelen);
+
+ ld = (struct local_data*)rbtree_search(&z->data, &key.node);
+ if(ld == NULL) {
+ verbose(VERB_ALGO, "rpz: nsdname: impossible: qname not found");
+ return NULL;
+ }
+
+ rrset = local_data_find_type(ld, ms->qinfo.qtype, 1);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: nsdname: no matching local data found");
+ return NULL;
+ }
+ return rpz_synthesize_localdata_from_rrset(r, ms, rrset);
+ }
+
+ static int
+ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
+ struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo,
+ struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
+ struct comm_reply* repinfo, struct ub_server_stats* stats)
+ {
+ struct local_data* ld = NULL;
+ int ret = 0;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
- qinfo->local_alias =
- regional_alloc_zero(temp, sizeof(struct local_rrset));
- if(!qinfo->local_alias) {
- lock_rw_unlock(&z->lock);
- lock_rw_unlock(&a->lock);
+ qinfo->local_alias = regional_alloc_zero(temp, sizeof(struct local_rrset));
+ if(qinfo->local_alias == NULL) {
return 0; /* out of memory */
}
- qinfo->local_alias->rrset =
- regional_alloc_init(temp, r->cname_override,
- sizeof(*r->cname_override));
- if(!qinfo->local_alias->rrset) {
- lock_rw_unlock(&z->lock);
- lock_rw_unlock(&a->lock);
+ qinfo->local_alias->rrset = regional_alloc_init(temp, r->cname_override,
+ sizeof(*r->cname_override));
+ if(qinfo->local_alias->rrset == NULL) {
return 0; /* out of memory */
}
qinfo->local_alias->rrset->rk.dname = qinfo->qname;