4 * conversion routines from the wire to the host
6 * This will usually just a re-ordering of the
7 * data (as we store it in network format)
9 * a Net::DNS like library for C
11 * (c) NLnet Labs, 2004-2006
13 * See the file LICENSE for the license
17 #include <ldns/config.h>
19 #include <ldns/ldns.h>
20 /*#include <ldns/wire2host.h>*/
28 * Set of macro's to deal with the dns message header as specified
29 * in RFC1035 in portable way.
36 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
37 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
39 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40 * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
41 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
43 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
45 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
47 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
49 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
54 /* allocates memory to *dname! */
56 ldns_wire2dname(ldns_rdf
**dname
, const uint8_t *wire
, size_t max
, size_t *pos
)
59 uint16_t pointer_target
;
60 uint8_t pointer_target_buf
[2];
62 size_t uncompressed_length
= 0;
63 size_t compression_pos
= 0;
64 uint8_t tmp_dname
[LDNS_MAX_DOMAINLEN
];
65 unsigned int pointer_count
= 0;
68 return LDNS_STATUS_PACKET_OVERFLOW
;
71 label_size
= wire
[*pos
];
72 while (label_size
> 0) {
74 while (label_size
>= 192) {
75 if (compression_pos
== 0) {
76 compression_pos
= *pos
+ 2;
81 /* remove first two bits */
83 return LDNS_STATUS_PACKET_OVERFLOW
;
85 pointer_target_buf
[0] = wire
[*pos
] & 63;
86 pointer_target_buf
[1] = wire
[*pos
+ 1];
87 pointer_target
= ldns_read_uint16(pointer_target_buf
);
89 if (pointer_target
== 0) {
90 return LDNS_STATUS_INVALID_POINTER
;
91 } else if (pointer_target
>= max
) {
92 return LDNS_STATUS_INVALID_POINTER
;
93 } else if (pointer_count
> LDNS_MAX_POINTERS
) {
94 return LDNS_STATUS_INVALID_POINTER
;
96 *pos
= pointer_target
;
97 label_size
= wire
[*pos
];
100 break; /* break from pointer to 0 byte */
101 if (label_size
> LDNS_MAX_LABELLEN
) {
102 return LDNS_STATUS_LABEL_OVERFLOW
;
104 if (*pos
+ 1 + label_size
> max
) {
105 return LDNS_STATUS_LABEL_OVERFLOW
;
108 /* check space for labelcount itself */
109 if (dname_pos
+ 1 > LDNS_MAX_DOMAINLEN
) {
110 return LDNS_STATUS_DOMAINNAME_OVERFLOW
;
112 tmp_dname
[dname_pos
] = label_size
;
113 if (label_size
> 0) {
117 if (dname_pos
+ label_size
> LDNS_MAX_DOMAINLEN
) {
118 return LDNS_STATUS_DOMAINNAME_OVERFLOW
;
120 memcpy(&tmp_dname
[dname_pos
], &wire
[*pos
], label_size
);
121 uncompressed_length
+= label_size
+ 1;
122 dname_pos
+= label_size
;
123 *pos
= *pos
+ label_size
;
126 label_size
= wire
[*pos
];
130 if (compression_pos
> 0) {
131 *pos
= compression_pos
;
136 if (dname_pos
>= LDNS_MAX_DOMAINLEN
) {
137 return LDNS_STATUS_DOMAINNAME_OVERFLOW
;
140 tmp_dname
[dname_pos
] = 0;
143 *dname
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME
,
144 (uint16_t) dname_pos
, tmp_dname
);
146 return LDNS_STATUS_MEM_ERR
;
148 return LDNS_STATUS_OK
;
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; }}
156 ldns_wire2rdf(ldns_rr
*rr
, const uint8_t *wire
, size_t max
, size_t *pos
)
159 size_t cur_rdf_length
;
163 ldns_rdf
*cur_rdf
= NULL
;
164 ldns_rdf_type cur_rdf_type
;
165 const ldns_rr_descriptor
*descriptor
= ldns_rr_descript(ldns_rr_get_type(rr
));
168 if (*pos
+ 2 > max
) {
169 return LDNS_STATUS_PACKET_OVERFLOW
;
172 rd_length
= ldns_read_uint16(&wire
[*pos
]);
175 if (*pos
+ rd_length
> max
) {
176 return LDNS_STATUS_PACKET_OVERFLOW
;
179 end
= *pos
+ (size_t) rd_length
;
182 rdf_index
< ldns_rr_descriptor_maximum(descriptor
); rdf_index
++) {
188 cur_rdf_type
= ldns_rr_descriptor_field_type(descriptor
, rdf_index
);
189 /* handle special cases immediately, set length
190 for fixed length rdata and do them below */
191 switch (cur_rdf_type
) {
192 case LDNS_RDF_TYPE_DNAME
:
193 status
= ldns_wire2dname(&cur_rdf
, wire
, max
, pos
);
194 LDNS_STATUS_CHECK_RETURN(status
);
196 case LDNS_RDF_TYPE_CLASS
:
197 case LDNS_RDF_TYPE_ALG
:
198 case LDNS_RDF_TYPE_INT8
:
199 cur_rdf_length
= LDNS_RDF_SIZE_BYTE
;
201 case LDNS_RDF_TYPE_TYPE
:
202 case LDNS_RDF_TYPE_INT16
:
203 case LDNS_RDF_TYPE_CERT_ALG
:
204 cur_rdf_length
= LDNS_RDF_SIZE_WORD
;
206 case LDNS_RDF_TYPE_TIME
:
207 case LDNS_RDF_TYPE_INT32
:
208 case LDNS_RDF_TYPE_A
:
209 case LDNS_RDF_TYPE_PERIOD
:
210 cur_rdf_length
= LDNS_RDF_SIZE_DOUBLEWORD
;
212 case LDNS_RDF_TYPE_TSIGTIME
:
213 cur_rdf_length
= LDNS_RDF_SIZE_6BYTES
;
215 case LDNS_RDF_TYPE_AAAA
:
216 cur_rdf_length
= LDNS_RDF_SIZE_16BYTES
;
218 case LDNS_RDF_TYPE_STR
:
219 case LDNS_RDF_TYPE_NSEC3_SALT
:
220 /* len is stored in first byte
221 * it should be in the rdf too, so just
222 * copy len+1 from this position
224 cur_rdf_length
= ((size_t) wire
[*pos
]) + 1;
226 case LDNS_RDF_TYPE_INT16_DATA
:
227 cur_rdf_length
= (size_t) ldns_read_uint16(&wire
[*pos
]) + 2;
229 case LDNS_RDF_TYPE_B32_EXT
:
230 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER
:
231 /* length is stored in first byte */
232 cur_rdf_length
= ((size_t) wire
[*pos
]) + 1;
234 case LDNS_RDF_TYPE_APL
:
235 case LDNS_RDF_TYPE_B64
:
236 case LDNS_RDF_TYPE_HEX
:
237 case LDNS_RDF_TYPE_NSEC
:
238 case LDNS_RDF_TYPE_UNKNOWN
:
239 case LDNS_RDF_TYPE_SERVICE
:
240 case LDNS_RDF_TYPE_LOC
:
241 case LDNS_RDF_TYPE_WKS
:
242 case LDNS_RDF_TYPE_NSAP
:
243 case LDNS_RDF_TYPE_ATMA
:
244 case LDNS_RDF_TYPE_IPSECKEY
:
245 case LDNS_RDF_TYPE_TSIG
:
246 case LDNS_RDF_TYPE_NONE
:
248 * Read to end of rr rdata
250 cur_rdf_length
= end
- *pos
;
254 /* fixed length rdata */
255 if (cur_rdf_length
> 0) {
256 if (cur_rdf_length
+ *pos
> end
) {
257 return LDNS_STATUS_PACKET_OVERFLOW
;
259 data
= LDNS_XMALLOC(uint8_t, rd_length
);
261 return LDNS_STATUS_MEM_ERR
;
263 memcpy(data
, &wire
[*pos
], cur_rdf_length
);
265 cur_rdf
= ldns_rdf_new(cur_rdf_type
, cur_rdf_length
, data
);
266 *pos
= *pos
+ cur_rdf_length
;
270 ldns_rr_push_rdf(rr
, cur_rdf
);
275 return LDNS_STATUS_OK
;
280 can *pos be incremented at READ_INT? or maybe use something like
285 ldns_wire2rr(ldns_rr
**rr_p
, const uint8_t *wire
, size_t max
,
286 size_t *pos
, ldns_pkt_section section
)
288 ldns_rdf
*owner
= NULL
;
289 ldns_rr
*rr
= ldns_rr_new();
292 status
= ldns_wire2dname(&owner
, wire
, max
, pos
);
293 LDNS_STATUS_CHECK_GOTO(status
, status_error
);
295 ldns_rr_set_owner(rr
, owner
);
297 if (*pos
+ 4 > max
) {
298 status
= LDNS_STATUS_PACKET_OVERFLOW
;
302 ldns_rr_set_type(rr
, ldns_read_uint16(&wire
[*pos
]));
305 ldns_rr_set_class(rr
, ldns_read_uint16(&wire
[*pos
]));
308 if (section
!= LDNS_SECTION_QUESTION
) {
309 if (*pos
+ 4 > max
) {
310 status
= LDNS_STATUS_PACKET_OVERFLOW
;
313 ldns_rr_set_ttl(rr
, ldns_read_uint32(&wire
[*pos
]));
316 status
= ldns_wire2rdf(rr
, wire
, max
, pos
);
318 LDNS_STATUS_CHECK_GOTO(status
, status_error
);
319 ldns_rr_set_question(rr
, false);
321 ldns_rr_set_question(rr
, true);
325 return LDNS_STATUS_OK
;
333 ldns_wire2pkt_hdr(ldns_pkt
*packet
, const uint8_t *wire
, size_t max
, size_t *pos
)
335 if (*pos
+ LDNS_HEADER_SIZE
> max
) {
336 return LDNS_STATUS_WIRE_INCOMPLETE_HEADER
;
338 ldns_pkt_set_id(packet
, LDNS_ID_WIRE(wire
));
339 ldns_pkt_set_qr(packet
, LDNS_QR_WIRE(wire
));
340 ldns_pkt_set_opcode(packet
, LDNS_OPCODE_WIRE(wire
));
341 ldns_pkt_set_aa(packet
, LDNS_AA_WIRE(wire
));
342 ldns_pkt_set_tc(packet
, LDNS_TC_WIRE(wire
));
343 ldns_pkt_set_rd(packet
, LDNS_RD_WIRE(wire
));
344 ldns_pkt_set_ra(packet
, LDNS_RA_WIRE(wire
));
345 ldns_pkt_set_ad(packet
, LDNS_AD_WIRE(wire
));
346 ldns_pkt_set_cd(packet
, LDNS_CD_WIRE(wire
));
347 ldns_pkt_set_rcode(packet
, LDNS_RCODE_WIRE(wire
));
349 ldns_pkt_set_qdcount(packet
, LDNS_QDCOUNT(wire
));
350 ldns_pkt_set_ancount(packet
, LDNS_ANCOUNT(wire
));
351 ldns_pkt_set_nscount(packet
, LDNS_NSCOUNT(wire
));
352 ldns_pkt_set_arcount(packet
, LDNS_ARCOUNT(wire
));
354 *pos
+= LDNS_HEADER_SIZE
;
356 return LDNS_STATUS_OK
;
361 ldns_buffer2pkt_wire(ldns_pkt
**packet
, ldns_buffer
*buffer
)
364 return ldns_wire2pkt(packet
, ldns_buffer_begin(buffer
),
365 ldns_buffer_limit(buffer
));
370 ldns_wire2pkt(ldns_pkt
**packet_p
, const uint8_t *wire
, size_t max
)
375 ldns_pkt
*packet
= ldns_pkt_new();
376 ldns_status status
= LDNS_STATUS_OK
;
381 status
= ldns_wire2pkt_hdr(packet
, wire
, max
, &pos
);
382 LDNS_STATUS_CHECK_GOTO(status
, status_error
);
384 for (i
= 0; i
< ldns_pkt_qdcount(packet
); i
++) {
386 status
= ldns_wire2rr(&rr
, wire
, max
, &pos
, LDNS_SECTION_QUESTION
);
387 if (status
== LDNS_STATUS_PACKET_OVERFLOW
) {
388 status
= LDNS_STATUS_WIRE_INCOMPLETE_QUESTION
;
390 LDNS_STATUS_CHECK_GOTO(status
, status_error
);
391 if (!ldns_rr_list_push_rr(ldns_pkt_question(packet
), rr
)) {
392 ldns_pkt_free(packet
);
393 return LDNS_STATUS_INTERNAL_ERR
;
396 for (i
= 0; i
< ldns_pkt_ancount(packet
); i
++) {
397 status
= ldns_wire2rr(&rr
, wire
, max
, &pos
, LDNS_SECTION_ANSWER
);
398 if (status
== LDNS_STATUS_PACKET_OVERFLOW
) {
399 status
= LDNS_STATUS_WIRE_INCOMPLETE_ANSWER
;
401 LDNS_STATUS_CHECK_GOTO(status
, status_error
);
402 if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet
), rr
)) {
403 ldns_pkt_free(packet
);
404 return LDNS_STATUS_INTERNAL_ERR
;
407 for (i
= 0; i
< ldns_pkt_nscount(packet
); i
++) {
408 status
= ldns_wire2rr(&rr
, wire
, max
, &pos
, LDNS_SECTION_AUTHORITY
);
409 if (status
== LDNS_STATUS_PACKET_OVERFLOW
) {
410 status
= LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY
;
412 LDNS_STATUS_CHECK_GOTO(status
, status_error
);
413 if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet
), rr
)) {
414 ldns_pkt_free(packet
);
415 return LDNS_STATUS_INTERNAL_ERR
;
418 for (i
= 0; i
< ldns_pkt_arcount(packet
); i
++) {
419 status
= ldns_wire2rr(&rr
, wire
, max
, &pos
, LDNS_SECTION_ADDITIONAL
);
420 if (status
== LDNS_STATUS_PACKET_OVERFLOW
) {
421 status
= LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL
;
423 LDNS_STATUS_CHECK_GOTO(status
, status_error
);
425 if (ldns_rr_get_type(rr
) == LDNS_RR_TYPE_OPT
) {
426 ldns_pkt_set_edns_udp_size(packet
, ldns_rr_get_class(rr
));
427 ldns_write_uint32(data
, ldns_rr_ttl(rr
));
428 ldns_pkt_set_edns_extended_rcode(packet
, data
[0]);
429 ldns_pkt_set_edns_version(packet
, data
[1]);
430 ldns_pkt_set_edns_z(packet
, ldns_read_uint16(&data
[2]));
431 /* edns might not have rdfs */
432 if (ldns_rr_rdf(rr
, 0)) {
433 ldns_pkt_set_edns_data(packet
, ldns_rdf_clone(ldns_rr_rdf(rr
, 0)));
437 } else if (ldns_rr_get_type(rr
) == LDNS_RR_TYPE_TSIG
) {
438 ldns_pkt_set_tsig(packet
, rr
);
439 ldns_pkt_set_arcount(packet
, ldns_pkt_arcount(packet
) - 1);
440 } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet
), rr
)) {
441 ldns_pkt_free(packet
);
442 return LDNS_STATUS_INTERNAL_ERR
;
445 ldns_pkt_set_size(packet
, max
);
447 ldns_pkt_set_arcount(packet
, ldns_pkt_arcount(packet
)
454 ldns_pkt_free(packet
);