/** * 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; }
ldns_status ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section) { uint16_t i; uint16_t rdl_pos = 0; if (ldns_rr_owner(rr)) { (void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr)); } if (ldns_buffer_reserve(buffer, 4)) { (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); } if (section != LDNS_SECTION_QUESTION) { if (ldns_buffer_reserve(buffer, 6)) { ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); /* remember pos for later */ rdl_pos = ldns_buffer_position(buffer); ldns_buffer_write_u16(buffer, 0); } for (i = 0; i < ldns_rr_rd_count(rr); i++) { (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i)); } if (rdl_pos != 0) { ldns_buffer_write_u16_at(buffer, rdl_pos, ldns_buffer_position(buffer) - rdl_pos - 2); } } return ldns_buffer_status(buffer); }
/** * Add RR to query. * */ int query_add_rr(query_type* q, ldns_rr* rr) { size_t i = 0; size_t tc_mark = 0; size_t rdlength_pos = 0; uint16_t rdlength = 0; ods_log_assert(q); ods_log_assert(q->buffer); ods_log_assert(rr); /* set truncation mark, in case rr does not fit */ tc_mark = buffer_position(q->buffer); /* owner type class ttl */ if (!buffer_available(q->buffer, ldns_rdf_size(ldns_rr_owner(rr)))) { goto query_add_rr_tc; } buffer_write_rdf(q->buffer, ldns_rr_owner(rr)); if (!buffer_available(q->buffer, sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(rdlength))) { goto query_add_rr_tc; } buffer_write_u16(q->buffer, (uint16_t) ldns_rr_get_type(rr)); buffer_write_u16(q->buffer, (uint16_t) ldns_rr_get_class(rr)); buffer_write_u32(q->buffer, (uint32_t) ldns_rr_ttl(rr)); /* skip rdlength */ rdlength_pos = buffer_position(q->buffer); buffer_skip(q->buffer, sizeof(rdlength)); /* write rdata */ for (i=0; i < ldns_rr_rd_count(rr); i++) { if (!buffer_available(q->buffer, ldns_rdf_size(ldns_rr_rdf(rr, i)))) { goto query_add_rr_tc; } buffer_write_rdf(q->buffer, ldns_rr_rdf(rr, i)); } if (!query_overflow(q)) { /* write rdlength */ rdlength = buffer_position(q->buffer) - rdlength_pos - sizeof(rdlength); buffer_write_u16_at(q->buffer, rdlength_pos, rdlength); /* position updated by buffer_write() */ return 1; } query_add_rr_tc: buffer_set_position(q->buffer, tc_mark); ods_log_assert(!query_overflow(q)); return 0; }
static int udp_bind(int sock, int port, const char *my_address) { struct sockaddr_in addr; in_addr_t maddr = INADDR_ANY; if (my_address) { #ifdef AF_INET6 if (inet_pton(AF_INET6, my_address, &maddr) < 1) { #else if (0) { #endif if (inet_pton(AF_INET, my_address, &maddr) < 1) { return -2; } } } #ifndef S_SPLINT_S addr.sin_family = AF_INET; #endif addr.sin_port = (in_port_t) htons((uint16_t)port); addr.sin_addr.s_addr = maddr; return bind(sock, (struct sockaddr *)&addr, (socklen_t) sizeof(addr)); } /* this will probably be moved to a better place in the library itself */ ldns_rr_list * get_rrset(const ldns_zone *zone, const ldns_rdf *owner_name, const ldns_rr_type qtype, const ldns_rr_class qclass) { uint16_t i; ldns_rr_list *rrlist = ldns_rr_list_new(); ldns_rr *cur_rr; if (!zone || !owner_name) { fprintf(stderr, "Warning: get_rrset called with NULL zone or owner name\n"); return rrlist; } for (i = 0; i < ldns_zone_rr_count(zone); i++) { cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i); if (ldns_dname_compare(ldns_rr_owner(cur_rr), owner_name) == 0 && ldns_rr_get_class(cur_rr) == qclass && ldns_rr_get_type(cur_rr) == qtype ) { ldns_rr_list_push_rr(rrlist, ldns_rr_clone(cur_rr)); } } printf("Found rrset of %u rrs\n", (unsigned int) ldns_rr_list_rr_count(rrlist)); return rrlist; }
/** 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; }
ldns_status ldns_rr2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rr *rr, int section) { uint16_t i; uint16_t rdl_pos = 0; bool pre_rfc3597 = false; switch (ldns_rr_get_type(rr)) { case LDNS_RR_TYPE_NS: case LDNS_RR_TYPE_MD: case LDNS_RR_TYPE_MF: case LDNS_RR_TYPE_CNAME: case LDNS_RR_TYPE_SOA: case LDNS_RR_TYPE_MB: case LDNS_RR_TYPE_MG: case LDNS_RR_TYPE_MR: case LDNS_RR_TYPE_PTR: case LDNS_RR_TYPE_HINFO: case LDNS_RR_TYPE_MINFO: case LDNS_RR_TYPE_MX: case LDNS_RR_TYPE_RP: case LDNS_RR_TYPE_AFSDB: case LDNS_RR_TYPE_RT: case LDNS_RR_TYPE_SIG: case LDNS_RR_TYPE_PX: case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NAPTR: case LDNS_RR_TYPE_KX: case LDNS_RR_TYPE_SRV: case LDNS_RR_TYPE_DNAME: case LDNS_RR_TYPE_A6: pre_rfc3597 = true; break; default: break; } if (ldns_rr_owner(rr)) { (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr)); } if (ldns_buffer_reserve(buffer, 4)) { (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); } if (section != LDNS_SECTION_QUESTION) { if (ldns_buffer_reserve(buffer, 6)) { ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); /* remember pos for later */ rdl_pos = ldns_buffer_position(buffer); ldns_buffer_write_u16(buffer, 0); } for (i = 0; i < ldns_rr_rd_count(rr); i++) { if (pre_rfc3597) { (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_rdf(rr, i)); } else { (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i)); } } if (rdl_pos != 0) { ldns_buffer_write_u16_at(buffer, rdl_pos, ldns_buffer_position(buffer) - rdl_pos - 2); } } return ldns_buffer_status(buffer); }
/** * Process query. * */ query_state query_process(query_type* q, void* engine) { ldns_status status = LDNS_STATUS_OK; ldns_pkt* pkt = NULL; ldns_rr* rr = NULL; ldns_pkt_rcode rcode = LDNS_RCODE_NOERROR; ldns_pkt_opcode opcode = LDNS_PACKET_QUERY; ldns_rr_type qtype = LDNS_RR_TYPE_SOA; engine_type* e = (engine_type*) engine; ods_log_assert(e); ods_log_assert(q); ods_log_assert(q->buffer); if (!e || !q || !q->buffer) { ods_log_error("[%s] drop query: assertion error", query_str); return QUERY_DISCARDED; /* should not happen */ } if (buffer_limit(q->buffer) < BUFFER_PKT_HEADER_SIZE) { ods_log_debug("[%s] drop query: packet too small", query_str); return QUERY_DISCARDED; /* too small */ } if (buffer_pkt_qr(q->buffer)) { ods_log_debug("[%s] drop query: qr bit set", query_str); return QUERY_DISCARDED; /* not a query */ } /* parse packet */ status = ldns_wire2pkt(&pkt, buffer_current(q->buffer), buffer_remaining(q->buffer)); if (status != LDNS_STATUS_OK) { ods_log_debug("[%s] got bad packet: %s", query_str, ldns_get_errorstr_by_id(status)); return query_formerr(q); } rr = ldns_rr_list_rr(ldns_pkt_question(pkt), 0); lock_basic_lock(&e->zonelist->zl_lock); /* we can just lookup the zone, because we will only handle SOA queries, zone transfers, updates and notifies */ q->zone = zonelist_lookup_zone_by_dname(e->zonelist, ldns_rr_owner(rr), ldns_rr_get_class(rr)); /* don't answer for zones that are just added */ if (q->zone && q->zone->zl_status == ZONE_ZL_ADDED) { ods_log_warning("[%s] zone %s just added, don't answer for now", query_str, q->zone->name); q->zone = NULL; } lock_basic_unlock(&e->zonelist->zl_lock); if (!q->zone) { ods_log_debug("[%s] zone not found", query_str); return query_servfail(q); } /* see if it is tsig signed */ if (!query_find_tsig(q)) { return query_formerr(q); } /* else: valid tsig, or no tsig present */ ods_log_debug("[%s] tsig %s", query_str, tsig_status2str(q->tsig_rr->status)); rcode = query_process_tsig(q); if (rcode != LDNS_RCODE_NOERROR) { return query_error(q, rcode); } /* process edns */ rcode = query_process_edns(q); if (rcode != LDNS_RCODE_NOERROR) { /* We should not return FORMERR, but BADVERS (=16). * BADVERS is created with Ext. RCODE, followed by RCODE. * Ext. RCODE is set to 1, RCODE must be 0 (getting 0x10 = 16). * Thus RCODE = NOERROR = NSD_RC_OK. */ return query_error(q, LDNS_RCODE_NOERROR); } /* handle incoming request */ opcode = ldns_pkt_get_opcode(pkt); qtype = ldns_rr_get_type(rr); ldns_pkt_free(pkt); switch (opcode) { case LDNS_PACKET_NOTIFY: return query_process_notify(q, qtype, engine); case LDNS_PACKET_QUERY: return query_process_query(q, qtype, engine); case LDNS_PACKET_UPDATE: return query_process_update(q); default: break; } return query_notimpl(q); }
void print_passet(pdns_record *l, pdns_asset *p, ldns_rr *rr, ldns_rdf *lname, uint16_t rcode) { FILE *fd = NULL; static char ip_addr_s[INET6_ADDRSTRLEN]; static char ip_addr_c[INET6_ADDRSTRLEN]; char *d = config.log_delimiter; char *rr_class; char *rr_type; char *rr_rcode; char buffer[1000] = ""; char *output = buffer; int offset = 0; uint8_t is_err_record = 0; #ifdef HAVE_JSON json_t *jdata; size_t data_flags = 0; /* Print in the same order as inserted */ data_flags |= JSON_PRESERVE_ORDER; /* No whitespace between fields */ data_flags |= JSON_COMPACT; #endif /* HAVE_JSON */ /* If pdns_asset is not defined, then this is a NXD record */ if (p == NULL) { is_err_record = 1; } /* Use the correct file descriptor */ if (is_err_record && config.output_log_nxd) { if (config.logfile_all) { fd = config.logfile_fd; } else { fd = config.logfile_nxd_fd; } if (fd == NULL) return; } else if (!is_err_record && config.output_log) { fd = config.logfile_fd; if (fd == NULL) return; } if (is_err_record) { u_ntop(l->sip, l->af, ip_addr_s); u_ntop(l->cip, l->af, ip_addr_c); } else { u_ntop(p->sip, p->af, ip_addr_s); u_ntop(p->cip, p->af, ip_addr_c); } rr_class = malloc(10); rr_type = malloc(10); rr_rcode = malloc(20); switch (ldns_rr_get_class(rr)) { case LDNS_RR_CLASS_IN: snprintf(rr_class, 10, "IN"); break; case LDNS_RR_CLASS_CH: snprintf(rr_class, 10, "CH"); break; case LDNS_RR_CLASS_HS: snprintf(rr_class, 10, "HS"); break; case LDNS_RR_CLASS_NONE: snprintf(rr_class, 10, "NONE"); break; case LDNS_RR_CLASS_ANY: snprintf(rr_class, 10, "ANY"); break; default: snprintf(rr_class, 10, "%d", ldns_rr_get_class(rr)); break; } switch (ldns_rr_get_type(rr)) { case LDNS_RR_TYPE_PTR: snprintf(rr_type, 10, "PTR"); break; case LDNS_RR_TYPE_A: snprintf(rr_type, 10, "A"); break; case LDNS_RR_TYPE_AAAA: snprintf(rr_type, 10, "AAAA"); break; case LDNS_RR_TYPE_CNAME: snprintf(rr_type, 10, "CNAME"); break; case LDNS_RR_TYPE_DNAME: snprintf(rr_type, 10, "DNAME"); break; case LDNS_RR_TYPE_NAPTR: snprintf(rr_type, 10, "NAPTR"); break; case LDNS_RR_TYPE_RP: snprintf(rr_type, 10, "RP"); break; case LDNS_RR_TYPE_SRV: snprintf(rr_type, 10, "SRV"); break; case LDNS_RR_TYPE_TXT: snprintf(rr_type, 10, "TXT"); break; case LDNS_RR_TYPE_SOA: snprintf(rr_type, 10, "SOA"); break; case LDNS_RR_TYPE_NS: snprintf(rr_type, 10, "NS"); break; case LDNS_RR_TYPE_MX: snprintf(rr_type, 10, "MX"); break; default: if (is_err_record) { snprintf(rr_type, 10, "%d", ldns_rdf_get_type(lname)); } else { snprintf(rr_type, 10, "%d", p->rr->_rr_type); } break; } if (is_err_record) { switch (rcode) { case 1: snprintf(rr_rcode, 20, "FORMERR"); break; case 2: snprintf(rr_rcode, 20, "SERVFAIL"); break; case 3: snprintf(rr_rcode, 20, "NXDOMAIN"); break; case 4: snprintf(rr_rcode, 20, "NOTIMPL"); break; case 5: snprintf(rr_rcode, 20, "REFUSED"); break; case 6: snprintf(rr_rcode, 20, "YXDOMAIN"); break; case 7: snprintf(rr_rcode, 20, "YXRRSET"); break; case 8: snprintf(rr_rcode, 20, "NXRRSET"); break; case 9: snprintf(rr_rcode, 20, "NOTAUTH"); break; case 10: snprintf(rr_rcode, 20, "NOTZONE"); break; default: snprintf(rr_rcode, 20, "UNKNOWN-ERROR-%d", rcode); break; } } #ifdef HAVE_JSON if ((is_err_record && config.use_json_nxd) || (!is_err_record && config.use_json)) { jdata = json_object(); if (config.fieldsf & FIELD_TIMESTAMP_S) json_object_set_new(jdata, JSON_TIMESTAMP_S, json_integer(l->last_seen.tv_sec)); if (config.fieldsf & FIELD_TIMESTAMP_MS) json_object_set_new(jdata, JSON_TIMESTAMP_MS, json_integer(l->last_seen.tv_usec)); if (config.fieldsf & FIELD_CLIENT) json_object_set_new(jdata, JSON_CLIENT, json_string(ip_addr_c)); if (config.fieldsf & FIELD_SERVER) json_object_set_new(jdata, JSON_SERVER, json_string(ip_addr_s)); if (config.fieldsf & FIELD_CLASS) json_object_set_new(jdata, JSON_CLASS, json_string(rr_class)); if (config.fieldsf & FIELD_QUERY) json_object_set_new(jdata, JSON_QUERY, json_string((const char *)l->qname)); if (config.fieldsf & FIELD_TYPE) json_object_set_new(jdata, JSON_TYPE, json_string(rr_type)); if (is_err_record) { if (config.fieldsf & FIELD_ANSWER) json_object_set_new(jdata, JSON_ANSWER, json_string(rr_rcode)); if (config.fieldsf & FIELD_TTL) json_object_set_new(jdata, JSON_TTL, json_integer(PASSET_ERR_TTL)); if (config.fieldsf & FIELD_COUNT) json_object_set_new(jdata, JSON_COUNT, json_integer(PASSET_ERR_COUNT)); } else { if (config.fieldsf & FIELD_ANSWER) json_object_set_new(jdata, JSON_ANSWER, json_string((const char *)p->answer)); if (config.fieldsf & FIELD_TTL) json_object_set_new(jdata, JSON_TTL, json_integer(p->rr->_ttl)); if (config.fieldsf & FIELD_COUNT) json_object_set_new(jdata, JSON_COUNT, json_integer(p->seen)); } output = json_dumps(jdata, data_flags); if (output == NULL) return; } else { #endif /* HAVE_JSON */ /* Print timestamp */ if ((config.fieldsf & FIELD_TIMESTAMP_S) && (config.fieldsf & FIELD_TIMESTAMP_MS)) { if (is_err_record) { offset += snprintf(output, sizeof(buffer) - offset, "%lu.%06lu", l->last_seen.tv_sec, l->last_seen.tv_usec); } else { offset += snprintf(output, sizeof(buffer) - offset, "%lu.%06lu", p->last_seen.tv_sec, p->last_seen.tv_usec); } } else if (config.fieldsf & FIELD_TIMESTAMP_S) { if (is_err_record) { offset += snprintf(output, sizeof(buffer) - offset, "%lu", l->last_seen.tv_sec); } else { offset += snprintf(output, sizeof(buffer) - offset, "%lu", p->last_seen.tv_sec); } } else if (config.fieldsf & FIELD_TIMESTAMP_MS) { if (is_err_record) { offset += snprintf(output, sizeof(buffer) - offset, "%06lu", l->last_seen.tv_usec); } else { offset += snprintf(output, sizeof(buffer) - offset, "%06lu", p->last_seen.tv_usec); } } /* Print client IP */ if (config.fieldsf & FIELD_CLIENT) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", ip_addr_c); } /* Print server IP */ if (config.fieldsf & FIELD_SERVER) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", ip_addr_s); } /* Print class */ if (config.fieldsf & FIELD_CLASS) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", rr_class); } /* Print query */ if (config.fieldsf & FIELD_QUERY) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", l->qname); } /* Print type */ if (config.fieldsf & FIELD_TYPE) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", rr_type); } /* Print answer */ if (config.fieldsf & FIELD_ANSWER) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); if (is_err_record) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", rr_rcode); else offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", p->answer); } /* Print TTL */ if (config.fieldsf & FIELD_TTL) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); if (is_err_record) offset += snprintf(output+offset, sizeof(buffer) - offset, "%d", PASSET_ERR_TTL); else offset += snprintf(output+offset, sizeof(buffer) - offset, "%u", p->rr->_ttl); } /* Print count */ if (config.fieldsf & FIELD_COUNT) { if (offset != 0) offset += snprintf(output+offset, sizeof(buffer) - offset, "%s", d); if (is_err_record) offset += snprintf(output+offset, sizeof(buffer) - offset, "%d", PASSET_ERR_COUNT); else offset += snprintf(output+offset, sizeof(buffer) - offset, "%lu", p->seen); } #ifdef HAVE_JSON } #endif /* HAVE_JSON */ /* Print to log file */ if (fd) { fprintf(fd, "%s\n", output); fflush(fd); } /* Print to syslog */ if ((is_err_record && config.output_syslog_nxd) || (!is_err_record && config.output_syslog)) { openlog(PDNS_IDENT, LOG_NDELAY, LOG_LOCAL7); syslog(LOG_INFO, "%s", output); closelog(); } if (is_err_record) { l->last_print = l->last_seen; l->seen = 0; } else { p->last_print = p->last_seen; p->seen = 0; } free(rr_class); free(rr_type); free(rr_rcode); }
static CborError cbor_ldns_rr_list(CborEncoder *encoder, ldns_rr_list *list, size_t count, int *should_flush) { CborError cbor_err = CborNoError; size_t n; ldns_buffer *dname; char *dname_str; if (!encoder) { return CborErrorInternalError; } if (!list) { return CborErrorInternalError; } if (!count) { return CborErrorInternalError; } if (!should_flush) { return CborErrorInternalError; } for (n = 0; cbor_err == CborNoError && n < count; n++) { CborEncoder cbor_rr; uint8_t *rdata_bytes; ldns_buffer *rdata; ldns_rr *rr = ldns_rr_list_rr(list, n); size_t rd_count; if (!rr) { return CborErrorInternalError; } rd_count = ldns_rr_rd_count(rr); if (!(dname = ldns_buffer_new(512))) { return CborErrorOutOfMemory; } if (ldns_rdf2buffer_str_dname(dname, ldns_rr_owner(rr)) != LDNS_STATUS_OK) { ldns_buffer_free(dname); return CborErrorInternalError; } ldns_buffer_write_u8(dname, 0); if (!(dname_str = ldns_buffer_export(dname))) { ldns_buffer_free(dname); return CborErrorOutOfMemory; } if (cbor_err == CborNoError) cbor_err = append_cbor_map(encoder, &cbor_rr, CborIndefiniteLength, should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, "NAME", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, dname_str, should_flush); free(dname_str); ldns_buffer_free(dname); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, "CLASS", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor_rr, ldns_rr_get_class(rr), should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, "TYPE", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor_rr, ldns_rr_get_type(rr), should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, "TTL", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor_rr, ldns_rr_ttl(rr), should_flush); if (rd_count == 1) { if (!(rdata = ldns_buffer_new(64*1024))) { return CborErrorOutOfMemory; } if (ldns_rdf2buffer_wire(rdata, ldns_rr_rdf(rr, 0)) != LDNS_STATUS_OK) { ldns_buffer_free(rdata); return CborErrorInternalError; } if (!(rdata_bytes = ldns_buffer_export(rdata))) { ldns_buffer_free(rdata); return CborErrorOutOfMemory; } if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, "RDLENGTH", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor_rr, ldns_buffer_position(rdata), should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, "RDATA", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_bytes(&cbor_rr, rdata_bytes, ldns_buffer_position(rdata), should_flush); free(rdata_bytes); ldns_buffer_free(rdata); } else if (rd_count > 1) { size_t n2; CborEncoder rr_set; if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor_rr, "rrSet", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_array(&cbor_rr, &rr_set, CborIndefiniteLength, should_flush); for (n2 = 0; n2 < rd_count; n2++) { if (!(rdata = ldns_buffer_new(64*1024))) { return CborErrorOutOfMemory; } if (ldns_rdf2buffer_wire(rdata, ldns_rr_rdf(rr, n2)) != LDNS_STATUS_OK) { ldns_buffer_free(rdata); return CborErrorInternalError; } if (!(rdata_bytes = ldns_buffer_export(rdata))) { ldns_buffer_free(rdata); return CborErrorOutOfMemory; } if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&rr_set, "RDLENGTH", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&rr_set, ldns_buffer_position(rdata), should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&rr_set, "RDATA", should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_bytes(&rr_set, rdata_bytes, ldns_buffer_position(rdata), should_flush); free(rdata_bytes); ldns_buffer_free(rdata); } if (cbor_err == CborNoError) cbor_err = close_cbor_container(&cbor_rr, &rr_set, should_flush); } if (cbor_err == CborNoError) cbor_err = close_cbor_container(encoder, &cbor_rr, should_flush); } return cbor_err; }
/** 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; }
ldns_rr * ldns_create_empty_rrsig(ldns_rr_list *rrset, ldns_key *current_key) { uint32_t orig_ttl; ldns_rr_class orig_class; time_t now; ldns_rr *current_sig; uint8_t label_count; ldns_rdf *signame; label_count = ldns_dname_label_count(ldns_rr_owner(ldns_rr_list_rr(rrset, 0))); /* RFC4035 2.2: not counting the leftmost label if it is a wildcard */ if(ldns_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0)))) label_count --; current_sig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG); /* set the type on the new signature */ orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0)); orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0)); ldns_rr_set_ttl(current_sig, orig_ttl); ldns_rr_set_class(current_sig, orig_class); ldns_rr_set_owner(current_sig, ldns_rdf_clone( ldns_rr_owner( ldns_rr_list_rr(rrset, 0)))); /* fill in what we know of the signature */ /* set the orig_ttl */ (void)ldns_rr_rrsig_set_origttl( current_sig, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, orig_ttl)); /* the signers name */ signame = ldns_rdf_clone(ldns_key_pubkey_owner(current_key)); ldns_dname2canonical(signame); (void)ldns_rr_rrsig_set_signame( current_sig, signame); /* label count - get it from the first rr in the rr_list */ (void)ldns_rr_rrsig_set_labels( current_sig, ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, label_count)); /* inception, expiration */ now = time(NULL); if (ldns_key_inception(current_key) != 0) { (void)ldns_rr_rrsig_set_inception( current_sig, ldns_native2rdf_int32( LDNS_RDF_TYPE_TIME, ldns_key_inception(current_key))); } else { (void)ldns_rr_rrsig_set_inception( current_sig, ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now)); } if (ldns_key_expiration(current_key) != 0) { (void)ldns_rr_rrsig_set_expiration( current_sig, ldns_native2rdf_int32( LDNS_RDF_TYPE_TIME, ldns_key_expiration(current_key))); } else { (void)ldns_rr_rrsig_set_expiration( current_sig, ldns_native2rdf_int32( LDNS_RDF_TYPE_TIME, now + LDNS_DEFAULT_EXP_TIME)); } (void)ldns_rr_rrsig_set_keytag( current_sig, ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_key_keytag(current_key))); (void)ldns_rr_rrsig_set_algorithm( current_sig, ldns_native2rdf_int8( LDNS_RDF_TYPE_ALG, ldns_key_algorithm(current_key))); (void)ldns_rr_rrsig_set_typecovered( current_sig, ldns_native2rdf_int16( LDNS_RDF_TYPE_TYPE, ldns_rr_get_type(ldns_rr_list_rr(rrset, 0)))); return current_sig; }
int getrrsetbyname(const char *hostname, unsigned int rdclass, unsigned int rdtype, unsigned int flags, struct rrsetinfo **res) { int result; unsigned int i, j, index_ans, index_sig; struct rrsetinfo *rrset = NULL; struct rdatainfo *rdata; size_t len; ldns_resolver *ldns_res; ldns_rdf *domain = NULL; ldns_pkt *pkt = NULL; ldns_rr_list *rrsigs = NULL, *rrdata = NULL; ldns_status err; ldns_rr *rr; /* check for invalid class and type */ if (rdclass > 0xffff || rdtype > 0xffff) { result = ERRSET_INVAL; goto fail; } /* don't allow queries of class or type ANY */ if (rdclass == 0xff || rdtype == 0xff) { result = ERRSET_INVAL; goto fail; } /* don't allow flags yet, unimplemented */ if (flags) { result = ERRSET_INVAL; goto fail; } /* Initialize resolver from resolv.conf */ domain = ldns_dname_new_frm_str(hostname); if ((err = ldns_resolver_new_frm_file(&ldns_res, NULL)) != \ LDNS_STATUS_OK) { result = ERRSET_FAIL; goto fail; } #ifdef LDNS_DEBUG ldns_resolver_set_debug(ldns_res, true); #endif /* LDNS_DEBUG */ ldns_resolver_set_dnssec(ldns_res, true); /* Use DNSSEC */ /* make query */ pkt = ldns_resolver_query(ldns_res, domain, rdtype, rdclass, LDNS_RD); /*** TODO: finer errcodes -- see original **/ if (!pkt || ldns_pkt_ancount(pkt) < 1) { result = ERRSET_FAIL; goto fail; } /* initialize rrset */ rrset = calloc(1, sizeof(struct rrsetinfo)); if (rrset == NULL) { result = ERRSET_NOMEMORY; goto fail; } rrdata = ldns_pkt_rr_list_by_type(pkt, rdtype, LDNS_SECTION_ANSWER); rrset->rri_nrdatas = ldns_rr_list_rr_count(rrdata); if (!rrset->rri_nrdatas) { result = ERRSET_NODATA; goto fail; } /* copy name from answer section */ len = ldns_rdf_size(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))); if ((rrset->rri_name = malloc(len)) == NULL) { result = ERRSET_NOMEMORY; goto fail; } memcpy(rrset->rri_name, ldns_rdf_data(ldns_rr_owner(ldns_rr_list_rr(rrdata, 0))), len); rrset->rri_rdclass = ldns_rr_get_class(ldns_rr_list_rr(rrdata, 0)); rrset->rri_rdtype = ldns_rr_get_type(ldns_rr_list_rr(rrdata, 0)); rrset->rri_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrdata, 0)); debug2("ldns: got %u answers from DNS", rrset->rri_nrdatas); /* Check for authenticated data */ if (ldns_pkt_ad(pkt)) { rrset->rri_flags |= RRSET_VALIDATED; } else { /* AD is not set, try autonomous validation */ ldns_rr_list * trusted_keys = ldns_rr_list_new(); debug2("ldns: trying to validate RRset"); /* Get eventual sigs */ rrsigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANSWER); rrset->rri_nsigs = ldns_rr_list_rr_count(rrsigs); debug2("ldns: got %u signature(s) (RRTYPE %u) from DNS", rrset->rri_nsigs, LDNS_RR_TYPE_RRSIG); if ((err = ldns_verify_trusted(ldns_res, rrdata, rrsigs, trusted_keys)) == LDNS_STATUS_OK) { rrset->rri_flags |= RRSET_VALIDATED; debug2("ldns: RRset is signed with a valid key"); } else { debug2("ldns: RRset validation failed: %s", ldns_get_errorstr_by_id(err)); } ldns_rr_list_deep_free(trusted_keys); } /* allocate memory for answers */ rrset->rri_rdatas = calloc(rrset->rri_nrdatas, sizeof(struct rdatainfo)); if (rrset->rri_rdatas == NULL) { result = ERRSET_NOMEMORY; goto fail; } /* allocate memory for signatures */ if (rrset->rri_nsigs > 0) { rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo)); if (rrset->rri_sigs == NULL) { result = ERRSET_NOMEMORY; goto fail; } } /* copy answers & signatures */ for (i=0, index_ans=0, index_sig=0; i< pkt->_header->_ancount; i++) { rdata = NULL; rr = ldns_rr_list_rr(ldns_pkt_answer(pkt), i); if (ldns_rr_get_class(rr) == rrset->rri_rdclass && ldns_rr_get_type(rr) == rrset->rri_rdtype) { rdata = &rrset->rri_rdatas[index_ans++]; } if (rr->_rr_class == rrset->rri_rdclass && rr->_rr_type == LDNS_RR_TYPE_RRSIG && rrset->rri_sigs) { rdata = &rrset->rri_sigs[index_sig++]; } if (rdata) { size_t rdata_offset = 0; rdata->rdi_length = 0; for (j=0; j< rr->_rd_count; j++) { rdata->rdi_length += ldns_rdf_size(ldns_rr_rdf(rr, j)); } rdata->rdi_data = malloc(rdata->rdi_length); if (rdata->rdi_data == NULL) { result = ERRSET_NOMEMORY; goto fail; } /* Re-create the raw DNS RDATA */ for (j=0; j< rr->_rd_count; j++) { len = ldns_rdf_size(ldns_rr_rdf(rr, j)); memcpy(rdata->rdi_data + rdata_offset, ldns_rdf_data(ldns_rr_rdf(rr, j)), len); rdata_offset += len; } } } *res = rrset; result = ERRSET_SUCCESS; fail: /* freerrset(rrset); */ ldns_rdf_deep_free(domain); ldns_pkt_free(pkt); ldns_rr_list_deep_free(rrsigs); ldns_rr_list_deep_free(rrdata); ldns_resolver_deep_free(ldns_res); return result; }
/* * Parses data buffer to a query, finds the correct answer * and calls the given function for every packet to send. */ void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count, enum transport_type transport, void (*sendfunc)(uint8_t*, size_t, void*), void* userdata, FILE* verbose_out) { ldns_status status; ldns_pkt *query_pkt = NULL; ldns_pkt *answer_pkt = NULL; struct reply_packet *p; ldns_rr *query_rr = NULL; uint8_t *outbuf = NULL; size_t answer_size = 0; struct entry* entry = NULL; ldns_rdf *stop_command = ldns_dname_new_frm_str("server.stop."); status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)inlen); if (status != LDNS_STATUS_OK) { verbose(1, "Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); ldns_rdf_free(stop_command); return; } query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); verbose(1, "query %d: id %d: %s %d bytes: ", ++(*count), (int)ldns_pkt_id(query_pkt), (transport==transport_tcp)?"TCP":"UDP", (int)inlen); if(verbose_out) ldns_rr_print(verbose_out, query_rr); if(verbose_out) ldns_pkt_print(verbose_out, query_pkt); if (ldns_rr_get_type(query_rr) == LDNS_RR_TYPE_TXT && ldns_rr_get_class(query_rr) == LDNS_RR_CLASS_CH && ldns_dname_compare(ldns_rr_owner(query_rr), stop_command) == 0) { exit(0); } /* fill up answer packet */ entry = find_match(entries, query_pkt, transport); if(!entry || !entry->reply_list) { verbose(1, "no answer packet for this query, no reply.\n"); ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); return; } for(p = entry->reply_list; p; p = p->next) { verbose(3, "Answer pkt:\n"); if (p->reply_from_hex) { /* try to parse the hex packet, if it can be * parsed, we can use adjust rules. if not, * send packet literally */ status = ldns_buffer2pkt_wire(&answer_pkt, p->reply_from_hex); if (status == LDNS_STATUS_OK) { adjust_packet(entry, answer_pkt, query_pkt); if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); verbose(2, "Answer packet size: %u bytes.\n", (unsigned int)answer_size); if (status != LDNS_STATUS_OK) { verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); return; } ldns_pkt_free(answer_pkt); answer_pkt = NULL; } else { verbose(3, "Could not parse hex data (%s), sending hex data directly.\n", ldns_get_errorstr_by_id(status)); /* still try to adjust ID */ answer_size = ldns_buffer_capacity(p->reply_from_hex); outbuf = LDNS_XMALLOC(uint8_t, answer_size); memcpy(outbuf, ldns_buffer_export(p->reply_from_hex), answer_size); if(entry->copy_id) { ldns_write_uint16(outbuf, ldns_pkt_id(query_pkt)); } } } else { answer_pkt = ldns_pkt_clone(p->reply); adjust_packet(entry, answer_pkt, query_pkt); if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); verbose(1, "Answer packet size: %u bytes.\n", (unsigned int)answer_size); if (status != LDNS_STATUS_OK) { verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); return; } ldns_pkt_free(answer_pkt); answer_pkt = NULL; } if(p->packet_sleep) { verbose(3, "sleeping for next packet %d secs\n", p->packet_sleep); #ifdef HAVE_SLEEP sleep(p->packet_sleep); #else Sleep(p->packet_sleep * 1000); #endif verbose(3, "wakeup for next packet " "(slept %d secs)\n", p->packet_sleep); } sendfunc(outbuf, answer_size, userdata); LDNS_FREE(outbuf); outbuf = NULL; answer_size = 0; } ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); }
int output_cbor(iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char *payload, size_t payloadlen) { ldns_pkt *pkt = 0; ldns_status ldns_rc; if (!payload) { return DUMP_CBOR_EINVAL; } if (!payloadlen) { return DUMP_CBOR_EINVAL; } /* if (!cbor_stringrefs) {*/ /* cbor_stringrefs = calloc(1, cbor_stringref_size);*/ /* }*/ if (!cbor_buf) { if (!(cbor_buf = calloc(1, cbor_size + cbor_reserve))) { return DUMP_CBOR_ENOMEM; } } if (cbor_flushed) { CborError cbor_err; cbor_encoder_init(&cbor_root, cbor_buf, cbor_size, 0); /* cbor_err = cbor_encode_tag(&cbor_root, 256);*/ /* if (cbor_err == CborNoError)*/ cbor_err = cbor_encoder_create_array(&cbor_root, &cbor_pkts, CborIndefiniteLength); if (cbor_err != CborNoError) { fprintf(stderr, "cbor init error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err)); return DUMP_CBOR_ECBOR; } cbor_flushed = 0; } ldns_rc = ldns_wire2pkt(&pkt, payload, payloadlen); if (ldns_rc != LDNS_STATUS_OK) { fprintf(stderr, "ldns error [%d]: %s\n", ldns_rc, ldns_get_errorstr_by_id(ldns_rc)); return DUMP_CBOR_ELDNS; } if (!pkt) { return DUMP_CBOR_ELDNS; } CborEncoder cbor, ip; CborError cbor_err = CborNoError; int should_flush = 0; cbor_err = append_cbor_map(&cbor_pkts, &cbor, CborIndefiniteLength, &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "dateSeconds", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_double(&cbor, (double)ts.tv_sec + ( (double)ts.tv_usec / 1000000 ), &should_flush); /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "dateNanoFractions", &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ts.tv_usec * 1000, &should_flush);*/ if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "ip", &should_flush); /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, proto, &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "sourceIpAddress", &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, ia_str(from), &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "sourcePort", &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, sport, &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "destinationIpAddress", &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, ia_str(to), &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "destinationPort", &should_flush);*/ /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, dport, &should_flush);*/ if (cbor_err == CborNoError) cbor_err = append_cbor_array(&cbor, &ip, CborIndefiniteLength, &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&ip, proto, &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&ip, ia_str(from), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&ip, sport, &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&ip, ia_str(to), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&ip, dport, &should_flush); if (cbor_err == CborNoError) cbor_err = close_cbor_container(&cbor, &ip, &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "ID", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_pkt_id(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "QR", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_boolean(&cbor, ldns_pkt_qr(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "Opcode", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_pkt_get_opcode(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "AA", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_boolean(&cbor, ldns_pkt_aa(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "TC", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_boolean(&cbor, ldns_pkt_tc(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "RD", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_boolean(&cbor, ldns_pkt_rd(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "RA", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_boolean(&cbor, ldns_pkt_ra(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "AD", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_boolean(&cbor, ldns_pkt_ad(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "CD", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_boolean(&cbor, ldns_pkt_cd(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "RCODE", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_pkt_get_rcode(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "QDCOUNT", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_pkt_qdcount(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "ANCOUNT", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_pkt_ancount(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "NSCOUNT", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_pkt_nscount(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "ARCOUNT", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_pkt_arcount(pkt), &should_flush); /* questionRRs */ if (ldns_pkt_qdcount(pkt) > 0) { ldns_rr_list *list = ldns_pkt_question(pkt); ldns_rr *rr; size_t n, qdcount = ldns_pkt_qdcount(pkt); ldns_buffer *dname; char *dname_str; if (!list) { ldns_pkt_free(pkt); return DUMP_CBOR_ELDNS; } rr = ldns_rr_list_rr(list, 0); if (!rr) { ldns_pkt_free(pkt); return DUMP_CBOR_ELDNS; } if (!(dname = ldns_buffer_new(512))) { ldns_pkt_free(pkt); return DUMP_CBOR_ENOMEM; } if (ldns_rdf2buffer_str_dname(dname, ldns_rr_owner(rr)) != LDNS_STATUS_OK) { ldns_buffer_free(dname); ldns_pkt_free(pkt); return DUMP_CBOR_ELDNS; } ldns_buffer_write_u8(dname, 0); if (!(dname_str = ldns_buffer_export(dname))) { ldns_buffer_free(dname); ldns_pkt_free(pkt); return DUMP_CBOR_ENOMEM; } if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "QNAME", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, dname_str, &should_flush); free(dname_str); ldns_buffer_free(dname); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "QCLASS", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_rr_get_class(rr), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "QTYPE", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ldns_rr_get_type(rr), &should_flush); if (qdcount > 1) { CborEncoder queries; if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "questionRRs", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_array(&cbor, &queries, CborIndefiniteLength, &should_flush); for (n = 1; cbor_err == CborNoError && n < qdcount; n++) { CborEncoder query; rr = ldns_rr_list_rr(list, n); if (!rr) { ldns_pkt_free(pkt); return DUMP_CBOR_ELDNS; } if (!(dname = ldns_buffer_new(512))) { ldns_pkt_free(pkt); return DUMP_CBOR_ENOMEM; } if (ldns_rdf2buffer_str_dname(dname, ldns_rr_owner(rr)) != LDNS_STATUS_OK) { ldns_buffer_free(dname); ldns_pkt_free(pkt); return DUMP_CBOR_ELDNS; } ldns_buffer_write_u8(dname, 0); if (!(dname_str = ldns_buffer_export(dname))) { ldns_buffer_free(dname); ldns_pkt_free(pkt); return DUMP_CBOR_ENOMEM; } if (cbor_err == CborNoError) cbor_err = append_cbor_map(&queries, &query, CborIndefiniteLength, &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&query, "NAME", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&query, dname_str, &should_flush); free(dname_str); ldns_buffer_free(dname); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&query, "CLASS", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&query, ldns_rr_get_class(rr), &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&query, "TYPE", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&query, ldns_rr_get_type(rr), &should_flush); if (cbor_err == CborNoError) cbor_err = close_cbor_container(&queries, &query, &should_flush); } if (cbor_err == CborNoError) cbor_err = close_cbor_container(&cbor, &queries, &should_flush); } } /* answerRRs */ if (ldns_pkt_ancount(pkt) > 0) { CborEncoder cbor_rrs; if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "answerRRs", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_array(&cbor, &cbor_rrs, CborIndefiniteLength, &should_flush); cbor_ldns_rr_list(&cbor_rrs, ldns_pkt_answer(pkt), ldns_pkt_ancount(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = close_cbor_container(&cbor, &cbor_rrs, &should_flush); } /* authorityRRs */ if (ldns_pkt_nscount(pkt) > 0) { CborEncoder cbor_rrs; if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "authorityRRs", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_array(&cbor, &cbor_rrs, CborIndefiniteLength, &should_flush); cbor_ldns_rr_list(&cbor_rrs, ldns_pkt_authority(pkt), ldns_pkt_nscount(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = close_cbor_container(&cbor, &cbor_rrs, &should_flush); } /* additionalRRs */ if (ldns_pkt_arcount(pkt) > 0) { CborEncoder cbor_rrs; if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "additionalRRs", &should_flush); if (cbor_err == CborNoError) cbor_err = append_cbor_array(&cbor, &cbor_rrs, CborIndefiniteLength, &should_flush); cbor_ldns_rr_list(&cbor_rrs, ldns_pkt_additional(pkt), ldns_pkt_arcount(pkt), &should_flush); if (cbor_err == CborNoError) cbor_err = close_cbor_container(&cbor, &cbor_rrs, &should_flush); } ldns_pkt_free(pkt); if (cbor_err == CborNoError) cbor_err = close_cbor_container(&cbor_pkts, &cbor, &should_flush); if (cbor_err != CborNoError) { fprintf(stderr, "cbor error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err)); return DUMP_CBOR_ECBOR; } if (should_flush) { if ((cbor_err = cbor_encoder_close_container_checked(&cbor_root, &cbor_pkts)) != CborNoError) { fprintf(stderr, "cbor error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err)); return DUMP_CBOR_ECBOR; } fprintf(stderr, "cbor output: %lu bytes\n", cbor_encoder_get_buffer_size(&cbor_root, cbor_buf)); cbor_flushed = 1; return DUMP_CBOR_FLUSH; } return DUMP_CBOR_OK; }
/** * Process RR. * */ static ods_status adapi_process_rr(zone_type* zone, ldns_rr* rr, int add, int backup) { ods_status status = ODS_STATUS_OK; uint32_t tmp = 0; ods_log_assert(rr); ods_log_assert(zone); ods_log_assert(zone->name); ods_log_assert(zone->db); ods_log_assert(zone->signconf); /* We only support IN class */ if (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) { ods_log_warning("[%s] only class in is supported, changing class " "to in", adapi_str); ldns_rr_set_class(rr, LDNS_RR_CLASS_IN); } /* RR processing */ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) { ods_log_error("[%s] unable to %s rr to zone: soa record has " "invalid owner name", adapi_str, add?"add":"delete"); return ODS_STATUS_ERR; } status = adapi_process_soa(zone, rr, add, backup); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to %s rr: failed to process soa " "record", adapi_str, add?"add":"delete"); return status; } } else { if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex) && !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->apex)) { ods_log_warning("[%s] zone %s contains out-of-zone data, " "skipping", adapi_str, zone->name); return ODS_STATUS_UNCHANGED; } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY) { adapi_process_dnskey(zone, rr); } else if (util_is_dnssec_rr(rr) && !backup) { ods_log_warning("[%s] zone %s contains dnssec data (type=%u), " "skipping", adapi_str, zone->name, (unsigned) ldns_rr_get_type(rr)); return ODS_STATUS_UNCHANGED; } else if (zone->signconf->max_zone_ttl) { /* Convert MaxZoneTTL */ tmp = (uint32_t) duration2time(zone->signconf->max_zone_ttl); } } /* //MaxZoneTTL. Only set for RRtype != SOA && RRtype != DNSKEY */ if (tmp && tmp < ldns_rr_ttl(rr)) { char* str = ldns_rdf2str(ldns_rr_owner(rr)); if (str) { size_t i = 0; str[(strlen(str))-1] = '\0'; /* replace tabs with white space */ for (i=0; i < strlen(str); i++) { if (str[i] == '\t') { str[i] = ' '; } } ods_log_debug("[%s] capping ttl %u to MaxZoneTTL %u for rrset " "<%s,%s>", adapi_str, ldns_rr_ttl(rr), tmp, str, rrset_type2str(ldns_rr_get_type(rr))); } ldns_rr_set_ttl(rr, tmp); } /* TODO: DNAME and CNAME checks */ /* TODO: NS and DS checks */ if (add) { return zone_add_rr(zone, rr, 1); } else { return zone_del_rr(zone, rr, 1); } /* not reached */ return ODS_STATUS_ERR; }
int main(int argc, char **argv) { /* arguments */ int port; const char *zone_file; /* network */ int sock; ssize_t nb; struct sockaddr addr_me; struct sockaddr addr_him; socklen_t hislen = (socklen_t) sizeof(addr_him); uint8_t inbuf[INBUF_SIZE]; uint8_t *outbuf; /* dns */ ldns_status status; ldns_pkt *query_pkt; ldns_pkt *answer_pkt; size_t answer_size; ldns_rr *query_rr; ldns_rr_list *answer_qr; ldns_rr_list *answer_an; ldns_rr_list *answer_ns; ldns_rr_list *answer_ad; ldns_rdf *origin = NULL; /* zone */ ldns_zone *zone; int line_nr; FILE *zone_fp; /* use this to listen on specified interfaces later? */ char *my_address = NULL; if (argc < 5) { usage(stderr); exit(EXIT_FAILURE); } else { my_address = argv[1]; port = atoi(argv[2]); if (port < 1) { usage(stderr); exit(EXIT_FAILURE); } if (ldns_str2rdf_dname(&origin, argv[3]) != LDNS_STATUS_OK) { fprintf(stderr, "Bad origin, not a correct domain name\n"); usage(stderr); exit(EXIT_FAILURE); } zone_file = argv[4]; } printf("Reading zone file %s\n", zone_file); zone_fp = fopen(zone_file, "r"); if (!zone_fp) { fprintf(stderr, "Unable to open %s: %s\n", zone_file, strerror(errno)); exit(EXIT_FAILURE); } line_nr = 0; status = ldns_zone_new_frm_fp_l(&zone, zone_fp, origin, 0, LDNS_RR_CLASS_IN, &line_nr); if (status != LDNS_STATUS_OK) { printf("Zone reader failed, aborting\n"); exit(EXIT_FAILURE); } else { printf("Read %u resource records in zone file\n", (unsigned int) ldns_zone_rr_count(zone)); } fclose(zone_fp); printf("Listening on port %d\n", port); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno)); exit(1); } memset(&addr_me, 0, sizeof(addr_me)); /* bind: try all ports in that range */ if (udp_bind(sock, port, my_address)) { fprintf(stderr, "%s: cannot bind(): %s\n", argv[0], strerror(errno)); exit(errno); } /* Done. Now receive */ while (1) { nb = recvfrom(sock, (void*)inbuf, INBUF_SIZE, 0, &addr_him, &hislen); if (nb < 1) { fprintf(stderr, "%s: recvfrom(): %s\n", argv[0], strerror(errno)); exit(1); } /* show(inbuf, nb, nn, hp, sp, ip, bp); */ printf("Got query of %u bytes\n", (unsigned int) nb); status = ldns_wire2pkt(&query_pkt, inbuf, (size_t) nb); if (status != LDNS_STATUS_OK) { printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); } else { ldns_pkt_print(stdout, query_pkt); } query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); printf("QUERY RR: \n"); ldns_rr_print(stdout, query_rr); answer_qr = ldns_rr_list_new(); ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr)); answer_an = get_rrset(zone, ldns_rr_owner(query_rr), ldns_rr_get_type(query_rr), ldns_rr_get_class(query_rr)); answer_pkt = ldns_pkt_new(); answer_ns = ldns_rr_list_new(); answer_ad = ldns_rr_list_new(); ldns_pkt_set_qr(answer_pkt, 1); ldns_pkt_set_aa(answer_pkt, 1); ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt)); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); printf("Answer packet size: %u bytes.\n", (unsigned int) answer_size); if (status != LDNS_STATUS_OK) { printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); } else { nb = sendto(sock, (void*)outbuf, answer_size, 0, &addr_him, hislen); } ldns_pkt_free(query_pkt); ldns_pkt_free(answer_pkt); LDNS_FREE(outbuf); ldns_rr_list_free(answer_qr); ldns_rr_list_free(answer_an); ldns_rr_list_free(answer_ns); ldns_rr_list_free(answer_ad); } /* No cleanup because of the infinite loop * * ldns_rdf_deep_free(origin); * ldns_zone_deep_free(zone); * return 0; */ }
ldns_status ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c, int *line_nr) { ldns_zone *newzone; ldns_rr *rr; uint32_t my_ttl = ttl; ldns_rr_class my_class = c; ldns_rr *last_rr = NULL; ldns_rdf *my_origin; ldns_rdf *my_prev; bool soa_seen = false; /* 2 soa are an error */ ldns_status s; newzone = ldns_zone_new(); my_origin = origin; my_ttl = ttl; my_class = c; if (origin) { my_origin = ldns_rdf_clone(origin); /* also set the prev */ my_prev = ldns_rdf_clone(origin); } else { my_origin = NULL; my_prev = NULL; } while(!feof(fp)) { s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr); switch (s) { case LDNS_STATUS_OK: if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { if (soa_seen) { /* second SOA * just skip, maybe we want to say * something??? */ ldns_rr_free(rr); continue; } soa_seen = true; ldns_zone_set_soa(newzone, rr); /* set origin to soa if not specified */ if (!my_origin) { my_origin = ldns_rdf_clone(ldns_rr_owner(rr)); } continue; } /* a normal RR - as sofar the DNS is normal */ last_rr = rr; if (!ldns_zone_push_rr(newzone, rr)) { if (my_origin) { ldns_rdf_deep_free(my_origin); } ldns_zone_free(newzone); return LDNS_STATUS_MEM_ERR; } /*my_origin = ldns_rr_owner(rr);*/ my_ttl = ldns_rr_ttl(rr); my_class = ldns_rr_get_class(rr); case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */ case LDNS_STATUS_SYNTAX_TTL: /* the function set the ttl */ break; case LDNS_STATUS_SYNTAX_ORIGIN: /* the function set the origin */ break; default: ldns_zone_free(newzone); return s; } } if (my_origin) { ldns_rdf_deep_free(my_origin); } if (my_prev) { ldns_rdf_deep_free(my_prev); } if (z) { *z = newzone; } return LDNS_STATUS_OK; }
void zkdns_start(const char* my_address, int port, const char* my_zone) { rp_handle = rp_initialize(my_zone); /* network */ int sock; ssize_t nb; struct sockaddr addr_me; struct sockaddr addr_him; socklen_t hislen = (socklen_t) sizeof(addr_him); uint8_t inbuf[INBUF_SIZE]; uint8_t *outbuf; /* dns */ ldns_status status; ldns_pkt *query_pkt; ldns_pkt *answer_pkt; size_t answer_size; ldns_rr *query_rr; ldns_rr_list *answer_qr; ldns_rr_list *answer_an; ldns_rr_list *answer_ns; ldns_rr_list *answer_ad; ldns_rdf *origin = NULL; /* zone */ ldns_zone *zone; int line_nr; FILE *zone_fp; if (ldns_str2rdf_dname(&origin, my_zone) != LDNS_STATUS_OK) { fprintf(stderr, "Bad origin, not a correct domain name\n"); exit(EXIT_FAILURE); } printf("Listening on port %d\n", port); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { fprintf(stderr, "socket(): %s\n", strerror(errno)); exit(1); } memset(&addr_me, 0, sizeof(addr_me)); /* bind: try all ports in that range */ if (udp_bind(sock, port, my_address)) { fprintf(stderr, "cannot bind(): %s\n", strerror(errno)); exit(errno); } /* Done. Now receive */ while (1) { nb = recvfrom(sock, (void*)inbuf, INBUF_SIZE, 0, &addr_him, &hislen); if (nb < 1) { fprintf(stderr, "recvfrom(): %s\n", strerror(errno)); exit(1); } /* show(inbuf, nb, nn, hp, sp, ip, bp); */ status = ldns_wire2pkt(&query_pkt, inbuf, (size_t) nb); if (status != LDNS_STATUS_OK) { printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); } query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); answer_qr = ldns_rr_list_new(); ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr)); answer_an = get_rrset(zone, ldns_rr_owner(query_rr), ldns_rr_get_type(query_rr), ldns_rr_get_class(query_rr)); answer_pkt = ldns_pkt_new(); answer_ns = ldns_rr_list_new(); answer_ad = ldns_rr_list_new(); ldns_pkt_set_qr(answer_pkt, 1); ldns_pkt_set_aa(answer_pkt, 1); ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt)); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); if (status != LDNS_STATUS_OK) { printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); } else { nb = sendto(sock, (void*)outbuf, answer_size, 0, &addr_him, hislen); } ldns_pkt_free(query_pkt); ldns_pkt_free(answer_pkt); LDNS_FREE(outbuf); ldns_rr_list_free(answer_qr); ldns_rr_list_free(answer_an); ldns_rr_list_free(answer_ns); ldns_rr_list_free(answer_ad); } ldns_rdf_deep_free(origin); ldns_zone_deep_free(zone); rp_shutdown(rp_handle); }
/** read root hints from file */ static int read_root_hints(struct iter_hints* hints, char* fname) { int lineno = 0; uint32_t default_ttl = 0; ldns_rdf* origin = NULL; ldns_rdf* prev_rr = NULL; struct delegpt* dp; ldns_rr* rr = NULL; ldns_status status; uint16_t c = LDNS_RR_CLASS_IN; FILE* f = fopen(fname, "r"); if(!f) { log_err("could not read root hints %s: %s", fname, strerror(errno)); return 0; } dp = delegpt_create_mlc(NULL); if(!dp) { log_err("out of memory reading root hints"); fclose(f); return 0; } verbose(VERB_QUERY, "Reading root hints from %s", fname); dp->has_parent_side_NS = 1; while(!feof(f)) { status = ldns_rr_new_frm_fp_l(&rr, f, &default_ttl, &origin, &prev_rr, &lineno); if(status == LDNS_STATUS_SYNTAX_EMPTY || status == LDNS_STATUS_SYNTAX_TTL || status == LDNS_STATUS_SYNTAX_ORIGIN) continue; if(status != LDNS_STATUS_OK) { log_err("reading root hints %s %d: %s", fname, lineno, ldns_get_errorstr_by_id(status)); goto stop_read; } if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) { if(!delegpt_add_ns_mlc(dp, ldns_rdf_data(ldns_rr_rdf(rr, 0)), 0)) { log_err("out of memory reading root hints"); goto stop_read; } c = ldns_rr_get_class(rr); if(!dp->name) { if(!delegpt_set_name_mlc(dp, ldns_rdf_data(ldns_rr_owner(rr)))){ log_err("out of memory."); goto stop_read; } } } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A) { struct sockaddr_in sa; socklen_t len = (socklen_t)sizeof(sa); memset(&sa, 0, len); sa.sin_family = AF_INET; sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); memmove(&sa.sin_addr, ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET_SIZE); if(!delegpt_add_target_mlc(dp, ldns_rdf_data(ldns_rr_owner(rr)), ldns_rdf_size(ldns_rr_owner(rr)), (struct sockaddr_storage*)&sa, len, 0, 0)) { log_err("out of memory reading root hints"); goto stop_read; } } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) { struct sockaddr_in6 sa; socklen_t len = (socklen_t)sizeof(sa); memset(&sa, 0, len); sa.sin6_family = AF_INET6; sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); memmove(&sa.sin6_addr, ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET6_SIZE); if(!delegpt_add_target_mlc(dp, ldns_rdf_data(ldns_rr_owner(rr)), ldns_rdf_size(ldns_rr_owner(rr)), (struct sockaddr_storage*)&sa, len, 0, 0)) { log_err("out of memory reading root hints"); goto stop_read; } } else { log_warn("root hints %s:%d skipping type %d", fname, lineno, ldns_rr_get_type(rr)); } ldns_rr_free(rr); } if (origin) ldns_rdf_deep_free(origin); if (prev_rr) ldns_rdf_deep_free(prev_rr); fclose(f); if(!dp->name) { log_warn("root hints %s: no NS content", fname); delegpt_free_mlc(dp); return 1; } if(!hints_insert(hints, c, dp, 0)) { return 0; } delegpt_log(VERB_QUERY, dp); return 1; stop_read: if (origin) ldns_rdf_deep_free(origin); if (prev_rr) ldns_rdf_deep_free(prev_rr); delegpt_free_mlc(dp); fclose(f); return 0; }