/** apply config caps whitelist items to name tree */ static int caps_white_apply_cfg(rbtree_t* ntree, struct config_file* cfg) { struct config_strlist* p; for(p=cfg->caps_whitelist; p; p=p->next) { struct name_tree_node* n; size_t len; uint8_t* nm = sldns_str2wire_dname(p->str, &len); if(!nm) { log_err("could not parse %s", p->str); return 0; } n = (struct name_tree_node*)calloc(1, sizeof(*n)); if(!n) { log_err("out of memory"); free(nm); return 0; } n->node.key = n; n->name = nm; n->len = len; n->labs = dname_count_labels(nm); n->dclass = LDNS_RR_CLASS_IN; if(!name_tree_insert(ntree, n, nm, len, n->labs, n->dclass)) { /* duplicate element ignored, idempotent */ free(n->name); free(n); } } name_tree_init_parents(ntree); return 1; }
/* form wireformat from text format domain name */ int parse_dname(const char* str, uint8_t** res, size_t* len, int* labs) { *res = sldns_str2wire_dname(str, len); *labs = 0; if(!*res) { log_err("cannot parse name %s", str); return 0; } *labs = dname_count_size_labels(*res, len); return 1; }
/** * Insert insecure anchor * @param anchors: anchor storage. * @param str: the domain name. * @return NULL on error, Else last trust anchor point */ static struct trust_anchor* anchor_insert_insecure(struct val_anchors* anchors, const char* str) { struct trust_anchor* ta; size_t dname_len = 0; uint8_t* nm = sldns_str2wire_dname(str, &dname_len); if(!nm) { log_err("parse error in domain name '%s'", str); return NULL; } ta = anchor_store_new_key(anchors, nm, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, NULL, 0); free(nm); return ta; }
/** Store RTT in infra cache */ static void do_infra_rtt(struct replay_runtime* runtime) { struct replay_moment* now = runtime->now; int rto; size_t dplen = 0; uint8_t* dp = sldns_str2wire_dname(now->variable, &dplen); if(!dp) fatal_exit("cannot parse %s", now->variable); rto = infra_rtt_update(runtime->infra, &now->addr, now->addrlen, dp, dplen, LDNS_RR_TYPE_A, atoi(now->string), -1, runtime->now_secs); log_addr(0, "INFRA_RTT for", &now->addr, now->addrlen); log_info("INFRA_RTT(%s roundtrip %d): rto of %d", now->variable, atoi(now->string), rto); if(rto == 0) fatal_exit("infra_rtt_update failed"); free(dp); }
/** find or create element in domainlimit tree */ static struct domain_limit_data* domain_limit_findcreate( struct infra_cache* infra, char* name) { uint8_t* nm; int labs; size_t nmlen; struct domain_limit_data* d; /* parse name */ nm = sldns_str2wire_dname(name, &nmlen); if(!nm) { log_err("could not parse %s", name); return NULL; } labs = dname_count_labels(nm); /* can we find it? */ d = (struct domain_limit_data*)name_tree_find(&infra->domain_limits, nm, nmlen, labs, LDNS_RR_CLASS_IN); if(d) { free(nm); return d; } /* create it */ d = (struct domain_limit_data*)calloc(1, sizeof(*d)); if(!d) { free(nm); return NULL; } d->node.node.key = &d->node; d->node.name = nm; d->node.len = nmlen; d->node.labs = labs; d->node.dclass = LDNS_RR_CLASS_IN; d->lim = -1; d->below = -1; if(!name_tree_insert(&infra->domain_limits, &d->node, nm, nmlen, labs, LDNS_RR_CLASS_IN)) { log_err("duplicate element in domainlimit tree"); free(nm); free(d); return NULL; } return d; }
/** parse a query line to a packet into buffer */ static int qlist_parse_line(sldns_buffer* buf, char* p) { char nm[1024], cl[1024], tp[1024], fl[1024]; int r; int rec = 1, edns = 0; struct query_info qinfo; nm[0] = 0; cl[0] = 0; tp[0] = 0; fl[0] = 0; r = sscanf(p, " %1023s %1023s %1023s %1023s", nm, cl, tp, fl); if(r != 3 && r != 4) return 0; /*printf("nm='%s', cl='%s', tp='%s', fl='%s'\n", nm, cl, tp, fl);*/ if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0) { qinfo.qtype = sldns_get_rr_type_by_name(cl); qinfo.qclass = sldns_get_rr_class_by_name(tp); } else { qinfo.qtype = sldns_get_rr_type_by_name(tp); qinfo.qclass = sldns_get_rr_class_by_name(cl); } if(fl[0] == '+') rec = 1; else if(fl[0] == '-') rec = 0; else if(fl[0] == 'E') edns = 1; if((fl[0] == '+' || fl[0] == '-') && fl[1] == 'E') edns = 1; qinfo.qname = sldns_str2wire_dname(nm, &qinfo.qname_len); if(!qinfo.qname) return 0; qinfo_query_encode(buf, &qinfo); sldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */ if(rec) LDNS_RD_SET(sldns_buffer_begin(buf)); if(edns) { struct edns_data ed; memset(&ed, 0, sizeof(ed)); ed.edns_present = 1; ed.udp_size = EDNS_ADVERTISED_SIZE; /* Set DO bit in all EDNS datagrams ... */ ed.bits = EDNS_DO; attach_edns_record(buf, &ed); } free(qinfo.qname); return 1; }
/** setup qinfo and edns */ static int setup_qinfo_edns(struct libworker* w, struct ctx_query* q, struct query_info* qinfo, struct edns_data* edns) { qinfo->qtype = (uint16_t)q->res->qtype; qinfo->qclass = (uint16_t)q->res->qclass; qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len); if(!qinfo->qname) { return 0; } edns->edns_present = 1; edns->ext_rcode = 0; edns->edns_version = 0; edns->bits = EDNS_DO; if(sldns_buffer_capacity(w->back->udp_buff) < 65535) edns->udp_size = (uint16_t)sldns_buffer_capacity( w->back->udp_buff); else edns->udp_size = 65535; return 1; }
/** add hint to delegation hints */ static int ah(struct delegpt* dp, const char* sv, const char* ip) { struct sockaddr_storage addr; socklen_t addrlen; size_t dname_len; uint8_t* dname = sldns_str2wire_dname(sv, &dname_len); if(!dname) { log_err("could not parse %s", sv); return 0; } if(!delegpt_add_ns_mlc(dp, dname, 0) || !extstrtoaddr(ip, &addr, &addrlen) || !delegpt_add_target_mlc(dp, dname, dname_len, &addr, addrlen, 0, 0)) { free(dname); return 0; } free(dname); return 1; }
/** set stub host names */ static int read_stubs_host(struct config_stub* s, struct delegpt* dp) { struct config_strlist* p; size_t dname_len; uint8_t* dname; for(p = s->hosts; p; p = p->next) { log_assert(p->str); dname = sldns_str2wire_dname(p->str, &dname_len); if(!dname) { log_err("cannot parse stub %s nameserver name: '%s'", s->name, p->str); return 0; } if(!delegpt_add_ns_mlc(dp, dname, 0)) { free(dname); log_err("out of memory"); return 0; } free(dname); } return 1; }
/** set stub name */ static struct delegpt* read_stubs_name(struct config_stub* s) { struct delegpt* dp; size_t dname_len; uint8_t* dname; if(!s->name) { log_err("stub zone without a name"); return NULL; } dname = sldns_str2wire_dname(s->name, &dname_len); if(!dname) { log_err("cannot parse stub zone name %s", s->name); return NULL; } if(!(dp=delegpt_create_mlc(dname))) { free(dname); log_err("out of memory"); return NULL; } free(dname); return dp; }
/** write a query over the TCP fd */ static void write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, const char* strname, const char* strtype, const char* strclass) { struct query_info qinfo; uint16_t len; /* qname */ qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len); if(!qinfo.qname) { printf("cannot parse query name: '%s'\n", strname); exit(1); } /* qtype and qclass */ qinfo.qtype = sldns_get_rr_type_by_name(strtype); qinfo.qclass = sldns_get_rr_class_by_name(strclass); /* make query */ qinfo_query_encode(buf, &qinfo); sldns_buffer_write_u16_at(buf, 0, id); sldns_buffer_write_u16_at(buf, 2, BIT_RD); if(1) { /* add EDNS DO */ struct edns_data edns; memset(&edns, 0, sizeof(edns)); edns.edns_present = 1; edns.bits = EDNS_DO; edns.udp_size = 4096; attach_edns_record(buf, &edns); } /* send it */ if(!udp) { len = (uint16_t)sldns_buffer_limit(buf); len = htons(len); if(ssl) { if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) { log_crypto_err("cannot SSL_write"); exit(1); } } else { if(send(fd, (void*)&len, sizeof(len), 0) < (ssize_t)sizeof(len)){ #ifndef USE_WINSOCK perror("send() len failed"); #else printf("send len: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } } if(ssl) { if(SSL_write(ssl, (void*)sldns_buffer_begin(buf), (int)sldns_buffer_limit(buf)) <= 0) { log_crypto_err("cannot SSL_write"); exit(1); } } else { if(send(fd, (void*)sldns_buffer_begin(buf), sldns_buffer_limit(buf), 0) < (ssize_t)sldns_buffer_limit(buf)) { #ifndef USE_WINSOCK perror("send() data failed"); #else printf("send data: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } free(qinfo.qname); }