xref: /dflybsd-src/contrib/ldns/wire2host.c (revision 7733acb50455a11cc2ee36edd926ff0fa3361e9a)
1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer  * wire2host.c
3825eb42bSJan Lentfer  *
4825eb42bSJan Lentfer  * conversion routines from the wire to the host
5825eb42bSJan Lentfer  * format.
6825eb42bSJan Lentfer  * This will usually just a re-ordering of the
7825eb42bSJan Lentfer  * data (as we store it in network format)
8825eb42bSJan Lentfer  *
9825eb42bSJan Lentfer  * a Net::DNS like library for C
10825eb42bSJan Lentfer  *
11825eb42bSJan Lentfer  * (c) NLnet Labs, 2004-2006
12825eb42bSJan Lentfer  *
13825eb42bSJan Lentfer  * See the file LICENSE for the license
14825eb42bSJan Lentfer  */
15825eb42bSJan Lentfer 
16825eb42bSJan Lentfer 
17825eb42bSJan Lentfer #include <ldns/config.h>
18825eb42bSJan Lentfer 
19825eb42bSJan Lentfer #include <ldns/ldns.h>
20825eb42bSJan Lentfer /*#include <ldns/wire2host.h>*/
21825eb42bSJan Lentfer 
22825eb42bSJan Lentfer #include <strings.h>
23825eb42bSJan Lentfer #include <limits.h>
24825eb42bSJan Lentfer 
25825eb42bSJan Lentfer 
26825eb42bSJan Lentfer 
27825eb42bSJan Lentfer /*
28825eb42bSJan Lentfer  * Set of macro's to deal with the dns message header as specified
29825eb42bSJan Lentfer  * in RFC1035 in portable way.
30825eb42bSJan Lentfer  *
31825eb42bSJan Lentfer  */
32825eb42bSJan Lentfer 
33825eb42bSJan Lentfer /*
34825eb42bSJan Lentfer  *
35825eb42bSJan Lentfer  *                                    1  1  1  1  1  1
36825eb42bSJan Lentfer  *      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
37825eb42bSJan Lentfer  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
38825eb42bSJan Lentfer  *    |                      ID                       |
39825eb42bSJan Lentfer  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40825eb42bSJan Lentfer  *    |QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
41825eb42bSJan Lentfer  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
42825eb42bSJan Lentfer  *    |                    QDCOUNT                    |
43825eb42bSJan Lentfer  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
44825eb42bSJan Lentfer  *    |                    ANCOUNT                    |
45825eb42bSJan Lentfer  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
46825eb42bSJan Lentfer  *    |                    NSCOUNT                    |
47825eb42bSJan Lentfer  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
48825eb42bSJan Lentfer  *    |                    ARCOUNT                    |
49825eb42bSJan Lentfer  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
50825eb42bSJan Lentfer  *
51825eb42bSJan Lentfer  */
52825eb42bSJan Lentfer 
53825eb42bSJan Lentfer 
54825eb42bSJan Lentfer /* allocates memory to *dname! */
55825eb42bSJan Lentfer ldns_status
ldns_wire2dname(ldns_rdf ** dname,const uint8_t * wire,size_t max,size_t * pos)56825eb42bSJan Lentfer ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos)
57825eb42bSJan Lentfer {
58825eb42bSJan Lentfer 	uint8_t label_size;
59825eb42bSJan Lentfer 	uint16_t pointer_target;
60825eb42bSJan Lentfer 	uint8_t pointer_target_buf[2];
61825eb42bSJan Lentfer 	size_t dname_pos = 0;
62825eb42bSJan Lentfer 	size_t uncompressed_length = 0;
63825eb42bSJan Lentfer 	size_t compression_pos = 0;
64825eb42bSJan Lentfer 	uint8_t tmp_dname[LDNS_MAX_DOMAINLEN];
65825eb42bSJan Lentfer 	unsigned int pointer_count = 0;
66825eb42bSJan Lentfer 
675340022aSzrj 	if (pos == NULL) {
685340022aSzrj 		return LDNS_STATUS_WIRE_RDATA_ERR;
695340022aSzrj 	}
70825eb42bSJan Lentfer 	if (*pos >= max) {
71825eb42bSJan Lentfer 		return LDNS_STATUS_PACKET_OVERFLOW;
72825eb42bSJan Lentfer 	}
73825eb42bSJan Lentfer 	label_size = wire[*pos];
74825eb42bSJan Lentfer 	while (label_size > 0) {
75825eb42bSJan Lentfer 		/* compression */
76825eb42bSJan Lentfer 		while (label_size >= 192) {
77825eb42bSJan Lentfer 			if (compression_pos == 0) {
78825eb42bSJan Lentfer 				compression_pos = *pos + 2;
79825eb42bSJan Lentfer 			}
80825eb42bSJan Lentfer 
81825eb42bSJan Lentfer 			pointer_count++;
82825eb42bSJan Lentfer 
83825eb42bSJan Lentfer 			/* remove first two bits */
84825eb42bSJan Lentfer 			if (*pos + 2 > max) {
85825eb42bSJan Lentfer 				return LDNS_STATUS_PACKET_OVERFLOW;
86825eb42bSJan Lentfer 			}
87825eb42bSJan Lentfer 			pointer_target_buf[0] = wire[*pos] & 63;
88825eb42bSJan Lentfer 			pointer_target_buf[1] = wire[*pos + 1];
89825eb42bSJan Lentfer 			pointer_target = ldns_read_uint16(pointer_target_buf);
90825eb42bSJan Lentfer 
91825eb42bSJan Lentfer 			if (pointer_target == 0) {
92825eb42bSJan Lentfer 				return LDNS_STATUS_INVALID_POINTER;
93ac996e71SJan Lentfer 			} else if (pointer_target >= max) {
94825eb42bSJan Lentfer 				return LDNS_STATUS_INVALID_POINTER;
95825eb42bSJan Lentfer 			} else if (pointer_count > LDNS_MAX_POINTERS) {
96825eb42bSJan Lentfer 				return LDNS_STATUS_INVALID_POINTER;
97825eb42bSJan Lentfer 			}
98825eb42bSJan Lentfer 			*pos = pointer_target;
99825eb42bSJan Lentfer 			label_size = wire[*pos];
100825eb42bSJan Lentfer 		}
101825eb42bSJan Lentfer 		if(label_size == 0)
102825eb42bSJan Lentfer 			break; /* break from pointer to 0 byte */
103825eb42bSJan Lentfer 		if (label_size > LDNS_MAX_LABELLEN) {
104825eb42bSJan Lentfer 			return LDNS_STATUS_LABEL_OVERFLOW;
105825eb42bSJan Lentfer 		}
106ac996e71SJan Lentfer 		if (*pos + 1 + label_size > max) {
107825eb42bSJan Lentfer 			return LDNS_STATUS_LABEL_OVERFLOW;
108825eb42bSJan Lentfer 		}
109825eb42bSJan Lentfer 
110825eb42bSJan Lentfer 		/* check space for labelcount itself */
111825eb42bSJan Lentfer 		if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
112825eb42bSJan Lentfer 			return LDNS_STATUS_DOMAINNAME_OVERFLOW;
113825eb42bSJan Lentfer 		}
114825eb42bSJan Lentfer 		tmp_dname[dname_pos] = label_size;
115825eb42bSJan Lentfer 		if (label_size > 0) {
116825eb42bSJan Lentfer 			dname_pos++;
117825eb42bSJan Lentfer 		}
118825eb42bSJan Lentfer 		*pos = *pos + 1;
119825eb42bSJan Lentfer 		if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
120825eb42bSJan Lentfer 			return LDNS_STATUS_DOMAINNAME_OVERFLOW;
121825eb42bSJan Lentfer 		}
122825eb42bSJan Lentfer 		memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
123825eb42bSJan Lentfer 		uncompressed_length += label_size + 1;
124825eb42bSJan Lentfer 		dname_pos += label_size;
125825eb42bSJan Lentfer 		*pos = *pos + label_size;
126825eb42bSJan Lentfer 
127825eb42bSJan Lentfer 		if (*pos < max) {
128825eb42bSJan Lentfer 			label_size = wire[*pos];
129825eb42bSJan Lentfer 		}
130825eb42bSJan Lentfer 	}
131825eb42bSJan Lentfer 
132825eb42bSJan Lentfer 	if (compression_pos > 0) {
133825eb42bSJan Lentfer 		*pos = compression_pos;
134825eb42bSJan Lentfer 	} else {
135825eb42bSJan Lentfer 		*pos = *pos + 1;
136825eb42bSJan Lentfer 	}
137825eb42bSJan Lentfer 
138825eb42bSJan Lentfer 	if (dname_pos >= LDNS_MAX_DOMAINLEN) {
139825eb42bSJan Lentfer 		return LDNS_STATUS_DOMAINNAME_OVERFLOW;
140825eb42bSJan Lentfer 	}
141825eb42bSJan Lentfer 
142825eb42bSJan Lentfer 	tmp_dname[dname_pos] = 0;
143825eb42bSJan Lentfer 	dname_pos++;
144825eb42bSJan Lentfer 
145825eb42bSJan Lentfer 	*dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
146825eb42bSJan Lentfer 			(uint16_t) dname_pos, tmp_dname);
147825eb42bSJan Lentfer 	if (!*dname) {
148825eb42bSJan Lentfer 		return LDNS_STATUS_MEM_ERR;
149825eb42bSJan Lentfer 	}
150825eb42bSJan Lentfer 	return LDNS_STATUS_OK;
151825eb42bSJan Lentfer }
152825eb42bSJan Lentfer 
153825eb42bSJan Lentfer /* maybe make this a goto error so data can be freed or something/ */
154825eb42bSJan Lentfer #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
155825eb42bSJan Lentfer #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; }}
156825eb42bSJan Lentfer 
157825eb42bSJan Lentfer ldns_status
ldns_wire2rdf(ldns_rr * rr,const uint8_t * wire,size_t max,size_t * pos)158825eb42bSJan Lentfer ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
159825eb42bSJan Lentfer {
160825eb42bSJan Lentfer 	size_t end;
161825eb42bSJan Lentfer 	size_t cur_rdf_length;
162825eb42bSJan Lentfer 	uint8_t rdf_index;
163825eb42bSJan Lentfer 	uint8_t *data;
164825eb42bSJan Lentfer 	uint16_t rd_length;
165825eb42bSJan Lentfer 	ldns_rdf *cur_rdf = NULL;
166825eb42bSJan Lentfer 	ldns_rdf_type cur_rdf_type;
1675340022aSzrj 	const ldns_rr_descriptor *descriptor;
168825eb42bSJan Lentfer 	ldns_status status;
169825eb42bSJan Lentfer 
1705340022aSzrj 	assert(rr != NULL);
1715340022aSzrj 
1725340022aSzrj 	descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
1735340022aSzrj 
174825eb42bSJan Lentfer 	if (*pos + 2 > max) {
175825eb42bSJan Lentfer 		return LDNS_STATUS_PACKET_OVERFLOW;
176825eb42bSJan Lentfer 	}
177825eb42bSJan Lentfer 
178825eb42bSJan Lentfer 	rd_length = ldns_read_uint16(&wire[*pos]);
179825eb42bSJan Lentfer 	*pos = *pos + 2;
180825eb42bSJan Lentfer 
181825eb42bSJan Lentfer 	if (*pos + rd_length > max) {
182825eb42bSJan Lentfer 		return LDNS_STATUS_PACKET_OVERFLOW;
183825eb42bSJan Lentfer 	}
184825eb42bSJan Lentfer 
185825eb42bSJan Lentfer 	end = *pos + (size_t) rd_length;
186825eb42bSJan Lentfer 
1875340022aSzrj 	rdf_index = 0;
1885340022aSzrj 	while (*pos < end &&
1895340022aSzrj 			rdf_index < ldns_rr_descriptor_maximum(descriptor)) {
1905340022aSzrj 
191825eb42bSJan Lentfer 		cur_rdf_length = 0;
192825eb42bSJan Lentfer 
1935340022aSzrj 		cur_rdf_type = ldns_rr_descriptor_field_type(
1945340022aSzrj 				descriptor, rdf_index);
1955340022aSzrj 
196825eb42bSJan Lentfer 		/* handle special cases immediately, set length
197825eb42bSJan Lentfer 		   for fixed length rdata and do them below */
198825eb42bSJan Lentfer 		switch (cur_rdf_type) {
199825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_DNAME:
200825eb42bSJan Lentfer 			status = ldns_wire2dname(&cur_rdf, wire, max, pos);
201825eb42bSJan Lentfer 			LDNS_STATUS_CHECK_RETURN(status);
202825eb42bSJan Lentfer 			break;
203825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_CLASS:
204825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_ALG:
2055340022aSzrj 		case LDNS_RDF_TYPE_CERTIFICATE_USAGE:
2065340022aSzrj 		case LDNS_RDF_TYPE_SELECTOR:
2075340022aSzrj 		case LDNS_RDF_TYPE_MATCHING_TYPE:
208825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_INT8:
209825eb42bSJan Lentfer 			cur_rdf_length = LDNS_RDF_SIZE_BYTE;
210825eb42bSJan Lentfer 			break;
211825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_TYPE:
212825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_INT16:
213825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_CERT_ALG:
214825eb42bSJan Lentfer 			cur_rdf_length = LDNS_RDF_SIZE_WORD;
215825eb42bSJan Lentfer 			break;
216825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_TIME:
217825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_INT32:
218825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_A:
219825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_PERIOD:
220825eb42bSJan Lentfer 			cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
221825eb42bSJan Lentfer 			break;
222825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_TSIGTIME:
2235340022aSzrj 		case LDNS_RDF_TYPE_EUI48:
224825eb42bSJan Lentfer 			cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
225825eb42bSJan Lentfer 			break;
2265340022aSzrj 		case LDNS_RDF_TYPE_ILNP64:
2275340022aSzrj 		case LDNS_RDF_TYPE_EUI64:
2285340022aSzrj 			cur_rdf_length = LDNS_RDF_SIZE_8BYTES;
2295340022aSzrj 			break;
230825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_AAAA:
231825eb42bSJan Lentfer 			cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
232825eb42bSJan Lentfer 			break;
233825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_STR:
234825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_NSEC3_SALT:
2355340022aSzrj 		case LDNS_RDF_TYPE_TAG:
236825eb42bSJan Lentfer 			/* len is stored in first byte
237825eb42bSJan Lentfer 			 * it should be in the rdf too, so just
238825eb42bSJan Lentfer 			 * copy len+1 from this position
239825eb42bSJan Lentfer 			 */
240825eb42bSJan Lentfer 			cur_rdf_length = ((size_t) wire[*pos]) + 1;
241825eb42bSJan Lentfer 			break;
2425340022aSzrj 
243825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_INT16_DATA:
2445340022aSzrj 			if (*pos + 2 > end) {
2455340022aSzrj 				return LDNS_STATUS_PACKET_OVERFLOW;
2465340022aSzrj 			}
2475340022aSzrj 			cur_rdf_length =
2485340022aSzrj 				(size_t) ldns_read_uint16(&wire[*pos]) + 2;
2495340022aSzrj 			break;
2505340022aSzrj 		case LDNS_RDF_TYPE_HIP:
2515340022aSzrj 			if (*pos + 4 > end) {
2525340022aSzrj 				return LDNS_STATUS_PACKET_OVERFLOW;
2535340022aSzrj 			}
2545340022aSzrj 			cur_rdf_length =
2555340022aSzrj 				(size_t) wire[*pos] +
2565340022aSzrj 				(size_t) ldns_read_uint16(&wire[*pos + 2]) + 4;
257825eb42bSJan Lentfer 			break;
258825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_B32_EXT:
259825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
260825eb42bSJan Lentfer 			/* length is stored in first byte */
261825eb42bSJan Lentfer 			cur_rdf_length = ((size_t) wire[*pos]) + 1;
262825eb42bSJan Lentfer 			break;
263825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_APL:
264825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_B64:
265825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_HEX:
266825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_NSEC:
267825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_UNKNOWN:
268825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_SERVICE:
269825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_LOC:
270825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_WKS:
271825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_NSAP:
272825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_ATMA:
273825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_IPSECKEY:
2745340022aSzrj 		case LDNS_RDF_TYPE_LONG_STR:
275819dec71SDaniel Fojt 		case LDNS_RDF_TYPE_AMTRELAY:
276*ee791febSAntonio Huete Jimenez 		case LDNS_RDF_TYPE_SVCPARAMS:
277825eb42bSJan Lentfer 		case LDNS_RDF_TYPE_NONE:
278825eb42bSJan Lentfer 			/*
279825eb42bSJan Lentfer 			 * Read to end of rr rdata
280825eb42bSJan Lentfer 			 */
281825eb42bSJan Lentfer 			cur_rdf_length = end - *pos;
282825eb42bSJan Lentfer 			break;
283825eb42bSJan Lentfer 		}
284825eb42bSJan Lentfer 
285825eb42bSJan Lentfer 		/* fixed length rdata */
286825eb42bSJan Lentfer 		if (cur_rdf_length > 0) {
287825eb42bSJan Lentfer 			if (cur_rdf_length + *pos > end) {
288825eb42bSJan Lentfer 				return LDNS_STATUS_PACKET_OVERFLOW;
289825eb42bSJan Lentfer 			}
290825eb42bSJan Lentfer 			data = LDNS_XMALLOC(uint8_t, rd_length);
291825eb42bSJan Lentfer 			if (!data) {
292825eb42bSJan Lentfer 				return LDNS_STATUS_MEM_ERR;
293825eb42bSJan Lentfer 			}
294825eb42bSJan Lentfer 			memcpy(data, &wire[*pos], cur_rdf_length);
295825eb42bSJan Lentfer 
2965340022aSzrj 			cur_rdf = ldns_rdf_new(cur_rdf_type,
2975340022aSzrj 					cur_rdf_length, data);
298825eb42bSJan Lentfer 			*pos = *pos + cur_rdf_length;
299825eb42bSJan Lentfer 		}
300825eb42bSJan Lentfer 
301825eb42bSJan Lentfer 		if (cur_rdf) {
302825eb42bSJan Lentfer 			ldns_rr_push_rdf(rr, cur_rdf);
303825eb42bSJan Lentfer 			cur_rdf = NULL;
304825eb42bSJan Lentfer 		}
3055340022aSzrj 
3065340022aSzrj 		rdf_index++;
3075340022aSzrj 
3085340022aSzrj 	} /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */
3095340022aSzrj 
310825eb42bSJan Lentfer 
311825eb42bSJan Lentfer 	return LDNS_STATUS_OK;
312825eb42bSJan Lentfer }
313825eb42bSJan Lentfer 
314825eb42bSJan Lentfer /* TODO:
315825eb42bSJan Lentfer          can *pos be incremented at READ_INT? or maybe use something like
316825eb42bSJan Lentfer          RR_CLASS(wire)?
317825eb42bSJan Lentfer 	 uhhm Jelte??
318825eb42bSJan Lentfer */
319825eb42bSJan Lentfer ldns_status
ldns_wire2rr(ldns_rr ** rr_p,const uint8_t * wire,size_t max,size_t * pos,ldns_pkt_section section)320825eb42bSJan Lentfer ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
321825eb42bSJan Lentfer              size_t *pos, ldns_pkt_section section)
322825eb42bSJan Lentfer {
323825eb42bSJan Lentfer 	ldns_rdf *owner = NULL;
324825eb42bSJan Lentfer 	ldns_rr *rr = ldns_rr_new();
325825eb42bSJan Lentfer 	ldns_status status;
326825eb42bSJan Lentfer 
327825eb42bSJan Lentfer 	status = ldns_wire2dname(&owner, wire, max, pos);
328825eb42bSJan Lentfer 	LDNS_STATUS_CHECK_GOTO(status, status_error);
329825eb42bSJan Lentfer 
330825eb42bSJan Lentfer 	ldns_rr_set_owner(rr, owner);
331825eb42bSJan Lentfer 
332825eb42bSJan Lentfer 	if (*pos + 4 > max) {
333825eb42bSJan Lentfer 		status = LDNS_STATUS_PACKET_OVERFLOW;
334825eb42bSJan Lentfer 		goto status_error;
335825eb42bSJan Lentfer 	}
336825eb42bSJan Lentfer 
337825eb42bSJan Lentfer 	ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
338825eb42bSJan Lentfer 	*pos = *pos + 2;
339825eb42bSJan Lentfer 
340825eb42bSJan Lentfer 	ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
341825eb42bSJan Lentfer 	*pos = *pos + 2;
342825eb42bSJan Lentfer 
343825eb42bSJan Lentfer 	if (section != LDNS_SECTION_QUESTION) {
344825eb42bSJan Lentfer 		if (*pos + 4 > max) {
345825eb42bSJan Lentfer 			status = LDNS_STATUS_PACKET_OVERFLOW;
346825eb42bSJan Lentfer 			goto status_error;
347825eb42bSJan Lentfer 		}
348825eb42bSJan Lentfer 		ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
349825eb42bSJan Lentfer 
350825eb42bSJan Lentfer 		*pos = *pos + 4;
351825eb42bSJan Lentfer 		status = ldns_wire2rdf(rr, wire, max, pos);
352825eb42bSJan Lentfer 
353825eb42bSJan Lentfer 		LDNS_STATUS_CHECK_GOTO(status, status_error);
354825eb42bSJan Lentfer         ldns_rr_set_question(rr, false);
355825eb42bSJan Lentfer 	} else {
356825eb42bSJan Lentfer         ldns_rr_set_question(rr, true);
357825eb42bSJan Lentfer     }
358825eb42bSJan Lentfer 
359825eb42bSJan Lentfer 	*rr_p = rr;
360825eb42bSJan Lentfer 	return LDNS_STATUS_OK;
361825eb42bSJan Lentfer 
362825eb42bSJan Lentfer status_error:
363825eb42bSJan Lentfer 	ldns_rr_free(rr);
364825eb42bSJan Lentfer 	return status;
365825eb42bSJan Lentfer }
366825eb42bSJan Lentfer 
367825eb42bSJan Lentfer static ldns_status
ldns_wire2pkt_hdr(ldns_pkt * packet,const uint8_t * wire,size_t max,size_t * pos)368825eb42bSJan Lentfer ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
369825eb42bSJan Lentfer {
370825eb42bSJan Lentfer 	if (*pos + LDNS_HEADER_SIZE > max) {
371825eb42bSJan Lentfer 		return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
372825eb42bSJan Lentfer 	} else {
373825eb42bSJan Lentfer 		ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
374825eb42bSJan Lentfer 		ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
375825eb42bSJan Lentfer 		ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
376825eb42bSJan Lentfer 		ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
377825eb42bSJan Lentfer 		ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
378825eb42bSJan Lentfer 		ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
379825eb42bSJan Lentfer 		ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
380825eb42bSJan Lentfer 		ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
381825eb42bSJan Lentfer 		ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
382825eb42bSJan Lentfer 		ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
383825eb42bSJan Lentfer 
384825eb42bSJan Lentfer 		ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
385825eb42bSJan Lentfer 		ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
386825eb42bSJan Lentfer 		ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
387825eb42bSJan Lentfer 		ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
388825eb42bSJan Lentfer 
389825eb42bSJan Lentfer 		*pos += LDNS_HEADER_SIZE;
390825eb42bSJan Lentfer 
391825eb42bSJan Lentfer 		return LDNS_STATUS_OK;
392825eb42bSJan Lentfer 	}
393825eb42bSJan Lentfer }
394825eb42bSJan Lentfer 
395825eb42bSJan Lentfer ldns_status
ldns_buffer2pkt_wire(ldns_pkt ** packet,const ldns_buffer * buffer)3965340022aSzrj ldns_buffer2pkt_wire(ldns_pkt **packet, const ldns_buffer *buffer)
397825eb42bSJan Lentfer {
398825eb42bSJan Lentfer 	/* lazy */
399825eb42bSJan Lentfer 	return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
400825eb42bSJan Lentfer 				ldns_buffer_limit(buffer));
401825eb42bSJan Lentfer 
402825eb42bSJan Lentfer }
403825eb42bSJan Lentfer 
404825eb42bSJan Lentfer ldns_status
ldns_wire2pkt(ldns_pkt ** packet_p,const uint8_t * wire,size_t max)405825eb42bSJan Lentfer ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
406825eb42bSJan Lentfer {
407825eb42bSJan Lentfer 	size_t pos = 0;
408825eb42bSJan Lentfer 	uint16_t i;
409825eb42bSJan Lentfer 	ldns_rr *rr;
410825eb42bSJan Lentfer 	ldns_pkt *packet = ldns_pkt_new();
411825eb42bSJan Lentfer 	ldns_status status = LDNS_STATUS_OK;
4125340022aSzrj 	uint8_t have_edns = 0;
413825eb42bSJan Lentfer 
414825eb42bSJan Lentfer 	uint8_t data[4];
415825eb42bSJan Lentfer 
416819dec71SDaniel Fojt 	if (!packet) {
417819dec71SDaniel Fojt 		return LDNS_STATUS_MEM_ERR;
418819dec71SDaniel Fojt 	}
419819dec71SDaniel Fojt 
420825eb42bSJan Lentfer 	status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
421825eb42bSJan Lentfer 	LDNS_STATUS_CHECK_GOTO(status, status_error);
422825eb42bSJan Lentfer 
423825eb42bSJan Lentfer 	for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
424825eb42bSJan Lentfer 
425825eb42bSJan Lentfer 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
426825eb42bSJan Lentfer 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
427825eb42bSJan Lentfer 			status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
428825eb42bSJan Lentfer 		}
429825eb42bSJan Lentfer 		LDNS_STATUS_CHECK_GOTO(status, status_error);
430825eb42bSJan Lentfer 		if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
431825eb42bSJan Lentfer 			ldns_pkt_free(packet);
432825eb42bSJan Lentfer 			return LDNS_STATUS_INTERNAL_ERR;
433825eb42bSJan Lentfer 		}
434825eb42bSJan Lentfer 	}
435825eb42bSJan Lentfer 	for (i = 0; i < ldns_pkt_ancount(packet); i++) {
436825eb42bSJan Lentfer 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
437825eb42bSJan Lentfer 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
438825eb42bSJan Lentfer 			status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
439825eb42bSJan Lentfer 		}
440825eb42bSJan Lentfer 		LDNS_STATUS_CHECK_GOTO(status, status_error);
441825eb42bSJan Lentfer 		if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
442825eb42bSJan Lentfer 			ldns_pkt_free(packet);
443825eb42bSJan Lentfer 			return LDNS_STATUS_INTERNAL_ERR;
444825eb42bSJan Lentfer 		}
445825eb42bSJan Lentfer 	}
446825eb42bSJan Lentfer 	for (i = 0; i < ldns_pkt_nscount(packet); i++) {
447825eb42bSJan Lentfer 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
448825eb42bSJan Lentfer 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
449825eb42bSJan Lentfer 			status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
450825eb42bSJan Lentfer 		}
451825eb42bSJan Lentfer 		LDNS_STATUS_CHECK_GOTO(status, status_error);
452825eb42bSJan Lentfer 		if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
453825eb42bSJan Lentfer 			ldns_pkt_free(packet);
454825eb42bSJan Lentfer 			return LDNS_STATUS_INTERNAL_ERR;
455825eb42bSJan Lentfer 		}
456825eb42bSJan Lentfer 	}
457825eb42bSJan Lentfer 	for (i = 0; i < ldns_pkt_arcount(packet); i++) {
458825eb42bSJan Lentfer 		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
459825eb42bSJan Lentfer 		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
460825eb42bSJan Lentfer 			status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
461825eb42bSJan Lentfer 		}
462825eb42bSJan Lentfer 		LDNS_STATUS_CHECK_GOTO(status, status_error);
463825eb42bSJan Lentfer 
464825eb42bSJan Lentfer 		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
465825eb42bSJan Lentfer 			ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
466825eb42bSJan Lentfer 			ldns_write_uint32(data, ldns_rr_ttl(rr));
467825eb42bSJan Lentfer 			ldns_pkt_set_edns_extended_rcode(packet, data[0]);
468825eb42bSJan Lentfer 			ldns_pkt_set_edns_version(packet, data[1]);
469825eb42bSJan Lentfer 			ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
470825eb42bSJan Lentfer 			/* edns might not have rdfs */
471825eb42bSJan Lentfer 			if (ldns_rr_rdf(rr, 0)) {
472819dec71SDaniel Fojt 				ldns_rdf_deep_free(ldns_pkt_edns_data(packet));
473825eb42bSJan Lentfer 				ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
474825eb42bSJan Lentfer 			}
475825eb42bSJan Lentfer 			ldns_rr_free(rr);
476ac996e71SJan Lentfer 			have_edns += 1;
477825eb42bSJan Lentfer 		} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
478825eb42bSJan Lentfer 			ldns_pkt_set_tsig(packet, rr);
479825eb42bSJan Lentfer 			ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
480825eb42bSJan Lentfer 		} else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
481825eb42bSJan Lentfer 			ldns_pkt_free(packet);
482825eb42bSJan Lentfer 			return LDNS_STATUS_INTERNAL_ERR;
483825eb42bSJan Lentfer 		}
484825eb42bSJan Lentfer 	}
485825eb42bSJan Lentfer 	ldns_pkt_set_size(packet, max);
486825eb42bSJan Lentfer 	if(have_edns)
487ac996e71SJan Lentfer 		ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
488ac996e71SJan Lentfer                         - have_edns);
4895340022aSzrj         packet->_edns_present = have_edns;
490825eb42bSJan Lentfer 
491825eb42bSJan Lentfer 	*packet_p = packet;
492825eb42bSJan Lentfer 	return status;
493825eb42bSJan Lentfer 
494825eb42bSJan Lentfer status_error:
495825eb42bSJan Lentfer 	ldns_pkt_free(packet);
496825eb42bSJan Lentfer 	return status;
497825eb42bSJan Lentfer }
498