xref: /dragonfly/contrib/ldns/host2wire.c (revision 7733acb50455a11cc2ee36edd926ff0fa3361e9a)
1 /*
2  * host2wire.c
3  *
4  * conversion routines from the host to the wire format.
5  * This will usually just a re-ordering of the
6  * data (as we store it in network format)
7  *
8  * a Net::DNS like library for C
9  *
10  * (c) NLnet Labs, 2004-2006
11  *
12  * See the file LICENSE for the license
13  */
14 
15 #include <ldns/config.h>
16 
17 #include <ldns/ldns.h>
18 
19 ldns_status
ldns_dname2buffer_wire(ldns_buffer * buffer,const ldns_rdf * name)20 ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
21 {
22           return ldns_dname2buffer_wire_compress(buffer, name, NULL);
23 }
24 
25 ldns_status
ldns_dname2buffer_wire_compress(ldns_buffer * buffer,const ldns_rdf * name,ldns_rbtree_t * compression_data)26 ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data)
27 {
28           ldns_rbnode_t *node;
29           uint8_t *data;
30           size_t size;
31           ldns_rdf *label;
32           ldns_rdf *rest;
33           ldns_status s;
34 
35           /* If no tree, just add the data */
36           if(!compression_data)
37           {
38                     if (ldns_buffer_reserve(buffer, ldns_rdf_size(name)))
39                     {
40                               ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
41                     }
42                     return ldns_buffer_status(buffer);
43           }
44 
45           /* No labels left, write final zero */
46           if(ldns_dname_label_count(name)==0)
47           {
48                     if(ldns_buffer_reserve(buffer,1))
49                     {
50                               ldns_buffer_write_u8(buffer, 0);
51                     }
52                     return ldns_buffer_status(buffer);
53           }
54 
55           /* Can we find the name in the tree? */
56           if((node = ldns_rbtree_search(compression_data, name)) != NULL)
57           {
58                     /* Found */
59                     uint16_t position = (uint16_t) (intptr_t) node->data | 0xC000;
60                     if (ldns_buffer_reserve(buffer, 2))
61                     {
62                               ldns_buffer_write_u16(buffer, position);
63                     }
64                     return ldns_buffer_status(buffer);
65           }
66           else
67           {
68                     /* Not found. Write cache entry, take off first label, write it, */
69                     /* try again with the rest of the name. */
70                     if (ldns_buffer_position(buffer) < 16384) {
71                               ldns_rdf *key;
72 
73                               node = LDNS_MALLOC(ldns_rbnode_t);
74                               if(!node)
75                               {
76                                         return LDNS_STATUS_MEM_ERR;
77                               }
78 
79                               key = ldns_rdf_clone(name);
80                               if (!key) {
81                                         LDNS_FREE(node);
82                                         return LDNS_STATUS_MEM_ERR;
83                               }
84                               node->key = key;
85                               node->data = (void *) (intptr_t) ldns_buffer_position(buffer);
86                               if(!ldns_rbtree_insert(compression_data,node))
87                               {
88                                         /* fprintf(stderr,"Name not found but now it's there?\n"); */
89                                         ldns_rdf_deep_free(key);
90                                         LDNS_FREE(node);
91                               }
92                     }
93                     label = ldns_dname_label(name, 0);
94                     rest = ldns_dname_left_chop(name);
95                     size = ldns_rdf_size(label) - 1; /* Don't want the final zero */
96                     data = ldns_rdf_data(label);
97                     if(ldns_buffer_reserve(buffer, size))
98                     {
99                               ldns_buffer_write(buffer, data, size);
100                     }
101                     ldns_rdf_deep_free(label);
102                     s = ldns_dname2buffer_wire_compress(buffer, rest, compression_data);
103                     ldns_rdf_deep_free(rest);
104                     return s;
105           }
106 }
107 
108 ldns_status
ldns_rdf2buffer_wire(ldns_buffer * buffer,const ldns_rdf * rdf)109 ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
110 {
111           return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
112 }
113 
114 ldns_status
ldns_rdf2buffer_wire_compress(ldns_buffer * buffer,const ldns_rdf * rdf,ldns_rbtree_t * compression_data)115 ldns_rdf2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *rdf, ldns_rbtree_t *compression_data)
116 {
117           /* If it's a DNAME, call that function to get compression */
118           if(compression_data && ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME)
119           {
120                     return ldns_dname2buffer_wire_compress(buffer,rdf,compression_data);
121           }
122 
123           if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
124                     ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
125           }
126           return ldns_buffer_status(buffer);
127 }
128 
129 ldns_status
ldns_rdf2buffer_wire_canonical(ldns_buffer * buffer,const ldns_rdf * rdf)130 ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
131 {
132           size_t i;
133           uint8_t *rdf_data;
134 
135           if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
136                     if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
137                               rdf_data = ldns_rdf_data(rdf);
138                               for (i = 0; i < ldns_rdf_size(rdf); i++) {
139                                         ldns_buffer_write_u8(buffer,
140                                             (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i]));
141                               }
142                     }
143           } else {
144                     /* direct copy for all other types */
145                     if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
146                               ldns_buffer_write(buffer,
147                                                                ldns_rdf_data(rdf),
148                                                                ldns_rdf_size(rdf));
149                     }
150           }
151           return ldns_buffer_status(buffer);
152 }
153 
154 /* convert a rr list to wireformat */
155 ldns_status
ldns_rr_list2buffer_wire(ldns_buffer * buffer,const ldns_rr_list * rr_list)156 ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
157 {
158           uint16_t rr_count;
159           uint16_t i;
160 
161           rr_count = ldns_rr_list_rr_count(rr_list);
162           for(i = 0; i < rr_count; i++) {
163                     (void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i),
164                                                     LDNS_SECTION_ANY);
165           }
166           return ldns_buffer_status(buffer);
167 }
168 
169 
170 ldns_status
ldns_rr2buffer_wire_canonical(ldns_buffer * buffer,const ldns_rr * rr,int section)171 ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
172                                                             const ldns_rr *rr,
173                                                             int section)
174 {
175           uint16_t i;
176           uint16_t rdl_pos = 0;
177           bool pre_rfc3597 = false;
178           switch (ldns_rr_get_type(rr)) {
179           case LDNS_RR_TYPE_NS:
180           case LDNS_RR_TYPE_MD:
181           case LDNS_RR_TYPE_MF:
182           case LDNS_RR_TYPE_CNAME:
183           case LDNS_RR_TYPE_SOA:
184           case LDNS_RR_TYPE_MB:
185           case LDNS_RR_TYPE_MG:
186           case LDNS_RR_TYPE_MR:
187           case LDNS_RR_TYPE_PTR:
188           case LDNS_RR_TYPE_HINFO:
189           case LDNS_RR_TYPE_MINFO:
190           case LDNS_RR_TYPE_MX:
191           case LDNS_RR_TYPE_RP:
192           case LDNS_RR_TYPE_AFSDB:
193           case LDNS_RR_TYPE_RT:
194           case LDNS_RR_TYPE_SIG:
195           case LDNS_RR_TYPE_PX:
196           case LDNS_RR_TYPE_NXT:
197           case LDNS_RR_TYPE_NAPTR:
198           case LDNS_RR_TYPE_KX:
199           case LDNS_RR_TYPE_SRV:
200           case LDNS_RR_TYPE_DNAME:
201           case LDNS_RR_TYPE_A6:
202           case LDNS_RR_TYPE_RRSIG:
203                     pre_rfc3597 = true;
204                     break;
205           default:
206                     break;
207           }
208 
209           if (ldns_rr_owner(rr)) {
210                     (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
211           }
212 
213           if (ldns_buffer_reserve(buffer, 4)) {
214                     (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
215                     (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
216           }
217 
218           if (section != LDNS_SECTION_QUESTION) {
219                     if (ldns_buffer_reserve(buffer, 6)) {
220                               ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
221                               /* remember pos for later */
222                               rdl_pos = ldns_buffer_position(buffer);
223                               ldns_buffer_write_u16(buffer, 0);
224                     }
225                     for (i = 0; i < ldns_rr_rd_count(rr); i++) {
226                               if (pre_rfc3597) {
227                                         (void) ldns_rdf2buffer_wire_canonical(
228                                                   buffer, ldns_rr_rdf(rr, i));
229                               } else {
230                                         (void) ldns_rdf2buffer_wire(
231                                                   buffer, ldns_rr_rdf(rr, i));
232                               }
233                     }
234                     if (rdl_pos != 0) {
235                               ldns_buffer_write_u16_at(buffer, rdl_pos,
236                                                        ldns_buffer_position(buffer)
237                                                  - rdl_pos - 2);
238                     }
239           }
240           return ldns_buffer_status(buffer);
241 }
242 
243 ldns_status
ldns_rr2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr,int section)244 ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
245 {
246           return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
247 }
248 
249 ldns_status
ldns_rr2buffer_wire_compress(ldns_buffer * buffer,const ldns_rr * rr,int section,ldns_rbtree_t * compression_data)250 ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data)
251 {
252           uint16_t i;
253           uint16_t rdl_pos = 0;
254 
255           if (ldns_rr_owner(rr)) {
256                     (void) ldns_dname2buffer_wire_compress(buffer, ldns_rr_owner(rr), compression_data);
257           }
258 
259           if (ldns_buffer_reserve(buffer, 4)) {
260                     (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
261                     (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
262           }
263 
264           if (section != LDNS_SECTION_QUESTION) {
265                     if (ldns_buffer_reserve(buffer, 6)) {
266                               ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
267                               /* remember pos for later */
268                               rdl_pos = ldns_buffer_position(buffer);
269                               ldns_buffer_write_u16(buffer, 0);
270                     }
271                     if (LDNS_RR_COMPRESS ==
272                         ldns_rr_descript(ldns_rr_get_type(rr))->_compress) {
273 
274                               for (i = 0; i < ldns_rr_rd_count(rr); i++) {
275                                         (void) ldns_rdf2buffer_wire_compress(buffer,
276                                             ldns_rr_rdf(rr, i), compression_data);
277                               }
278                     } else {
279                               for (i = 0; i < ldns_rr_rd_count(rr); i++) {
280                                         (void) ldns_rdf2buffer_wire(
281                                             buffer, ldns_rr_rdf(rr, i));
282                               }
283                     }
284                     if (rdl_pos != 0) {
285                               ldns_buffer_write_u16_at(buffer, rdl_pos,
286                                                        ldns_buffer_position(buffer)
287                                                  - rdl_pos - 2);
288                     }
289           }
290           return ldns_buffer_status(buffer);
291 }
292 
293 ldns_status
ldns_rrsig2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr)294 ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
295 {
296           uint16_t i;
297 
298           /* it must be a sig RR */
299           if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
300                     return LDNS_STATUS_ERR;
301           }
302 
303           /* Convert all the rdfs, except the actual signature data
304            * rdf number 8  - the last, hence: -1 */
305           for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) {
306                     (void) ldns_rdf2buffer_wire_canonical(buffer,
307                                         ldns_rr_rdf(rr, i));
308           }
309 
310           return ldns_buffer_status(buffer);
311 }
312 
313 ldns_status
ldns_rr_rdata2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr)314 ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
315 {
316           uint16_t i;
317 
318           /* convert all the rdf's */
319           for (i = 0; i < ldns_rr_rd_count(rr); i++) {
320                     (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i));
321           }
322           return ldns_buffer_status(buffer);
323 }
324 
325 /*
326  * Copies the packet header data to the buffer in wire format
327  */
328 static ldns_status
ldns_hdr2buffer_wire(ldns_buffer * buffer,const ldns_pkt * packet)329 ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
330 {
331           uint8_t flags;
332           uint16_t arcount;
333 
334           if (ldns_buffer_reserve(buffer, 12)) {
335                     ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
336 
337                     flags = ldns_pkt_qr(packet) << 7
338                             | ldns_pkt_get_opcode(packet) << 3
339                             | ldns_pkt_aa(packet) << 2
340                             | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
341                     ldns_buffer_write_u8(buffer, flags);
342 
343                     flags = ldns_pkt_ra(packet) << 7
344                             /*| ldns_pkt_z(packet) << 6*/
345                             | ldns_pkt_ad(packet) << 5
346                             | ldns_pkt_cd(packet) << 4
347                               | ldns_pkt_get_rcode(packet);
348                     ldns_buffer_write_u8(buffer, flags);
349 
350                     ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
351                     ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
352                     ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
353                     /* add EDNS0 and TSIG to additional if they are there */
354                     arcount = ldns_pkt_arcount(packet);
355                     if (ldns_pkt_tsig(packet)) {
356                               arcount++;
357                     }
358                     if (ldns_pkt_edns(packet)) {
359                               arcount++;
360                     }
361                     ldns_buffer_write_u16(buffer, arcount);
362           }
363 
364           return ldns_buffer_status(buffer);
365 }
366 
367 static void
compression_node_free(ldns_rbnode_t * node,void * arg)368 compression_node_free(ldns_rbnode_t *node, void *arg)
369 {
370           (void)arg; /* Yes, dear compiler, it is used */
371           ldns_rdf_deep_free((ldns_rdf *)node->key);
372           LDNS_FREE(node);
373 }
374 
375 ldns_status
ldns_pkt2buffer_wire(ldns_buffer * buffer,const ldns_pkt * packet)376 ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
377 {
378           ldns_status status;
379           ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare);
380 
381           status = ldns_pkt2buffer_wire_compress(buffer, packet, compression_data);
382 
383           ldns_traverse_postorder(compression_data,compression_node_free,NULL);
384           ldns_rbtree_free(compression_data);
385 
386           return status;
387 }
388 
389 ldns_status
ldns_pkt2buffer_wire_compress(ldns_buffer * buffer,const ldns_pkt * packet,ldns_rbtree_t * compression_data)390 ldns_pkt2buffer_wire_compress(ldns_buffer *buffer, const ldns_pkt *packet, ldns_rbtree_t *compression_data)
391 {
392           ldns_rr_list *rr_list;
393           uint16_t i;
394 
395           /* edns tmp vars */
396           ldns_rr *edns_rr;
397           uint8_t edata[4];
398 
399           ldns_buffer *edns_buf = NULL;
400           ldns_rdf    *edns_rdf = NULL;
401 
402           (void) ldns_hdr2buffer_wire(buffer, packet);
403 
404           rr_list = ldns_pkt_question(packet);
405           if (rr_list) {
406                     for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
407                               (void) ldns_rr2buffer_wire_compress(buffer,
408                                            ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION, compression_data);
409                     }
410           }
411           rr_list = ldns_pkt_answer(packet);
412           if (rr_list) {
413                     for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
414                               (void) ldns_rr2buffer_wire_compress(buffer,
415                                            ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER, compression_data);
416                     }
417           }
418           rr_list = ldns_pkt_authority(packet);
419           if (rr_list) {
420                     for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
421                               (void) ldns_rr2buffer_wire_compress(buffer,
422                                            ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY, compression_data);
423                     }
424           }
425           rr_list = ldns_pkt_additional(packet);
426           if (rr_list) {
427                     for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
428                               (void) ldns_rr2buffer_wire_compress(buffer,
429                                            ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL, compression_data);
430                     }
431           }
432 
433           /* add EDNS to additional if it is needed */
434           if (ldns_pkt_edns(packet)) {
435                     edns_rr = ldns_rr_new();
436                     if(!edns_rr) return LDNS_STATUS_MEM_ERR;
437                     ldns_rr_set_owner(edns_rr,
438                                         ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
439                     ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
440                     ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
441                     edata[0] = ldns_pkt_edns_extended_rcode(packet);
442                     edata[1] = ldns_pkt_edns_version(packet);
443                     ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
444                     ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
445                     /* don't forget to add the edns rdata (if any) */
446                     if ((edns_buf = ldns_edns_option_list2wireformat_buffer(packet->_edns_list))) {
447                               edns_rdf = ldns_rdf_new( LDNS_RDF_TYPE_UNKNOWN
448                                                      , ldns_buffer_limit(edns_buf)
449                                                      , ldns_buffer_export(edns_buf));
450                               ldns_buffer_free(edns_buf);
451                     }
452                     if (edns_rdf)
453                               ldns_rr_push_rdf(edns_rr, edns_rdf);
454                     else if (packet->_edns_data)
455                               ldns_rr_push_rdf(edns_rr, packet->_edns_data);
456                     (void)ldns_rr2buffer_wire_compress(buffer, edns_rr, LDNS_SECTION_ADDITIONAL, compression_data);
457                     /* if the rdata of the OPT came from packet->_edns_data
458                      * we need to take it back out of the edns_rr before we free it
459                      * so packet->_edns_data doesn't get freed
460                      */
461                     if (!edns_rdf && packet->_edns_data)
462                               (void)ldns_rr_pop_rdf (edns_rr);
463                     ldns_rr_free(edns_rr);
464           }
465 
466           /* add TSIG to additional if it is there */
467           if (ldns_pkt_tsig(packet)) {
468                     (void) ldns_rr2buffer_wire_compress(buffer,
469                                                ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL, compression_data);
470           }
471 
472           return LDNS_STATUS_OK;
473 }
474 
475 ldns_status
ldns_rdf2wire(uint8_t ** dest,const ldns_rdf * rdf,size_t * result_size)476 ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
477 {
478           ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
479           ldns_status status;
480           *result_size = 0;
481           *dest = NULL;
482           if(!buffer) return LDNS_STATUS_MEM_ERR;
483 
484           status = ldns_rdf2buffer_wire(buffer, rdf);
485           if (status == LDNS_STATUS_OK) {
486                     *result_size =  ldns_buffer_position(buffer);
487                     *dest = (uint8_t *) ldns_buffer_export(buffer);
488           }
489           ldns_buffer_free(buffer);
490           return status;
491 }
492 
493 ldns_status
ldns_rr2wire(uint8_t ** dest,const ldns_rr * rr,int section,size_t * result_size)494 ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
495 {
496           ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
497           ldns_status status;
498           *result_size = 0;
499           *dest = NULL;
500           if(!buffer) return LDNS_STATUS_MEM_ERR;
501 
502           status = ldns_rr2buffer_wire(buffer, rr, section);
503           if (status == LDNS_STATUS_OK) {
504                     *result_size =  ldns_buffer_position(buffer);
505                     *dest = (uint8_t *) ldns_buffer_export(buffer);
506           }
507           ldns_buffer_free(buffer);
508           return status;
509 }
510 
511 ldns_status
ldns_pkt2wire(uint8_t ** dest,const ldns_pkt * packet,size_t * result_size)512 ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
513 {
514           ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
515           ldns_status status;
516           *result_size = 0;
517           *dest = NULL;
518           if(!buffer) return LDNS_STATUS_MEM_ERR;
519 
520           status = ldns_pkt2buffer_wire(buffer, packet);
521           if (status == LDNS_STATUS_OK) {
522                     *result_size =  ldns_buffer_position(buffer);
523                     *dest = (uint8_t *) ldns_buffer_export(buffer);
524           }
525           ldns_buffer_free(buffer);
526           return status;
527 }
528