Beispiel #1
0
/** Add rr (from packet here) to rrset, skips rr */
static int
add_rr_to_rrset(struct rrset_parse* rrset, sldns_buffer* pkt, 
	struct msg_parse* msg, struct regional* region, 
	sldns_pkt_section section, uint16_t type)
{
	struct rr_parse* rr;
	/* check section of rrset. */
	if(rrset->section != section && type != LDNS_RR_TYPE_RRSIG &&
		rrset->type != LDNS_RR_TYPE_RRSIG) {
		/* silently drop it - we drop the last part, since
		 * trust in rr data depends on the section it is in. 
		 * the less trustworthy part is discarded. 
		 * also the last part is more likely to be incomplete.
		 * RFC 2181: must put RRset only once in response. */
		/*
		verbose(VERB_QUERY, "Packet contains rrset data in "
			"multiple sections, dropped last part.");
		log_buf(VERB_QUERY, "packet was", pkt);
		*/
		/* forwards */
		if(!skip_ttl_rdata(pkt))
			return LDNS_RCODE_FORMERR;
		return 0;
	} 

	if( (msg->qtype == LDNS_RR_TYPE_RRSIG ||
	     msg->qtype == LDNS_RR_TYPE_ANY) 
	    && sig_is_double(pkt, rrset, sldns_buffer_current(pkt))) {
		if(!skip_ttl_rdata(pkt))
			return LDNS_RCODE_FORMERR;
		return 0;
	}
	
	/* create rr */
	if(!(rr = (struct rr_parse*)regional_alloc(region, sizeof(*rr))))
		return LDNS_RCODE_SERVFAIL;
	rr->outside_packet = 0;
	rr->ttl_data = sldns_buffer_current(pkt);
	rr->next = 0;
	if(type == LDNS_RR_TYPE_RRSIG && rrset->type != LDNS_RR_TYPE_RRSIG) {
		if(rrset->rrsig_last) 
			rrset->rrsig_last->next = rr;
		else	rrset->rrsig_first = rr;
		rrset->rrsig_last = rr;
		rrset->rrsig_count++;
	} else {
		if(rrset->rr_last)
			rrset->rr_last->next = rr;
		else	rrset->rr_first = rr;
		rrset->rr_last = rr;
		rrset->rr_count++;
	}

	/* calc decompressed size */
	if(!calc_size(pkt, type, rr))
		return LDNS_RCODE_FORMERR;
	rrset->size += rr->size;

	return 0;
}
Beispiel #2
0
/**
 * Inser canonical owner name into buffer.
 * @param buf: buffer to insert into at current position.
 * @param k: rrset with its owner name.
 * @param sig: signature with signer name and label count.
 * 	must be length checked, at least 18 bytes long.
 * @param can_owner: position in buffer returned for future use.
 * @param can_owner_len: length of canonical owner name.
 */
static void
insert_can_owner(sldns_buffer* buf, struct ub_packed_rrset_key* k,
	uint8_t* sig, uint8_t** can_owner, size_t* can_owner_len)
{
	int rrsig_labels = (int)sig[3];
	int fqdn_labels = dname_signame_label_count(k->rk.dname);
	*can_owner = sldns_buffer_current(buf);
	if(rrsig_labels == fqdn_labels) {
		/* no change */
		sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len);
		query_dname_tolower(*can_owner);
		*can_owner_len = k->rk.dname_len;
		return;
	}
	log_assert(rrsig_labels < fqdn_labels);
	/* *. | fqdn(rightmost rrsig_labels) */
	if(rrsig_labels < fqdn_labels) {
		int i;
		uint8_t* nm = k->rk.dname;
		size_t len = k->rk.dname_len;
		/* so skip fqdn_labels-rrsig_labels */
		for(i=0; i<fqdn_labels-rrsig_labels; i++) {
			dname_remove_label(&nm, &len);	
		}
		*can_owner_len = len+2;
		sldns_buffer_write(buf, (uint8_t*)"\001*", 2);
		sldns_buffer_write(buf, nm, len);
		query_dname_tolower(*can_owner);
	}
}
Beispiel #3
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;
}
Beispiel #4
0
/** analyze domain name in packet, possibly compressed */
static void analyze_dname(sldns_buffer* pkt)
{
	size_t oldpos = sldns_buffer_position(pkt);
	size_t len;
	printf("[pos %d] dname: ", (int)oldpos);
	dname_print(stdout, pkt, sldns_buffer_current(pkt));
	len = pkt_dname_len(pkt);
	printf(" len=%d", (int)len);
	if(sldns_buffer_position(pkt)-oldpos != len)
		printf(" comprlen=%d\n", 
			(int)(sldns_buffer_position(pkt)-oldpos));
	else	printf("\n");
}
Beispiel #5
0
/** analyze rdata in packet */
static void analyze_rdata(sldns_buffer*pkt, const sldns_rr_descriptor* desc, 
	uint16_t rdlen)
{
	int rdf = 0;
	int count = (int)desc->_dname_count;
	size_t len, oldpos;
	while(rdlen > 0 && count) {
		switch(desc->_wireformat[rdf]) {
		case LDNS_RDF_TYPE_DNAME:
			oldpos = sldns_buffer_position(pkt);
			analyze_dname(pkt);
			rdlen -= 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]);
		}
		if(len) {
			printf(" wf[%d]", (int)len);
			sldns_buffer_skip(pkt, (ssize_t)len);
			rdlen -= len;
		}
		rdf++;
	}
	if(rdlen) {
		size_t i;
		printf(" remain[%d]\n", (int)rdlen);
		for(i=0; i<rdlen; i++)
			printf(" %2.2X", (unsigned)sldns_buffer_current(pkt)[i]);
		printf("\n");
	}
	else	printf("\n");
	sldns_buffer_skip(pkt, (ssize_t)rdlen);
}
Beispiel #6
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;
}
Beispiel #7
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 #8
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;
}
Beispiel #9
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;
}
Beispiel #10
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;
}
Beispiel #11
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;
}
Beispiel #12
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;
}
Beispiel #13
0
/** Find rrset. If equal to previous it is fast. hash if not so.
 * @param msg: the message with hash table.
 * @param pkt: the packet in wireformat (needed for compression ptrs).
 * @param dname: pointer to start of dname (compressed) in packet.
 * @param dnamelen: uncompressed wirefmt length of dname.
 * @param type: type of current rr.
 * @param dclass: class of current rr.
 * @param hash: hash value is returned if the rrset could not be found.
 * @param rrset_flags: is returned if the rrset could not be found.
 * @param prev_dname_first: dname of last seen RR. First seen dname.
 * @param prev_dname_last: dname of last seen RR. Last seen dname.
 * @param prev_dnamelen: dname len of last seen RR.
 * @param prev_type: type of last seen RR.
 * @param prev_dclass: class of last seen RR.
 * @param rrset_prev: last seen RRset.
 * @param section: the current section in the packet.
 * @param region: used to allocate temporary parsing data.
 * @return 0 on out of memory.
 */
static int
find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname, 
	size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_t* hash, 
	uint32_t* rrset_flags,
	uint8_t** prev_dname_first, uint8_t** prev_dname_last,
	size_t* prev_dnamelen, uint16_t* prev_type,
	uint16_t* prev_dclass, struct rrset_parse** rrset_prev,
	sldns_pkt_section section, struct regional* region)
{
	hashvalue_t dname_h = pkt_hash_rrset_first(pkt, dname);
	uint16_t covtype;
	if(*rrset_prev) {
		/* check if equal to previous item */
		if(type == *prev_type && dclass == *prev_dclass &&
			dnamelen == *prev_dnamelen &&
			smart_compare(pkt, dname, *prev_dname_first, 
				*prev_dname_last) == 0 &&
			type != LDNS_RR_TYPE_RRSIG) {
			/* same as previous */
			*prev_dname_last = dname;
			return 1;
		}
		/* check if rrsig over previous item */
		if(type == LDNS_RR_TYPE_RRSIG && dclass == *prev_dclass &&
			pkt_rrsig_covered_equals(pkt, sldns_buffer_current(pkt),
				*prev_type) &&
			smart_compare(pkt, dname, *prev_dname_first,
				*prev_dname_last) == 0) {
			/* covers previous */
			*prev_dname_last = dname;
			return 1;
		}
	}
	/* find by hashing and lookup in hashtable */
	*rrset_flags = pkt_rrset_flags(pkt, type, section);
	
	/* if rrsig - try to lookup matching data set first */
	if(type == LDNS_RR_TYPE_RRSIG && pkt_rrsig_covered(pkt, 
		sldns_buffer_current(pkt), &covtype)) {
		*hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, 
			*rrset_flags);
		*rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, 
			*rrset_flags, dname, dnamelen, covtype, dclass);
		if(!*rrset_prev && covtype == LDNS_RR_TYPE_NSEC) {
			/* if NSEC try with NSEC apex bit twiddled */
			*rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX;
			*hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, 
				*rrset_flags);
			*rrset_prev = msgparse_hashtable_lookup(msg, pkt, 
				*hash, *rrset_flags, dname, dnamelen, covtype, 
				dclass);
			if(!*rrset_prev) /* untwiddle if not found */
				*rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX;
		}
		if(!*rrset_prev && covtype == LDNS_RR_TYPE_SOA) {
			/* if SOA try with SOA neg flag twiddled */
			*rrset_flags ^= PACKED_RRSET_SOA_NEG;
			*hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, 
				*rrset_flags);
			*rrset_prev = msgparse_hashtable_lookup(msg, pkt, 
				*hash, *rrset_flags, dname, dnamelen, covtype, 
				dclass);
			if(!*rrset_prev) /* untwiddle if not found */
				*rrset_flags ^= PACKED_RRSET_SOA_NEG;
		}
		if(*rrset_prev) {
			*prev_dname_first = (*rrset_prev)->dname;
			*prev_dname_last = dname;
			*prev_dnamelen = dnamelen;
			*prev_type = covtype;
			*prev_dclass = dclass;
			return 1;
		}
	}
	if(type != LDNS_RR_TYPE_RRSIG) {
		int hasother = 0;
		/* find matching rrsig */
		*hash = pkt_hash_rrset_rest(dname_h, LDNS_RR_TYPE_RRSIG, 
			dclass, 0);
		*rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, 
			0, dname, dnamelen, LDNS_RR_TYPE_RRSIG, 
			dclass);
		if(*rrset_prev && rrset_has_sigover(pkt, *rrset_prev, type,
			&hasother)) {
			/* yes! */
			*prev_dname_first = (*rrset_prev)->dname;
			*prev_dname_last = dname;
			*prev_dnamelen = dnamelen;
			*prev_type = type;
			*prev_dclass = dclass;
			*rrset_prev = change_rrsig_rrset(*rrset_prev, msg, 
				pkt, type, *rrset_flags, hasother, section, 
				region);
			if(!*rrset_prev) return 0;
			return 1;
		}
	}

	*hash = pkt_hash_rrset_rest(dname_h, type, dclass, *rrset_flags);
	*rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, *rrset_flags, 
		dname, dnamelen, type, dclass);
	if(*rrset_prev)
		*prev_dname_first = (*rrset_prev)->dname;
	else 	*prev_dname_first = dname;
	*prev_dname_last = dname;
	*prev_dnamelen = dnamelen;
	*prev_type = type;
	*prev_dclass = dclass;
	return 1;
}
Beispiel #14
0
/**
 * Canonicalize Rdata in buffer.
 * @param buf: buffer at position just after the rdata.
 * @param rrset: rrset with type.
 * @param len: length of the rdata (including rdatalen uint16).
 */
static void
canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset,
	size_t len)
{
	uint8_t* datstart = sldns_buffer_current(buf)-len+2;
	switch(ntohs(rrset->rk.type)) {
		case LDNS_RR_TYPE_NXT: 
		case LDNS_RR_TYPE_NS:
		case LDNS_RR_TYPE_MD:
		case LDNS_RR_TYPE_MF:
		case LDNS_RR_TYPE_CNAME:
		case LDNS_RR_TYPE_MB:
		case LDNS_RR_TYPE_MG:
		case LDNS_RR_TYPE_MR:
		case LDNS_RR_TYPE_PTR:
		case LDNS_RR_TYPE_DNAME:
			/* type only has a single argument, the name */
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_MINFO:
		case LDNS_RR_TYPE_RP:
		case LDNS_RR_TYPE_SOA:
			/* two names after another */
			query_dname_tolower(datstart);
			query_dname_tolower(datstart + 
				dname_valid(datstart, len-2));
			return;
		case LDNS_RR_TYPE_RT:
		case LDNS_RR_TYPE_AFSDB:
		case LDNS_RR_TYPE_KX:
		case LDNS_RR_TYPE_MX:
			/* skip fixed part */
			if(len < 2+2+1) /* rdlen, skiplen, 1byteroot */
				return;
			datstart += 2;
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_SIG:
		/* downcase the RRSIG, compat with BIND (kept it from SIG) */
		case LDNS_RR_TYPE_RRSIG:
			/* skip fixed part */
			if(len < 2+18+1)
				return;
			datstart += 18;
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_PX:
			/* skip, then two names after another */
			if(len < 2+2+1) 
				return;
			datstart += 2;
			query_dname_tolower(datstart);
			query_dname_tolower(datstart + 
				dname_valid(datstart, len-2-2));
			return;
		case LDNS_RR_TYPE_NAPTR:
			if(len < 2+4)
				return;
			len -= 2+4;
			datstart += 4;
			if(len < (size_t)datstart[0]+1) /* skip text field */
				return;
			len -= (size_t)datstart[0]+1;
			datstart += (size_t)datstart[0]+1;
			if(len < (size_t)datstart[0]+1) /* skip text field */
				return;
			len -= (size_t)datstart[0]+1;
			datstart += (size_t)datstart[0]+1;
			if(len < (size_t)datstart[0]+1) /* skip text field */
				return;
			len -= (size_t)datstart[0]+1;
			datstart += (size_t)datstart[0]+1;
			if(len < 1)	/* check name is at least 1 byte*/
				return;
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_SRV:
			/* skip fixed part */
			if(len < 2+6+1)
				return;
			datstart += 6;
			query_dname_tolower(datstart);
			return;

		/* do not canonicalize NSEC rdata name, compat with 
		 * from bind 9.4 signer, where it does not do so */
		case LDNS_RR_TYPE_NSEC: /* type starts with the name */
		case LDNS_RR_TYPE_HINFO: /* not downcased */
		/* A6 not supported */
		default:	
			/* nothing to do for unknown types */
			return;
	}
}
Beispiel #15
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;
}