void comm_point_send_reply(struct comm_reply* repinfo) { struct replay_answer* ans = (struct replay_answer*)calloc(1, sizeof(struct replay_answer)); ldns_status status; struct replay_runtime* runtime = (struct replay_runtime*)repinfo->c->ev; log_info("testbound: comm_point_send_reply fake"); /* dump it into the todo list */ log_assert(ans); memcpy(&ans->repinfo, repinfo, sizeof(struct comm_reply)); ans->next = NULL; if(runtime->answer_last) runtime->answer_last->next = ans; else runtime->answer_list = ans; runtime->answer_last = ans; /* try to parse packet */ status = ldns_buffer2pkt_wire(&ans->pkt, ans->repinfo.c->buffer); if(status != LDNS_STATUS_OK) { log_err("ldns error parsing packet: %s", ldns_get_errorstr_by_id(status)); fatal_exit("Sending unparseable DNS replies to clients!"); } log_pkt("reply pkt: ", ans->pkt); }
/** * 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); }
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); }
struct waiting_tcp* pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet, struct sockaddr_storage* addr, socklen_t addrlen, int timeout, comm_point_callback_t* callback, void* callback_arg) { struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct fake_pending* pend = (struct fake_pending*)calloc(1, sizeof(struct fake_pending)); ldns_status status; log_assert(pend); pend->buffer = ldns_buffer_new(ldns_buffer_capacity(packet)); log_assert(pend->buffer); ldns_buffer_write(pend->buffer, ldns_buffer_begin(packet), ldns_buffer_limit(packet)); ldns_buffer_flip(pend->buffer); memcpy(&pend->addr, addr, addrlen); pend->addrlen = addrlen; pend->callback = callback; pend->cb_arg = callback_arg; pend->timeout = timeout; pend->transport = transport_tcp; pend->pkt = NULL; pend->runtime = runtime; pend->serviced = 0; status = ldns_buffer2pkt_wire(&pend->pkt, packet); if(status != LDNS_STATUS_OK) { log_err("ldns error parsing tcp output packet: %s", ldns_get_errorstr_by_id(status)); fatal_exit("Sending unparseable DNS packets to servers!"); } log_pkt("pending tcp pkt: ", pend->pkt); /* see if it matches the current moment */ if(runtime->now && runtime->now->evt_type == repevt_back_query && (runtime->now->addrlen == 0 || sockaddr_cmp( &runtime->now->addr, runtime->now->addrlen, &pend->addr, pend->addrlen) == 0) && find_match(runtime->now->match, pend->pkt, pend->transport)) { log_info("testbound: matched pending to event. " "advance time between events."); log_info("testbound: do STEP %d %s", runtime->now->time_step, repevt_string(runtime->now->evt_type)); advance_moment(runtime); /* still create the pending, because we need it to callback */ } log_info("testbound: created fake pending"); /* add to list */ pend->next = runtime->pending_list; runtime->pending_list = pend; return (struct waiting_tcp*)pend; }
/** check if unbound formerr equals ldns formerr */ static void checkformerr(ldns_buffer* pkt) { ldns_pkt* p; ldns_status status = ldns_buffer2pkt_wire(&p, pkt); if(vbmp) printf("formerr, ldns parse is: %s\n", ldns_get_errorstr_by_id(status)); if(status == LDNS_STATUS_OK) { printf("Formerr, but ldns gives packet:\n"); ldns_pkt_print(stdout, p); exit(1); } unit_assert(status != LDNS_STATUS_OK); }
/* ============ CONVERSION ============ */ static int l_buf2pkt(lua_State *L) { ldns_buffer *b = (ldns_buffer *)lua_touserdata(L, 1); ldns_pkt *p; if (!b) { return 0; } if (ldns_buffer2pkt_wire(&p, b) != LDNS_STATUS_OK) { return 0; } lua_pushlightuserdata(L, p); return 1; }
/** see if buffers contain the same packet */ static int test_buffers(ldns_buffer* pkt, ldns_buffer* out) { ldns_pkt* p1=0, *p2=0; ldns_status s1, s2; /* check binary same */ if(ldns_buffer_limit(pkt) == ldns_buffer_limit(out) && memcmp(ldns_buffer_begin(pkt), ldns_buffer_begin(out), ldns_buffer_limit(pkt)) == 0) { if(vbmp) printf("binary the same (length=%u)\n", (unsigned)ldns_buffer_limit(pkt)); return 1; } if(vbmp) { size_t sz = 16; size_t count; size_t lim = ldns_buffer_limit(out); if(ldns_buffer_limit(pkt) < lim) lim = ldns_buffer_limit(pkt); for(count=0; count<lim; count+=sz) { size_t rem = sz; if(lim-count < sz) rem = lim-count; if(memcmp(ldns_buffer_at(pkt, count), ldns_buffer_at(out, count), rem) == 0) { log_info("same %d %d", (int)count, (int)rem); log_hex("same: ", ldns_buffer_at(pkt, count), rem); } else { log_info("diff %d %d", (int)count, (int)rem); log_hex("difp: ", ldns_buffer_at(pkt, count), rem); log_hex("difo: ", ldns_buffer_at(out, count), rem); } } } /* check if it 'means the same' */ s1 = ldns_buffer2pkt_wire(&p1, pkt); s2 = ldns_buffer2pkt_wire(&p2, out); if(vbmp) { log_buf(0, "orig in hex", pkt); log_buf(0, "unbound out in hex", out); printf("\npacket from unbound (%d):\n", (int)ldns_buffer_limit(out)); ldns_pkt_print(stdout, p2); printf("\npacket original (%d):\n", (int)ldns_buffer_limit(pkt)); ldns_pkt_print(stdout, p1); printf("\n"); } if(s1 != s2) { /* oops! */ printf("input ldns parse: %s, output ldns parse: %s.\n", ldns_get_errorstr_by_id(s1), ldns_get_errorstr_by_id(s2)); unit_assert(0); } /* compare packets */ unit_assert(match_all(p1, p2)); ldns_pkt_free(p1); ldns_pkt_free(p2); return 0; }
/* * 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); }
struct serviced_query* outnet_serviced_query(struct outside_network* outnet, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec), struct sockaddr_storage* addr, socklen_t addrlen, comm_point_callback_t* callback, void* callback_arg, ldns_buffer* ATTR_UNUSED(buff), int (*arg_compare)(void*,void*)) { struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct fake_pending* pend = (struct fake_pending*)calloc(1, sizeof(struct fake_pending)); ldns_status status; (void)arg_compare; log_assert(pend); log_nametypeclass(VERB_OPS, "pending serviced query", qname, qtype, qclass); verbose(VERB_OPS, "pending serviced query flags%s%s%s%s", (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"", (flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":""); /* create packet with EDNS */ pend->buffer = ldns_buffer_new(512); log_assert(pend->buffer); ldns_buffer_write_u16(pend->buffer, 0); /* id */ ldns_buffer_write_u16(pend->buffer, flags); ldns_buffer_write_u16(pend->buffer, 1); /* qdcount */ ldns_buffer_write_u16(pend->buffer, 0); /* ancount */ ldns_buffer_write_u16(pend->buffer, 0); /* nscount */ ldns_buffer_write_u16(pend->buffer, 0); /* arcount */ ldns_buffer_write(pend->buffer, qname, qnamelen); ldns_buffer_write_u16(pend->buffer, qtype); ldns_buffer_write_u16(pend->buffer, qclass); ldns_buffer_flip(pend->buffer); if(1) { /* add edns */ struct edns_data edns; edns.edns_present = 1; edns.ext_rcode = 0; edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits = 0; if(dnssec) edns.bits = EDNS_DO; attach_edns_record(pend->buffer, &edns); } memcpy(&pend->addr, addr, addrlen); pend->addrlen = addrlen; pend->callback = callback; pend->cb_arg = callback_arg; pend->timeout = UDP_AUTH_QUERY_TIMEOUT; pend->transport = transport_udp; /* pretend UDP */ pend->pkt = NULL; pend->runtime = runtime; pend->serviced = 1; status = ldns_buffer2pkt_wire(&pend->pkt, pend->buffer); if(status != LDNS_STATUS_OK) { log_err("ldns error parsing serviced output packet: %s", ldns_get_errorstr_by_id(status)); fatal_exit("internal error"); } /*log_pkt("pending serviced query: ", pend->pkt);*/ /* see if it matches the current moment */ if(runtime->now && runtime->now->evt_type == repevt_back_query && (runtime->now->addrlen == 0 || sockaddr_cmp( &runtime->now->addr, runtime->now->addrlen, &pend->addr, pend->addrlen) == 0) && find_match(runtime->now->match, pend->pkt, pend->transport)) { log_info("testbound: matched pending to event. " "advance time between events."); log_info("testbound: do STEP %d %s", runtime->now->time_step, repevt_string(runtime->now->evt_type)); advance_moment(runtime); /* still create the pending, because we need it to callback */ } log_info("testbound: created fake pending"); /* add to list */ pend->next = runtime->pending_list; runtime->pending_list = pend; return (struct serviced_query*)pend; }