Example #1
0
/** check request sanity.
 * @param pkt: the wire packet to examine for sanity.
 * @param worker: parameters for checking.
 * @return error code, 0 OK, or -1 discard.
*/
static int 
worker_check_request(sldns_buffer* pkt, struct worker* worker)
{
	if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
		verbose(VERB_QUERY, "request too short, discarded");
		return -1;
	}
	if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE && 
		worker->daemon->cfg->harden_large_queries) {
		verbose(VERB_QUERY, "request too large, discarded");
		return -1;
	}
	if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
		verbose(VERB_QUERY, "request has QR bit on, discarded");
		return -1;
	}
	if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
		LDNS_TC_CLR(sldns_buffer_begin(pkt));
		verbose(VERB_QUERY, "request bad, has TC bit on");
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
		verbose(VERB_QUERY, "request unknown opcode %d", 
			LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
	}
	if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
		verbose(VERB_QUERY, "request wrong nr qd=%d", 
			LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) {
		verbose(VERB_QUERY, "request wrong nr an=%d", 
			LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
		verbose(VERB_QUERY, "request wrong nr ns=%d", 
			LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
		verbose(VERB_QUERY, "request wrong nr ar=%d", 
			LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	return 0;
}
Example #2
0
int 
worker_handle_reply(struct comm_point* c, void* arg, int error, 
	struct comm_reply* reply_info)
{
	struct module_qstate* q = (struct module_qstate*)arg;
	struct worker* worker = q->env->worker;
	struct outbound_entry e;
	e.qstate = q;
	e.qsent = NULL;

	if(error != 0) {
		mesh_report_reply(worker->env.mesh, &e, reply_info, error);
		worker_mem_report(worker, NULL);
		return 0;
	}
	/* sanity check. */
	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 
			LDNS_PACKET_QUERY
		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
		/* error becomes timeout for the module as if this reply
		 * never arrived. */
		mesh_report_reply(worker->env.mesh, &e, reply_info, 
			NETEVENT_TIMEOUT);
		worker_mem_report(worker, NULL);
		return 0;
	}
	mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR);
	worker_mem_report(worker, NULL);
	return 0;
}
Example #3
0
int 
worker_handle_service_reply(struct comm_point* c, void* arg, int error, 
	struct comm_reply* reply_info)
{
	struct outbound_entry* e = (struct outbound_entry*)arg;
	struct worker* worker = e->qstate->env->worker;
	struct serviced_query *sq = e->qsent;

	verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate);
	if(error != 0) {
		mesh_report_reply(worker->env.mesh, e, reply_info, error);
		worker_mem_report(worker, sq);
		return 0;
	}
	/* sanity check. */
	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 
			LDNS_PACKET_QUERY
		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
		/* error becomes timeout for the module as if this reply
		 * never arrived. */
		verbose(VERB_ALGO, "worker: bad reply handled as timeout");
		mesh_report_reply(worker->env.mesh, e, reply_info, 
			NETEVENT_TIMEOUT);
		worker_mem_report(worker, sq);
		return 0;
	}
	mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR);
	worker_mem_report(worker, sq);
	return 0;
}
Example #4
0
int 
libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
        struct comm_reply* reply_info)
{
	struct outbound_entry* e = (struct outbound_entry*)arg;
	struct libworker* lw = (struct libworker*)e->qstate->env->worker;

	if(error != 0) {
		mesh_report_reply(lw->env->mesh, e, reply_info, error);
		return 0;
	}
	/* sanity check. */
	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
			LDNS_PACKET_QUERY
		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
		/* error becomes timeout for the module as if this reply
		 * never arrived. */
		mesh_report_reply(lw->env->mesh, e, reply_info, 
			NETEVENT_TIMEOUT);
		return 0;
	}
	mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
	return 0;
}
Example #5
0
int 
parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns)
{
	log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1);
	log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0);
	log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0);
	/* check edns section is present */
	if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
		return LDNS_RCODE_FORMERR;
	}
	if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) == 0) {
		memset(edns, 0, sizeof(*edns));
		edns->udp_size = 512;
		return 0;
	}
	/* domain name must be the root of length 1. */
	if(pkt_dname_len(pkt) != 1)
		return LDNS_RCODE_FORMERR;
	if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, rdatalen */
		return LDNS_RCODE_FORMERR;
	if(sldns_buffer_read_u16(pkt) != LDNS_RR_TYPE_OPT)
		return LDNS_RCODE_FORMERR;
	edns->edns_present = 1;
	edns->udp_size = sldns_buffer_read_u16(pkt); /* class is udp size */
	edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */
	edns->edns_version = sldns_buffer_read_u8(pkt);
	edns->bits = sldns_buffer_read_u16(pkt);
	/* ignore rdata and rrsigs */
	return 0;
}
Example #6
0
int 
query_info_parse(struct query_info* m, sldns_buffer* query)
{
	uint8_t* q = sldns_buffer_begin(query);
	/* minimum size: header + \0 + qtype + qclass */
	if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
		return 0;
	if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY || 
		LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0)
		return 0;
	sldns_buffer_skip(query, LDNS_HEADER_SIZE);
	m->qname = sldns_buffer_current(query);
	if((m->qname_len = query_dname_len(query)) == 0)
		return 0; /* parse error */
	if(sldns_buffer_remaining(query) < 4)
		return 0; /* need qtype, qclass */
	m->qtype = sldns_buffer_read_u16(query);
	m->qclass = sldns_buffer_read_u16(query);
	return 1;
}
Example #7
0
/*
 *  Makes an exact copy of the wire, but with the tsig rr removed
 */
static uint8_t *
ldns_tsig_prepare_pkt_wire(uint8_t *wire, size_t wire_len, size_t *result_len)
{
	uint8_t *wire2 = NULL;
	uint16_t qd_count;
	uint16_t an_count;
	uint16_t ns_count;
	uint16_t ar_count;
	ldns_rr *rr;

	size_t pos;
	uint16_t i;

	ldns_status status;

	if(wire_len < LDNS_HEADER_SIZE) {
		return NULL;
	}
	/* fake parse the wire */
	qd_count = LDNS_QDCOUNT(wire);
	an_count = LDNS_ANCOUNT(wire);
	ns_count = LDNS_NSCOUNT(wire);
	ar_count = LDNS_ARCOUNT(wire);

	if (ar_count > 0) {
		ar_count--;
	} else {
		return NULL;
	}

	pos = LDNS_HEADER_SIZE;

	for (i = 0; i < qd_count; i++) {
		status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_QUESTION);
		if (status != LDNS_STATUS_OK) {
			return NULL;
		}
		ldns_rr_free(rr);
	}

	for (i = 0; i < an_count; i++) {
		status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ANSWER);
		if (status != LDNS_STATUS_OK) {
			return NULL;
		}
		ldns_rr_free(rr);
	}

	for (i = 0; i < ns_count; i++) {
		status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_AUTHORITY);
		if (status != LDNS_STATUS_OK) {
			return NULL;
		}
		ldns_rr_free(rr);
	}

	for (i = 0; i < ar_count; i++) {
		status = ldns_wire2rr(&rr, wire, wire_len, &pos,
				LDNS_SECTION_ADDITIONAL);
		if (status != LDNS_STATUS_OK) {
			return NULL;
		}
		ldns_rr_free(rr);
	}

	*result_len = pos;
	wire2 = LDNS_XMALLOC(uint8_t, *result_len);
	if(!wire2) {
		return NULL;
	}
	memcpy(wire2, wire, *result_len);

	ldns_write_uint16(wire2 + LDNS_ARCOUNT_OFF, ar_count);

	return wire2;
}
Example #8
0
/** test a packet */
static void
testpkt(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, 
	const char* hex)
{
	struct query_info qi;
	struct reply_info* rep = 0;
	int ret;
	uint16_t id;
	uint16_t flags;
	uint32_t timenow = 0;
	struct regional* region = regional_create();
	struct edns_data edns;

	hex_to_buf(pkt, hex);
	memmove(&id, sldns_buffer_begin(pkt), sizeof(id));
	if(sldns_buffer_limit(pkt) < 2)
		flags = 0;
	else	memmove(&flags, sldns_buffer_at(pkt, 2), sizeof(flags));
	flags = ntohs(flags);
	ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns);
	if(ret != 0) {
		char rbuf[16];
		sldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf));
		if(vbmp) printf("parse code %d: %s\n", ret, rbuf);
		if(ret == LDNS_RCODE_FORMERR) {
			unit_assert(!check_formerr_gone);
			checkformerr(pkt);
		}
		unit_assert(ret != LDNS_RCODE_SERVFAIL);
	} else if(!check_formerr_gone) {
		const size_t lim = 512;
		ret = reply_info_encode(&qi, rep, id, flags, out, timenow,
			region, 65535, (int)(edns.bits & EDNS_DO) );
		unit_assert(ret != 0); /* udp packets should fit */
		attach_edns_record(out, &edns);
		if(vbmp) printf("inlen %u outlen %u\n", 
			(unsigned)sldns_buffer_limit(pkt),
			(unsigned)sldns_buffer_limit(out));
		if(!check_nosameness)
			test_buffers(pkt, out);
		if(check_rrsigs)
			check_the_rrsigs(&qi, rep);

		if(sldns_buffer_limit(out) > lim) {
			ret = reply_info_encode(&qi, rep, id, flags, out, 
				timenow, region, 
				lim - calc_edns_field_size(&edns),
				(int)(edns.bits & EDNS_DO));
			unit_assert(ret != 0); /* should fit, but with TC */
			attach_edns_record(out, &edns);
			if( LDNS_QDCOUNT(sldns_buffer_begin(out)) !=
				LDNS_QDCOUNT(sldns_buffer_begin(pkt)) ||
				LDNS_ANCOUNT(sldns_buffer_begin(out)) !=
				LDNS_ANCOUNT(sldns_buffer_begin(pkt)) ||
				LDNS_NSCOUNT(sldns_buffer_begin(out)) !=
				LDNS_NSCOUNT(sldns_buffer_begin(pkt)))
				unit_assert(
				LDNS_TC_WIRE(sldns_buffer_begin(out)));
				/* must set TC bit if shortened */
			unit_assert(sldns_buffer_limit(out) <= lim);
		}
	} 

	query_info_clear(&qi);
	reply_info_parsedelete(rep, alloc);
	regional_destroy(region);
}