xref: /freebsd-src/contrib/ldns/wire2host.c (revision 2e1665ff345498c3f99ffd07b6e90669172d2df2)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * wire2host.c
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * conversion routines from the wire to the host
57b5038d7SDag-Erling Smørgrav  * format.
67b5038d7SDag-Erling Smørgrav  * This will usually just a re-ordering of the
77b5038d7SDag-Erling Smørgrav  * data (as we store it in network format)
87b5038d7SDag-Erling Smørgrav  *
97b5038d7SDag-Erling Smørgrav  * a Net::DNS like library for C
107b5038d7SDag-Erling Smørgrav  *
117b5038d7SDag-Erling Smørgrav  * (c) NLnet Labs, 2004-2006
127b5038d7SDag-Erling Smørgrav  *
137b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
147b5038d7SDag-Erling Smørgrav  */
157b5038d7SDag-Erling Smørgrav 
167b5038d7SDag-Erling Smørgrav 
177b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
187b5038d7SDag-Erling Smørgrav 
197b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
207b5038d7SDag-Erling Smørgrav /*#include <ldns/wire2host.h>*/
217b5038d7SDag-Erling Smørgrav 
227b5038d7SDag-Erling Smørgrav #include <strings.h>
237b5038d7SDag-Erling Smørgrav #include <limits.h>
247b5038d7SDag-Erling Smørgrav 
257b5038d7SDag-Erling Smørgrav 
267b5038d7SDag-Erling Smørgrav 
277b5038d7SDag-Erling Smørgrav /*
287b5038d7SDag-Erling Smørgrav  * Set of macro's to deal with the dns message header as specified
297b5038d7SDag-Erling Smørgrav  * in RFC1035 in portable way.
307b5038d7SDag-Erling Smørgrav  *
317b5038d7SDag-Erling Smørgrav  */
327b5038d7SDag-Erling Smørgrav 
337b5038d7SDag-Erling Smørgrav /*
347b5038d7SDag-Erling Smørgrav  *
357b5038d7SDag-Erling Smørgrav  *                                    1  1  1  1  1  1
367b5038d7SDag-Erling Smørgrav  *      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
377b5038d7SDag-Erling Smørgrav  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
387b5038d7SDag-Erling Smørgrav  *    |                      ID                       |
397b5038d7SDag-Erling Smørgrav  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
407b5038d7SDag-Erling Smørgrav  *    |QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
417b5038d7SDag-Erling Smørgrav  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
427b5038d7SDag-Erling Smørgrav  *    |                    QDCOUNT                    |
437b5038d7SDag-Erling Smørgrav  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
447b5038d7SDag-Erling Smørgrav  *    |                    ANCOUNT                    |
457b5038d7SDag-Erling Smørgrav  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
467b5038d7SDag-Erling Smørgrav  *    |                    NSCOUNT                    |
477b5038d7SDag-Erling Smørgrav  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
487b5038d7SDag-Erling Smørgrav  *    |                    ARCOUNT                    |
497b5038d7SDag-Erling Smørgrav  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
507b5038d7SDag-Erling Smørgrav  *
517b5038d7SDag-Erling Smørgrav  */
527b5038d7SDag-Erling Smørgrav 
537b5038d7SDag-Erling Smørgrav 
547b5038d7SDag-Erling Smørgrav /* allocates memory to *dname! */
557b5038d7SDag-Erling Smørgrav ldns_status
ldns_wire2dname(ldns_rdf ** dname,const uint8_t * wire,size_t max,size_t * pos)567b5038d7SDag-Erling Smørgrav ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos)
577b5038d7SDag-Erling Smørgrav {
587b5038d7SDag-Erling Smørgrav 	uint8_t label_size;
597b5038d7SDag-Erling Smørgrav 	uint16_t pointer_target;
607b5038d7SDag-Erling Smørgrav 	uint8_t pointer_target_buf[2];
617b5038d7SDag-Erling Smørgrav 	size_t dname_pos = 0;
627b5038d7SDag-Erling Smørgrav 	size_t compression_pos = 0;
637b5038d7SDag-Erling Smørgrav 	uint8_t tmp_dname[LDNS_MAX_DOMAINLEN];
647b5038d7SDag-Erling Smørgrav 	unsigned int pointer_count = 0;
657b5038d7SDag-Erling Smørgrav 
6617d15b25SDag-Erling Smørgrav 	if (pos == NULL) {
6717d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_WIRE_RDATA_ERR;
6817d15b25SDag-Erling Smørgrav 	}
697b5038d7SDag-Erling Smørgrav 	if (*pos >= max) {
707b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_PACKET_OVERFLOW;
717b5038d7SDag-Erling Smørgrav 	}
727b5038d7SDag-Erling Smørgrav 	label_size = wire[*pos];
737b5038d7SDag-Erling Smørgrav 	while (label_size > 0) {
747b5038d7SDag-Erling Smørgrav 		/* compression */
757b5038d7SDag-Erling Smørgrav 		while (label_size >= 192) {
767b5038d7SDag-Erling Smørgrav 			if (compression_pos == 0) {
777b5038d7SDag-Erling Smørgrav 				compression_pos = *pos + 2;
787b5038d7SDag-Erling Smørgrav 			}
797b5038d7SDag-Erling Smørgrav 
807b5038d7SDag-Erling Smørgrav 			pointer_count++;
817b5038d7SDag-Erling Smørgrav 
827b5038d7SDag-Erling Smørgrav 			/* remove first two bits */
837b5038d7SDag-Erling Smørgrav 			if (*pos + 2 > max) {
847b5038d7SDag-Erling Smørgrav 				return LDNS_STATUS_PACKET_OVERFLOW;
857b5038d7SDag-Erling Smørgrav 			}
867b5038d7SDag-Erling Smørgrav 			pointer_target_buf[0] = wire[*pos] & 63;
877b5038d7SDag-Erling Smørgrav 			pointer_target_buf[1] = wire[*pos + 1];
887b5038d7SDag-Erling Smørgrav 			pointer_target = ldns_read_uint16(pointer_target_buf);
897b5038d7SDag-Erling Smørgrav 
907b5038d7SDag-Erling Smørgrav 			if (pointer_target == 0) {
917b5038d7SDag-Erling Smørgrav 				return LDNS_STATUS_INVALID_POINTER;
927b5038d7SDag-Erling Smørgrav 			} else if (pointer_target >= max) {
937b5038d7SDag-Erling Smørgrav 				return LDNS_STATUS_INVALID_POINTER;
947b5038d7SDag-Erling Smørgrav 			} else if (pointer_count > LDNS_MAX_POINTERS) {
957b5038d7SDag-Erling Smørgrav 				return LDNS_STATUS_INVALID_POINTER;
967b5038d7SDag-Erling Smørgrav 			}
977b5038d7SDag-Erling Smørgrav 			*pos = pointer_target;
987b5038d7SDag-Erling Smørgrav 			label_size = wire[*pos];
997b5038d7SDag-Erling Smørgrav 		}
1007b5038d7SDag-Erling Smørgrav 		if(label_size == 0)
1017b5038d7SDag-Erling Smørgrav 			break; /* break from pointer to 0 byte */
1027b5038d7SDag-Erling Smørgrav 		if (label_size > LDNS_MAX_LABELLEN) {
1037b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_LABEL_OVERFLOW;
1047b5038d7SDag-Erling Smørgrav 		}
1057b5038d7SDag-Erling Smørgrav 		if (*pos + 1 + label_size > max) {
1067b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_LABEL_OVERFLOW;
1077b5038d7SDag-Erling Smørgrav 		}
1087b5038d7SDag-Erling Smørgrav 
1097b5038d7SDag-Erling Smørgrav 		/* check space for labelcount itself */
1107b5038d7SDag-Erling Smørgrav 		if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
1117b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_DOMAINNAME_OVERFLOW;
1127b5038d7SDag-Erling Smørgrav 		}
1137b5038d7SDag-Erling Smørgrav 		tmp_dname[dname_pos] = label_size;
1147b5038d7SDag-Erling Smørgrav 		if (label_size > 0) {
1157b5038d7SDag-Erling Smørgrav 			dname_pos++;
1167b5038d7SDag-Erling Smørgrav 		}
1177b5038d7SDag-Erling Smørgrav 		*pos = *pos + 1;
1187b5038d7SDag-Erling Smørgrav 		if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
1197b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_DOMAINNAME_OVERFLOW;
1207b5038d7SDag-Erling Smørgrav 		}
1217b5038d7SDag-Erling Smørgrav 		memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
1227b5038d7SDag-Erling Smørgrav 		dname_pos += label_size;
1237b5038d7SDag-Erling Smørgrav 		*pos = *pos + label_size;
1247b5038d7SDag-Erling Smørgrav 
1257b5038d7SDag-Erling Smørgrav 		if (*pos < max) {
1267b5038d7SDag-Erling Smørgrav 			label_size = wire[*pos];
1277b5038d7SDag-Erling Smørgrav 		}
1287b5038d7SDag-Erling Smørgrav 	}
1297b5038d7SDag-Erling Smørgrav 
1307b5038d7SDag-Erling Smørgrav 	if (compression_pos > 0) {
1317b5038d7SDag-Erling Smørgrav 		*pos = compression_pos;
1327b5038d7SDag-Erling Smørgrav 	} else {
1337b5038d7SDag-Erling Smørgrav 		*pos = *pos + 1;
1347b5038d7SDag-Erling Smørgrav 	}
1357b5038d7SDag-Erling Smørgrav 
1367b5038d7SDag-Erling Smørgrav 	if (dname_pos >= LDNS_MAX_DOMAINLEN) {
1377b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_DOMAINNAME_OVERFLOW;
1387b5038d7SDag-Erling Smørgrav 	}
1397b5038d7SDag-Erling Smørgrav 
1407b5038d7SDag-Erling Smørgrav 	tmp_dname[dname_pos] = 0;
1417b5038d7SDag-Erling Smørgrav 	dname_pos++;
1427b5038d7SDag-Erling Smørgrav 
1437b5038d7SDag-Erling Smørgrav 	*dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
1447b5038d7SDag-Erling Smørgrav 			(uint16_t) dname_pos, tmp_dname);
1457b5038d7SDag-Erling Smørgrav 	if (!*dname) {
1467b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_MEM_ERR;
1477b5038d7SDag-Erling Smørgrav 	}
1487b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
1497b5038d7SDag-Erling Smørgrav }
1507b5038d7SDag-Erling Smørgrav 
1517b5038d7SDag-Erling Smørgrav /* maybe make this a goto error so data can be freed or something/ */
1527b5038d7SDag-Erling Smørgrav #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
1537b5038d7SDag-Erling Smørgrav #define LDNS_STATUS_CHECK_GOTO(st, label) {if (st != LDNS_STATUS_OK) { /*printf("STG %s:%d: status code %d\n", __FILE__, __LINE__, st);*/  goto label; }}
1547b5038d7SDag-Erling Smørgrav 
1557b5038d7SDag-Erling Smørgrav ldns_status
ldns_wire2rdf(ldns_rr * rr,const uint8_t * wire,size_t max,size_t * pos)1567b5038d7SDag-Erling Smørgrav ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
1577b5038d7SDag-Erling Smørgrav {
1587b5038d7SDag-Erling Smørgrav 	size_t end;
1597b5038d7SDag-Erling Smørgrav 	size_t cur_rdf_length;
1607b5038d7SDag-Erling Smørgrav 	uint8_t rdf_index;
1617b5038d7SDag-Erling Smørgrav 	uint8_t *data;
1627b5038d7SDag-Erling Smørgrav 	uint16_t rd_length;
1637b5038d7SDag-Erling Smørgrav 	ldns_rdf *cur_rdf = NULL;
1647b5038d7SDag-Erling Smørgrav 	ldns_rdf_type cur_rdf_type;
16517d15b25SDag-Erling Smørgrav 	const ldns_rr_descriptor *descriptor;
1667b5038d7SDag-Erling Smørgrav 	ldns_status status;
1677b5038d7SDag-Erling Smørgrav 
16817d15b25SDag-Erling Smørgrav 	assert(rr != NULL);
16917d15b25SDag-Erling Smørgrav 
17017d15b25SDag-Erling Smørgrav 	descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
17117d15b25SDag-Erling Smørgrav 
1727b5038d7SDag-Erling Smørgrav 	if (*pos + 2 > max) {
1737b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_PACKET_OVERFLOW;
1747b5038d7SDag-Erling Smørgrav 	}
1757b5038d7SDag-Erling Smørgrav 
1767b5038d7SDag-Erling Smørgrav 	rd_length = ldns_read_uint16(&wire[*pos]);
1777b5038d7SDag-Erling Smørgrav 	*pos = *pos + 2;
1787b5038d7SDag-Erling Smørgrav 
1797b5038d7SDag-Erling Smørgrav 	if (*pos + rd_length > max) {
1807b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_PACKET_OVERFLOW;
1817b5038d7SDag-Erling Smørgrav 	}
1827b5038d7SDag-Erling Smørgrav 
1837b5038d7SDag-Erling Smørgrav 	end = *pos + (size_t) rd_length;
1847b5038d7SDag-Erling Smørgrav 
18517d15b25SDag-Erling Smørgrav 	rdf_index = 0;
18617d15b25SDag-Erling Smørgrav 	while (*pos < end &&
18717d15b25SDag-Erling Smørgrav 			rdf_index < ldns_rr_descriptor_maximum(descriptor)) {
18817d15b25SDag-Erling Smørgrav 
1897b5038d7SDag-Erling Smørgrav 		cur_rdf_length = 0;
1907b5038d7SDag-Erling Smørgrav 
19117d15b25SDag-Erling Smørgrav 		cur_rdf_type = ldns_rr_descriptor_field_type(
19217d15b25SDag-Erling Smørgrav 				descriptor, rdf_index);
19317d15b25SDag-Erling Smørgrav 
1947b5038d7SDag-Erling Smørgrav 		/* handle special cases immediately, set length
1957b5038d7SDag-Erling Smørgrav 		   for fixed length rdata and do them below */
1967b5038d7SDag-Erling Smørgrav 		switch (cur_rdf_type) {
1977b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_DNAME:
1987b5038d7SDag-Erling Smørgrav 			status = ldns_wire2dname(&cur_rdf, wire, max, pos);
1997b5038d7SDag-Erling Smørgrav 			LDNS_STATUS_CHECK_RETURN(status);
2007b5038d7SDag-Erling Smørgrav 			break;
2017b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_CLASS:
2027b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_ALG:
203986ba33cSDag-Erling Smørgrav 		case LDNS_RDF_TYPE_CERTIFICATE_USAGE:
204986ba33cSDag-Erling Smørgrav 		case LDNS_RDF_TYPE_SELECTOR:
205986ba33cSDag-Erling Smørgrav 		case LDNS_RDF_TYPE_MATCHING_TYPE:
2067b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_INT8:
2077b5038d7SDag-Erling Smørgrav 			cur_rdf_length = LDNS_RDF_SIZE_BYTE;
2087b5038d7SDag-Erling Smørgrav 			break;
2097b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_TYPE:
2107b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_INT16:
2117b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_CERT_ALG:
2127b5038d7SDag-Erling Smørgrav 			cur_rdf_length = LDNS_RDF_SIZE_WORD;
2137b5038d7SDag-Erling Smørgrav 			break;
2147b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_TIME:
2157b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_INT32:
2167b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_A:
2177b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_PERIOD:
2187b5038d7SDag-Erling Smørgrav 			cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
2197b5038d7SDag-Erling Smørgrav 			break;
2207b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_TSIGTIME:
22117d15b25SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_EUI48:
2227b5038d7SDag-Erling Smørgrav 			cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
2237b5038d7SDag-Erling Smørgrav 			break;
22417d15b25SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_ILNP64:
22517d15b25SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_EUI64:
22617d15b25SDag-Erling Smørgrav 			cur_rdf_length = LDNS_RDF_SIZE_8BYTES;
22717d15b25SDag-Erling Smørgrav 			break;
2287b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_AAAA:
2297b5038d7SDag-Erling Smørgrav 			cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
2307b5038d7SDag-Erling Smørgrav 			break;
2317b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_STR:
2327b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_NSEC3_SALT:
23317d15b25SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_TAG:
2347b5038d7SDag-Erling Smørgrav 			/* len is stored in first byte
2357b5038d7SDag-Erling Smørgrav 			 * it should be in the rdf too, so just
2367b5038d7SDag-Erling Smørgrav 			 * copy len+1 from this position
2377b5038d7SDag-Erling Smørgrav 			 */
2387b5038d7SDag-Erling Smørgrav 			cur_rdf_length = ((size_t) wire[*pos]) + 1;
2397b5038d7SDag-Erling Smørgrav 			break;
24017d15b25SDag-Erling Smørgrav 
2417b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_INT16_DATA:
24217d15b25SDag-Erling Smørgrav 			if (*pos + 2 > end) {
24317d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_PACKET_OVERFLOW;
24417d15b25SDag-Erling Smørgrav 			}
24517d15b25SDag-Erling Smørgrav 			cur_rdf_length =
24617d15b25SDag-Erling Smørgrav 				(size_t) ldns_read_uint16(&wire[*pos]) + 2;
24717d15b25SDag-Erling Smørgrav 			break;
24817d15b25SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_HIP:
24917d15b25SDag-Erling Smørgrav 			if (*pos + 4 > end) {
25017d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_PACKET_OVERFLOW;
25117d15b25SDag-Erling Smørgrav 			}
25217d15b25SDag-Erling Smørgrav 			cur_rdf_length =
25317d15b25SDag-Erling Smørgrav 				(size_t) wire[*pos] +
25417d15b25SDag-Erling Smørgrav 				(size_t) ldns_read_uint16(&wire[*pos + 2]) + 4;
2557b5038d7SDag-Erling Smørgrav 			break;
2567b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_B32_EXT:
2577b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
2587b5038d7SDag-Erling Smørgrav 			/* length is stored in first byte */
2597b5038d7SDag-Erling Smørgrav 			cur_rdf_length = ((size_t) wire[*pos]) + 1;
2607b5038d7SDag-Erling Smørgrav 			break;
2617b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_APL:
2627b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_B64:
2637b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_HEX:
2647b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_NSEC:
2657b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_UNKNOWN:
2667b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_SERVICE:
2677b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_LOC:
2687b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_WKS:
2697b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_NSAP:
2707b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_ATMA:
2717b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_IPSECKEY:
27217d15b25SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_LONG_STR:
273*5afab0e5SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_AMTRELAY:
274*5afab0e5SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_SVCPARAMS:
2757b5038d7SDag-Erling Smørgrav 		case LDNS_RDF_TYPE_NONE:
2767b5038d7SDag-Erling Smørgrav 			/*
2777b5038d7SDag-Erling Smørgrav 			 * Read to end of rr rdata
2787b5038d7SDag-Erling Smørgrav 			 */
2797b5038d7SDag-Erling Smørgrav 			cur_rdf_length = end - *pos;
2807b5038d7SDag-Erling Smørgrav 			break;
2817b5038d7SDag-Erling Smørgrav 		}
2827b5038d7SDag-Erling Smørgrav 
2837b5038d7SDag-Erling Smørgrav 		/* fixed length rdata */
2847b5038d7SDag-Erling Smørgrav 		if (cur_rdf_length > 0) {
2857b5038d7SDag-Erling Smørgrav 			if (cur_rdf_length + *pos > end) {
2867b5038d7SDag-Erling Smørgrav 				return LDNS_STATUS_PACKET_OVERFLOW;
2877b5038d7SDag-Erling Smørgrav 			}
2887b5038d7SDag-Erling Smørgrav 			data = LDNS_XMALLOC(uint8_t, rd_length);
2897b5038d7SDag-Erling Smørgrav 			if (!data) {
2907b5038d7SDag-Erling Smørgrav 				return LDNS_STATUS_MEM_ERR;
2917b5038d7SDag-Erling Smørgrav 			}
2927b5038d7SDag-Erling Smørgrav 			memcpy(data, &wire[*pos], cur_rdf_length);
2937b5038d7SDag-Erling Smørgrav 
29417d15b25SDag-Erling Smørgrav 			cur_rdf = ldns_rdf_new(cur_rdf_type,
29517d15b25SDag-Erling Smørgrav 					cur_rdf_length, data);
2967b5038d7SDag-Erling Smørgrav 			*pos = *pos + cur_rdf_length;
2977b5038d7SDag-Erling Smørgrav 		}
2987b5038d7SDag-Erling Smørgrav 
2997b5038d7SDag-Erling Smørgrav 		if (cur_rdf) {
3007b5038d7SDag-Erling Smørgrav 			ldns_rr_push_rdf(rr, cur_rdf);
3017b5038d7SDag-Erling Smørgrav 			cur_rdf = NULL;
3027b5038d7SDag-Erling Smørgrav 		}
30317d15b25SDag-Erling Smørgrav 
30417d15b25SDag-Erling Smørgrav 		rdf_index++;
30517d15b25SDag-Erling Smørgrav 
30617d15b25SDag-Erling Smørgrav 	} /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */
30717d15b25SDag-Erling Smørgrav 
3087b5038d7SDag-Erling Smørgrav 
3097b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
3107b5038d7SDag-Erling Smørgrav }
3117b5038d7SDag-Erling Smørgrav 
3127b5038d7SDag-Erling Smørgrav /* TODO:
3137b5038d7SDag-Erling Smørgrav          can *pos be incremented at READ_INT? or maybe use something like
3147b5038d7SDag-Erling Smørgrav          RR_CLASS(wire)?
3157b5038d7SDag-Erling Smørgrav 	 uhhm Jelte??
3167b5038d7SDag-Erling Smørgrav */
3177b5038d7SDag-Erling Smørgrav ldns_status
ldns_wire2rr(ldns_rr ** rr_p,const uint8_t * wire,size_t max,size_t * pos,ldns_pkt_section section)3187b5038d7SDag-Erling Smørgrav ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
3197b5038d7SDag-Erling Smørgrav              size_t *pos, ldns_pkt_section section)
3207b5038d7SDag-Erling Smørgrav {
3217b5038d7SDag-Erling Smørgrav 	ldns_rdf *owner = NULL;
3227b5038d7SDag-Erling Smørgrav 	ldns_rr *rr = ldns_rr_new();
3237b5038d7SDag-Erling Smørgrav 	ldns_status status;
3247b5038d7SDag-Erling Smørgrav 
3257b5038d7SDag-Erling Smørgrav 	status = ldns_wire2dname(&owner, wire, max, pos);
3267b5038d7SDag-Erling Smørgrav 	LDNS_STATUS_CHECK_GOTO(status, status_error);
3277b5038d7SDag-Erling Smørgrav 
3287b5038d7SDag-Erling Smørgrav 	ldns_rr_set_owner(rr, owner);
3297b5038d7SDag-Erling Smørgrav 
3307b5038d7SDag-Erling Smørgrav 	if (*pos + 4 > max) {
3317b5038d7SDag-Erling Smørgrav 		status = LDNS_STATUS_PACKET_OVERFLOW;
3327b5038d7SDag-Erling Smørgrav 		goto status_error;
3337b5038d7SDag-Erling Smørgrav 	}
3347b5038d7SDag-Erling Smørgrav 
3357b5038d7SDag-Erling Smørgrav 	ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
3367b5038d7SDag-Erling Smørgrav 	*pos = *pos + 2;
3377b5038d7SDag-Erling Smørgrav 
3387b5038d7SDag-Erling Smørgrav 	ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
3397b5038d7SDag-Erling Smørgrav 	*pos = *pos + 2;
3407b5038d7SDag-Erling Smørgrav 
3417b5038d7SDag-Erling Smørgrav 	if (section != LDNS_SECTION_QUESTION) {
3427b5038d7SDag-Erling Smørgrav 		if (*pos + 4 > max) {
3437b5038d7SDag-Erling Smørgrav 			status = LDNS_STATUS_PACKET_OVERFLOW;
3447b5038d7SDag-Erling Smørgrav 			goto status_error;
3457b5038d7SDag-Erling Smørgrav 		}
3467b5038d7SDag-Erling Smørgrav 		ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
3477b5038d7SDag-Erling Smørgrav 
3487b5038d7SDag-Erling Smørgrav 		*pos = *pos + 4;
3497b5038d7SDag-Erling Smørgrav 		status = ldns_wire2rdf(rr, wire, max, pos);
3507b5038d7SDag-Erling Smørgrav 
3517b5038d7SDag-Erling Smørgrav 		LDNS_STATUS_CHECK_GOTO(status, status_error);
3527b5038d7SDag-Erling Smørgrav         ldns_rr_set_question(rr, false);
3537b5038d7SDag-Erling Smørgrav 	} else {
3547b5038d7SDag-Erling Smørgrav         ldns_rr_set_question(rr, true);
3557b5038d7SDag-Erling Smørgrav     }
3567b5038d7SDag-Erling Smørgrav 
3577b5038d7SDag-Erling Smørgrav 	*rr_p = rr;
3587b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
3597b5038d7SDag-Erling Smørgrav 
3607b5038d7SDag-Erling Smørgrav status_error:
3617b5038d7SDag-Erling Smørgrav 	ldns_rr_free(rr);
3627b5038d7SDag-Erling Smørgrav 	return status;
3637b5038d7SDag-Erling Smørgrav }
3647b5038d7SDag-Erling Smørgrav 
3657b5038d7SDag-Erling Smørgrav static ldns_status
ldns_wire2pkt_hdr(ldns_pkt * packet,const uint8_t * wire,size_t max,size_t * pos)3667b5038d7SDag-Erling Smørgrav ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
3677b5038d7SDag-Erling Smørgrav {
3687b5038d7SDag-Erling Smørgrav 	if (*pos + LDNS_HEADER_SIZE > max) {
3697b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
3707b5038d7SDag-Erling Smørgrav 	} else {
3717b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
3727b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
3737b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
3747b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
3757b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
3767b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
3777b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
3787b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
3797b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
3807b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
3817b5038d7SDag-Erling Smørgrav 
3827b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
3837b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
3847b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
3857b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
3867b5038d7SDag-Erling Smørgrav 
3877b5038d7SDag-Erling Smørgrav 		*pos += LDNS_HEADER_SIZE;
3887b5038d7SDag-Erling Smørgrav 
3897b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_OK;
3907b5038d7SDag-Erling Smørgrav 	}
3917b5038d7SDag-Erling Smørgrav }
3927b5038d7SDag-Erling Smørgrav 
3937b5038d7SDag-Erling Smørgrav ldns_status
ldns_buffer2pkt_wire(ldns_pkt ** packet,const ldns_buffer * buffer)394986ba33cSDag-Erling Smørgrav ldns_buffer2pkt_wire(ldns_pkt **packet, const ldns_buffer *buffer)
3957b5038d7SDag-Erling Smørgrav {
3967b5038d7SDag-Erling Smørgrav 	/* lazy */
3977b5038d7SDag-Erling Smørgrav 	return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
3987b5038d7SDag-Erling Smørgrav 				ldns_buffer_limit(buffer));
3997b5038d7SDag-Erling Smørgrav 
4007b5038d7SDag-Erling Smørgrav }
4017b5038d7SDag-Erling Smørgrav 
4027b5038d7SDag-Erling Smørgrav ldns_status
ldns_wire2pkt(ldns_pkt ** packet_p,const uint8_t * wire,size_t max)4037b5038d7SDag-Erling Smørgrav ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
4047b5038d7SDag-Erling Smørgrav {
4057b5038d7SDag-Erling Smørgrav 	size_t pos = 0;
4067b5038d7SDag-Erling Smørgrav 	uint16_t i;
4077b5038d7SDag-Erling Smørgrav 	ldns_rr *rr;
4087b5038d7SDag-Erling Smørgrav 	ldns_pkt *packet = ldns_pkt_new();
4097b5038d7SDag-Erling Smørgrav 	ldns_status status = LDNS_STATUS_OK;
410986ba33cSDag-Erling Smørgrav 	uint8_t have_edns = 0;
4117b5038d7SDag-Erling Smørgrav 
4127b5038d7SDag-Erling Smørgrav 	uint8_t data[4];
4137b5038d7SDag-Erling Smørgrav 
414*5afab0e5SDag-Erling Smørgrav 	if (!packet) {
415*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_MEM_ERR;
416*5afab0e5SDag-Erling Smørgrav 	}
417*5afab0e5SDag-Erling Smørgrav 
4187b5038d7SDag-Erling Smørgrav 	status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
4197b5038d7SDag-Erling Smørgrav 	LDNS_STATUS_CHECK_GOTO(status, status_error);
4207b5038d7SDag-Erling Smørgrav 
4217b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
4227b5038d7SDag-Erling Smørgrav 
4237b5038d7SDag-Erling Smørgrav 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
4247b5038d7SDag-Erling Smørgrav 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
4257b5038d7SDag-Erling Smørgrav 			status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
4267b5038d7SDag-Erling Smørgrav 		}
4277b5038d7SDag-Erling Smørgrav 		LDNS_STATUS_CHECK_GOTO(status, status_error);
4287b5038d7SDag-Erling Smørgrav 		if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
4297b5038d7SDag-Erling Smørgrav 			ldns_pkt_free(packet);
4307b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_INTERNAL_ERR;
4317b5038d7SDag-Erling Smørgrav 		}
4327b5038d7SDag-Erling Smørgrav 	}
4337b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_pkt_ancount(packet); i++) {
4347b5038d7SDag-Erling Smørgrav 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
4357b5038d7SDag-Erling Smørgrav 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
4367b5038d7SDag-Erling Smørgrav 			status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
4377b5038d7SDag-Erling Smørgrav 		}
4387b5038d7SDag-Erling Smørgrav 		LDNS_STATUS_CHECK_GOTO(status, status_error);
4397b5038d7SDag-Erling Smørgrav 		if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
4407b5038d7SDag-Erling Smørgrav 			ldns_pkt_free(packet);
4417b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_INTERNAL_ERR;
4427b5038d7SDag-Erling Smørgrav 		}
4437b5038d7SDag-Erling Smørgrav 	}
4447b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_pkt_nscount(packet); i++) {
4457b5038d7SDag-Erling Smørgrav 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
4467b5038d7SDag-Erling Smørgrav 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
4477b5038d7SDag-Erling Smørgrav 			status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
4487b5038d7SDag-Erling Smørgrav 		}
4497b5038d7SDag-Erling Smørgrav 		LDNS_STATUS_CHECK_GOTO(status, status_error);
4507b5038d7SDag-Erling Smørgrav 		if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
4517b5038d7SDag-Erling Smørgrav 			ldns_pkt_free(packet);
4527b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_INTERNAL_ERR;
4537b5038d7SDag-Erling Smørgrav 		}
4547b5038d7SDag-Erling Smørgrav 	}
4557b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_pkt_arcount(packet); i++) {
4567b5038d7SDag-Erling Smørgrav 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
4577b5038d7SDag-Erling Smørgrav 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
4587b5038d7SDag-Erling Smørgrav 			status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
4597b5038d7SDag-Erling Smørgrav 		}
4607b5038d7SDag-Erling Smørgrav 		LDNS_STATUS_CHECK_GOTO(status, status_error);
4617b5038d7SDag-Erling Smørgrav 
4627b5038d7SDag-Erling Smørgrav 		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
4637b5038d7SDag-Erling Smørgrav 			ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
4647b5038d7SDag-Erling Smørgrav 			ldns_write_uint32(data, ldns_rr_ttl(rr));
4657b5038d7SDag-Erling Smørgrav 			ldns_pkt_set_edns_extended_rcode(packet, data[0]);
4667b5038d7SDag-Erling Smørgrav 			ldns_pkt_set_edns_version(packet, data[1]);
4677b5038d7SDag-Erling Smørgrav 			ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
4687b5038d7SDag-Erling Smørgrav 			/* edns might not have rdfs */
4697b5038d7SDag-Erling Smørgrav 			if (ldns_rr_rdf(rr, 0)) {
470*5afab0e5SDag-Erling Smørgrav 				ldns_rdf_deep_free(ldns_pkt_edns_data(packet));
4717b5038d7SDag-Erling Smørgrav 				ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
4727b5038d7SDag-Erling Smørgrav 			}
4737b5038d7SDag-Erling Smørgrav 			ldns_rr_free(rr);
4747b5038d7SDag-Erling Smørgrav 			have_edns += 1;
4757b5038d7SDag-Erling Smørgrav 		} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
4767b5038d7SDag-Erling Smørgrav 			ldns_pkt_set_tsig(packet, rr);
4777b5038d7SDag-Erling Smørgrav 			ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
4787b5038d7SDag-Erling Smørgrav 		} else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
4797b5038d7SDag-Erling Smørgrav 			ldns_pkt_free(packet);
4807b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_INTERNAL_ERR;
4817b5038d7SDag-Erling Smørgrav 		}
4827b5038d7SDag-Erling Smørgrav 	}
4837b5038d7SDag-Erling Smørgrav 	ldns_pkt_set_size(packet, max);
4847b5038d7SDag-Erling Smørgrav 	if(have_edns)
4857b5038d7SDag-Erling Smørgrav 		ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
4867b5038d7SDag-Erling Smørgrav                         - have_edns);
487986ba33cSDag-Erling Smørgrav         packet->_edns_present = have_edns;
4887b5038d7SDag-Erling Smørgrav 
4897b5038d7SDag-Erling Smørgrav 	*packet_p = packet;
4907b5038d7SDag-Erling Smørgrav 	return status;
4917b5038d7SDag-Erling Smørgrav 
4927b5038d7SDag-Erling Smørgrav status_error:
4937b5038d7SDag-Erling Smørgrav 	ldns_pkt_free(packet);
4947b5038d7SDag-Erling Smørgrav 	return status;
4957b5038d7SDag-Erling Smørgrav }
496