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);
}
Example #3
0
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);
}
Example #6
0
File: lua.c Project: benlaurie/ldns
/*
============
 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;
}
Example #8
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;
}