示例#1
0
文件: msgparse.c 项目: 2asoft/freebsd
/** 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;
}
示例#2
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;
}
/** analyze rdata in packet */
static void analyze_rdata(ldns_buffer*pkt, const ldns_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 = ldns_buffer_position(pkt);
			analyze_dname(pkt);
			rdlen -= ldns_buffer_position(pkt)-oldpos;
			count --;
			len = 0;
			break;
		case LDNS_RDF_TYPE_STR:
			len = ldns_buffer_current(pkt)[0] + 1;
			break;
		default:
			len = get_rdf_size(desc->_wireformat[rdf]);
		}
		if(len) {
			printf(" wf[%d]", (int)len);
			ldns_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)ldns_buffer_current(pkt)[i]);
		printf("\n");
	}
	else	printf("\n");
	ldns_buffer_skip(pkt, (ssize_t)rdlen);
}
示例#4
0
/**
 * Compare two RR for canonical order, in a field-style sweep.
 * @param d: rrset data
 * @param desc: ldns wireformat descriptor.
 * @param i: first RR to compare
 * @param j: first RR to compare
 * @return comparison code.
 */
static int
canonical_compare_byfield(struct packed_rrset_data* d, 
	const sldns_rr_descriptor* desc, size_t i, size_t j)
{
	/* sweep across rdata, keep track of some state:
	 * 	which rr field, and bytes left in field.
	 * 	current position in rdata, length left.
	 * 	are we in a dname, length left in a label.
	 */
	int wfi = -1;	/* current wireformat rdata field (rdf) */
	int wfj = -1;
	uint8_t* di = d->rr_data[i]+2; /* ptr to current rdata byte */
	uint8_t* dj = d->rr_data[j]+2;
	size_t ilen = d->rr_len[i]-2; /* length left in rdata */
	size_t jlen = d->rr_len[j]-2;
	int dname_i = 0;  /* true if these bytes are part of a name */
	int dname_j = 0;
	size_t lablen_i = 0; /* 0 for label length byte,for first byte of rdf*/
	size_t lablen_j = 0; /* otherwise remaining length of rdf or label */
	int dname_num_i = (int)desc->_dname_count; /* decreased at root label */
	int dname_num_j = (int)desc->_dname_count;

	/* loop while there are rdata bytes available for both rrs,
	 * and still some lowercasing needs to be done; either the dnames
	 * have not been reached yet, or they are currently being processed */
	while(ilen > 0 && jlen > 0 && (dname_num_i > 0 || dname_num_j > 0)) {
		/* compare these two bytes */
		/* lowercase if in a dname and not a label length byte */
		if( ((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di)
		 != ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj)
		 ) {
		  if(((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di)
		  < ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj))
		 	return -1;
		    return 1;
		}
		ilen--;
		jlen--;
		/* bytes are equal */

		/* advance field i */
		/* lablen 0 means that this byte is the first byte of the
		 * next rdata field; inspect this rdata field and setup
		 * to process the rest of this rdata field.
		 * The reason to first read the byte, then setup the rdf,
		 * is that we are then sure the byte is available and short
		 * rdata is handled gracefully (even if it is a formerr). */
		if(lablen_i == 0) { 
			if(dname_i) {
				/* scan this dname label */
				/* capture length to lowercase */
				lablen_i = (size_t)*di;
				if(lablen_i == 0) {
					/* end root label */
					dname_i = 0;
					dname_num_i--;
					/* if dname num is 0, then the
					 * remainder is binary only */
					if(dname_num_i == 0)
						lablen_i = ilen;
				}
			} else {
				/* scan this rdata field */
				wfi++;
				if(desc->_wireformat[wfi] 
					== LDNS_RDF_TYPE_DNAME) {
					dname_i = 1; 
					lablen_i = (size_t)*di;
					if(lablen_i == 0) {
						dname_i = 0;
						dname_num_i--;
						if(dname_num_i == 0)
							lablen_i = ilen;
					}
				} else if(desc->_wireformat[wfi] 
					== LDNS_RDF_TYPE_STR)
					lablen_i = (size_t)*di;
				else	lablen_i = get_rdf_size(
					desc->_wireformat[wfi]) - 1;
			}
		} else	lablen_i--;

		/* advance field j; same as for i */
		if(lablen_j == 0) { 
			if(dname_j) {
				lablen_j = (size_t)*dj;
				if(lablen_j == 0) {
					dname_j = 0;
					dname_num_j--;
					if(dname_num_j == 0)
						lablen_j = jlen;
				}
			} else {
				wfj++;
				if(desc->_wireformat[wfj] 
					== LDNS_RDF_TYPE_DNAME) {
					dname_j = 1; 
					lablen_j = (size_t)*dj;
					if(lablen_j == 0) {
						dname_j = 0;
						dname_num_j--;
						if(dname_num_j == 0)
							lablen_j = jlen;
					}
				} else if(desc->_wireformat[wfj] 
					== LDNS_RDF_TYPE_STR)
					lablen_j = (size_t)*dj;
				else	lablen_j = get_rdf_size(
					desc->_wireformat[wfj]) - 1;
			}
		} else	lablen_j--;
		di++;
		dj++;
	}
	/* end of the loop; because we advanced byte by byte; now we have
	 * that the rdata has ended, or that there is a binary remainder */
	/* shortest first */
	if(ilen == 0 && jlen == 0)
		return 0;
	if(ilen == 0)
		return -1;
	if(jlen == 0)
		return 1;
	/* binary remainder, capture comparison in wfi variable */
	if((wfi = memcmp(di, dj, (ilen<jlen)?ilen:jlen)) != 0)
		return wfi;
	if(ilen < jlen)
		return -1;
	if(jlen < ilen)
		return 1;
	return 0;
}
示例#5
0
文件: msgreply.c 项目: Karm/unbound
/** 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;
}