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