Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/ldns/host2wire.c
39478 views
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
529