aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/util/data/msgreply.c
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/util/data/msgreply.c')
-rw-r--r--external/unbound/util/data/msgreply.c367
1 files changed, 357 insertions, 10 deletions
diff --git a/external/unbound/util/data/msgreply.c b/external/unbound/util/data/msgreply.c
index 06593ffe1..2ce898d7f 100644
--- a/external/unbound/util/data/msgreply.c
+++ b/external/unbound/util/data/msgreply.c
@@ -52,6 +52,8 @@
#include "util/data/msgencode.h"
#include "sldns/sbuffer.h"
#include "sldns/wire2str.h"
+#include "util/module.h"
+#include "util/fptr_wlist.h"
/** MAX TTL default for messages and rrsets */
time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
@@ -76,6 +78,7 @@ parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg,
qinf->qname_len = msg->qname_len;
qinf->qtype = msg->qtype;
qinf->qclass = msg->qclass;
+ qinf->local_alias = NULL;
return 1;
}
@@ -130,9 +133,8 @@ parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
return 1;
}
-/** allocate (special) rrset keys, return 0 on error */
-static int
-repinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
+int
+reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
struct regional* region)
{
size_t i;
@@ -435,7 +437,7 @@ parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg,
return 0;
if(!parse_create_repinfo(msg, rep, region))
return 0;
- if(!repinfo_alloc_rrset_keys(*rep, alloc, region))
+ if(!reply_info_alloc_rrset_keys(*rep, alloc, region))
return 0;
if(!parse_copy_decompress(pkt, msg, *rep, region))
return 0;
@@ -451,6 +453,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
int ret;
qinf->qname = NULL;
+ qinf->local_alias = NULL;
*rep = NULL;
if(!(msg = regional_alloc(region, sizeof(*msg)))) {
return LDNS_RCODE_SERVFAIL;
@@ -461,7 +464,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
if((ret = parse_packet(pkt, msg, region)) != 0) {
return ret;
}
- if((ret = parse_extract_edns(msg, edns)) != 0)
+ if((ret = parse_extract_edns(msg, edns, region)) != 0)
return ret;
/* parse OK, allocate return structures */
@@ -542,6 +545,7 @@ query_info_parse(struct query_info* m, sldns_buffer* query)
return 0; /* need qtype, qclass */
m->qtype = sldns_buffer_read_u16(query);
m->qclass = sldns_buffer_read_u16(query);
+ m->local_alias = NULL;
return 1;
}
@@ -603,10 +607,10 @@ reply_info_delete(void* d, void* ATTR_UNUSED(arg))
free(r);
}
-hashvalue_t
+hashvalue_type
query_info_hash(struct query_info *q, uint16_t flags)
{
- hashvalue_t h = 0xab;
+ hashvalue_type h = 0xab;
h = hashlittle(&q->qtype, sizeof(q->qtype), h);
if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD))
h++;
@@ -617,7 +621,7 @@ query_info_hash(struct query_info *q, uint16_t flags)
struct msgreply_entry*
query_info_entrysetup(struct query_info* q, struct reply_info* r,
- hashvalue_t h)
+ hashvalue_type h)
{
struct msgreply_entry* e = (struct msgreply_entry*)malloc(
sizeof(struct msgreply_entry));
@@ -683,7 +687,7 @@ reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
if(!cp)
return NULL;
/* allocate ub_key structures special or not */
- if(!repinfo_alloc_rrset_keys(cp, alloc, region)) {
+ if(!reply_info_alloc_rrset_keys(cp, alloc, region)) {
if(!region)
reply_info_parsedelete(cp, alloc);
return NULL;
@@ -814,7 +818,39 @@ log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
regional_destroy(region);
}
-void
+void
+log_reply_info(enum verbosity_value v, struct query_info *qinf,
+ struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur,
+ int cached, struct sldns_buffer *rmsg)
+{
+ char qname_buf[LDNS_MAX_DOMAINLEN+1];
+ char clientip_buf[128];
+ char rcode_buf[16];
+ char type_buf[16];
+ char class_buf[16];
+ size_t pktlen;
+ uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2));
+
+ if(verbosity < v)
+ return;
+
+ sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf));
+ addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf));
+ if(rcode == LDNS_RCODE_FORMERR)
+ {
+ log_info("%s - - - %s - - - ", clientip_buf, rcode_buf);
+ } else {
+ dname_str(qinf->qname, qname_buf);
+ pktlen = sldns_buffer_limit(rmsg);
+ sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf));
+ sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf));
+ log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d",
+ clientip_buf, qname_buf, type_buf, class_buf,
+ rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen);
+ }
+}
+
+void
log_query_info(enum verbosity_value v, const char* str,
struct query_info* qinf)
{
@@ -857,3 +893,314 @@ reply_all_rrsets_secure(struct reply_info* rep)
}
return 1;
}
+
+int edns_opt_append(struct edns_data* edns, struct regional* region,
+ uint16_t code, size_t len, uint8_t* data)
+{
+ struct edns_option** prevp;
+ struct edns_option* opt;
+
+ /* allocate new element */
+ opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
+ if(!opt)
+ return 0;
+ opt->next = NULL;
+ opt->opt_code = code;
+ opt->opt_len = len;
+ opt->opt_data = NULL;
+ if(len > 0) {
+ opt->opt_data = regional_alloc_init(region, data, len);
+ if(!opt->opt_data)
+ return 0;
+ }
+
+ /* append at end of list */
+ prevp = &edns->opt_list;
+ while(*prevp != NULL)
+ prevp = &((*prevp)->next);
+ *prevp = opt;
+ return 1;
+}
+
+int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
+ uint8_t* data, struct regional* region)
+{
+ struct edns_option** prevp;
+ struct edns_option* opt;
+
+ /* allocate new element */
+ opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
+ if(!opt)
+ return 0;
+ opt->next = NULL;
+ opt->opt_code = code;
+ opt->opt_len = len;
+ opt->opt_data = NULL;
+ if(len > 0) {
+ opt->opt_data = regional_alloc_init(region, data, len);
+ if(!opt->opt_data)
+ return 0;
+ }
+
+ /* append at end of list */
+ prevp = list;
+ while(*prevp != NULL) {
+ prevp = &((*prevp)->next);
+ }
+ *prevp = opt;
+ return 1;
+}
+
+int edns_opt_list_remove(struct edns_option** list, uint16_t code)
+{
+ /* The list should already be allocated in a region. Freeing the
+ * allocated space in a region is not possible. We just unlink the
+ * required elements and they will be freed together with the region. */
+
+ struct edns_option* prev;
+ struct edns_option* curr;
+ if(!list || !(*list)) return 0;
+
+ /* Unlink and repoint if the element(s) are first in list */
+ while(list && *list && (*list)->opt_code == code) {
+ *list = (*list)->next;
+ }
+
+ if(!list || !(*list)) return 1;
+ /* Unlink elements and reattach the list */
+ prev = *list;
+ curr = (*list)->next;
+ while(curr != NULL) {
+ if(curr->opt_code == code) {
+ prev->next = curr->next;
+ curr = curr->next;
+ } else {
+ prev = curr;
+ curr = curr->next;
+ }
+ }
+ return 1;
+}
+
+static int inplace_cb_reply_call_generic(
+ struct inplace_cb* callback_list, enum inplace_cb_list_type type,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
+{
+ struct inplace_cb* cb;
+ struct edns_option* opt_list_out = NULL;
+ if(qstate)
+ opt_list_out = qstate->edns_opts_front_out;
+ for(cb=callback_list; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_reply_generic(
+ (inplace_cb_reply_func_type*)cb->cb, type));
+ (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
+ rcode, edns, &opt_list_out, region, cb->id, cb->cb_arg);
+ }
+ edns->opt_list = opt_list_out;
+ return 1;
+}
+
+int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
+ struct module_qstate* qstate, struct reply_info* rep, int rcode,
+ struct edns_data* edns, struct regional* region)
+{
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
+ qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_reply_cache_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
+{
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
+ qinfo, qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_reply_local_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
+{
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
+ qinfo, qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_reply_servfail_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
+{
+ /* We are going to servfail. Remove any potential edns options. */
+ if(qstate)
+ qstate->edns_opts_front_out = NULL;
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply_servfail],
+ inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
+ uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
+ struct regional* region)
+{
+ struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query];
+ for(; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_query(
+ (inplace_cb_query_func_type*)cb->cb));
+ (void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags,
+ qstate, addr, addrlen, zone, zonelen, region,
+ cb->id, cb->cb_arg);
+ }
+ return 1;
+}
+
+int inplace_cb_edns_back_parsed_call(struct module_env* env,
+ struct module_qstate* qstate)
+{
+ struct inplace_cb* cb =
+ env->inplace_cb_lists[inplace_cb_edns_back_parsed];
+ for(; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed(
+ (inplace_cb_edns_back_parsed_func_type*)cb->cb));
+ (void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate,
+ cb->id, cb->cb_arg);
+ }
+ return 1;
+}
+
+int inplace_cb_query_response_call(struct module_env* env,
+ struct module_qstate* qstate, struct dns_msg* response) {
+ struct inplace_cb* cb =
+ env->inplace_cb_lists[inplace_cb_query_response];
+ for(; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_query_response(
+ (inplace_cb_query_response_func_type*)cb->cb));
+ (void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate,
+ response, cb->id, cb->cb_arg);
+ }
+ return 1;
+}
+
+struct edns_option* edns_opt_copy_region(struct edns_option* list,
+ struct regional* region)
+{
+ struct edns_option* result = NULL, *cur = NULL, *s;
+ while(list) {
+ /* copy edns option structure */
+ s = regional_alloc_init(region, list, sizeof(*list));
+ if(!s) return NULL;
+ s->next = NULL;
+
+ /* copy option data */
+ if(s->opt_data) {
+ s->opt_data = regional_alloc_init(region, s->opt_data,
+ s->opt_len);
+ if(!s->opt_data)
+ return NULL;
+ }
+
+ /* link into list */
+ if(cur)
+ cur->next = s;
+ else result = s;
+ cur = s;
+
+ /* examine next element */
+ list = list->next;
+ }
+ return result;
+}
+
+int edns_opt_compare(struct edns_option* p, struct edns_option* q)
+{
+ if(!p && !q) return 0;
+ if(!p) return -1;
+ if(!q) return 1;
+ log_assert(p && q);
+ if(p->opt_code != q->opt_code)
+ return (int)q->opt_code - (int)p->opt_code;
+ if(p->opt_len != q->opt_len)
+ return (int)q->opt_len - (int)p->opt_len;
+ if(p->opt_len != 0)
+ return memcmp(p->opt_data, q->opt_data, p->opt_len);
+ return 0;
+}
+
+int edns_opt_list_compare(struct edns_option* p, struct edns_option* q)
+{
+ int r;
+ while(p && q) {
+ r = edns_opt_compare(p, q);
+ if(r != 0)
+ return r;
+ p = p->next;
+ q = q->next;
+ }
+ if(p || q) {
+ /* uneven length lists */
+ if(p) return 1;
+ if(q) return -1;
+ }
+ return 0;
+}
+
+void edns_opt_list_free(struct edns_option* list)
+{
+ struct edns_option* n;
+ while(list) {
+ free(list->opt_data);
+ n = list->next;
+ free(list);
+ list = n;
+ }
+}
+
+struct edns_option* edns_opt_copy_alloc(struct edns_option* list)
+{
+ struct edns_option* result = NULL, *cur = NULL, *s;
+ while(list) {
+ /* copy edns option structure */
+ s = memdup(list, sizeof(*list));
+ if(!s) {
+ edns_opt_list_free(result);
+ return NULL;
+ }
+ s->next = NULL;
+
+ /* copy option data */
+ if(s->opt_data) {
+ s->opt_data = memdup(s->opt_data, s->opt_len);
+ if(!s->opt_data) {
+ free(s);
+ edns_opt_list_free(result);
+ return NULL;
+ }
+ }
+
+ /* link into list */
+ if(cur)
+ cur->next = s;
+ else result = s;
+ cur = s;
+
+ /* examine next element */
+ list = list->next;
+ }
+ return result;
+}
+
+struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code)
+{
+ struct edns_option* p;
+ for(p=list; p; p=p->next) {
+ if(p->opt_code == code)
+ return p;
+ }
+ return NULL;
+}