size_t nsec3_get_hashed(ldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max) { size_t i, hash_len; /* prepare buffer for first iteration */ ldns_buffer_clear(buf); ldns_buffer_write(buf, nm, nmlen); query_dname_tolower(ldns_buffer_begin(buf)); ldns_buffer_write(buf, salt, saltlen); ldns_buffer_flip(buf); switch(algo) { #if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS) case NSEC3_HASH_SHA1: #ifdef HAVE_SSL hash_len = SHA_DIGEST_LENGTH; #else hash_len = SHA1_LENGTH; #endif if(hash_len > max) return 0; # ifdef HAVE_SSL (void)SHA1((unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf), (unsigned char*)res); # else (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)res, (unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf)); # endif for(i=0; i<iter; i++) { ldns_buffer_clear(buf); ldns_buffer_write(buf, res, hash_len); ldns_buffer_write(buf, salt, saltlen); ldns_buffer_flip(buf); # ifdef HAVE_SSL (void)SHA1( (unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf), (unsigned char*)res); # else (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)res, (unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf)); # endif } break; #endif /* HAVE_EVP_SHA1 or NSS */ default: log_err("nsec3 hash of unknown algo %d", algo); return 0; } return hash_len; }
void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) { /* not particularly fast but flexible, make wireformat and print */ ldns_buffer* buf = ldns_buffer_new(65535); struct regional* region = regional_create(); if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, region, 65535, 1)) { log_info("%s: log_dns_msg: out of memory", str); } else { ldns_status s; ldns_pkt* pkt = NULL; s = ldns_buffer2pkt_wire(&pkt, buf); if(s != LDNS_STATUS_OK) { log_info("%s: log_dns_msg: ldns parse gave: %s", str, ldns_get_errorstr_by_id(s)); } else { ldns_buffer_clear(buf); s = ldns_pkt2buffer_str(buf, pkt); if(s != LDNS_STATUS_OK) { log_info("%s: log_dns_msg: ldns tostr gave: %s", str, ldns_get_errorstr_by_id(s)); } else { log_info("%s %s", str, (char*)ldns_buffer_begin(buf)); } } ldns_pkt_free(pkt); } ldns_buffer_free(buf); regional_destroy(region); }
/** * Fill CH class answer into buffer. Keeps query. * @param pkt: buffer * @param str: string to put into text record (<255). * @param edns: edns reply information. */ static void chaos_replystr(ldns_buffer* pkt, const char* str, struct edns_data* edns) { size_t len = strlen(str); unsigned int rd = LDNS_RD_WIRE(ldns_buffer_begin(pkt)); unsigned int cd = LDNS_CD_WIRE(ldns_buffer_begin(pkt)); if(len>255) len=255; /* cap size of TXT record */ ldns_buffer_clear(pkt); ldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ ldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); if(rd) LDNS_RD_SET(ldns_buffer_begin(pkt)); if(cd) LDNS_CD_SET(ldns_buffer_begin(pkt)); ldns_buffer_write_u16(pkt, 1); /* qdcount */ ldns_buffer_write_u16(pkt, 1); /* ancount */ ldns_buffer_write_u16(pkt, 0); /* nscount */ ldns_buffer_write_u16(pkt, 0); /* arcount */ (void)query_dname_len(pkt); /* skip qname */ ldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ ldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ ldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); ldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); ldns_buffer_write_u32(pkt, 0); /* TTL */ ldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); ldns_buffer_write_u8(pkt, len); ldns_buffer_write(pkt, str, len); ldns_buffer_flip(pkt); edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->bits &= EDNS_DO; attach_edns_record(pkt, edns); }
/** * Create a DS digest for a DNSKEY entry. * * @param env: module environment. Uses scratch space. * @param dnskey_rrset: DNSKEY rrset. * @param dnskey_idx: index of RR in rrset. * @param ds_rrset: DS rrset * @param ds_idx: index of RR in DS rrset. * @param digest: digest is returned in here (must be correctly sized). * @return false on error. */ static int ds_create_dnskey_digest(struct module_env* env, struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx, struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, uint8_t* digest) { ldns_buffer* b = env->scratch_buffer; uint8_t* dnskey_rdata; size_t dnskey_len; rrset_get_rdata(dnskey_rrset, dnskey_idx, &dnskey_rdata, &dnskey_len); /* create digest source material in buffer * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */ ldns_buffer_clear(b); ldns_buffer_write(b, dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len); query_dname_tolower(ldns_buffer_begin(b)); ldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/ ldns_buffer_flip(b); return secalgo_ds_digest(ds_get_digest_algo(ds_rrset, ds_idx), (unsigned char*)ldns_buffer_begin(b), ldns_buffer_limit(b), (unsigned char*)digest); }
/** * Add new RR. It converts ldns RR to wire format. * @param anchors: anchor storage. * @param buffer: parsing buffer. * @param rr: the rr (allocated by caller). * @return NULL on error, else the trust anchor. */ static struct trust_anchor* anchor_store_new_rr(struct val_anchors* anchors, ldns_buffer* buffer, ldns_rr* rr) { struct trust_anchor* ta; ldns_rdf* owner = ldns_rr_owner(rr); ldns_status status; ldns_buffer_clear(buffer); ldns_buffer_skip(buffer, 2); /* skip rdatalen */ status = ldns_rr_rdata2buffer_wire(buffer, rr); if(status != LDNS_STATUS_OK) { log_err("error converting trustanchor to wireformat: %s", ldns_get_errorstr_by_id(status)); return NULL; } ldns_buffer_flip(buffer); ldns_buffer_write_u16_at(buffer, 0, ldns_buffer_limit(buffer) - 2); if(!(ta=anchor_store_new_key(anchors, ldns_rdf_data(owner), ldns_rr_get_type(rr), ldns_rr_get_class(rr), ldns_buffer_begin(buffer), ldns_buffer_limit(buffer)))) { return NULL; } log_nametypeclass(VERB_QUERY, "adding trusted key", ldns_rdf_data(owner), ldns_rr_get_type(rr), ldns_rr_get_class(rr)); return ta; }
/** * Fill buffer with reply from the entry. */ static void fill_buffer_with_reply(ldns_buffer* buffer, struct entry* entry, ldns_pkt* q) { ldns_status status; ldns_pkt* answer_pkt = NULL; log_assert(entry && entry->reply_list); ldns_buffer_clear(buffer); if(entry->reply_list->reply_from_hex) { status = ldns_buffer2pkt_wire(&answer_pkt, entry->reply_list->reply_from_hex); if(status != LDNS_STATUS_OK) { log_err("testbound: hex packet unparsable, used asis."); ldns_buffer_write(buffer, ldns_buffer_begin(entry->reply_list->reply_from_hex), ldns_buffer_limit(entry->reply_list->reply_from_hex)); } } else { answer_pkt = ldns_pkt_clone(entry->reply_list->reply); } if(answer_pkt) { if(q) adjust_packet(entry, answer_pkt, q); status = ldns_pkt2buffer_wire(buffer, answer_pkt); if(status != LDNS_STATUS_OK) fatal_exit("ldns: cannot pkt2buffer_wire parsed pkt"); } ldns_pkt_free(answer_pkt); ldns_buffer_flip(buffer); }
/** * Read a BIND9 like file with trust anchors in named.conf format. * @param anchors: anchor storage. * @param buffer: parsing buffer. * @param fname: string. * @return false on error. */ static int anchor_read_bind_file(struct val_anchors* anchors, ldns_buffer* buffer, const char* fname) { int line_nr = 1; FILE* in = fopen(fname, "r"); int rdlen = 0; if(!in) { log_err("error opening file %s: %s", fname, strerror(errno)); return 0; } verbose(VERB_QUERY, "reading in bind-compat-mode: '%s'", fname); /* scan for trusted-keys keyword, ignore everything else */ ldns_buffer_clear(buffer); while((rdlen=readkeyword_bindfile(in, buffer, &line_nr, 1)) != 0) { if(rdlen != 12 || strncmp((char*)ldns_buffer_begin(buffer), "trusted-keys", 12) != 0) { ldns_buffer_clear(buffer); /* ignore everything but trusted-keys */ continue; } if(!skip_to_special(in, buffer, &line_nr, '{')) { log_err("error in trusted key: \"%s\"", fname); fclose(in); return 0; } /* process contents */ if(!process_bind_contents(anchors, buffer, &line_nr, in)) { log_err("error in trusted key: \"%s\"", fname); fclose(in); return 0; } if(!skip_to_special(in, buffer, &line_nr, ';')) { log_err("error in trusted key: \"%s\"", fname); fclose(in); return 0; } ldns_buffer_clear(buffer); } fclose(in); return 1; }
void ldns_buffer_copy(ldns_buffer* result, ldns_buffer* from) { size_t tocopy = ldns_buffer_limit(from); if(tocopy > ldns_buffer_capacity(result)) tocopy = ldns_buffer_capacity(result); ldns_buffer_clear(result); ldns_buffer_write(result, ldns_buffer_begin(from), tocopy); ldns_buffer_flip(result); }
/** skip through file to { or ; */ static int skip_to_special(FILE* in, ldns_buffer* buf, int* line, int spec) { int rdlen; ldns_buffer_clear(buf); while((rdlen=readkeyword_bindfile(in, buf, line, 1))) { if(rdlen == 1 && isspace((int)*ldns_buffer_begin(buf))) { ldns_buffer_clear(buf); continue; } if(rdlen != 1 || *ldns_buffer_begin(buf) != (uint8_t)spec) { ldns_buffer_write_u8(buf, 0); log_err("trusted-keys, line %d, expected %c", *line, spec); return 0; } return 1; } log_err("trusted-keys, line %d, expected %c got EOF", *line, spec); return 0; }
/** * Create canonical form of rrset in the scratch buffer. * @param region: temporary region. * @param buf: the buffer to use. * @param k: the rrset to insert. * @param sig: RRSIG rdata to include. * @param siglen: RRSIG rdata len excluding signature field, but inclusive * signer name length. * @param sortree: if NULL is passed a new sorted rrset tree is built. * Otherwise it is reused. * @return false on alloc error. */ static int rrset_canonical(struct regional* region, ldns_buffer* buf, struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen, struct rbtree_t** sortree) { struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; uint8_t* can_owner = NULL; size_t can_owner_len = 0; struct canon_rr* walk; struct canon_rr* rrs; if(!*sortree) { *sortree = (struct rbtree_t*)regional_alloc(region, sizeof(rbtree_t)); if(!*sortree) return 0; rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count); if(!rrs) { *sortree = NULL; return 0; } rbtree_init(*sortree, &canonical_tree_compare); canonical_sort(k, d, *sortree, rrs); } ldns_buffer_clear(buf); ldns_buffer_write(buf, sig, siglen); /* canonicalize signer name */ query_dname_tolower(ldns_buffer_begin(buf)+18); RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { /* see if there is enough space left in the buffer */ if(ldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { log_err("verify: failed to canonicalize, " "rrset too big"); return 0; } /* determine canonical owner name */ if(can_owner) ldns_buffer_write(buf, can_owner, can_owner_len); else insert_can_owner(buf, k, sig, &can_owner, &can_owner_len); ldns_buffer_write(buf, &k->rk.type, 2); ldns_buffer_write(buf, &k->rk.rrset_class, 2); ldns_buffer_write(buf, sig+4, 4); ldns_buffer_write(buf, d->rr_data[walk->rr_idx], d->rr_len[walk->rr_idx]); canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]); } ldns_buffer_flip(buf); return 1; }
void qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo) { uint16_t flags = 0; /* QUERY, NOERROR */ ldns_buffer_clear(pkt); log_assert(ldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); ldns_buffer_skip(pkt, 2); /* id done later */ ldns_buffer_write_u16(pkt, flags); ldns_buffer_write_u16(pkt, 1); /* query count */ ldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ ldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len); ldns_buffer_write_u16(pkt, qinfo->qtype); ldns_buffer_write_u16(pkt, qinfo->qclass); ldns_buffer_flip(pkt); }
/** read qinfo from next three words */ static char* load_qinfo(char* str, struct query_info* qinfo, ldns_buffer* buf, struct regional* region) { /* s is part of the buf */ char* s = str; ldns_rr* rr; ldns_status status; /* skip three words */ s = strchr(str, ' '); if(s) s = strchr(s+1, ' '); if(s) s = strchr(s+1, ' '); if(!s) { log_warn("error line too short, %s", str); return NULL; } s[0] = 0; s++; /* parse them */ status = ldns_rr_new_question_frm_str(&rr, str, NULL, NULL); if(status != LDNS_STATUS_OK) { log_warn("error cannot parse: %s %s", ldns_get_errorstr_by_id(status), str); return NULL; } qinfo->qtype = ldns_rr_get_type(rr); qinfo->qclass = ldns_rr_get_class(rr); ldns_buffer_clear(buf); status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr)); ldns_rr_free(rr); if(status != LDNS_STATUS_OK) { log_warn("error cannot dname2wire: %s", ldns_get_errorstr_by_id(status)); return NULL; } ldns_buffer_flip(buf); qinfo->qname_len = ldns_buffer_limit(buf); qinfo->qname = (uint8_t*)regional_alloc_init(region, ldns_buffer_begin(buf), ldns_buffer_limit(buf)); if(!qinfo->qname) { log_warn("error out of memory"); return NULL; } return s; }
int nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* rrset, int rr, ldns_buffer* buf) { uint8_t* next, *owner; size_t nextlen; int len; if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen)) return 0; /* malformed RR proves nothing */ /* check the owner name is a hashed value . apex * base32 encoded values must have equal length. * hash_value and next hash value must have equal length. */ if(nextlen != hash->hash_len || hash->hash_len==0||hash->b32_len==0|| (size_t)*rrset->rk.dname != hash->b32_len || query_dname_compare(rrset->rk.dname+1+ (size_t)*rrset->rk.dname, zone) != 0) return 0; /* bad lengths or owner name */ /* This is the "normal case: owner < next and owner < hash < next */ if(label_compare_lower(rrset->rk.dname+1, hash->b32, hash->b32_len) < 0 && memcmp(hash->hash, next, nextlen) < 0) return 1; /* convert owner name from text to binary */ ldns_buffer_clear(buf); owner = ldns_buffer_begin(buf); len = ldns_b32_pton_extended_hex((char*)rrset->rk.dname+1, hash->b32_len, owner, ldns_buffer_limit(buf)); if(len<1) return 0; /* bad owner name in some way */ if((size_t)len != hash->hash_len || (size_t)len != nextlen) return 0; /* wrong length */ /* this is the end of zone case: next <= owner && * (hash > owner || hash < next) * this also covers the only-apex case of next==owner. */ if(memcmp(next, owner, nextlen) <= 0 && ( memcmp(hash->hash, owner, nextlen) > 0 || memcmp(hash->hash, next, nextlen) < 0)) { return 1; } return 0; }
/** * callback results to mesh cb entry * @param m: mesh state to send it for. * @param rcode: if not 0, error code. * @param rep: reply to send (or NULL if rcode is set). * @param r: callback entry */ static void mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, struct mesh_cb* r) { int secure; char* reason = NULL; /* bogus messages are not made into servfail, sec_status passed * to the callback function */ if(rep && rep->security == sec_status_secure) secure = 1; else secure = 0; if(!rep && rcode == LDNS_RCODE_NOERROR) rcode = LDNS_RCODE_SERVFAIL; if(!rcode && rep->security == sec_status_bogus) { if(!(reason = errinf_to_str(&m->s))) rcode = LDNS_RCODE_SERVFAIL; } /* send the reply */ if(rcode) { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL); } else { size_t udp_size = r->edns.udp_size; ldns_buffer_clear(r->buf); r->edns.edns_version = EDNS_ADVERTISED_VERSION; r->edns.udp_size = EDNS_ADVERTISED_SIZE; r->edns.ext_rcode = 0; r->edns.bits &= EDNS_DO; if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid, r->qflags, r->buf, 0, 1, m->s.env->scratch, udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO), secure)) { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf, sec_status_unchecked, NULL); } else { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf, rep->security, reason); } } free(reason); m->s.env->mesh->num_reply_addrs--; }
/** perform b32 encoding of hash */ static int nsec3_calc_b32(struct regional* region, ldns_buffer* buf, struct nsec3_cached_hash* c) { int r; ldns_buffer_clear(buf); r = ldns_b32_ntop_extended_hex(c->hash, c->hash_len, (char*)ldns_buffer_begin(buf), ldns_buffer_limit(buf)); if(r < 1) { log_err("b32_ntop_extended_hex: error in encoding: %d", r); return 0; } c->b32_len = (size_t)r; c->b32 = regional_alloc_init(region, ldns_buffer_begin(buf), c->b32_len); if(!c->b32) return 0; return 1; }
void attach_edns_record(ldns_buffer* pkt, struct edns_data* edns) { size_t len; if(!edns || !edns->edns_present) return; /* inc additional count */ ldns_buffer_write_u16_at(pkt, 10, ldns_buffer_read_u16_at(pkt, 10) + 1); len = ldns_buffer_limit(pkt); ldns_buffer_clear(pkt); ldns_buffer_set_position(pkt, len); /* write EDNS record */ ldns_buffer_write_u8(pkt, 0); /* '.' label */ ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ ldns_buffer_write_u16(pkt, edns->udp_size); /* class */ ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ ldns_buffer_write_u8(pkt, edns->edns_version); ldns_buffer_write_u16(pkt, edns->bits); ldns_buffer_write_u16(pkt, 0); /* rdatalen */ ldns_buffer_flip(pkt); }
void error_encode(ldns_buffer* buf, int r, struct query_info* qinfo, uint16_t qid, uint16_t qflags, struct edns_data* edns) { uint16_t flags; ldns_buffer_clear(buf); ldns_buffer_write(buf, &qid, sizeof(uint16_t)); flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/ flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ ldns_buffer_write_u16(buf, flags); if(qinfo) flags = 1; else flags = 0; ldns_buffer_write_u16(buf, flags); flags = 0; ldns_buffer_write(buf, &flags, sizeof(uint16_t)); ldns_buffer_write(buf, &flags, sizeof(uint16_t)); ldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { if(ldns_buffer_current(buf) == qinfo->qname) ldns_buffer_skip(buf, (ssize_t)qinfo->qname_len); else ldns_buffer_write(buf, qinfo->qname, qinfo->qname_len); ldns_buffer_write_u16(buf, qinfo->qtype); ldns_buffer_write_u16(buf, qinfo->qclass); } ldns_buffer_flip(buf); if(edns) { struct edns_data es = *edns; es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; es.ext_rcode = 0; es.bits &= EDNS_DO; if(ldns_buffer_limit(buf) + calc_edns_field_size(&es) > edns->udp_size) return; attach_edns_record(buf, &es); } }
/** entry to packet buffer with wireformat */ static void entry_to_buf(struct entry* e, ldns_buffer* pkt) { unit_assert(e->reply_list); if(e->reply_list->reply_from_hex) { ldns_buffer_copy(pkt, e->reply_list->reply_from_hex); } else { ldns_status status; size_t answer_size; uint8_t* ans = NULL; status = ldns_pkt2wire(&ans, e->reply_list->reply, &answer_size); if(status != LDNS_STATUS_OK) { log_err("could not create reply: %s", ldns_get_errorstr_by_id(status)); fatal_exit("error in test"); } ldns_buffer_clear(pkt); ldns_buffer_write(pkt, ans, answer_size); ldns_buffer_flip(pkt); free(ans); } }
/** load an RR into rrset */ static int load_rr(SSL* ssl, ldns_buffer* buf, struct regional* region, struct ub_packed_rrset_key* rk, struct packed_rrset_data* d, unsigned int i, int is_rrsig, int* go_on, uint32_t now) { ldns_rr* rr; ldns_status status; /* read the line */ if(!ssl_read_buf(ssl, buf)) return 0; if(strncmp((char*)ldns_buffer_begin(buf), "BADRR\n", 6) == 0) { *go_on = 0; return 1; } status = ldns_rr_new_frm_str(&rr, (char*)ldns_buffer_begin(buf), LDNS_DEFAULT_TTL, NULL, NULL); if(status != LDNS_STATUS_OK) { log_warn("error cannot parse rr: %s: %s", ldns_get_errorstr_by_id(status), (char*)ldns_buffer_begin(buf)); return 0; } if(is_rrsig && ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { log_warn("error expected rrsig but got %s", (char*)ldns_buffer_begin(buf)); return 0; } /* convert ldns rr into packed_rr */ d->rr_ttl[i] = ldns_rr_ttl(rr) + now; ldns_buffer_clear(buf); ldns_buffer_skip(buf, 2); status = ldns_rr_rdata2buffer_wire(buf, rr); if(status != LDNS_STATUS_OK) { log_warn("error cannot rr2wire: %s", ldns_get_errorstr_by_id(status)); ldns_rr_free(rr); return 0; } ldns_buffer_flip(buf); ldns_buffer_write_u16_at(buf, 0, ldns_buffer_limit(buf) - 2); d->rr_len[i] = ldns_buffer_limit(buf); d->rr_data[i] = (uint8_t*)regional_alloc_init(region, ldns_buffer_begin(buf), ldns_buffer_limit(buf)); if(!d->rr_data[i]) { ldns_rr_free(rr); log_warn("error out of memory"); return 0; } /* if first entry, fill the key structure */ if(i==0) { rk->rk.type = htons(ldns_rr_get_type(rr)); rk->rk.rrset_class = htons(ldns_rr_get_class(rr)); ldns_buffer_clear(buf); status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr)); if(status != LDNS_STATUS_OK) { log_warn("error cannot dname2buffer: %s", ldns_get_errorstr_by_id(status)); ldns_rr_free(rr); return 0; } ldns_buffer_flip(buf); rk->rk.dname_len = ldns_buffer_limit(buf); rk->rk.dname = regional_alloc_init(region, ldns_buffer_begin(buf), ldns_buffer_limit(buf)); if(!rk->rk.dname) { log_warn("error out of memory"); ldns_rr_free(rr); return 0; } } ldns_rr_free(rr); return 1; }
/** * read contents of trusted-keys{ ... ; clauses and insert keys into storage. * @param anchors: where to store keys * @param buf: buffer to use * @param line: line number in file * @param in: file to read from. * @return 0 on error. */ static int process_bind_contents(struct val_anchors* anchors, ldns_buffer* buf, int* line, FILE* in) { /* loop over contents, collate strings before ; */ /* contents is (numbered): 0 1 2 3 4 5 6 7 8 */ /* name. 257 3 5 base64 base64 */ /* quoted value: 0 "111" 0 0 0 0 0 0 0 */ /* comments value: 1 "000" 1 1 1 "0 0 0 0" 1 */ int contnum = 0; int quoted = 0; int comments = 1; int rdlen; char* str = 0; ldns_buffer_clear(buf); while((rdlen=readkeyword_bindfile(in, buf, line, comments))) { if(rdlen == 1 && ldns_buffer_position(buf) == 1 && isspace((int)*ldns_buffer_begin(buf))) { /* starting whitespace is removed */ ldns_buffer_clear(buf); continue; } else if(rdlen == 1 && ldns_buffer_current(buf)[-1] == '"') { /* remove " from the string */ if(contnum == 0) { quoted = 1; comments = 0; } ldns_buffer_skip(buf, -1); if(contnum > 0 && quoted) { if(ldns_buffer_remaining(buf) < 8+1) { log_err("line %d, too long", *line); return 0; } ldns_buffer_write(buf, " DNSKEY ", 8); quoted = 0; comments = 1; } else if(contnum > 0) comments = !comments; continue; } else if(rdlen == 1 && ldns_buffer_current(buf)[-1] == ';') { if(contnum < 5) { ldns_buffer_write_u8(buf, 0); log_err("line %d, bad key", *line); return 0; } ldns_buffer_skip(buf, -1); ldns_buffer_write_u8(buf, 0); str = strdup((char*)ldns_buffer_begin(buf)); if(!str) { log_err("line %d, allocation failure", *line); return 0; } if(!anchor_store_str(anchors, buf, str)) { log_err("line %d, bad key", *line); free(str); return 0; } free(str); ldns_buffer_clear(buf); contnum = 0; quoted = 0; comments = 1; continue; } else if(rdlen == 1 && ldns_buffer_current(buf)[-1] == '}') { if(contnum > 0) { ldns_buffer_write_u8(buf, 0); log_err("line %d, bad key before }", *line); return 0; } return 1; } else if(rdlen == 1 && isspace((int)ldns_buffer_current(buf)[-1])) { /* leave whitespace here */ } else { /* not space or whatnot, so actual content */ contnum ++; if(contnum == 1 && !quoted) { if(ldns_buffer_remaining(buf) < 8+1) { log_err("line %d, too long", *line); return 0; } ldns_buffer_write(buf, " DNSKEY ", 8); } } } log_err("line %d, EOF before }", *line); return 0; }
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, struct regional* region, uint16_t udpsize, int dnssec) { uint16_t ancount=0, nscount=0, arcount=0; struct compress_tree_node* tree = 0; int r; size_t rr_offset; ldns_buffer_clear(buffer); if(udpsize < ldns_buffer_limit(buffer)) ldns_buffer_set_limit(buffer, udpsize); if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) return 0; ldns_buffer_write(buffer, &id, sizeof(uint16_t)); ldns_buffer_write_u16(buffer, flags); ldns_buffer_write_u16(buffer, rep->qdcount); /* set an, ns, ar counts to zero in case of small packets */ ldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); /* insert query section */ if(rep->qdcount) { if((r=insert_query(qinfo, &tree, buffer, region)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 4, 0); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } } /* roundrobin offset. using query id for random number */ rr_offset = RRSET_ROUNDROBIN?id:0; /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 6, ancount); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 6, ancount); /* if response is positive answer, auth/add sections are not required */ if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) { /* insert auth section */ if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, rep->an_numrrsets, timenow, region, &tree, LDNS_SECTION_AUTHORITY, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 8, nscount); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 8, nscount); /* insert add section */ if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, rep->an_numrrsets + rep->ns_numrrsets, timenow, region, &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* no need to set TC bit, this is the additional */ ldns_buffer_write_u16_at(buffer, 10, arcount); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 10, arcount); } else { ldns_buffer_write_u16_at(buffer, 8, nscount); ldns_buffer_write_u16_at(buffer, 10, arcount); } ldns_buffer_flip(buffer); return 1; }
int cache_dns_objects(packetinfo *pi, ldns_rdf *rdf_data, ldns_buffer *buff, ldns_pkt *dns_pkt) { int j; int dns_answer_domain_cnt; uint64_t dnshash; ldns_status status; pdns_record *pr = NULL; ldns_rr_list *dns_answer_domains; unsigned char *domain_name = 0; ldns_buffer_clear(buff); status = ldns_rdf2buffer_str(buff, rdf_data); if (status != LDNS_STATUS_OK) { dlog("[D] Error in ldns_rdf2buffer_str(): %d\n", status); return(-1); } dns_answer_domains = ldns_pkt_answer(dns_pkt); dns_answer_domain_cnt = ldns_rr_list_rr_count(dns_answer_domains); domain_name = (unsigned char *) ldns_buffer2str(buff); if (domain_name == NULL) { dlog("[D] Error in ldns_buffer2str(%p)\n", buff); return(-1); } else { dlog("[D] domain_name: %s\n", domain_name); dlog("[D] dns_answer_domain_cnt: %d\n",dns_answer_domain_cnt); } if (dns_answer_domain_cnt == 0 && ldns_pkt_get_rcode(dns_pkt) != 0) { uint16_t rcode = ldns_pkt_get_rcode(dns_pkt); dlog("[D] Error return code: %d\n", rcode); /* PROBLEM: * As there is no valid ldns_rr here and we cant fake one that will * be very unique, we cant push this to the normal * bucket[hash->linked_list]. We should probably allocate a static * bucket[MAX_NXDOMAIN] to hold NXDOMAINS, and when that is full, pop * out the oldest (LRU). A simple script quering for random non existing * domains could easly put stress on passivedns (think conficker etc.) * if the bucket is to big or non efficient. We would still store data * such as: fistseen,lastseen,client_ip,server_ip,class,query,NXDOMAIN */ if (config.dnsfe & (pdns_chk_dnsfe(rcode))) { ldns_rr_list *dns_query_domains; ldns_rr_class class; ldns_rr_type type; ldns_rr *rr; dnshash = hash(domain_name); dlog("[D] Hash: %lu\n", dnshash); /* Check if the node exists, if not, make it */ pr = get_pdns_record(dnshash, pi, domain_name); /* Set the SRC flag: */ //lname_node->srcflag |= pdns_chk_dnsfe(rcode); dns_query_domains = ldns_pkt_question(dns_pkt); rr = ldns_rr_list_rr(dns_query_domains, 0); class = ldns_rr_get_class(rr); type = ldns_rr_get_type(rr); if ((pr->last_seen.tv_sec - pr->last_print.tv_sec) >= config.dnsprinttime) { /* Print the SRC Error record */ print_passet_err(pr, rdf_data, rr, rcode); } } else {
int cache_dns_objects(packetinfo *pi, ldns_rdf *rdf_data, ldns_buffer *buff, ldns_pkt *dns_pkt) { int j; int dns_answer_domain_cnt; uint64_t dnshash; ldns_status status; pdns_record *pr = NULL; ldns_rr_list *dns_answer_domains; unsigned char *domain_name = 0; ldns_buffer_clear(buff); status = ldns_rdf2buffer_str(buff, rdf_data); if (status != LDNS_STATUS_OK) { dlog("[D] Error in ldns_rdf2buffer_str(): %d\n", status); return -1; } dns_answer_domains = ldns_pkt_answer(dns_pkt); dns_answer_domain_cnt = ldns_rr_list_rr_count(dns_answer_domains); domain_name = (unsigned char *) ldns_buffer2str(buff); if (domain_name == NULL) { dlog("[D] Error in ldns_buffer2str(%p)\n", buff); return -1; } else { dlog("[D] domain_name: %s\n", domain_name); dlog("[D] dns_answer_domain_cnt: %d\n",dns_answer_domain_cnt); } if (dns_answer_domain_cnt == 0 && ldns_pkt_get_rcode(dns_pkt) != 0) { uint16_t rcode = ldns_pkt_get_rcode(dns_pkt); dlog("[D] Error return code: %d\n", rcode); /* PROBLEM: * As there is no valid ldns_rr here and we can't fake one that will * be very unique, we cant push this to the normal * bucket[hash->linked_list]. We should probably allocate a static * bucket[MAX_NXDOMAIN] to hold NXDOMAINS, and when that is full, pop * out the oldest (LRU). A simple script querying for random non-existing * domains could easily put stress on passivedns (think conficker etc.) * if the bucket is to big or non-efficient. We would still store data * such as: firstseen,lastseen,client_ip,server_ip,class,query,NXDOMAIN */ if (config.dnsfe & (pdns_chk_dnsfe(rcode))) { ldns_rr_list *dns_query_domains; ldns_rr *rr; dnshash = hash(domain_name); dlog("[D] Hash: %lu\n", dnshash); /* Check if the node exists, if not, make it */ pr = get_pdns_record(dnshash, pi, domain_name); /* Set the SRC flag: */ //lname_node->srcflag |= pdns_chk_dnsfe(rcode); dns_query_domains = ldns_pkt_question(dns_pkt); rr = ldns_rr_list_rr(dns_query_domains, 0); if ((pr->last_seen.tv_sec - pr->last_print.tv_sec) >= config.dnsprinttime) { /* Print the SRC Error record */ print_passet(pr, NULL, rr, rdf_data, rcode); } } else { dlog("[D] Error return code %d was not processed:%d\n", pdns_chk_dnsfe(rcode), config.dnsfe); } free(domain_name); return 0; } for (j = 0; j < dns_answer_domain_cnt; j++) { int offset = -1; ldns_rr *rr; ldns_rdf *rname; unsigned char *rdomain_name = 0; rr = ldns_rr_list_rr(dns_answer_domains, j); switch (ldns_rr_get_type(rr)) { case LDNS_RR_TYPE_AAAA: if (config.dnsf & DNS_CHK_AAAA) offset = 0; break; case LDNS_RR_TYPE_A: if (config.dnsf & DNS_CHK_A) offset = 0; break; case LDNS_RR_TYPE_PTR: if (config.dnsf & DNS_CHK_PTR) offset = 0; break; case LDNS_RR_TYPE_CNAME: if (config.dnsf & DNS_CHK_CNAME) offset = 0; break; case LDNS_RR_TYPE_DNAME: if (config.dnsf & DNS_CHK_DNAME) offset = 0; break; case LDNS_RR_TYPE_NAPTR: if (config.dnsf & DNS_CHK_NAPTR) offset = 0; break; case LDNS_RR_TYPE_RP: if (config.dnsf & DNS_CHK_RP) offset = 0; break; case LDNS_RR_TYPE_SRV: if (config.dnsf & DNS_CHK_SRV) offset = 3; break; case LDNS_RR_TYPE_TXT: if (config.dnsf & DNS_CHK_TXT) offset = 0; break; case LDNS_RR_TYPE_SOA: if (config.dnsf & DNS_CHK_SOA) offset = 0; break; case LDNS_RR_TYPE_MX: if (config.dnsf & DNS_CHK_MX) offset = 1; break; case LDNS_RR_TYPE_NS: if (config.dnsf & DNS_CHK_NS) offset = 0; break; default: offset = -1; dlog("[D] ldns_rr_get_type: %d\n", ldns_rr_get_type(rr)); break; } if (offset == -1) { dlog("[D] LDNS_RR_TYPE not enabled/supported: %d\n", ldns_rr_get_type(rr)); //data_offset = 0; continue; } /* Get the rdf data from the rr */ rname = ldns_rr_rdf(rr, offset); if (rname == NULL) { dlog("[D] ldns_rr_rdf returned: NULL\n"); continue; } ldns_buffer_clear(buff); ldns_rdf2buffer_str(buff, rname); rdomain_name = (unsigned char *) ldns_buffer2str(buff); if (rdomain_name == NULL) { dlog("[D] ldns_buffer2str returned: NULL\n"); continue; } dlog("[D] rdomain_name: %s\n", rdomain_name); if (pr == NULL) { dnshash = hash(domain_name); dlog("[D] Hash: %lu\n", dnshash); /* Check if the node exists, if not, make it */ pr = get_pdns_record(dnshash, pi, domain_name); } /* Update the pdns record with the pdns asset */ update_pdns_record_asset(pi, pr, rr, rdomain_name); /* If CNAME, free domain_name, and cp rdomain_name to domain_name */ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_CNAME) { if (config.dnsf & DNS_CHK_CNAME) { int len; free(domain_name); len = strlen((char *)rdomain_name); domain_name = calloc(1, (len + 1)); strncpy((char *)domain_name, (char *)rdomain_name, len); dnshash = hash(domain_name); dlog("[D] Hash: %lu\n", dnshash); pr = get_pdns_record(dnshash, pi, domain_name); } } /* Free the rdomain_name */ free(rdomain_name); } free(domain_name); return 0; }
/** process answer from bg worker */ static int process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, ub_callback_t* cb, void** cbarg, int* err, struct ub_result** res) { struct ctx_query* q; if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) { log_err("error: bad data from bg worker %d", (int)context_serial_getcmd(msg, len)); return 0; } lock_basic_lock(&ctx->cfglock); q = context_deserialize_answer(ctx, msg, len, err); if(!q) { lock_basic_unlock(&ctx->cfglock); /* probably simply the lookup that failed, i.e. * response returned before cancel was sent out, so noerror */ return 1; } log_assert(q->async); /* grab cb while locked */ if(q->cancelled) { *cb = NULL; *cbarg = NULL; } else { *cb = q->cb; *cbarg = q->cb_arg; } if(*err) { *res = NULL; ub_resolve_free(q->res); } else { /* parse the message, extract rcode, fill result */ ldns_buffer* buf = ldns_buffer_new(q->msg_len); struct regional* region = regional_create(); *res = q->res; (*res)->rcode = LDNS_RCODE_SERVFAIL; if(region && buf) { ldns_buffer_clear(buf); ldns_buffer_write(buf, q->msg, q->msg_len); ldns_buffer_flip(buf); libworker_enter_result(*res, buf, region, q->msg_security); } (*res)->answer_packet = q->msg; (*res)->answer_len = (int)q->msg_len; q->msg = NULL; ldns_buffer_free(buf); regional_destroy(region); } q->res = NULL; /* delete the q from list */ (void)rbtree_delete(&ctx->queries, q->node.key); ctx->num_async--; context_query_delete(q); lock_basic_unlock(&ctx->cfglock); if(*cb) return 2; ub_resolve_free(*res); return 1; }
/** perform hash of name */ static int nsec3_calc_hash(struct regional* region, ldns_buffer* buf, struct nsec3_cached_hash* c) { int algo = nsec3_get_algo(c->nsec3, c->rr); size_t iter = nsec3_get_iter(c->nsec3, c->rr); uint8_t* salt; size_t saltlen, i; if(!nsec3_get_salt(c->nsec3, c->rr, &salt, &saltlen)) return -1; /* prepare buffer for first iteration */ ldns_buffer_clear(buf); ldns_buffer_write(buf, c->dname, c->dname_len); query_dname_tolower(ldns_buffer_begin(buf)); ldns_buffer_write(buf, salt, saltlen); ldns_buffer_flip(buf); switch(algo) { #if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS) case NSEC3_HASH_SHA1: #ifdef HAVE_SSL c->hash_len = SHA_DIGEST_LENGTH; #else c->hash_len = SHA1_LENGTH; #endif c->hash = (uint8_t*)regional_alloc(region, c->hash_len); if(!c->hash) return 0; # ifdef HAVE_SSL (void)SHA1((unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf), (unsigned char*)c->hash); # else (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)c->hash, (unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf)); # endif for(i=0; i<iter; i++) { ldns_buffer_clear(buf); ldns_buffer_write(buf, c->hash, c->hash_len); ldns_buffer_write(buf, salt, saltlen); ldns_buffer_flip(buf); # ifdef HAVE_SSL (void)SHA1( (unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf), (unsigned char*)c->hash); # else (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)c->hash, (unsigned char*)ldns_buffer_begin(buf), (unsigned long)ldns_buffer_limit(buf)); # endif } break; #endif /* HAVE_EVP_SHA1 or NSS */ default: log_err("nsec3 hash of unknown algo %d", algo); return -1; } return 1; }