File Coverage

src/ldns/wire2host.c
Criterion Covered Total %
statement 171 229 74.6
branch 65 110 59.0
condition n/a
subroutine n/a
pod n/a
total 236 339 69.6


line stmt bran cond sub pod time code
1             /*
2             * wire2host.c
3             *
4             * conversion routines from the wire to the host
5             * format.
6             * This will usually just a re-ordering of the
7             * data (as we store it in network format)
8             *
9             * a Net::DNS like library for C
10             *
11             * (c) NLnet Labs, 2004-2006
12             *
13             * See the file LICENSE for the license
14             */
15              
16              
17             #include
18              
19             #include
20             /*#include */
21              
22             #include
23             #include
24              
25              
26              
27             /*
28             * Set of macro's to deal with the dns message header as specified
29             * in RFC1035 in portable way.
30             *
31             */
32              
33             /*
34             *
35             * 1 1 1 1 1 1
36             * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
37             * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
38             * | ID |
39             * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40             * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
41             * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
42             * | QDCOUNT |
43             * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
44             * | ANCOUNT |
45             * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
46             * | NSCOUNT |
47             * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
48             * | ARCOUNT |
49             * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
50             *
51             */
52              
53              
54             /* allocates memory to *dname! */
55             ldns_status
56 418           ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos)
57             {
58             uint8_t label_size;
59             uint16_t pointer_target;
60             uint8_t pointer_target_buf[2];
61 418           size_t dname_pos = 0;
62 418           size_t uncompressed_length = 0;
63 418           size_t compression_pos = 0;
64             uint8_t tmp_dname[LDNS_MAX_DOMAINLEN];
65 418           unsigned int pointer_count = 0;
66              
67 418 50         if (pos == NULL) {
68 0           return LDNS_STATUS_WIRE_RDATA_ERR;
69             }
70 418 50         if (*pos >= max) {
71 0           return LDNS_STATUS_PACKET_OVERFLOW;
72             }
73 418           label_size = wire[*pos];
74 1447 100         while (label_size > 0) {
75             /* compression */
76 1550 100         while (label_size >= 192) {
77 521 100         if (compression_pos == 0) {
78 322           compression_pos = *pos + 2;
79             }
80              
81 521           pointer_count++;
82              
83             /* remove first two bits */
84 521 50         if (*pos + 2 > max) {
85 0           return LDNS_STATUS_PACKET_OVERFLOW;
86             }
87 521           pointer_target_buf[0] = wire[*pos] & 63;
88 521           pointer_target_buf[1] = wire[*pos + 1];
89 521           pointer_target = ldns_read_uint16(pointer_target_buf);
90              
91 521 50         if (pointer_target == 0) {
92 0           return LDNS_STATUS_INVALID_POINTER;
93 521 50         } else if (pointer_target >= max) {
94 0           return LDNS_STATUS_INVALID_POINTER;
95 521 50         } else if (pointer_count > LDNS_MAX_POINTERS) {
96 0           return LDNS_STATUS_INVALID_POINTER;
97             }
98 521           *pos = pointer_target;
99 521           label_size = wire[*pos];
100             }
101 1029 50         if(label_size == 0)
102 0           break; /* break from pointer to 0 byte */
103 1029 50         if (label_size > LDNS_MAX_LABELLEN) {
104 0           return LDNS_STATUS_LABEL_OVERFLOW;
105             }
106 1029 50         if (*pos + 1 + label_size > max) {
107 0           return LDNS_STATUS_LABEL_OVERFLOW;
108             }
109              
110             /* check space for labelcount itself */
111 1029 50         if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
112 0           return LDNS_STATUS_DOMAINNAME_OVERFLOW;
113             }
114 1029           tmp_dname[dname_pos] = label_size;
115 1029 50         if (label_size > 0) {
116 1029           dname_pos++;
117             }
118 1029           *pos = *pos + 1;
119 1029 50         if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
120 0           return LDNS_STATUS_DOMAINNAME_OVERFLOW;
121             }
122 1029           memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
123 1029           uncompressed_length += label_size + 1;
124 1029           dname_pos += label_size;
125 1029           *pos = *pos + label_size;
126              
127 1029 50         if (*pos < max) {
128 1029           label_size = wire[*pos];
129             }
130             }
131              
132 418 100         if (compression_pos > 0) {
133 322           *pos = compression_pos;
134             } else {
135 96           *pos = *pos + 1;
136             }
137              
138 418 50         if (dname_pos >= LDNS_MAX_DOMAINLEN) {
139 0           return LDNS_STATUS_DOMAINNAME_OVERFLOW;
140             }
141              
142 418           tmp_dname[dname_pos] = 0;
143 418           dname_pos++;
144              
145 418           *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
146             (uint16_t) dname_pos, tmp_dname);
147 418 50         if (!*dname) {
148 0           return LDNS_STATUS_MEM_ERR;
149             }
150 418           return LDNS_STATUS_OK;
151             }
152              
153             /* maybe make this a goto error so data can be freed or something/ */
154             #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
155             #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; }}
156              
157             ldns_status
158 245           ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
159             {
160             size_t end;
161             size_t cur_rdf_length;
162             uint8_t rdf_index;
163             uint8_t *data;
164             uint16_t rd_length;
165 245           ldns_rdf *cur_rdf = NULL;
166             ldns_rdf_type cur_rdf_type;
167             const ldns_rr_descriptor *descriptor;
168             ldns_status status;
169              
170             assert(rr != NULL);
171              
172 245           descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
173              
174 245 50         if (*pos + 2 > max) {
175 0           return LDNS_STATUS_PACKET_OVERFLOW;
176             }
177              
178 245           rd_length = ldns_read_uint16(&wire[*pos]);
179 245           *pos = *pos + 2;
180              
181 245 50         if (*pos + rd_length > max) {
182 0           return LDNS_STATUS_PACKET_OVERFLOW;
183             }
184              
185 245           end = *pos + (size_t) rd_length;
186              
187 245           rdf_index = 0;
188 1599           while (*pos < end &&
189 677           rdf_index < ldns_rr_descriptor_maximum(descriptor)) {
190              
191 677           cur_rdf_length = 0;
192              
193 677           cur_rdf_type = ldns_rr_descriptor_field_type(
194             descriptor, rdf_index);
195              
196             /* handle special cases immediately, set length
197             for fixed length rdata and do them below */
198 677           switch (cur_rdf_type) {
199             case LDNS_RDF_TYPE_DNAME:
200 145           status = ldns_wire2dname(&cur_rdf, wire, max, pos);
201 145 50         LDNS_STATUS_CHECK_RETURN(status);
202 145           break;
203             case LDNS_RDF_TYPE_CLASS:
204             case LDNS_RDF_TYPE_ALG:
205             case LDNS_RDF_TYPE_CERTIFICATE_USAGE:
206             case LDNS_RDF_TYPE_SELECTOR:
207             case LDNS_RDF_TYPE_MATCHING_TYPE:
208             case LDNS_RDF_TYPE_INT8:
209 102           cur_rdf_length = LDNS_RDF_SIZE_BYTE;
210 102           break;
211             case LDNS_RDF_TYPE_TYPE:
212             case LDNS_RDF_TYPE_INT16:
213             case LDNS_RDF_TYPE_CERT_ALG:
214 99           cur_rdf_length = LDNS_RDF_SIZE_WORD;
215 99           break;
216             case LDNS_RDF_TYPE_TIME:
217             case LDNS_RDF_TYPE_INT32:
218             case LDNS_RDF_TYPE_A:
219             case LDNS_RDF_TYPE_PERIOD:
220 222           cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
221 222           break;
222             case LDNS_RDF_TYPE_TSIGTIME:
223             case LDNS_RDF_TYPE_EUI48:
224 0           cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
225 0           break;
226             case LDNS_RDF_TYPE_ILNP64:
227             case LDNS_RDF_TYPE_EUI64:
228 0           cur_rdf_length = LDNS_RDF_SIZE_8BYTES;
229 0           break;
230             case LDNS_RDF_TYPE_AAAA:
231 38           cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
232 38           break;
233             case LDNS_RDF_TYPE_STR:
234             case LDNS_RDF_TYPE_NSEC3_SALT:
235             case LDNS_RDF_TYPE_TAG:
236             /* len is stored in first byte
237             * it should be in the rdf too, so just
238             * copy len+1 from this position
239             */
240 3           cur_rdf_length = ((size_t) wire[*pos]) + 1;
241 3           break;
242              
243             case LDNS_RDF_TYPE_INT16_DATA:
244 0 0         if (*pos + 2 > end) {
245 0           return LDNS_STATUS_PACKET_OVERFLOW;
246             }
247 0           cur_rdf_length =
248 0           (size_t) ldns_read_uint16(&wire[*pos]) + 2;
249 0           break;
250             case LDNS_RDF_TYPE_HIP:
251 0 0         if (*pos + 4 > end) {
252 0           return LDNS_STATUS_PACKET_OVERFLOW;
253             }
254 0           cur_rdf_length =
255 0           (size_t) wire[*pos] +
256 0           (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4;
257 0           break;
258             case LDNS_RDF_TYPE_B32_EXT:
259             case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
260             /* length is stored in first byte */
261 0           cur_rdf_length = ((size_t) wire[*pos]) + 1;
262 0           break;
263             case LDNS_RDF_TYPE_APL:
264             case LDNS_RDF_TYPE_B64:
265             case LDNS_RDF_TYPE_HEX:
266             case LDNS_RDF_TYPE_NSEC:
267             case LDNS_RDF_TYPE_UNKNOWN:
268             case LDNS_RDF_TYPE_SERVICE:
269             case LDNS_RDF_TYPE_LOC:
270             case LDNS_RDF_TYPE_WKS:
271             case LDNS_RDF_TYPE_NSAP:
272             case LDNS_RDF_TYPE_ATMA:
273             case LDNS_RDF_TYPE_IPSECKEY:
274             case LDNS_RDF_TYPE_LONG_STR:
275             case LDNS_RDF_TYPE_NONE:
276             /*
277             * Read to end of rr rdata
278             */
279 68           cur_rdf_length = end - *pos;
280 68           break;
281             }
282              
283             /* fixed length rdata */
284 677 100         if (cur_rdf_length > 0) {
285 532 50         if (cur_rdf_length + *pos > end) {
286 0           return LDNS_STATUS_PACKET_OVERFLOW;
287             }
288 532           data = LDNS_XMALLOC(uint8_t, rd_length);
289 532 50         if (!data) {
290 0           return LDNS_STATUS_MEM_ERR;
291             }
292 532           memcpy(data, &wire[*pos], cur_rdf_length);
293              
294 532           cur_rdf = ldns_rdf_new(cur_rdf_type,
295             cur_rdf_length, data);
296 532           *pos = *pos + cur_rdf_length;
297             }
298              
299 677 50         if (cur_rdf) {
300 677           ldns_rr_push_rdf(rr, cur_rdf);
301 677           cur_rdf = NULL;
302             }
303              
304 677           rdf_index++;
305              
306             } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */
307              
308              
309 245           return LDNS_STATUS_OK;
310             }
311              
312              
313             /* TODO:
314             can *pos be incremented at READ_INT? or maybe use something like
315             RR_CLASS(wire)?
316             uhhm Jelte??
317             */
318             ldns_status
319 273           ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
320             size_t *pos, ldns_pkt_section section)
321             {
322 273           ldns_rdf *owner = NULL;
323 273           ldns_rr *rr = ldns_rr_new();
324             ldns_status status;
325              
326 273           status = ldns_wire2dname(&owner, wire, max, pos);
327 273 50         LDNS_STATUS_CHECK_GOTO(status, status_error);
328              
329 273           ldns_rr_set_owner(rr, owner);
330              
331 273 50         if (*pos + 4 > max) {
332 0           status = LDNS_STATUS_PACKET_OVERFLOW;
333 0           goto status_error;
334             }
335              
336 273           ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
337 273           *pos = *pos + 2;
338              
339 273           ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
340 273           *pos = *pos + 2;
341              
342 273 100         if (section != LDNS_SECTION_QUESTION) {
343 245 50         if (*pos + 4 > max) {
344 0           status = LDNS_STATUS_PACKET_OVERFLOW;
345 0           goto status_error;
346             }
347 245           ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
348              
349 245           *pos = *pos + 4;
350 245           status = ldns_wire2rdf(rr, wire, max, pos);
351              
352 245 50         LDNS_STATUS_CHECK_GOTO(status, status_error);
353 245           ldns_rr_set_question(rr, false);
354             } else {
355 28           ldns_rr_set_question(rr, true);
356             }
357              
358 273           *rr_p = rr;
359 273           return LDNS_STATUS_OK;
360              
361             status_error:
362 0           ldns_rr_free(rr);
363 273           return status;
364             }
365              
366             static ldns_status
367 28           ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
368             {
369 28 50         if (*pos + LDNS_HEADER_SIZE > max) {
370 0           return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
371             } else {
372 28           ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
373 28           ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
374 28           ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
375 28           ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
376 28           ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
377 28           ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
378 28           ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
379 28           ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
380 28           ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
381 28           ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
382              
383 28           ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
384 28           ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
385 28           ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
386 28           ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
387              
388 28           *pos += LDNS_HEADER_SIZE;
389              
390 28           return LDNS_STATUS_OK;
391             }
392             }
393              
394             ldns_status
395 0           ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer)
396             {
397             /* lazy */
398 0           return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
399             ldns_buffer_limit(buffer));
400              
401             }
402              
403             ldns_status
404 28           ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
405             {
406 28           size_t pos = 0;
407             uint16_t i;
408             ldns_rr *rr;
409 28           ldns_pkt *packet = ldns_pkt_new();
410 28           ldns_status status = LDNS_STATUS_OK;
411 28           uint8_t have_edns = 0;
412              
413             uint8_t data[4];
414              
415 28           status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
416 28 50         LDNS_STATUS_CHECK_GOTO(status, status_error);
417              
418 56 100         for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
419              
420 28           status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
421 28 50         if (status == LDNS_STATUS_PACKET_OVERFLOW) {
422 0           status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
423             }
424 28 50         LDNS_STATUS_CHECK_GOTO(status, status_error);
425 28 50         if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
426 0           ldns_pkt_free(packet);
427 0           return LDNS_STATUS_INTERNAL_ERR;
428             }
429             }
430 144 100         for (i = 0; i < ldns_pkt_ancount(packet); i++) {
431 116           status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
432 116 50         if (status == LDNS_STATUS_PACKET_OVERFLOW) {
433 0           status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
434             }
435 116 50         LDNS_STATUS_CHECK_GOTO(status, status_error);
436 116 50         if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
437 0           ldns_pkt_free(packet);
438 0           return LDNS_STATUS_INTERNAL_ERR;
439             }
440             }
441 78 100         for (i = 0; i < ldns_pkt_nscount(packet); i++) {
442 50           status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
443 50 50         if (status == LDNS_STATUS_PACKET_OVERFLOW) {
444 0           status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
445             }
446 50 50         LDNS_STATUS_CHECK_GOTO(status, status_error);
447 50 50         if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
448 0           ldns_pkt_free(packet);
449 0           return LDNS_STATUS_INTERNAL_ERR;
450             }
451             }
452 107 100         for (i = 0; i < ldns_pkt_arcount(packet); i++) {
453 79           status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
454 79 50         if (status == LDNS_STATUS_PACKET_OVERFLOW) {
455 0           status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
456             }
457 79 50         LDNS_STATUS_CHECK_GOTO(status, status_error);
458              
459 79 100         if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
460 2           ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
461 2           ldns_write_uint32(data, ldns_rr_ttl(rr));
462 2           ldns_pkt_set_edns_extended_rcode(packet, data[0]);
463 2           ldns_pkt_set_edns_version(packet, data[1]);
464 2           ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
465             /* edns might not have rdfs */
466 2 50         if (ldns_rr_rdf(rr, 0)) {
467 0           ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
468             }
469 2           ldns_rr_free(rr);
470 2           have_edns += 1;
471 77 50         } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
472 0           ldns_pkt_set_tsig(packet, rr);
473 0           ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
474 77 50         } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
475 0           ldns_pkt_free(packet);
476 0           return LDNS_STATUS_INTERNAL_ERR;
477             }
478             }
479 28           ldns_pkt_set_size(packet, max);
480 28 100         if(have_edns)
481 2           ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
482             - have_edns);
483 28           packet->_edns_present = have_edns;
484              
485 28           *packet_p = packet;
486 28           return status;
487              
488             status_error:
489 0           ldns_pkt_free(packet);
490 28           return status;
491             }