Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/ldns/dname.c
39478 views
1
/*
2
* dname.c
3
*
4
* dname specific rdata implementations
5
* A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
6
* It is not a /real/ type! All function must therefore check
7
* for LDNS_RDF_TYPE_DNAME.
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
#include <ldns/config.h>
17
18
#include <ldns/ldns.h>
19
20
#ifdef HAVE_NETINET_IN_H
21
#include <netinet/in.h>
22
#endif
23
#ifdef HAVE_SYS_SOCKET_H
24
#include <sys/socket.h>
25
#endif
26
#ifdef HAVE_NETDB_H
27
#include <netdb.h>
28
#endif
29
#ifdef HAVE_ARPA_INET_H
30
#include <arpa/inet.h>
31
#endif
32
33
/* Returns whether the last label in the name is a root label (a empty label).
34
* Note that it is not enough to just test the last character to be 0,
35
* because it may be part of the last label itself.
36
*/
37
static bool
38
ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
39
{
40
size_t src_pos;
41
size_t len = 0;
42
43
for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
44
len = ldns_rdf_data(dname)[src_pos];
45
}
46
assert(src_pos == ldns_rdf_size(dname));
47
48
return src_pos > 0 && len == 0;
49
}
50
51
ldns_rdf *
52
ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
53
{
54
ldns_rdf *new;
55
uint16_t new_size;
56
uint8_t *buf;
57
uint16_t left_size;
58
59
if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
60
ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
61
return NULL;
62
}
63
64
/* remove root label if it is present at the end of the left
65
* rd, by reducing the size with 1
66
*/
67
left_size = ldns_rdf_size(rd1);
68
if (ldns_dname_last_label_is_root_label(rd1)) {
69
left_size--;
70
}
71
72
/* we overwrite the nullbyte of rd1 */
73
new_size = left_size + ldns_rdf_size(rd2);
74
buf = LDNS_XMALLOC(uint8_t, new_size);
75
if (!buf) {
76
return NULL;
77
}
78
79
/* put the two dname's after each other */
80
memcpy(buf, ldns_rdf_data(rd1), left_size);
81
memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
82
83
new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
84
85
LDNS_FREE(buf);
86
return new;
87
}
88
89
ldns_status
90
ldns_dname_cat(ldns_rdf *rd1, const ldns_rdf *rd2)
91
{
92
uint16_t left_size;
93
uint16_t size;
94
uint8_t* newd;
95
96
if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
97
ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
98
return LDNS_STATUS_ERR;
99
}
100
101
/* remove root label if it is present at the end of the left
102
* rd, by reducing the size with 1
103
*/
104
left_size = ldns_rdf_size(rd1);
105
if (ldns_dname_last_label_is_root_label(rd1)) {
106
left_size--;
107
}
108
109
size = left_size + ldns_rdf_size(rd2);
110
newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
111
if(!newd) {
112
return LDNS_STATUS_MEM_ERR;
113
}
114
115
ldns_rdf_set_data(rd1, newd);
116
memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
117
ldns_rdf_size(rd2));
118
ldns_rdf_set_size(rd1, size);
119
120
return LDNS_STATUS_OK;
121
}
122
123
ldns_rdf*
124
ldns_dname_reverse(const ldns_rdf *dname)
125
{
126
size_t rd_size;
127
uint8_t* buf;
128
ldns_rdf* new;
129
size_t src_pos;
130
size_t len ;
131
132
assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME);
133
134
rd_size = ldns_rdf_size(dname);
135
buf = LDNS_XMALLOC(uint8_t, rd_size);
136
if (! buf) {
137
return NULL;
138
}
139
new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
140
if (! new) {
141
LDNS_FREE(buf);
142
return NULL;
143
}
144
145
/* If dname ends in a root label, the reverse should too.
146
*/
147
if (ldns_dname_last_label_is_root_label(dname)) {
148
buf[rd_size - 1] = 0;
149
rd_size -= 1;
150
}
151
for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) {
152
len = ldns_rdf_data(dname)[src_pos];
153
memcpy(&buf[rd_size - src_pos - len - 1],
154
&ldns_rdf_data(dname)[src_pos], len + 1);
155
}
156
return new;
157
}
158
159
ldns_rdf *
160
ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
161
{
162
uint8_t *data;
163
uint8_t label_size;
164
size_t data_size;
165
166
if (!d ||
167
ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
168
ldns_dname_label_count(d) < n) {
169
return NULL;
170
}
171
172
data = ldns_rdf_data(d);
173
data_size = ldns_rdf_size(d);
174
while (n > 0) {
175
label_size = data[0] + 1;
176
data += label_size;
177
if (data_size < label_size) {
178
/* this label is very broken */
179
return NULL;
180
}
181
data_size -= label_size;
182
n--;
183
}
184
185
return ldns_dname_new_frm_data(data_size, data);
186
}
187
188
ldns_rdf *
189
ldns_dname_left_chop(const ldns_rdf *d)
190
{
191
uint8_t label_pos;
192
ldns_rdf *chop;
193
194
if (!d) {
195
return NULL;
196
}
197
198
if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
199
return NULL;
200
}
201
if (ldns_dname_label_count(d) == 0) {
202
/* root label */
203
return NULL;
204
}
205
/* 05blaat02nl00 */
206
label_pos = ldns_rdf_data(d)[0];
207
208
chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
209
ldns_rdf_data(d) + label_pos + 1);
210
return chop;
211
}
212
213
uint8_t
214
ldns_dname_label_count(const ldns_rdf *r)
215
{
216
uint16_t src_pos;
217
uint16_t len;
218
uint8_t i;
219
size_t r_size;
220
221
if (!r) {
222
return 0;
223
}
224
225
i = 0;
226
src_pos = 0;
227
r_size = ldns_rdf_size(r);
228
229
if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
230
return 0;
231
} else {
232
len = ldns_rdf_data(r)[src_pos]; /* start of the label */
233
234
/* single root label */
235
if (1 == r_size) {
236
return 0;
237
} else {
238
while ((len > 0) && src_pos < r_size) {
239
src_pos++;
240
src_pos += len;
241
len = ldns_rdf_data(r)[src_pos];
242
i++;
243
}
244
}
245
}
246
return i;
247
}
248
249
ldns_rdf *
250
ldns_dname_new(uint16_t s, void *d)
251
{
252
ldns_rdf *rd;
253
254
if (!s || !d) {
255
return NULL;
256
}
257
rd = LDNS_MALLOC(ldns_rdf);
258
if (!rd) {
259
return NULL;
260
}
261
ldns_rdf_set_size(rd, s);
262
ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
263
ldns_rdf_set_data(rd, d);
264
return rd;
265
}
266
267
ldns_rdf *
268
ldns_dname_new_frm_str(const char *str)
269
{
270
return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
271
}
272
273
ldns_rdf *
274
ldns_dname_new_frm_data(uint16_t size, const void *data)
275
{
276
return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
277
}
278
279
void
280
ldns_dname2canonical(const ldns_rdf *rd)
281
{
282
uint8_t *rdd;
283
uint16_t i;
284
285
if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
286
return;
287
}
288
289
rdd = (uint8_t*)ldns_rdf_data(rd);
290
for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
291
*rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
292
}
293
}
294
295
bool
296
ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
297
{
298
uint8_t sub_lab;
299
uint8_t par_lab;
300
int8_t i, j;
301
ldns_rdf *tmp_sub = NULL;
302
ldns_rdf *tmp_par = NULL;
303
ldns_rdf *sub_clone;
304
ldns_rdf *parent_clone;
305
bool result = true;
306
307
if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
308
ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
309
ldns_rdf_compare(sub, parent) == 0) {
310
return false;
311
}
312
313
/* would be nicer if we do not have to clone... */
314
sub_clone = ldns_dname_clone_from(sub, 0);
315
parent_clone = ldns_dname_clone_from(parent, 0);
316
ldns_dname2canonical(sub_clone);
317
ldns_dname2canonical(parent_clone);
318
319
sub_lab = ldns_dname_label_count(sub_clone);
320
par_lab = ldns_dname_label_count(parent_clone);
321
322
/* if sub sits above parent, it cannot be a child/sub domain */
323
if (sub_lab < par_lab) {
324
result = false;
325
} else {
326
/* check all labels the from the parent labels, from right to left.
327
* When they /all/ match we have found a subdomain
328
*/
329
j = sub_lab - 1; /* we count from zero, thank you */
330
for (i = par_lab -1; i >= 0; i--) {
331
tmp_sub = ldns_dname_label(sub_clone, j);
332
tmp_par = ldns_dname_label(parent_clone, i);
333
if (!tmp_sub || !tmp_par) {
334
/* deep free does null check */
335
ldns_rdf_deep_free(tmp_sub);
336
ldns_rdf_deep_free(tmp_par);
337
result = false;
338
break;
339
}
340
341
if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
342
/* they are not equal */
343
ldns_rdf_deep_free(tmp_sub);
344
ldns_rdf_deep_free(tmp_par);
345
result = false;
346
break;
347
}
348
ldns_rdf_deep_free(tmp_sub);
349
ldns_rdf_deep_free(tmp_par);
350
j--;
351
}
352
}
353
ldns_rdf_deep_free(sub_clone);
354
ldns_rdf_deep_free(parent_clone);
355
return result;
356
}
357
358
int
359
ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
360
{
361
size_t lc1, lc2, lc1f, lc2f;
362
size_t i;
363
int result = 0;
364
uint8_t *lp1, *lp2;
365
366
/* see RFC4034 for this algorithm */
367
/* this algorithm assumes the names are normalized to case */
368
369
/* only when both are not NULL we can say anything about them */
370
if (!dname1 && !dname2) {
371
return 0;
372
}
373
if (!dname1 || !dname2) {
374
return -1;
375
}
376
/* asserts must happen later as we are looking in the
377
* dname, which could be NULL. But this case is handled
378
* above
379
*/
380
assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
381
assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
382
383
lc1 = ldns_dname_label_count(dname1);
384
lc2 = ldns_dname_label_count(dname2);
385
386
if (lc1 == 0 && lc2 == 0) {
387
return 0;
388
}
389
if (lc1 == 0) {
390
return -1;
391
}
392
if (lc2 == 0) {
393
return 1;
394
}
395
lc1--;
396
lc2--;
397
/* we start at the last label */
398
while (true) {
399
/* find the label first */
400
lc1f = lc1;
401
lp1 = ldns_rdf_data(dname1);
402
while (lc1f > 0) {
403
lp1 += *lp1 + 1;
404
lc1f--;
405
}
406
407
/* and find the other one */
408
lc2f = lc2;
409
lp2 = ldns_rdf_data(dname2);
410
while (lc2f > 0) {
411
lp2 += *lp2 + 1;
412
lc2f--;
413
}
414
415
/* now check the label character for character. */
416
for (i = 1; i < (size_t)(*lp1 + 1); i++) {
417
if (i > *lp2) {
418
/* apparently label 1 is larger */
419
result = 1;
420
goto done;
421
}
422
if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
423
LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
424
result = -1;
425
goto done;
426
} else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
427
LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
428
result = 1;
429
goto done;
430
}
431
}
432
if (*lp1 < *lp2) {
433
/* apparently label 2 is larger */
434
result = -1;
435
goto done;
436
}
437
if (lc1 == 0 && lc2 > 0) {
438
result = -1;
439
goto done;
440
} else if (lc1 > 0 && lc2 == 0) {
441
result = 1;
442
goto done;
443
} else if (lc1 == 0 && lc2 == 0) {
444
result = 0;
445
goto done;
446
}
447
lc1--;
448
lc2--;
449
}
450
451
done:
452
return result;
453
}
454
455
int
456
ldns_dname_is_wildcard(const ldns_rdf* dname)
457
{
458
return ( ldns_dname_label_count(dname) > 0 &&
459
ldns_rdf_data(dname)[0] == 1 &&
460
ldns_rdf_data(dname)[1] == '*');
461
}
462
463
int
464
ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
465
{
466
ldns_rdf *wc_chopped;
467
int result;
468
/* check whether it really is a wildcard */
469
if (ldns_dname_is_wildcard(wildcard)) {
470
/* ok, so the dname needs to be a subdomain of the wildcard
471
* without the *
472
*/
473
wc_chopped = ldns_dname_left_chop(wildcard);
474
result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
475
ldns_rdf_deep_free(wc_chopped);
476
} else {
477
result = (ldns_dname_compare(dname, wildcard) == 0);
478
}
479
return result;
480
}
481
482
/* nsec test: does prev <= middle < next
483
* -1 = yes
484
* 0 = error/can't tell
485
* 1 = no
486
*/
487
int
488
ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
489
const ldns_rdf *next)
490
{
491
int prev_check, next_check;
492
493
assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
494
assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
495
assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
496
497
prev_check = ldns_dname_compare(prev, middle);
498
next_check = ldns_dname_compare(middle, next);
499
/* <= next. This cannot be the case for nsec, because then we would
500
* have gotten the nsec of next...
501
*/
502
if (next_check == 0) {
503
return 0;
504
}
505
506
/* <= */
507
if ((prev_check == -1 || prev_check == 0) &&
508
/* < */
509
next_check == -1) {
510
return -1;
511
} else {
512
return 1;
513
}
514
}
515
516
517
bool
518
ldns_dname_str_absolute(const char *dname_str)
519
{
520
const char* s;
521
if(dname_str && strcmp(dname_str, ".") == 0)
522
return 1;
523
if(!dname_str || strlen(dname_str) < 2)
524
return 0;
525
if(dname_str[strlen(dname_str) - 1] != '.')
526
return 0;
527
if(dname_str[strlen(dname_str) - 2] != '\\')
528
return 1; /* ends in . and no \ before it */
529
/* so we have the case of ends in . and there is \ before it */
530
for(s=dname_str; *s; s++) {
531
if(*s == '\\') {
532
if(s[1] && s[2] && s[3] /* check length */
533
&& isdigit((unsigned char)s[1])
534
&& isdigit((unsigned char)s[2])
535
&& isdigit((unsigned char)s[3]))
536
s += 3;
537
else if(!s[1] || isdigit((unsigned char)s[1])) /* escape of nul,0-9 */
538
return 0; /* parse error */
539
else s++; /* another character escaped */
540
}
541
else if(!*(s+1) && *s == '.')
542
return 1; /* trailing dot, unescaped */
543
}
544
return 0;
545
}
546
547
bool
548
ldns_dname_absolute(const ldns_rdf *rdf)
549
{
550
char *str = ldns_rdf2str(rdf);
551
if (str) {
552
bool r = ldns_dname_str_absolute(str);
553
LDNS_FREE(str);
554
return r;
555
}
556
return false;
557
}
558
559
ldns_rdf *
560
ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
561
{
562
uint8_t labelcnt;
563
uint16_t src_pos;
564
uint16_t len;
565
ldns_rdf *tmpnew;
566
size_t s;
567
uint8_t *data;
568
569
if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
570
return NULL;
571
}
572
573
labelcnt = 0;
574
src_pos = 0;
575
s = ldns_rdf_size(rdf);
576
577
len = ldns_rdf_data(rdf)[src_pos]; /* label start */
578
while ((len > 0) && src_pos < s) {
579
if (labelcnt == labelpos) {
580
/* found our label */
581
data = LDNS_XMALLOC(uint8_t, len + 2);
582
if (!data) {
583
return NULL;
584
}
585
memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
586
data[len + 2 - 1] = 0;
587
588
tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
589
, len + 2, data);
590
if (!tmpnew) {
591
LDNS_FREE(data);
592
return NULL;
593
}
594
return tmpnew;
595
}
596
src_pos++;
597
src_pos += len;
598
len = ldns_rdf_data(rdf)[src_pos];
599
labelcnt++;
600
}
601
return NULL;
602
}
603
604