コード例 #1
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
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;
}
コード例 #2
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
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;
}
コード例 #3
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
/** 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;
}
コード例 #4
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;
}
コード例 #5
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
/**
 * 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;
}
コード例 #6
0
ファイル: msgreply.c プロジェクト: Karm/unbound
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;
}
コード例 #7
0
ファイル: pktview.c プロジェクト: CryptArc/bitmonero
/** 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++;
	}
}
コード例 #8
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
/** 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;
}
コード例 #9
0
ファイル: pktview.c プロジェクト: CryptArc/bitmonero
/** analyze rr in packet */
static void analyze_rr(sldns_buffer* pkt, int q)
{
	uint16_t type, dclass, len;
	uint32_t ttl;
	analyze_dname(pkt);
	type = sldns_buffer_read_u16(pkt);
	dclass = sldns_buffer_read_u16(pkt);
	printf("type %s(%d)", sldns_rr_descript(type)?  
		sldns_rr_descript(type)->_name: "??" , (int)type);
	printf(" class %s(%d) ", sldns_lookup_by_id(sldns_rr_classes, 
		(int)dclass)?sldns_lookup_by_id(sldns_rr_classes, 
		(int)dclass)->name:"??", (int)dclass);
	if(q) {
		printf("\n");
	} else {
		ttl = sldns_buffer_read_u32(pkt);
		printf(" ttl %d (0x%x)", (int)ttl, (unsigned)ttl);
		len = sldns_buffer_read_u16(pkt);
		printf(" rdata len %d:\n", (int)len);
		if(sldns_rr_descript(type))
			analyze_rdata(pkt, sldns_rr_descript(type), len);
		else sldns_buffer_skip(pkt, (ssize_t)len);
	}
}
コード例 #10
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
/** 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;
}
コード例 #11
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
/** 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;
}
コード例 #12
0
ファイル: msgparse.c プロジェクト: 2asoft/freebsd
/**
 * 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;
}
コード例 #13
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;
}