Exemple #1
0
int
parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
{
	int ret;
	if(sldns_buffer_remaining(pkt) < LDNS_HEADER_SIZE)
		return LDNS_RCODE_FORMERR;
	/* read the header */
	sldns_buffer_read(pkt, &msg->id, sizeof(uint16_t));
	msg->flags = sldns_buffer_read_u16(pkt);
	msg->qdcount = sldns_buffer_read_u16(pkt);
	msg->ancount = sldns_buffer_read_u16(pkt);
	msg->nscount = sldns_buffer_read_u16(pkt);
	msg->arcount = sldns_buffer_read_u16(pkt);
	if(msg->qdcount > 1)
		return LDNS_RCODE_FORMERR;
	if((ret = parse_query_section(pkt, msg)) != 0)
		return ret;
	if((ret = parse_section(pkt, msg, region, LDNS_SECTION_ANSWER,
		msg->ancount, &msg->an_rrsets)) != 0)
		return ret;
	if((ret = parse_section(pkt, msg, region, LDNS_SECTION_AUTHORITY,
		msg->nscount, &msg->ns_rrsets)) != 0)
		return ret;
	if(sldns_buffer_remaining(pkt) == 0 && msg->arcount == 1) {
		/* BIND accepts leniently that an EDNS record is missing.
		 * so, we do too. */
	} else if((ret = parse_section(pkt, msg, region,
		LDNS_SECTION_ADDITIONAL, msg->arcount, &msg->ar_rrsets)) != 0)
		return ret;
	/* if(sldns_buffer_remaining(pkt) > 0) { */
		/* there is spurious data at end of packet. ignore */
	/* } */
	msg->rrset_count = msg->an_rrsets + msg->ns_rrsets + msg->ar_rrsets;
	return 0;
}
Exemple #2
0
/** compress a domain name */
static int
write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs,
	struct compress_tree_node* p)
{
	/* compress it */
	int labcopy = labs - p->labs;
	uint8_t lablen;
	uint16_t ptr;

	if(labs == 1) {
		/* write root label */
		if(sldns_buffer_remaining(pkt) < 1)
			return 0;
		sldns_buffer_write_u8(pkt, 0);
		return 1;
	}

	/* copy the first couple of labels */
	while(labcopy--) {
		lablen = *dname++;
		if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
			return 0;
		sldns_buffer_write_u8(pkt, lablen);
		sldns_buffer_write(pkt, dname, lablen);
		dname += lablen;
	}
	/* insert compression ptr */
	if(sldns_buffer_remaining(pkt) < 2)
		return 0;
	ptr = PTR_CREATE(p->offset);
	sldns_buffer_write_u16(pkt, ptr);
	return 1;
}
Exemple #3
0
/** compress domain names in rdata, return RETVAL_* */
static int
compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, 
	struct regional* region, struct compress_tree_node** tree, 
	const sldns_rr_descriptor* desc)
{
	int labs, r, rdf = 0;
	size_t dname_len, len, pos = sldns_buffer_position(pkt);
	uint8_t count = desc->_dname_count;

	sldns_buffer_skip(pkt, 2); /* rdata len fill in later */
	/* space for rdatalen checked for already */
	rdata += 2;
	todolen -= 2;
	while(todolen > 0 && count) {
		switch(desc->_wireformat[rdf]) {
		case LDNS_RDF_TYPE_DNAME:
			labs = dname_count_size_labels(rdata, &dname_len);
			if((r=compress_any_dname(rdata, pkt, labs, region, 
				tree)) != RETVAL_OK)
				return r;
			rdata += dname_len;
			todolen -= dname_len;
			count--;
			len = 0;
			break;
		case LDNS_RDF_TYPE_STR:
			len = *rdata + 1;
			break;
		default:
			len = get_rdf_size(desc->_wireformat[rdf]);
		}
		if(len) {
			/* copy over */
			if(sldns_buffer_remaining(pkt) < len)
				return RETVAL_TRUNC;
			sldns_buffer_write(pkt, rdata, len);
			todolen -= len;
			rdata += len;
		}
		rdf++;
	}
	/* copy remainder */
	if(todolen > 0) {
		if(sldns_buffer_remaining(pkt) < todolen)
			return RETVAL_TRUNC;
		sldns_buffer_write(pkt, rdata, todolen);
	}

	/* set rdata len */
	sldns_buffer_write_u16_at(pkt, pos, sldns_buffer_position(pkt)-pos-2);
	return RETVAL_OK;
}
Exemple #4
0
/** skip rr ttl and rdata */
static int
skip_ttl_rdata(sldns_buffer* pkt) 
{
	uint16_t rdatalen;
	if(sldns_buffer_remaining(pkt) < 6) /* ttl + rdatalen */
		return 0;
	sldns_buffer_skip(pkt, 4); /* ttl */
	rdatalen = sldns_buffer_read_u16(pkt);
	if(sldns_buffer_remaining(pkt) < rdatalen)
		return 0;
	sldns_buffer_skip(pkt, (ssize_t)rdatalen);
	return 1;
}
Exemple #5
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;
}
Exemple #6
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++;
	}
}
Exemple #7
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;
}
Exemple #8
0
/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
static int
compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, 
	struct regional* region, struct compress_tree_node** tree, 
	size_t owner_pos, uint16_t* owner_ptr, int owner_labs)
{
	struct compress_tree_node* p;
	struct compress_tree_node** insertpt = NULL;
	if(!*owner_ptr) {
		/* compress first time dname */
		if((p = compress_tree_lookup(tree, key->rk.dname, 
			owner_labs, &insertpt))) {
			if(p->labs == owner_labs) 
				/* avoid ptr chains, since some software is
				 * not capable of decoding ptr after a ptr. */
				*owner_ptr = htons(PTR_CREATE(p->offset));
			if(!write_compressed_dname(pkt, key->rk.dname, 
				owner_labs, p))
				return RETVAL_TRUNC;
			/* check if typeclass+4 ttl + rdatalen is available */
			if(sldns_buffer_remaining(pkt) < 4+4+2)
				return RETVAL_TRUNC;
		} else {
			/* no compress */
			if(sldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2)
				return RETVAL_TRUNC;
			sldns_buffer_write(pkt, key->rk.dname, 
				key->rk.dname_len);
			if(owner_pos <= PTR_MAX_OFFSET)
				*owner_ptr = htons(PTR_CREATE(owner_pos));
		}
		if(!compress_tree_store(key->rk.dname, owner_labs, 
			owner_pos, region, p, insertpt))
			return RETVAL_OUTMEM;
	} else {
		/* always compress 2nd-further RRs in RRset */
		if(owner_labs == 1) {
			if(sldns_buffer_remaining(pkt) < 1+4+4+2) 
				return RETVAL_TRUNC;
			sldns_buffer_write_u8(pkt, 0);
		} else {
			if(sldns_buffer_remaining(pkt) < 2+4+4+2) 
				return RETVAL_TRUNC;
			sldns_buffer_write(pkt, owner_ptr, 2);
		}
	}
	return RETVAL_OK;
}
Exemple #9
0
/** calculate the size of one rr */
static int
calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
{
	const sldns_rr_descriptor* desc;
	uint16_t pkt_len; /* length of rr inside the packet */
	rr->size = sizeof(uint16_t); /* the rdatalen */
	sldns_buffer_skip(pkt, 4); /* skip ttl */
	pkt_len = sldns_buffer_read_u16(pkt);
	if(sldns_buffer_remaining(pkt) < pkt_len)
		return 0;
	desc = sldns_rr_descript(type);
	if(pkt_len > 0 && desc && desc->_dname_count > 0) {
		int count = (int)desc->_dname_count;
		int rdf = 0;
		size_t len;
		size_t oldpos;
		/* skip first part. */
		while(pkt_len > 0 && count) {
			switch(desc->_wireformat[rdf]) {
			case LDNS_RDF_TYPE_DNAME:
				/* decompress every domain name */
				oldpos = sldns_buffer_position(pkt);
				if((len = pkt_dname_len(pkt)) == 0)
					return 0; /* malformed dname */
				if(sldns_buffer_position(pkt)-oldpos > pkt_len)
					return 0; /* dname exceeds rdata */
				pkt_len -= sldns_buffer_position(pkt)-oldpos;
				rr->size += len;
				count--;
				len = 0;
				break;
			case LDNS_RDF_TYPE_STR:
				if(pkt_len < 1) {
					/* NOTREACHED, due to 'while(>0)' */
					return 0; /* len byte exceeds rdata */
				}
				len = sldns_buffer_current(pkt)[0] + 1;
				break;
			default:
				len = get_rdf_size(desc->_wireformat[rdf]);
			}
			if(len) {
				if(pkt_len < len)
					return 0; /* exceeds rdata */
				pkt_len -= len;
				sldns_buffer_skip(pkt, (ssize_t)len);
				rr->size += len;
			}
			rdf++;
		}
	}
	/* remaining rdata */
	rr->size += pkt_len;
	sldns_buffer_skip(pkt, (ssize_t)pkt_len);
	return 1;
}
Exemple #10
0
/** See if next rrset is nsec at zone apex */
static int
nsec_at_apex(sldns_buffer* pkt)
{
	/* we are at ttl position in packet. */
	size_t pos = sldns_buffer_position(pkt);
	uint16_t rdatalen;
	if(sldns_buffer_remaining(pkt) < 7) /* ttl+len+root */
		return 0; /* eek! */
	sldns_buffer_skip(pkt, 4); /* ttl */;
	rdatalen = sldns_buffer_read_u16(pkt);
	if(sldns_buffer_remaining(pkt) < rdatalen) {
		sldns_buffer_set_position(pkt, pos);
		return 0; /* parse error happens later */
	}
	/* must validate the nsec next domain name format */
	if(pkt_dname_len(pkt) == 0) {
		sldns_buffer_set_position(pkt, pos);
		return 0; /* parse error */
	}

	/* see if SOA bit is set. */
	if(sldns_buffer_position(pkt) < pos+4+rdatalen) {
		/* nsec type bitmap contains items */
		uint8_t win, blen, bits;
		/* need: windownum, bitmap len, firstbyte */
		if(sldns_buffer_position(pkt)+3 > pos+4+rdatalen) {
			sldns_buffer_set_position(pkt, pos);
			return 0; /* malformed nsec */
		}
		win = sldns_buffer_read_u8(pkt);
		blen = sldns_buffer_read_u8(pkt);
		bits = sldns_buffer_read_u8(pkt);
		/* 0window always first window. bitlen >=1 or parse
		   error really. bit 0x2 is SOA. */
		if(win == 0 && blen >= 1 && (bits & 0x02)) {
			sldns_buffer_set_position(pkt, pos);
			return 1;
		}
	}

	sldns_buffer_set_position(pkt, pos);
	return 0;
}
Exemple #11
0
int
dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
{
    uint8_t lablen;

    if(sldns_buffer_remaining(pkt) < 1)
        return 0;
    lablen = *dname++;
    sldns_buffer_write_u8(pkt, lablen);
    while(lablen) {
        if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
            return 0;
        sldns_buffer_write(pkt, dname, lablen);
        dname += lablen;
        lablen = *dname++;
        sldns_buffer_write_u8(pkt, lablen);
    }
    return 1;
}
Exemple #12
0
/**
 * Parse query section. 
 * @param pkt: packet, position at call must be at start of query section.
 *	at end position is after query section.
 * @param msg: store results here.
 * @return: 0 if OK, or rcode on error.
 */
static int
parse_query_section(sldns_buffer* pkt, struct msg_parse* msg)
{
	if(msg->qdcount == 0)
		return 0;
	if(msg->qdcount > 1)
		return LDNS_RCODE_FORMERR;
	log_assert(msg->qdcount == 1);
	if(sldns_buffer_remaining(pkt) <= 0)
		return LDNS_RCODE_FORMERR;
	msg->qname = sldns_buffer_current(pkt);
	if((msg->qname_len = pkt_dname_len(pkt)) == 0)
		return LDNS_RCODE_FORMERR;
	if(sldns_buffer_remaining(pkt) < sizeof(uint16_t)*2)
		return LDNS_RCODE_FORMERR;
	msg->qtype = sldns_buffer_read_u16(pkt);
	msg->qclass = sldns_buffer_read_u16(pkt);
	return 0;
}
Exemple #13
0
/**
 * Create canonical form of rrset in the scratch buffer.
 * @param region: temporary region.
 * @param buf: the buffer to use.
 * @param k: the rrset to insert.
 * @param sig: RRSIG rdata to include.
 * @param siglen: RRSIG rdata len excluding signature field, but inclusive
 * 	signer name length.
 * @param sortree: if NULL is passed a new sorted rrset tree is built.
 * 	Otherwise it is reused.
 * @return false on alloc error.
 */
static int
rrset_canonical(struct regional* region, sldns_buffer* buf, 
	struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen,
	struct rbtree_t** sortree)
{
	struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
	uint8_t* can_owner = NULL;
	size_t can_owner_len = 0;
	struct canon_rr* walk;
	struct canon_rr* rrs;

	if(!*sortree) {
		*sortree = (struct rbtree_t*)regional_alloc(region, 
			sizeof(rbtree_t));
		if(!*sortree)
			return 0;
		if(d->count > RR_COUNT_MAX)
			return 0; /* integer overflow protection */
		rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count);
		if(!rrs) {
			*sortree = NULL;
			return 0;
		}
		rbtree_init(*sortree, &canonical_tree_compare);
		canonical_sort(k, d, *sortree, rrs);
	}

	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, sig, siglen);
	/* canonicalize signer name */
	query_dname_tolower(sldns_buffer_begin(buf)+18); 
	RBTREE_FOR(walk, struct canon_rr*, (*sortree)) {
		/* see if there is enough space left in the buffer */
		if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4
			+ d->rr_len[walk->rr_idx]) {
			log_err("verify: failed to canonicalize, "
				"rrset too big");
			return 0;
		}
		/* determine canonical owner name */
		if(can_owner)
			sldns_buffer_write(buf, can_owner, can_owner_len);
		else	insert_can_owner(buf, k, sig, &can_owner, 
				&can_owner_len);
		sldns_buffer_write(buf, &k->rk.type, 2);
		sldns_buffer_write(buf, &k->rk.rrset_class, 2);
		sldns_buffer_write(buf, sig+4, 4);
		sldns_buffer_write(buf, d->rr_data[walk->rr_idx], 
			d->rr_len[walk->rr_idx]);
		canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]);
	}
	sldns_buffer_flip(buf);
	return 1;
}
Exemple #14
0
/* determine length of a dname in buffer, no compression pointers allowed */
size_t
query_dname_len(sldns_buffer* query)
{
    size_t len = 0;
    size_t labellen;
    while(1) {
        if(sldns_buffer_remaining(query) < 1)
            return 0; /* parse error, need label len */
        labellen = sldns_buffer_read_u8(query);
        if(labellen&0xc0)
            return 0; /* no compression allowed in queries */
        len += labellen + 1;
        if(len > LDNS_MAX_DOMAINLEN)
            return 0; /* too long */
        if(labellen == 0)
            return len;
        if(sldns_buffer_remaining(query) < labellen)
            return 0; /* parse error, need content */
        sldns_buffer_skip(query, (ssize_t)labellen);
    }
}
Exemple #15
0
/** see if RRSIG is a duplicate of another */
static int
sig_is_double(sldns_buffer* pkt, struct rrset_parse* rrset, uint8_t* ttldata)
{
	uint16_t rlen, siglen;
	size_t pos = sldns_buffer_position(pkt);
	struct rr_parse* sig;
	if(sldns_buffer_remaining(pkt) < 6) 
		return 0;
	sldns_buffer_skip(pkt, 4); /* ttl */
	rlen = sldns_buffer_read_u16(pkt);
	if(sldns_buffer_remaining(pkt) < rlen) {
		sldns_buffer_set_position(pkt, pos);
		return 0;
	}
	sldns_buffer_set_position(pkt, pos);

	sig = rrset->rrsig_first;
	while(sig) {
		/* check if rdatalen is same */
		memmove(&siglen, sig->ttl_data+4, sizeof(siglen));
		siglen = ntohs(siglen);
		/* checks if data in packet is exactly the same, this means
		 * also dname in rdata is the same, but rrsig is not allowed
		 * to have compressed dnames anyway. If it is compressed anyway
		 * it will lead to duplicate rrs for qtype=RRSIG. (or ANY).
		 *
		 * Cannot use sig->size because size of the other one is not 
		 * calculated yet.
		 */
		if(siglen == rlen) {
			if(siglen>0 && memcmp(sig->ttl_data+6, ttldata+6, 
				siglen) == 0) {
				/* same! */
				return 1;
			}
		}
		sig = sig->next;
	}
	return 0;
}
Exemple #16
0
int
sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
{
	va_list args;
	int written = 0;
	size_t remaining;
	
	if (sldns_buffer_status_ok(buffer)) {
		sldns_buffer_invariant(buffer);
		assert(buffer->_limit == buffer->_capacity);

		remaining = sldns_buffer_remaining(buffer);
		va_start(args, format);
		written = vsnprintf((char *) sldns_buffer_current(buffer), remaining,
				    format, args);
		va_end(args);
		if (written == -1) {
			buffer->_status_err = 1;
			return -1;
		} else if ((size_t) written >= remaining) {
			if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) {
				buffer->_status_err = 1;
				return -1;
			}
			va_start(args, format);
			written = vsnprintf((char *) sldns_buffer_current(buffer),
			    sldns_buffer_remaining(buffer), format, args);
			va_end(args);
			if (written == -1) {
				buffer->_status_err = 1;
				return -1;
			}
		}
		buffer->_position += written;
	}
	return written;
}
Exemple #17
0
void 
qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
{
	uint16_t flags = 0; /* QUERY, NOERROR */
	sldns_buffer_clear(pkt);
	log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
	sldns_buffer_skip(pkt, 2); /* id done later */
	sldns_buffer_write_u16(pkt, flags);
	sldns_buffer_write_u16(pkt, 1); /* query count */
	sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
	sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len);
	sldns_buffer_write_u16(pkt, qinfo->qtype);
	sldns_buffer_write_u16(pkt, qinfo->qclass);
	sldns_buffer_flip(pkt);
}
Exemple #18
0
/** return type networkformat that rrsig in packet covers */
static int
pkt_rrsig_covered(sldns_buffer* pkt, uint8_t* here, uint16_t* type)
{
	size_t pos = sldns_buffer_position(pkt);
	sldns_buffer_set_position(pkt, (size_t)(here-sldns_buffer_begin(pkt)));
	/* ttl + len + size of small rrsig(rootlabel, no signature) */
	if(sldns_buffer_remaining(pkt) < 4+2+19)
		return 0;
	sldns_buffer_skip(pkt, 4); /* ttl */
	if(sldns_buffer_read_u16(pkt) < 19) /* too short */ {
		sldns_buffer_set_position(pkt, pos);
		return 0;
	}
	*type = sldns_buffer_read_u16(pkt);
	sldns_buffer_set_position(pkt, pos);
	return 1;
}
Exemple #19
0
/** add result to the bg worker result queue */
static void
add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, 
	int err, char* reason)
{
	uint8_t* msg = NULL;
	uint32_t len = 0;

	if(w->want_quit) {
		context_query_delete(q);
		return;
	}
	/* serialize and delete unneeded q */
	if(w->is_bg_thread) {
		lock_basic_lock(&w->ctx->cfglock);
		if(reason)
			q->res->why_bogus = strdup(reason);
		if(pkt) {
			q->msg_len = sldns_buffer_remaining(pkt);
			q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
			if(!q->msg)
				msg = context_serialize_answer(q, UB_NOMEM, 
				NULL, &len);
			else	msg = context_serialize_answer(q, err, 
				NULL, &len);
		} else msg = context_serialize_answer(q, err, NULL, &len);
		lock_basic_unlock(&w->ctx->cfglock);
	} else {
		if(reason)
			q->res->why_bogus = strdup(reason);
		msg = context_serialize_answer(q, err, pkt, &len);
		(void)rbtree_delete(&w->ctx->queries, q->node.key);
		w->ctx->num_async--;
		context_query_delete(q);
	}

	if(!msg) {
		log_err("out of memory for async answer");
		return;
	}
	if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
		log_err("out of memory for async answer");
		return;
	}
}
Exemple #20
0
/** store query section in wireformat buffer, return RETVAL */
static int
insert_query(struct query_info* qinfo, struct compress_tree_node** tree, 
	sldns_buffer* buffer, struct regional* region)
{
	if(sldns_buffer_remaining(buffer) < 
		qinfo->qname_len+sizeof(uint16_t)*2)
		return RETVAL_TRUNC; /* buffer too small */
	/* the query is the first name inserted into the tree */
	if(!compress_tree_store(qinfo->qname, 
		dname_count_labels(qinfo->qname), 
		sldns_buffer_position(buffer), region, NULL, tree))
		return RETVAL_OUTMEM;
	if(sldns_buffer_current(buffer) == qinfo->qname)
		sldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len);
	else	sldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
	sldns_buffer_write_u16(buffer, qinfo->qtype);
	sldns_buffer_write_u16(buffer, qinfo->qclass);
	return RETVAL_OK;
}
Exemple #21
0
void 
qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
{
	uint16_t flags = 0; /* QUERY, NOERROR */
	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;
	sldns_buffer_clear(pkt);
	log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
	sldns_buffer_skip(pkt, 2); /* id done later */
	sldns_buffer_write_u16(pkt, flags);
	sldns_buffer_write_u16(pkt, 1); /* query count */
	sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
	sldns_buffer_write(pkt, qname, qname_len);
	sldns_buffer_write_u16(pkt, qinfo->qtype);
	sldns_buffer_write_u16(pkt, qinfo->qclass);
	sldns_buffer_flip(pkt);
}
Exemple #22
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;
}
Exemple #23
0
/**
 * Parse packet RR section, for answer, authority and additional sections. 
 * @param pkt: packet, position at call must be at start of section.
 *	at end position is after section.
 * @param msg: store results here.
 * @param region: how to alloc results.
 * @param section: section enum.
 * @param num_rrs: how many rrs are in the section.
 * @param num_rrsets: returns number of rrsets in the section.
 * @return: 0 if OK, or rcode on error.
 */
static int
parse_section(sldns_buffer* pkt, struct msg_parse* msg, 
	struct regional* region, sldns_pkt_section section, 
	uint16_t num_rrs, size_t* num_rrsets)
{
	uint16_t i;
	uint8_t* dname, *prev_dname_f = NULL, *prev_dname_l = NULL;
	size_t dnamelen, prev_dnamelen = 0;
	uint16_t type, prev_type = 0;
	uint16_t dclass, prev_dclass = 0;
	uint32_t rrset_flags = 0;
	hashvalue_t hash = 0;
	struct rrset_parse* rrset = NULL;
	int r;

	if(num_rrs == 0)
		return 0;
	if(sldns_buffer_remaining(pkt) <= 0)
		return LDNS_RCODE_FORMERR;
	for(i=0; i<num_rrs; i++) {
		/* parse this RR. */
		dname = sldns_buffer_current(pkt);
		if((dnamelen = pkt_dname_len(pkt)) == 0)
			return LDNS_RCODE_FORMERR;
		if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, len */
			return LDNS_RCODE_FORMERR;
		type = sldns_buffer_read_u16(pkt);
		sldns_buffer_read(pkt, &dclass, sizeof(dclass));

		if(0) { /* debug show what is being parsed. */
			if(type == LDNS_RR_TYPE_RRSIG) {
				uint16_t t;
				if(pkt_rrsig_covered(pkt, 
					sldns_buffer_current(pkt), &t))
					fprintf(stderr, "parse of %s(%d) [%s(%d)]",
					sldns_rr_descript(type)?
					sldns_rr_descript(type)->_name: "??",
					(int)type,
					sldns_rr_descript(t)?
					sldns_rr_descript(t)->_name: "??",
					(int)t);
			} else
			  fprintf(stderr, "parse of %s(%d)",
				sldns_rr_descript(type)?
				sldns_rr_descript(type)->_name: "??",
				(int)type);
			fprintf(stderr, " %s(%d) ",
				sldns_lookup_by_id(sldns_rr_classes, 
				(int)ntohs(dclass))?sldns_lookup_by_id(
				sldns_rr_classes, (int)ntohs(dclass))->name: 
				"??", (int)ntohs(dclass));
			dname_print(stderr, pkt, dname);
			fprintf(stderr, "\n");
		}

		/* see if it is part of an existing RR set */
		if(!find_rrset(msg, pkt, dname, dnamelen, type, dclass, &hash, 
			&rrset_flags, &prev_dname_f, &prev_dname_l, 
			&prev_dnamelen, &prev_type, &prev_dclass, &rrset, 
			section, region))
			return LDNS_RCODE_SERVFAIL;
		if(!rrset) {
			/* it is a new RR set. hash&flags already calculated.*/
			(*num_rrsets)++;
			rrset = new_rrset(msg, dname, dnamelen, type, dclass,
				hash, rrset_flags, section, region);
			if(!rrset) 
				return LDNS_RCODE_SERVFAIL;
		}
		else if(0)	{ 
			fprintf(stderr, "is part of existing: ");
			dname_print(stderr, pkt, rrset->dname);
			fprintf(stderr, " type %s(%d)\n",
				sldns_rr_descript(rrset->type)?
				sldns_rr_descript(rrset->type)->_name: "??",
				(int)rrset->type);
		}
		/* add to rrset. */
		if((r=add_rr_to_rrset(rrset, pkt, msg, region, section, 
			type)) != 0)
			return r;
	}
	return 0;
}
Exemple #24
0
/** 
 * read contents of trusted-keys{ ... ; clauses and insert keys into storage.
 * @param anchors: where to store keys
 * @param buf: buffer to use
 * @param line: line number in file
 * @param in: file to read from.
 * @return 0 on error.
 */
static int
process_bind_contents(struct val_anchors* anchors, sldns_buffer* buf, 
	int* line, FILE* in)
{
	/* loop over contents, collate strings before ; */
	/* contents is (numbered): 0   1    2  3 4   5  6 7 8    */
	/*                           name. 257 3 5 base64 base64 */
	/* quoted value:           0 "111"  0  0 0   0  0 0 0    */
	/* comments value:         1 "000"  1  1  1 "0  0 0 0"  1 */
	int contnum = 0;
	int quoted = 0;
	int comments = 1;
	int rdlen;
	char* str = 0;
	sldns_buffer_clear(buf);
	while((rdlen=readkeyword_bindfile(in, buf, line, comments))) {
		if(rdlen == 1 && sldns_buffer_position(buf) == 1
			&& isspace((unsigned char)*sldns_buffer_begin(buf))) {
			/* starting whitespace is removed */
			sldns_buffer_clear(buf);
			continue;
		} else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '"') {
			/* remove " from the string */
			if(contnum == 0) {
				quoted = 1;
				comments = 0;
			}
			sldns_buffer_skip(buf, -1);
			if(contnum > 0 && quoted) {
				if(sldns_buffer_remaining(buf) < 8+1) {
					log_err("line %d, too long", *line);
					return 0;
				}
				sldns_buffer_write(buf, " DNSKEY ", 8);
				quoted = 0;
				comments = 1;
			} else if(contnum > 0)
				comments = !comments;
			continue;
		} else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == ';') {

			if(contnum < 5) {
				sldns_buffer_write_u8(buf, 0);
				log_err("line %d, bad key", *line);
				return 0;
			}
			sldns_buffer_skip(buf, -1);
			sldns_buffer_write_u8(buf, 0);
			str = strdup((char*)sldns_buffer_begin(buf));
			if(!str) {
				log_err("line %d, allocation failure", *line);
				return 0;
			}
			if(!anchor_store_str(anchors, buf, str)) {
				log_err("line %d, bad key", *line);
				free(str);
				return 0;
			}
			free(str);
			sldns_buffer_clear(buf);
			contnum = 0;
			quoted = 0;
			comments = 1;
			continue;
		} else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '}') {
			if(contnum > 0) {
				sldns_buffer_write_u8(buf, 0);
				log_err("line %d, bad key before }", *line);
				return 0;
			}
			return 1;
		} else if(rdlen == 1 && 
			isspace((unsigned char)sldns_buffer_current(buf)[-1])) {
			/* leave whitespace here */
		} else {
			/* not space or whatnot, so actual content */
			contnum ++;
			if(contnum == 1 && !quoted) {
				if(sldns_buffer_remaining(buf) < 8+1) {
					log_err("line %d, too long", *line);
					return 0;
				}	
				sldns_buffer_write(buf, " DNSKEY ", 8);
			}
		}
	}

	log_err("line %d, EOF before }", *line);
	return 0;
}
Exemple #25
0
/** 
 * Read a keyword skipping bind comments; spaces, specials, restkeywords. 
 * The file is split into the following tokens:
 *	* special characters, on their own, rdlen=1, { } doublequote ;
 *	* whitespace becomes a single ' ' or tab. Newlines become spaces.
 *	* other words ('keywords')
 *	* comments are skipped if desired
 *		/ / C++ style comment to end of line
 *		# to end of line
 *		/ * C style comment * /
 * @param in: file to read from.
 * @param buf: buffer, what is read is stored after current buffer position.
 *	Space is left in the buffer to write a terminating 0.
 * @param line: line number is increased per line, for error reports.
 * @param comments: if 0, comments are not possible and become text.
 *	if 1, comments are skipped entirely.
 *	In BIND files, this is when reading quoted strings, for example
 *	" base 64 text with / / in there "
 * @return the number of character written to the buffer. 
 *	0 on end of file.
 */
static int
readkeyword_bindfile(FILE* in, sldns_buffer* buf, int* line, int comments)
{
	int c;
	int numdone = 0;
	while((c = getc(in)) != EOF ) {
		if(comments && c == '#') {	/*   # blabla   */
			skip_to_eol(in);
			(*line)++;
			continue;
		} else if(comments && c=='/' && numdone>0 && /* /_/ bla*/
			sldns_buffer_read_u8_at(buf, 
			sldns_buffer_position(buf)-1) == '/') {
			sldns_buffer_skip(buf, -1);
			numdone--;
			skip_to_eol(in);
			(*line)++;
			continue;
		} else if(comments && c=='*' && numdone>0 && /* /_* bla *_/ */
			sldns_buffer_read_u8_at(buf, 
			sldns_buffer_position(buf)-1) == '/') {
			sldns_buffer_skip(buf, -1);
			numdone--;
			/* skip to end of comment */
			while(c != EOF && (c=getc(in)) != EOF ) {
				if(c == '*') {
					if((c=getc(in)) == '/')
						break;
				}
				if(c == '\n')
					(*line)++;
			}
			continue;
		}
		/* not a comment, complete the keyword */
		if(numdone > 0) {
			/* check same type */
			if(isspace((unsigned char)c)) {
				ungetc(c, in);
				return numdone;
			}
			if(is_bind_special(c)) {
				ungetc(c, in);
				return numdone;
			}
		}
		if(c == '\n') {
			c = ' ';
			(*line)++;
		}
		/* space for 1 char + 0 string terminator */
		if(sldns_buffer_remaining(buf) < 2) {
			fatal_exit("trusted-keys, %d, string too long", *line);
		}
		sldns_buffer_write_u8(buf, (uint8_t)c);
		numdone++;
		if(isspace((unsigned char)c)) {
			/* collate whitespace into ' ' */
			while((c = getc(in)) != EOF ) {
				if(c == '\n')
					(*line)++;
				if(!isspace((unsigned char)c)) {
					ungetc(c, in);
					break;
				}
			}
			return numdone;
		}
		if(is_bind_special(c))
			return numdone;
	}
	return numdone;
}
Exemple #26
0
/** do the rdata copy */
static int
rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 
	struct rr_parse* rr, time_t* rr_ttl, uint16_t type,
	sldns_pkt_section section)
{
	uint16_t pkt_len;
	const sldns_rr_descriptor* desc;

	*rr_ttl = sldns_read_uint32(rr->ttl_data);
	/* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
	if(*rr_ttl & 0x80000000U)
		*rr_ttl = 0;
	if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
		/* negative response. see if TTL of SOA record larger than the
		 * minimum-ttl in the rdata of the SOA record */
		if(*rr_ttl > soa_find_minttl(rr))
			*rr_ttl = soa_find_minttl(rr);
		if(*rr_ttl > MAX_NEG_TTL)
			*rr_ttl = MAX_NEG_TTL;
	}
	if(*rr_ttl < MIN_TTL)
		*rr_ttl = MIN_TTL;
	if(*rr_ttl < data->ttl)
		data->ttl = *rr_ttl;

	if(rr->outside_packet) {
		/* uncompressed already, only needs copy */
		memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size);
		return 1;
	}

	sldns_buffer_set_position(pkt, (size_t)
		(rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t)));
	/* insert decompressed size into rdata len stored in memory */
	/* -2 because rdatalen bytes are not included. */
	pkt_len = htons(rr->size - 2);
	memmove(to, &pkt_len, sizeof(uint16_t));
	to += 2;
	/* read packet rdata len */
	pkt_len = sldns_buffer_read_u16(pkt);
	if(sldns_buffer_remaining(pkt) < pkt_len)
		return 0;
	desc = sldns_rr_descript(type);
	if(pkt_len > 0 && desc && desc->_dname_count > 0) {
		int count = (int)desc->_dname_count;
		int rdf = 0;
		size_t len;
		size_t oldpos;
		/* decompress dnames. */
		while(pkt_len > 0 && count) {
			switch(desc->_wireformat[rdf]) {
			case LDNS_RDF_TYPE_DNAME:
				oldpos = sldns_buffer_position(pkt);
				dname_pkt_copy(pkt, to, 
					sldns_buffer_current(pkt));
				to += pkt_dname_len(pkt);
				pkt_len -= sldns_buffer_position(pkt)-oldpos;
				count--;
				len = 0;
				break;
			case LDNS_RDF_TYPE_STR:
				len = sldns_buffer_current(pkt)[0] + 1;
				break;
			default:
				len = get_rdf_size(desc->_wireformat[rdf]);
				break;
			}
			if(len) {
				memmove(to, sldns_buffer_current(pkt), len);
				to += len;
				sldns_buffer_skip(pkt, (ssize_t)len);
				log_assert(len <= pkt_len);
				pkt_len -= len;
			}
			rdf++;
		}
	}
	/* copy remaining rdata */
	if(pkt_len >  0)
		memmove(to, sldns_buffer_current(pkt), pkt_len);
	
	return 1;
}
Exemple #27
0
int 
reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
	uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, 
	struct regional* region, uint16_t udpsize, int dnssec)
{
	uint16_t ancount=0, nscount=0, arcount=0;
	struct compress_tree_node* tree = 0;
	int r;
	size_t rr_offset; 

	sldns_buffer_clear(buffer);
	if(udpsize < sldns_buffer_limit(buffer))
		sldns_buffer_set_limit(buffer, udpsize);
	if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
		return 0;

	sldns_buffer_write(buffer, &id, sizeof(uint16_t));
	sldns_buffer_write_u16(buffer, flags);
	sldns_buffer_write_u16(buffer, rep->qdcount);
	/* set an, ns, ar counts to zero in case of small packets */
	sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);

	/* insert query section */
	if(rep->qdcount) {
		if((r=insert_query(qinfo, &tree, buffer, region)) != 
			RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 4, 0);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
	}
	/* roundrobin offset. using query id for random number.  With ntohs
	 * for different roundrobins for sequential id client senders. */
	rr_offset = RRSET_ROUNDROBIN?ntohs(id):0;

	/* insert answer section */
	if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 
		0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, 
		dnssec, rr_offset)) != RETVAL_OK) {
		if(r == RETVAL_TRUNC) {
			/* create truncated message */
			sldns_buffer_write_u16_at(buffer, 6, ancount);
			LDNS_TC_SET(sldns_buffer_begin(buffer));
			sldns_buffer_flip(buffer);
			return 1;
		}
		return 0;
	}
	sldns_buffer_write_u16_at(buffer, 6, ancount);

	/* if response is positive answer, auth/add sections are not required */
	if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) {
		/* insert auth section */
		if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, 
			rep->an_numrrsets, timenow, region, &tree,
			LDNS_SECTION_AUTHORITY, qinfo->qtype,
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 8, nscount);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 8, nscount);

		/* insert add section */
		if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, 
			rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 
			&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, 
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* no need to set TC bit, this is the additional */
				sldns_buffer_write_u16_at(buffer, 10, arcount);
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 10, arcount);
	}
	sldns_buffer_flip(buffer);
	return 1;
}
Exemple #28
0
int 
reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
	uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, 
	struct regional* region, uint16_t udpsize, int dnssec)
{
	uint16_t ancount=0, nscount=0, arcount=0;
	struct compress_tree_node* tree = 0;
	int r;
	size_t rr_offset; 

	sldns_buffer_clear(buffer);
	if(udpsize < sldns_buffer_limit(buffer))
		sldns_buffer_set_limit(buffer, udpsize);
	if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
		return 0;

	sldns_buffer_write(buffer, &id, sizeof(uint16_t));
	sldns_buffer_write_u16(buffer, flags);
	sldns_buffer_write_u16(buffer, rep->qdcount);
	/* set an, ns, ar counts to zero in case of small packets */
	sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);

	/* insert query section */
	if(rep->qdcount) {
		if((r=insert_query(qinfo, &tree, buffer, region)) != 
			RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 4, 0);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
	}
	/* roundrobin offset. using query id for random number.  With ntohs
	 * for different roundrobins for sequential id client senders. */
	rr_offset = RRSET_ROUNDROBIN?ntohs(id):0;

	/* "prepend" any local alias records in the answer section if this
	 * response is supposed to be authoritative.  Currently it should
	 * be a single CNAME record (sanity-checked in worker_handle_request())
	 * but it can be extended if and when we support more variations of
	 * aliases. */
	if(qinfo->local_alias && (flags & BIT_AA)) {
		struct reply_info arep;
		time_t timezero = 0; /* to use the 'authoritative' TTL */
		memset(&arep, 0, sizeof(arep));
		arep.flags = rep->flags;
		arep.an_numrrsets = 1;
		arep.rrset_count = 1;
		arep.rrsets = &qinfo->local_alias->rrset;
		if((r=insert_section(&arep, 1, &ancount, buffer, 0,
			timezero, region, &tree, LDNS_SECTION_ANSWER,
			qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 6, ancount);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
	}

	/* insert answer section */
	if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 
		0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, 
		dnssec, rr_offset)) != RETVAL_OK) {
		if(r == RETVAL_TRUNC) {
			/* create truncated message */
			sldns_buffer_write_u16_at(buffer, 6, ancount);
			LDNS_TC_SET(sldns_buffer_begin(buffer));
			sldns_buffer_flip(buffer);
			return 1;
		}
		return 0;
	}
	sldns_buffer_write_u16_at(buffer, 6, ancount);

	/* if response is positive answer, auth/add sections are not required */
	if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) {
		/* insert auth section */
		if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, 
			rep->an_numrrsets, timenow, region, &tree,
			LDNS_SECTION_AUTHORITY, qinfo->qtype,
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 8, nscount);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 8, nscount);

		/* insert add section */
		if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, 
			rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 
			&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, 
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* no need to set TC bit, this is the additional */
				sldns_buffer_write_u16_at(buffer, 10, arcount);
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 10, arcount);
	}
	sldns_buffer_flip(buffer);
	return 1;
}
Exemple #29
0
/** store rrset in buffer in wireformat, return RETVAL_* */
static int
packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, 
	uint16_t* num_rrs, time_t timenow, struct regional* region,
	int do_data, int do_sig, struct compress_tree_node** tree,
	sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
{
	size_t i, j, owner_pos;
	int r, owner_labs;
	uint16_t owner_ptr = 0;
	struct packed_rrset_data* data = (struct packed_rrset_data*)
		key->entry.data;
	
	/* does this RR type belong in the answer? */
	if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec))
		return RETVAL_OK;

	owner_labs = dname_count_labels(key->rk.dname);
	owner_pos = sldns_buffer_position(pkt);

	if(do_data) {
		const sldns_rr_descriptor* c = type_rdata_compressable(key);
		for(i=0; i<data->count; i++) {
			/* rrset roundrobin */
			j = (i + rr_offset) % data->count;
			if((r=compress_owner(key, pkt, region, tree, 
				owner_pos, &owner_ptr, owner_labs))
				!= RETVAL_OK)
				return r;
			sldns_buffer_write(pkt, &key->rk.type, 2);
			sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
			if(data->rr_ttl[j] < timenow)
				sldns_buffer_write_u32(pkt, 0);
			else 	sldns_buffer_write_u32(pkt, 
					data->rr_ttl[j]-timenow);
			if(c) {
				if((r=compress_rdata(pkt, data->rr_data[j],
					data->rr_len[j], region, tree, c))
					!= RETVAL_OK)
					return r;
			} else {
				if(sldns_buffer_remaining(pkt) < data->rr_len[j])
					return RETVAL_TRUNC;
				sldns_buffer_write(pkt, data->rr_data[j],
					data->rr_len[j]);
			}
		}
	}
	/* insert rrsigs */
	if(do_sig && dnssec) {
		size_t total = data->count+data->rrsig_count;
		for(i=data->count; i<total; i++) {
			if(owner_ptr && owner_labs != 1) {
				if(sldns_buffer_remaining(pkt) <
					2+4+4+data->rr_len[i]) 
					return RETVAL_TRUNC;
				sldns_buffer_write(pkt, &owner_ptr, 2);
			} else {
				if((r=compress_any_dname(key->rk.dname, 
					pkt, owner_labs, region, tree))
					!= RETVAL_OK)
					return r;
				if(sldns_buffer_remaining(pkt) < 
					4+4+data->rr_len[i])
					return RETVAL_TRUNC;
			}
			sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
			sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
			if(data->rr_ttl[i] < timenow)
				sldns_buffer_write_u32(pkt, 0);
			else 	sldns_buffer_write_u32(pkt, 
					data->rr_ttl[i]-timenow);
			/* rrsig rdata cannot be compressed, perform 100+ byte
			 * memcopy. */
			sldns_buffer_write(pkt, data->rr_data[i],
				data->rr_len[i]);
		}
	}
	/* change rrnum only after we are sure it fits */
	if(do_data)
		*num_rrs += data->count;
	if(do_sig && dnssec)
		*num_rrs += data->rrsig_count;

	return RETVAL_OK;
}