Beispiel #1
0
/** analyse pkt */
static void analyze(sldns_buffer* pkt)
{
	uint16_t i, f, qd, an, ns, ar;
	int rrnum = 0;
	printf("packet length %d\n", (int)sldns_buffer_limit(pkt));
	if(sldns_buffer_limit(pkt) < 12) return;

	i = sldns_buffer_read_u16(pkt);
	printf("id (hostorder): %d (0x%x)\n", (int)i, (unsigned)i);
	f = sldns_buffer_read_u16(pkt);
	printf("flags: 0x%x\n", (unsigned)f);
	qd = sldns_buffer_read_u16(pkt);
	printf("qdcount: %d\n", (int)qd);
	an = sldns_buffer_read_u16(pkt);
	printf("ancount: %d\n", (int)an);
	ns = sldns_buffer_read_u16(pkt);
	printf("nscount: %d\n", (int)ns);
	ar = sldns_buffer_read_u16(pkt);
	printf("arcount: %d\n", (int)ar);
	
	printf(";-- query section\n");
	while(sldns_buffer_remaining(pkt) > 0) {
		if(rrnum == (int)qd) 
			printf(";-- answer section\n");
		if(rrnum == (int)qd+(int)an) 
			printf(";-- authority section\n");
		if(rrnum == (int)qd+(int)an+(int)ns) 
			printf(";-- additional section\n");
		printf("rr %d ", rrnum);
		analyze_rr(pkt, rrnum < (int)qd);
		rrnum++;
	}
}
Beispiel #2
0
size_t
nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, 
	size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
{
	size_t i, hash_len;
	/* prepare buffer for first iteration */
	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, nm, nmlen);
	query_dname_tolower(sldns_buffer_begin(buf));
	sldns_buffer_write(buf, salt, saltlen);
	sldns_buffer_flip(buf);
	hash_len = nsec3_hash_algo_size_supported(algo);
	if(hash_len == 0) {
		log_err("nsec3 hash of unknown algo %d", algo);
		return 0;
	}
	if(hash_len > max)
		return 0;
	if(!secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf),
		sldns_buffer_limit(buf), (unsigned char*)res))
		return 0;
	for(i=0; i<iter; i++) {
		sldns_buffer_clear(buf);
		sldns_buffer_write(buf, res, hash_len);
		sldns_buffer_write(buf, salt, saltlen);
		sldns_buffer_flip(buf);
		if(!secalgo_nsec3_hash(algo,
			(unsigned char*)sldns_buffer_begin(buf),
			sldns_buffer_limit(buf), (unsigned char*)res))
			return 0;
	}
	return hash_len;
}
Beispiel #3
0
/** add entry to ringbuffer */
static void
ring_add(struct ringbuf* r, sldns_buffer* pkt, struct timeval* now, 
	struct timeval* delay, struct proxy* p)
{
	/* time -- proxy* -- 16bitlen -- message */
	uint16_t len = (uint16_t)sldns_buffer_limit(pkt);
	struct timeval when;
	size_t needed;
	uint8_t* where = NULL;
	log_assert(sldns_buffer_limit(pkt) <= 65535);
	needed = sizeof(when) + sizeof(p) + sizeof(len) + len;
	/* put item into ringbuffer */
	if(r->low < r->high) {
		/* used part is in the middle */
		if(r->size - r->high >= needed) {
			where = r->buf + r->high;
			r->high += needed;
		} else if(r->low > needed) {
			/* wrap around ringbuffer */
			/* make sure r->low == r->high means empty */
			/* so r->low == r->high cannot be used to signify
			 * a completely full ringbuf */
			if(r->size - r->high > sizeof(when)+sizeof(p)) {
				/* zero entry at end of buffer */
				memset(r->buf+r->high, 0, 
					sizeof(when)+sizeof(p));
			}
			where = r->buf;
			r->high = needed;
		} else {
			/* drop message */
			log_warn("warning: mem full, dropped message");
			return;
		}
	} else {
		/* empty */
		if(r->high == r->low) {
			where = r->buf;
			r->low = 0;
			r->high = needed;
		/* unused part is in the middle */
		/* so ringbuffer has wrapped around */
		} else if(r->low - r->high > needed) {
			where = r->buf + r->high;
			r->high += needed;
		} else {
			log_warn("warning: mem full, dropped message");
			return;
		}
	}
	when = *now;
	dl_tv_add(&when, delay);
	/* copy it at where part */
	log_assert(where != NULL);
	memmove(where, &when, sizeof(when));
	memmove(where+sizeof(when), &p, sizeof(p));
	memmove(where+sizeof(when)+sizeof(p), &len, sizeof(len));
	memmove(where+sizeof(when)+sizeof(p)+sizeof(len), 
		sldns_buffer_begin(pkt), len);
}
Beispiel #4
0
/** send out waiting packets */
static void
service_send(struct ringbuf* ring, struct timeval* now, sldns_buffer* pkt,
	struct sockaddr_storage* srv_addr, socklen_t srv_len)
{
	struct proxy* p;
	struct timeval tv;
	ssize_t sent;
	while(!ring_empty(ring) && 
		dl_tv_smaller(ring_peek_time(ring), now)) {
		/* this items needs to be sent out */
		if(!ring_pop(ring, pkt, &tv, &p))
			fatal_exit("ringbuf error: pop failed");
		verbose(1, "send out query %d.%6.6d", 
			(unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
		log_addr(1, "from client", &p->addr, p->addr_len);
		/* send it */
		sent = sendto(p->s, (void*)sldns_buffer_begin(pkt), 
			sldns_buffer_limit(pkt), 0, 
			(struct sockaddr*)srv_addr, srv_len);
		if(sent == -1) {
#ifndef USE_WINSOCK
			log_err("sendto: %s", strerror(errno));
#else
			log_err("sendto: %s", wsa_strerror(WSAGetLastError()));
#endif
		} else if(sent != (ssize_t)sldns_buffer_limit(pkt)) {
			log_err("sendto: partial send");
		}
		p->lastuse = *now;
		p->numsent++;
	}
}
Beispiel #5
0
size_t
nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, 
	size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
{
	size_t i, hash_len;
	/* prepare buffer for first iteration */
	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, nm, nmlen);
	query_dname_tolower(sldns_buffer_begin(buf));
	sldns_buffer_write(buf, salt, saltlen);
	sldns_buffer_flip(buf);
	switch(algo) {
#if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS)
		case NSEC3_HASH_SHA1:
#ifdef HAVE_SSL
			hash_len = SHA_DIGEST_LENGTH;
#else
			hash_len = SHA1_LENGTH;
#endif
			if(hash_len > max)
				return 0;
#  ifdef HAVE_SSL
			(void)SHA1((unsigned char*)sldns_buffer_begin(buf),
				(unsigned long)sldns_buffer_limit(buf),
				(unsigned char*)res);
#  else
			(void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)res,
				(unsigned char*)sldns_buffer_begin(buf),
				(unsigned long)sldns_buffer_limit(buf));
#  endif
			for(i=0; i<iter; i++) {
				sldns_buffer_clear(buf);
				sldns_buffer_write(buf, res, hash_len);
				sldns_buffer_write(buf, salt, saltlen);
				sldns_buffer_flip(buf);
#  ifdef HAVE_SSL
				(void)SHA1(
					(unsigned char*)sldns_buffer_begin(buf),
					(unsigned long)sldns_buffer_limit(buf),
					(unsigned char*)res);
#  else
				(void)HASH_HashBuf(HASH_AlgSHA1,
					(unsigned char*)res,
					(unsigned char*)sldns_buffer_begin(buf),
					(unsigned long)sldns_buffer_limit(buf));
#  endif
			}
			break;
#endif /* HAVE_EVP_SHA1 or NSS */
		default:
			log_err("nsec3 hash of unknown algo %d", algo);
			return 0;
	}
	return hash_len;
}
Beispiel #6
0
struct waiting_tcp* 
pending_tcp_query(struct outside_network* outnet, sldns_buffer* packet,
	struct sockaddr_storage* addr, socklen_t addrlen, int timeout,
	comm_point_callback_t* callback, void* callback_arg,
	int ATTR_UNUSED(ssl_upstream))
{
	struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
	struct fake_pending* pend = (struct fake_pending*)calloc(1,
		sizeof(struct fake_pending));
	log_assert(pend);
	pend->buffer = sldns_buffer_new(sldns_buffer_capacity(packet));
	log_assert(pend->buffer);
	sldns_buffer_write(pend->buffer, sldns_buffer_begin(packet),
		sldns_buffer_limit(packet));
	sldns_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->zone = NULL;
	pend->runtime = runtime;
	pend->serviced = 0;
	pend->pkt_len = sldns_buffer_limit(packet);
	pend->pkt = memdup(sldns_buffer_begin(packet), pend->pkt_len);
	if(!pend->pkt) fatal_exit("out of memory");
	log_pkt("pending tcp pkt: ", pend->pkt, pend->pkt_len);

	/* 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->pkt_len,
			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;
}
Beispiel #7
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;
}
Beispiel #8
0
void
attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
{
	size_t len;
	size_t rdatapos;
	struct edns_option* opt;
	if(!edns || !edns->edns_present)
		return;
	/* inc additional count */
	sldns_buffer_write_u16_at(pkt, 10,
		sldns_buffer_read_u16_at(pkt, 10) + 1);
	len = sldns_buffer_limit(pkt);
	sldns_buffer_clear(pkt);
	sldns_buffer_set_position(pkt, len);
	/* write EDNS record */
	sldns_buffer_write_u8(pkt, 0); /* '.' label */
	sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
	sldns_buffer_write_u16(pkt, edns->udp_size); /* class */
	sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
	sldns_buffer_write_u8(pkt, edns->edns_version);
	sldns_buffer_write_u16(pkt, edns->bits);
	rdatapos = sldns_buffer_position(pkt);
	sldns_buffer_write_u16(pkt, 0); /* rdatalen */
	/* write rdata */
	for(opt=edns->opt_list; opt; opt=opt->next) {
		sldns_buffer_write_u16(pkt, opt->opt_code);
		sldns_buffer_write_u16(pkt, opt->opt_len);
		if(opt->opt_len != 0)
			sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
	}
	if(edns->opt_list)
		sldns_buffer_write_u16_at(pkt, rdatapos, 
			sldns_buffer_position(pkt)-rdatapos-2);
	sldns_buffer_flip(pkt);
}
Beispiel #9
0
void
pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
{
    uint8_t lablen;
    int count = 0;
    if(dname >= sldns_buffer_end(pkt))
        return;
    lablen = *dname++;
    while(lablen) {
        if(LABEL_IS_PTR(lablen)) {
            if((size_t)PTR_OFFSET(lablen, *dname)
                    >= sldns_buffer_limit(pkt))
                return;
            dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
            lablen = *dname++;
            if(count++ > MAX_COMPRESS_PTRS)
                return;
            continue;
        }
        if(dname+lablen >= sldns_buffer_end(pkt))
            return;
        while(lablen--) {
            *dname = (uint8_t)tolower((int)*dname);
            dname++;
        }
        if(dname >= sldns_buffer_end(pkt))
            return;
        lablen = *dname++;
    }
}
Beispiel #10
0
/** performance test message encoding */
static void
perf_encode(struct query_info* qi, struct reply_info* rep, uint16_t id, 
	uint16_t flags, sldns_buffer* out, time_t timenow, 
	struct edns_data* edns)
{
	static int num = 0;
	int ret;
	size_t max = 10000;
	size_t i;
	struct timeval start, end;
	double dt;
	struct regional* r2 = regional_create();
	if(gettimeofday(&start, NULL) < 0)
		fatal_exit("gettimeofday: %s", strerror(errno));
	/* encode a couple times */
	for(i=0; i<max; i++) {
		ret = reply_info_encode(qi, rep, id, flags, out, timenow,
			r2, 65535, (int)(edns->bits & EDNS_DO) );
		unit_assert(ret != 0); /* udp packets should fit */
		attach_edns_record(out, edns);
		regional_free_all(r2);
	}
	if(gettimeofday(&end, NULL) < 0)
		fatal_exit("gettimeofday: %s", strerror(errno));
	/* time in millisec */
	dt = (double)(end.tv_sec - start.tv_sec)*1000. + 
		((double)end.tv_usec - (double)start.tv_usec)/1000.;
	printf("[%d] did %u in %g msec for %f encode/sec size %d\n", num++,
		(unsigned)max, dt, (double)max / (dt/1000.), 
		(int)sldns_buffer_limit(out));
	regional_destroy(r2);
}
Beispiel #11
0
/** perf test a packet */
static void
perftestpkt(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;
	time_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)
			checkformerr(pkt);
		unit_assert(ret != LDNS_RCODE_SERVFAIL);
	} else {
		perf_encode(&qi, rep, id, flags, out, timenow, &edns);
	} 

	query_info_clear(&qi);
	reply_info_parsedelete(rep, alloc);
	regional_destroy(region);
}
Beispiel #12
0
void
libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf,
	enum sec_status s, char* why_bogus)
{
	struct ctx_query* q = (struct ctx_query*)arg;
	ub_event_callback_type cb = (ub_event_callback_type)q->cb;
	void* cb_arg = q->cb_arg;
	int cancelled = q->cancelled;

	/* delete it now */
	struct ub_ctx* ctx = q->w->ctx;
	lock_basic_lock(&ctx->cfglock);
	(void)rbtree_delete(&ctx->queries, q->node.key);
	ctx->num_async--;
	context_query_delete(q);
	lock_basic_unlock(&ctx->cfglock);

	if(!cancelled) {
		/* call callback */
		int sec = 0;
		if(s == sec_status_bogus)
			sec = 1;
		else if(s == sec_status_secure)
			sec = 2;
		(*cb)(cb_arg, rcode, (void*)sldns_buffer_begin(buf),
			(int)sldns_buffer_limit(buf), sec, why_bogus);
	}
}
Beispiel #13
0
/**
 * Create a DS digest for a DNSKEY entry.
 *
 * @param env: module environment. Uses scratch space.
 * @param dnskey_rrset: DNSKEY rrset.
 * @param dnskey_idx: index of RR in rrset.
 * @param ds_rrset: DS rrset
 * @param ds_idx: index of RR in DS rrset.
 * @param digest: digest is returned in here (must be correctly sized).
 * @return false on error.
 */
static int
ds_create_dnskey_digest(struct module_env* env, 
	struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
	struct ub_packed_rrset_key* ds_rrset, size_t ds_idx,
	uint8_t* digest)
{
	sldns_buffer* b = env->scratch_buffer;
	uint8_t* dnskey_rdata;
	size_t dnskey_len;
	rrset_get_rdata(dnskey_rrset, dnskey_idx, &dnskey_rdata, &dnskey_len);

	/* create digest source material in buffer 
	 * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
	 *	DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */
	sldns_buffer_clear(b);
	sldns_buffer_write(b, dnskey_rrset->rk.dname, 
		dnskey_rrset->rk.dname_len);
	query_dname_tolower(sldns_buffer_begin(b));
	sldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/
	sldns_buffer_flip(b);
	
	return secalgo_ds_digest(ds_get_digest_algo(ds_rrset, ds_idx),
		(unsigned char*)sldns_buffer_begin(b), sldns_buffer_limit(b),
		(unsigned char*)digest);
}
Beispiel #14
0
/** check expiry, return true if matches OK */
static int
good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
{
	uint64_t expiry;
	/* the expiry time is the last bytes of the buffer */
	if(sldns_buffer_limit(buf) < sizeof(expiry))
		return 0;
	sldns_buffer_read_at(buf, sldns_buffer_limit(buf)-sizeof(expiry),
		&expiry, sizeof(expiry));
	expiry = be64toh(expiry);

	if((time_t)expiry < *qstate->env->now &&
		!qstate->env->cfg->serve_expired)
		return 0;

	return 1;
}
Beispiel #15
0
static void
dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has)
{
	log_assert(b != NULL);
	p->len = sldns_buffer_limit(b);
	p->data = sldns_buffer_begin(b);
	*has = 1;
}
Beispiel #16
0
/** setup query list in info */
static void
qlist_add_line(struct perfinfo* info, char* line, int no)
{
	if(!qlist_parse_line(info->buf, line)) {
		printf("error parsing query %d: %s\n", no, line);
		exit(1);
	}
	sldns_buffer_write_u16_at(info->buf, 0, (uint16_t)info->qlist_size); 
	if(info->qlist_size + 1 > info->qlist_capacity) {
		qlist_grow_capacity(info);
	}
	info->qlist_len[info->qlist_size] = sldns_buffer_limit(info->buf);
	info->qlist_data[info->qlist_size] = memdup(
		sldns_buffer_begin(info->buf), sldns_buffer_limit(info->buf));
	if(!info->qlist_data[info->qlist_size])
		fatal_exit("out of memory");
	info->qlist_size ++;
}
void server_stats_insrcode(struct ub_server_stats* stats, sldns_buffer* buf)
{
	if(stats->extended && sldns_buffer_limit(buf) != 0) {
		int r = (int)LDNS_RCODE_WIRE( sldns_buffer_begin(buf) );
		stats->ans_rcode[r] ++;
		if(r == 0 && LDNS_ANCOUNT( sldns_buffer_begin(buf) ) == 0)
			stats->ans_rcode_nodata ++;
	}
}
Beispiel #18
0
void 
sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from)
{
	size_t tocopy = sldns_buffer_limit(from);

	if(tocopy > sldns_buffer_capacity(result))
		tocopy = sldns_buffer_capacity(result);
	sldns_buffer_clear(result);
	sldns_buffer_write(result, sldns_buffer_begin(from), tocopy);
	sldns_buffer_flip(result);
}
Beispiel #19
0
int 
reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, 
	uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow,
	int cached, struct regional* region, uint16_t udpsize, 
	struct edns_data* edns, int dnssec, int secure)
{
	uint16_t flags;
	unsigned int attach_edns = 0;

	if(!cached || rep->authoritative) {
		/* original flags, copy RD and CD bits from query. */
		flags = rep->flags | (qflags & (BIT_RD|BIT_CD)); 
	} else {
		/* remove AA bit, copy RD and CD bits from query. */
		flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); 
	}
	if(secure && (dnssec || (qflags&BIT_AD)))
		flags |= BIT_AD;
	/* restore AA bit if we have a local alias and the response can be
	 * authoritative.  Also clear AD bit if set as the local data is the
	 * primary answer. */
	if(qinf->local_alias &&
		(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR ||
		FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) {
		flags |= BIT_AA;
		flags &= ~BIT_AD;
	}
	log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
	if(udpsize < LDNS_HEADER_SIZE)
		return 0;
	if(sldns_buffer_capacity(pkt) < udpsize)
		udpsize = sldns_buffer_capacity(pkt);
	if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) {
		/* packet too small to contain edns, omit it. */
		attach_edns = 0;
	} else {
		/* reserve space for edns record */
		attach_edns = (unsigned int)calc_edns_field_size(edns);
		udpsize -= attach_edns;
	}

	if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
		udpsize, dnssec)) {
		log_err("reply encode: out of memory");
		return 0;
	}
	if(attach_edns && sldns_buffer_capacity(pkt) >=
		sldns_buffer_limit(pkt)+attach_edns)
		attach_edns_record(pkt, edns);
	return 1;
}
Beispiel #20
0
void 
comm_point_send_reply(struct comm_reply* repinfo)
{
	struct replay_answer* ans = (struct replay_answer*)calloc(1,
		sizeof(struct replay_answer));
	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 */
	ans->pkt = memdup(sldns_buffer_begin(ans->repinfo.c->buffer),
		sldns_buffer_limit(ans->repinfo.c->buffer));
	ans->pkt_len = sldns_buffer_limit(ans->repinfo.c->buffer);
	if(!ans->pkt) fatal_exit("out of memory");
	log_pkt("reply pkt: ", ans->pkt, ans->pkt_len);
}
Beispiel #21
0
/** perform hash of name */
static int
nsec3_calc_hash(struct regional* region, sldns_buffer* buf, 
	struct nsec3_cached_hash* c)
{
	int algo = nsec3_get_algo(c->nsec3, c->rr);
	size_t iter = nsec3_get_iter(c->nsec3, c->rr);
	uint8_t* salt;
	size_t saltlen, i;
	if(!nsec3_get_salt(c->nsec3, c->rr, &salt, &saltlen))
		return -1;
	/* prepare buffer for first iteration */
	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, c->dname, c->dname_len);
	query_dname_tolower(sldns_buffer_begin(buf));
	sldns_buffer_write(buf, salt, saltlen);
	sldns_buffer_flip(buf);
	c->hash_len = nsec3_hash_algo_size_supported(algo);
	if(c->hash_len == 0) {
		log_err("nsec3 hash of unknown algo %d", algo);
		return -1;
	}
	c->hash = (uint8_t*)regional_alloc(region, c->hash_len);
	if(!c->hash)
		return 0;
	(void)secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf),
		sldns_buffer_limit(buf), (unsigned char*)c->hash);
	for(i=0; i<iter; i++) {
		sldns_buffer_clear(buf);
		sldns_buffer_write(buf, c->hash, c->hash_len);
		sldns_buffer_write(buf, salt, saltlen);
		sldns_buffer_flip(buf);
		(void)secalgo_nsec3_hash(algo,
			(unsigned char*)sldns_buffer_begin(buf),
			sldns_buffer_limit(buf), (unsigned char*)c->hash);
	}
	return 1;
}
Beispiel #22
0
size_t
pkt_dname_len(sldns_buffer* pkt)
{
    size_t len = 0;
    int ptrcount = 0;
    uint8_t labellen;
    size_t endpos = 0;

    /* read dname and determine length */
    /* check compression pointers, loops, out of bounds */
    while(1) {
        /* read next label */
        if(sldns_buffer_remaining(pkt) < 1)
            return 0;
        labellen = sldns_buffer_read_u8(pkt);
        if(LABEL_IS_PTR(labellen)) {
            /* compression ptr */
            uint16_t ptr;
            if(sldns_buffer_remaining(pkt) < 1)
                return 0;
            ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
            if(ptrcount++ > MAX_COMPRESS_PTRS)
                return 0; /* loop! */
            if(sldns_buffer_limit(pkt) <= ptr)
                return 0; /* out of bounds! */
            if(!endpos)
                endpos = sldns_buffer_position(pkt);
            sldns_buffer_set_position(pkt, ptr);
        } else {
            /* label contents */
            if(labellen > 0x3f)
                return 0; /* label too long */
            len += 1 + labellen;
            if(len > LDNS_MAX_DOMAINLEN)
                return 0;
            if(labellen == 0) {
                /* end of dname */
                break;
            }
            if(sldns_buffer_remaining(pkt) < labellen)
                return 0;
            sldns_buffer_skip(pkt, (ssize_t)labellen);
        }
    }
    if(endpos)
        sldns_buffer_set_position(pkt, endpos);

    return len;
}
Beispiel #23
0
/** convert data from return_msg into the data buffer */
static int
prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
{
	uint64_t timestamp, expiry;
	size_t oldlim;
	struct edns_data edns;
	memset(&edns, 0, sizeof(edns));
	edns.edns_present = 1;
	edns.bits = EDNS_DO;
	edns.ext_rcode = 0;
	edns.edns_version = EDNS_ADVERTISED_VERSION;
	edns.udp_size = EDNS_ADVERTISED_SIZE;

	if(!qstate->return_msg || !qstate->return_msg->rep)
		return 0;
	/* We don't store the reply if its TTL is 0 unless serve-expired is
	 * enabled.  Such a reply won't be reusable and simply be a waste for
	 * the backend.  It's also compatible with the default behavior of
	 * dns_cache_store_msg(). */
	if(qstate->return_msg->rep->ttl == 0 &&
		!qstate->env->cfg->serve_expired)
		return 0;
	if(verbosity >= VERB_ALGO)
		log_dns_msg("cachedb encoding", &qstate->return_msg->qinfo,
	                qstate->return_msg->rep);
	if(!reply_info_answer_encode(&qstate->return_msg->qinfo,
		qstate->return_msg->rep, 0, qstate->query_flags,
		buf, 0, 1, qstate->env->scratch, 65535, &edns, 1, 0))
		return 0;

	/* TTLs in the return_msg are relative to time(0) so we have to
	 * store that, we also store the smallest ttl in the packet+time(0)
	 * as the packet expiry time */
	/* qstate->return_msg->rep->ttl contains that relative shortest ttl */
	timestamp = (uint64_t)*qstate->env->now;
	expiry = timestamp + (uint64_t)qstate->return_msg->rep->ttl;
	timestamp = htobe64(timestamp);
	expiry = htobe64(expiry);
	oldlim = sldns_buffer_limit(buf);
	if(oldlim + sizeof(timestamp)+sizeof(expiry) >=
		sldns_buffer_capacity(buf))
		return 0; /* doesn't fit. */
	sldns_buffer_set_limit(buf, oldlim + sizeof(timestamp)+sizeof(expiry));
	sldns_buffer_write_at(buf, oldlim, &timestamp, sizeof(timestamp));
	sldns_buffer_write_at(buf, oldlim+sizeof(timestamp), &expiry,
		sizeof(expiry));

	return 1;
}
Beispiel #24
0
/** fillup fg results */
static void
libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, 
	enum sec_status s, char* why_bogus)
{
	if(why_bogus)
		q->res->why_bogus = strdup(why_bogus);
	if(rcode != 0) {
		q->res->rcode = rcode;
		q->msg_security = s;
		return;
	}

	q->res->rcode = LDNS_RCODE_SERVFAIL;
	q->msg_security = 0;
	q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf));
	q->msg_len = sldns_buffer_limit(buf);
	if(!q->msg) {
		return; /* the error is in the rcode */
	}

	/* canonname and results */
	q->msg_security = s;
	libworker_enter_result(q->res, buf, q->w->env->scratch, s);
}
Beispiel #25
0
/**
 * Store the qstate.return_msg in extcache for key qstate.info
 */
static void
cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie)
{
	char key[(CACHEDB_HASHSIZE/8)*2+1];
	calc_hash(qstate, key, sizeof(key));

	/* prepare data in scratch buffer */
	if(!prep_data(qstate, qstate->env->scratch_buffer))
		return;
	
	/* call backend */
	(*ie->backend->store)(qstate->env, ie, key,
		sldns_buffer_begin(qstate->env->scratch_buffer),
		sldns_buffer_limit(qstate->env->scratch_buffer));
}
Beispiel #26
0
int
nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
	struct ub_packed_rrset_key* rrset, int rr, sldns_buffer* buf)
{
	uint8_t* next, *owner;
	size_t nextlen;
	int len;
	if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen))
		return 0; /* malformed RR proves nothing */

	/* check the owner name is a hashed value . apex
	 * base32 encoded values must have equal length. 
	 * hash_value and next hash value must have equal length. */
	if(nextlen != hash->hash_len || hash->hash_len==0||hash->b32_len==0|| 
		(size_t)*rrset->rk.dname != hash->b32_len ||
		query_dname_compare(rrset->rk.dname+1+
			(size_t)*rrset->rk.dname, zone) != 0)
		return 0; /* bad lengths or owner name */

	/* This is the "normal case: owner < next and owner < hash < next */
	if(label_compare_lower(rrset->rk.dname+1, hash->b32, 
		hash->b32_len) < 0 && 
		memcmp(hash->hash, next, nextlen) < 0)
		return 1;

	/* convert owner name from text to binary */
	sldns_buffer_clear(buf);
	owner = sldns_buffer_begin(buf);
	len = sldns_b32_pton_extended_hex((char*)rrset->rk.dname+1, 
		hash->b32_len, owner, sldns_buffer_limit(buf));
	if(len<1)
		return 0; /* bad owner name in some way */
	if((size_t)len != hash->hash_len || (size_t)len != nextlen)
		return 0; /* wrong length */

	/* this is the end of zone case: next <= owner && 
	 * 	(hash > owner || hash < next) 
	 * this also covers the only-apex case of next==owner.
	 */
	if(memcmp(next, owner, nextlen) <= 0 &&
		( memcmp(hash->hash, owner, nextlen) > 0 ||
		  memcmp(hash->hash, next, nextlen) < 0)) {
		return 1;
	}
	return 0;
}
Beispiel #27
0
/** check if unbound formerr equals ldns formerr */
static void
checkformerr(sldns_buffer* pkt)
{
	int status = 0;
	char* s = sldns_wire2str_pkt(sldns_buffer_begin(pkt),
		sldns_buffer_limit(pkt));
	if(!s) fatal_exit("out of memory");
	if(strstr(s, "Error")) status = 1;
	if(strstr(s, "error")) status = 1;
	if(status == 0) {
		printf("Formerr, but ldns gives packet:\n");
		printf("%s\n", s);
		free(s);
		exit(1);
	}
	free(s);
	unit_assert(status != 0);
}
Beispiel #28
0
/** perform b32 encoding of hash */
static int
nsec3_calc_b32(struct regional* region, sldns_buffer* buf, 
	struct nsec3_cached_hash* c)
{
	int r;
	sldns_buffer_clear(buf);
	r = sldns_b32_ntop_extended_hex(c->hash, c->hash_len,
		(char*)sldns_buffer_begin(buf), sldns_buffer_limit(buf));
	if(r < 1) {
		log_err("b32_ntop_extended_hex: error in encoding: %d", r);
		return 0;
	}
	c->b32_len = (size_t)r;
	c->b32 = regional_alloc_init(region, sldns_buffer_begin(buf), 
		c->b32_len);
	if(!c->b32)
		return 0;
	return 1;
}
Beispiel #29
0
void 
error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
	uint16_t qid, uint16_t qflags, struct edns_data* edns)
{
	uint16_t flags;

	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, &qid, sizeof(uint16_t));
	flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
	flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
	sldns_buffer_write_u16(buf, flags);
	if(qinfo) flags = 1;
	else	flags = 0;
	sldns_buffer_write_u16(buf, flags);
	flags = 0;
	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
	if(qinfo) {
		const uint8_t* qname = qinfo->local_alias ?
			qinfo->local_alias->rrset->rk.dname : qinfo->qname;
		size_t qname_len = qinfo->local_alias ?
			qinfo->local_alias->rrset->rk.dname_len :
			qinfo->qname_len;
		if(sldns_buffer_current(buf) == qname)
			sldns_buffer_skip(buf, (ssize_t)qname_len);
		else	sldns_buffer_write(buf, qname, qname_len);
		sldns_buffer_write_u16(buf, qinfo->qtype);
		sldns_buffer_write_u16(buf, qinfo->qclass);
	}
	sldns_buffer_flip(buf);
	if(edns) {
		struct edns_data es = *edns;
		es.edns_version = EDNS_ADVERTISED_VERSION;
		es.udp_size = EDNS_ADVERTISED_SIZE;
		es.ext_rcode = 0;
		es.bits &= EDNS_DO;
		if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
			edns->udp_size)
			return;
		attach_edns_record(buf, &es);
	}
}
Beispiel #30
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;
}