Coverage Report

Created: 2026-09-01 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/avahi/avahi-core/rr.c
Line
Count
Source
1
/***
2
  This file is part of avahi.
3
4
  avahi is free software; you can redistribute it and/or modify it
5
  under the terms of the GNU Lesser General Public License as
6
  published by the Free Software Foundation; either version 2.1 of the
7
  License, or (at your option) any later version.
8
9
  avahi is distributed in the hope that it will be useful, but WITHOUT
10
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12
  Public License for more details.
13
14
  You should have received a copy of the GNU Lesser General Public
15
  License along with avahi; if not, write to the Free Software
16
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17
  USA.
18
***/
19
20
#ifdef HAVE_CONFIG_H
21
#include <config.h>
22
#endif
23
24
#include <string.h>
25
#include <stdio.h>
26
#include <sys/types.h>
27
#include <sys/socket.h>
28
#include <arpa/inet.h>
29
#include <assert.h>
30
31
#include <avahi-common/domain.h>
32
#include <avahi-common/malloc.h>
33
#include <avahi-common/defs.h>
34
35
#include "dns.h"
36
#include "rr.h"
37
#include "log.h"
38
#include "util.h"
39
#include "hashmap.h"
40
#include "domain-util.h"
41
#include "rr-util.h"
42
#include "addr-util.h"
43
44
7.61k
AvahiKey *avahi_key_new(const char *name, uint16_t class, uint16_t type) {
45
7.61k
    AvahiKey *k;
46
7.61k
    assert(name);
47
48
7.61k
    if (!(k = avahi_new(AvahiKey, 1))) {
49
0
        avahi_log_error("avahi_new() failed.");
50
0
        return NULL;
51
0
    }
52
53
7.61k
    if (!(k->name = avahi_normalize_name_strdup(name))) {
54
121
        avahi_log_error("avahi_normalize_name() failed.");
55
121
        avahi_free(k);
56
121
        return NULL;
57
121
    }
58
59
7.49k
    k->ref = 1;
60
7.49k
    k->clazz = class;
61
7.49k
    k->type = type;
62
63
7.49k
    return k;
64
7.61k
}
65
66
634
AvahiKey *avahi_key_new_cname(AvahiKey *key) {
67
634
    assert(key);
68
69
634
    if (key->clazz != AVAHI_DNS_CLASS_IN)
70
577
        return NULL;
71
72
57
    if (key->type == AVAHI_DNS_TYPE_CNAME)
73
1
        return NULL;
74
75
56
    return avahi_key_new(key->name, key->clazz, AVAHI_DNS_TYPE_CNAME);
76
57
}
77
78
8.84k
AvahiKey *avahi_key_ref(AvahiKey *k) {
79
8.84k
    assert(k);
80
8.84k
    assert(k->ref >= 1);
81
82
8.84k
    k->ref++;
83
84
8.84k
    return k;
85
8.84k
}
86
87
16.3k
void avahi_key_unref(AvahiKey *k) {
88
16.3k
    assert(k);
89
16.3k
    assert(k->ref >= 1);
90
91
16.3k
    if ((--k->ref) <= 0) {
92
7.49k
        avahi_free(k->name);
93
7.49k
        avahi_free(k);
94
7.49k
    }
95
16.3k
}
96
97
6.50k
AvahiRecord *avahi_record_new(AvahiKey *k, uint32_t ttl) {
98
6.50k
    AvahiRecord *r;
99
100
6.50k
    assert(k);
101
102
6.50k
    if (!(r = avahi_new(AvahiRecord, 1))) {
103
0
        avahi_log_error("avahi_new() failed.");
104
0
        return NULL;
105
0
    }
106
107
6.50k
    r->ref = 1;
108
6.50k
    r->key = avahi_key_ref(k);
109
110
6.50k
    memset(&r->data, 0, sizeof(r->data));
111
112
6.50k
    r->ttl = ttl != (uint32_t) -1 ? ttl : AVAHI_DEFAULT_TTL;
113
114
6.50k
    return r;
115
6.50k
}
116
117
6.52k
AvahiRecord *avahi_record_new_full(const char *name, uint16_t class, uint16_t type, uint32_t ttl) {
118
6.52k
    AvahiRecord *r;
119
6.52k
    AvahiKey *k;
120
121
6.52k
    assert(name);
122
123
6.52k
    if (!(k = avahi_key_new(name, class, type))) {
124
17
        avahi_log_error("avahi_key_new() failed.");
125
17
        return NULL;
126
17
    }
127
128
6.50k
    r = avahi_record_new(k, ttl);
129
6.50k
    avahi_key_unref(k);
130
131
6.50k
    if (!r) {
132
0
        avahi_log_error("avahi_record_new() failed.");
133
0
        return NULL;
134
0
    }
135
136
6.50k
    return r;
137
6.50k
}
138
139
0
AvahiRecord *avahi_record_ref(AvahiRecord *r) {
140
0
    assert(r);
141
0
    assert(r->ref >= 1);
142
143
0
    r->ref++;
144
0
    return r;
145
0
}
146
147
8.84k
void avahi_record_unref(AvahiRecord *r) {
148
8.84k
    assert(r);
149
8.84k
    assert(r->ref >= 1);
150
151
8.84k
    if ((--r->ref) <= 0) {
152
8.84k
        switch (r->key->type) {
153
154
652
            case AVAHI_DNS_TYPE_SRV:
155
652
                avahi_free(r->data.srv.name);
156
652
                break;
157
158
406
            case AVAHI_DNS_TYPE_PTR:
159
1.37k
            case AVAHI_DNS_TYPE_CNAME:
160
1.92k
            case AVAHI_DNS_TYPE_NS:
161
1.92k
                avahi_free(r->data.ptr.name);
162
1.92k
                break;
163
164
1.67k
            case AVAHI_DNS_TYPE_HINFO:
165
1.67k
                avahi_free(r->data.hinfo.cpu);
166
1.67k
                avahi_free(r->data.hinfo.os);
167
1.67k
                break;
168
169
1.43k
            case AVAHI_DNS_TYPE_TXT:
170
1.43k
                avahi_string_list_free(r->data.txt.string_list);
171
1.43k
                break;
172
173
210
            case AVAHI_DNS_TYPE_A:
174
332
            case AVAHI_DNS_TYPE_AAAA:
175
332
                break;
176
177
2.83k
            default:
178
2.83k
                avahi_free(r->data.generic.data);
179
8.84k
        }
180
181
8.84k
        avahi_key_unref(r->key);
182
8.84k
        avahi_free(r);
183
8.84k
    }
184
8.84k
}
185
186
2.97k
const char *avahi_dns_class_to_string(uint16_t class) {
187
2.97k
    if (class & AVAHI_DNS_CACHE_FLUSH)
188
0
        return "FLUSH";
189
190
2.97k
    switch (class) {
191
131
        case AVAHI_DNS_CLASS_IN:
192
131
            return "IN";
193
38
        case AVAHI_DNS_CLASS_ANY:
194
38
            return "ANY";
195
2.80k
        default:
196
2.80k
            return NULL;
197
2.97k
    }
198
2.97k
}
199
200
2.97k
const char *avahi_dns_type_to_string(uint16_t type) {
201
2.97k
    switch (type) {
202
283
        case AVAHI_DNS_TYPE_CNAME:
203
283
            return "CNAME";
204
76
        case AVAHI_DNS_TYPE_A:
205
76
            return "A";
206
35
        case AVAHI_DNS_TYPE_AAAA:
207
35
            return "AAAA";
208
104
        case AVAHI_DNS_TYPE_PTR:
209
104
            return "PTR";
210
421
        case AVAHI_DNS_TYPE_HINFO:
211
421
            return "HINFO";
212
423
        case AVAHI_DNS_TYPE_TXT:
213
423
            return "TXT";
214
170
        case AVAHI_DNS_TYPE_SRV:
215
170
            return "SRV";
216
33
        case AVAHI_DNS_TYPE_ANY:
217
33
            return "ANY";
218
4
        case AVAHI_DNS_TYPE_SOA:
219
4
            return "SOA";
220
169
        case AVAHI_DNS_TYPE_NS:
221
169
            return "NS";
222
1.25k
        default:
223
1.25k
            return NULL;
224
2.97k
    }
225
2.97k
}
226
227
2.97k
char *avahi_key_to_string(const AvahiKey *k) {
228
2.97k
    char class[16], type[16];
229
2.97k
    const char *c, *t;
230
231
2.97k
    assert(k);
232
2.97k
    assert(k->ref >= 1);
233
234
    /* According to RFC3597 */
235
236
2.97k
    if (!(c = avahi_dns_class_to_string(k->clazz))) {
237
2.80k
        snprintf(class, sizeof(class), "CLASS%u", k->clazz);
238
2.80k
        c = class;
239
2.80k
    }
240
241
2.97k
    if (!(t = avahi_dns_type_to_string(k->type))) {
242
1.25k
        snprintf(type, sizeof(type), "TYPE%u", k->type);
243
1.25k
        t = type;
244
1.25k
    }
245
246
2.97k
    return avahi_strdup_printf("%s\t%s\t%s", k->name, c, t);
247
2.97k
}
248
249
2.34k
char *avahi_record_to_string(const AvahiRecord *r) {
250
2.34k
    char *p, *s;
251
2.34k
    char buf[1024], *t = NULL, *d = NULL;
252
253
2.34k
    assert(r);
254
2.34k
    assert(r->ref >= 1);
255
256
2.34k
    switch (r->key->type) {
257
62
        case AVAHI_DNS_TYPE_A:
258
62
            inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
259
62
            break;
260
261
32
        case AVAHI_DNS_TYPE_AAAA:
262
32
            inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
263
32
            break;
264
265
103
        case AVAHI_DNS_TYPE_PTR:
266
383
        case AVAHI_DNS_TYPE_CNAME:
267
547
        case AVAHI_DNS_TYPE_NS:
268
269
547
            t = r->data.ptr.name;
270
547
            break;
271
272
414
        case AVAHI_DNS_TYPE_TXT:
273
414
            t = d = avahi_string_list_to_string(r->data.txt.string_list);
274
414
            break;
275
276
417
        case AVAHI_DNS_TYPE_HINFO:
277
278
417
            snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os);
279
417
            break;
280
281
167
        case AVAHI_DNS_TYPE_SRV:
282
283
167
            snprintf(t = buf, sizeof(buf), "%u %u %u %s",
284
167
                     r->data.srv.priority,
285
167
                     r->data.srv.weight,
286
167
                     r->data.srv.port,
287
167
                     r->data.srv.name);
288
289
167
            break;
290
291
702
        default: {
292
293
702
            uint8_t *c;
294
702
            uint16_t n;
295
702
            int i;
296
702
            char *e;
297
298
            /* According to RFC3597 */
299
300
702
            snprintf(t = buf, sizeof(buf), "\\# %u", r->data.generic.size);
301
302
702
            e = strchr(t, 0);
303
304
702
            for (c = r->data.generic.data, n = r->data.generic.size, i = 0;
305
5.86k
                 n > 0 && i < 20;
306
5.16k
                 c ++, n --, i++) {
307
308
5.16k
                sprintf(e, " %02X", *c);
309
5.16k
                e = strchr(e, 0);
310
5.16k
            }
311
312
702
            break;
313
383
        }
314
2.34k
    }
315
316
2.34k
    p = avahi_key_to_string(r->key);
317
2.34k
    s = avahi_strdup_printf("%s %s ; ttl=%u", p, t, r->ttl);
318
2.34k
    avahi_free(p);
319
2.34k
    avahi_free(d);
320
321
2.34k
    return s;
322
2.34k
}
323
324
6.19k
int avahi_key_equal(const AvahiKey *a, const AvahiKey *b) {
325
6.19k
    assert(a);
326
6.19k
    assert(b);
327
328
6.19k
    if (a == b)
329
2.34k
        return 1;
330
331
3.85k
    return avahi_domain_equal(a->name, b->name) &&
332
3.28k
        a->type == b->type &&
333
3.17k
        a->clazz == b->clazz;
334
6.19k
}
335
336
296
int avahi_key_pattern_match(const AvahiKey *pattern, const AvahiKey *k) {
337
296
    assert(pattern);
338
296
    assert(k);
339
340
296
    assert(!avahi_key_is_pattern(k));
341
342
296
    if (pattern == k)
343
0
        return 1;
344
345
296
    return avahi_domain_equal(pattern->name, k->name) &&
346
117
        (pattern->type == k->type || pattern->type == AVAHI_DNS_TYPE_ANY) &&
347
48
        (pattern->clazz == k->clazz || pattern->clazz == AVAHI_DNS_CLASS_ANY);
348
296
}
349
350
594
int avahi_key_is_pattern(const AvahiKey *k) {
351
594
    assert(k);
352
353
594
    return
354
594
        k->type == AVAHI_DNS_TYPE_ANY ||
355
593
        k->clazz == AVAHI_DNS_CLASS_ANY;
356
594
}
357
358
634
unsigned avahi_key_hash(const AvahiKey *k) {
359
634
    assert(k);
360
361
634
    return
362
634
        avahi_domain_hash(k->name) +
363
634
        k->type +
364
634
        k->clazz;
365
634
}
366
367
5.48k
static int rdata_equal(const AvahiRecord *a, const AvahiRecord *b) {
368
5.48k
    assert(a);
369
5.48k
    assert(b);
370
5.48k
    assert(a->key->type == b->key->type);
371
372
5.48k
    switch (a->key->type) {
373
415
        case AVAHI_DNS_TYPE_SRV:
374
415
            return
375
415
                a->data.srv.priority == b->data.srv.priority &&
376
391
                a->data.srv.weight == b->data.srv.weight &&
377
363
                a->data.srv.port == b->data.srv.port &&
378
336
                avahi_domain_equal(a->data.srv.name, b->data.srv.name);
379
380
237
        case AVAHI_DNS_TYPE_PTR:
381
810
        case AVAHI_DNS_TYPE_CNAME:
382
1.14k
        case AVAHI_DNS_TYPE_NS:
383
1.14k
            return avahi_domain_equal(a->data.ptr.name, b->data.ptr.name);
384
385
1.13k
        case AVAHI_DNS_TYPE_HINFO:
386
1.13k
            return
387
1.13k
                !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) &&
388
981
                !strcmp(a->data.hinfo.os, b->data.hinfo.os);
389
390
976
        case AVAHI_DNS_TYPE_TXT:
391
976
            return avahi_string_list_equal(a->data.txt.string_list, b->data.txt.string_list);
392
393
133
        case AVAHI_DNS_TYPE_A:
394
133
            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address)) == 0;
395
396
74
        case AVAHI_DNS_TYPE_AAAA:
397
74
            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address)) == 0;
398
399
1.60k
        default:
400
1.60k
            return a->data.generic.size == b->data.generic.size &&
401
1.52k
                (a->data.generic.size == 0 || memcmp(a->data.generic.data, b->data.generic.data, a->data.generic.size) == 0);
402
5.48k
    }
403
404
5.48k
}
405
406
6.19k
int avahi_record_equal_no_ttl(const AvahiRecord *a, const AvahiRecord *b) {
407
6.19k
    assert(a);
408
6.19k
    assert(b);
409
410
6.19k
    if (a == b)
411
0
        return 1;
412
413
6.19k
    return
414
6.19k
        avahi_key_equal(a->key, b->key) &&
415
5.48k
        rdata_equal(a, b);
416
6.19k
}
417
418
419
2.34k
AvahiRecord *avahi_record_copy(AvahiRecord *r) {
420
2.34k
    AvahiRecord *copy;
421
422
2.34k
    if (!(copy = avahi_new(AvahiRecord, 1))) {
423
0
        avahi_log_error("avahi_new() failed.");
424
0
        return NULL;
425
0
    }
426
427
2.34k
    copy->ref = 1;
428
2.34k
    copy->key = avahi_key_ref(r->key);
429
2.34k
    copy->ttl = r->ttl;
430
2.34k
    memset(&copy->data, 0, sizeof(copy->data));
431
432
2.34k
    switch (r->key->type) {
433
103
        case AVAHI_DNS_TYPE_PTR:
434
383
        case AVAHI_DNS_TYPE_CNAME:
435
547
        case AVAHI_DNS_TYPE_NS:
436
547
            if (!(copy->data.ptr.name = avahi_strdup(r->data.ptr.name)))
437
0
                goto fail;
438
547
            break;
439
440
547
        case AVAHI_DNS_TYPE_SRV:
441
167
            copy->data.srv.priority = r->data.srv.priority;
442
167
            copy->data.srv.weight = r->data.srv.weight;
443
167
            copy->data.srv.port = r->data.srv.port;
444
167
            if (!(copy->data.srv.name = avahi_strdup(r->data.srv.name)))
445
0
                goto fail;
446
167
            break;
447
448
417
        case AVAHI_DNS_TYPE_HINFO:
449
417
            if (!(copy->data.hinfo.os = avahi_strdup(r->data.hinfo.os)))
450
0
                goto fail;
451
452
417
            if (!(copy->data.hinfo.cpu = avahi_strdup(r->data.hinfo.cpu))) {
453
0
                avahi_free(copy->data.hinfo.os);
454
0
                goto fail;
455
0
            }
456
417
            break;
457
458
417
        case AVAHI_DNS_TYPE_TXT:
459
414
            if (r->data.txt.string_list && !(copy->data.txt.string_list = avahi_string_list_copy(r->data.txt.string_list)))
460
0
                goto fail;
461
414
            break;
462
463
414
        case AVAHI_DNS_TYPE_A:
464
62
            copy->data.a.address = r->data.a.address;
465
62
            break;
466
467
32
        case AVAHI_DNS_TYPE_AAAA:
468
32
            copy->data.aaaa.address = r->data.aaaa.address;
469
32
            break;
470
471
702
        default:
472
702
            if (r->data.generic.size && !(copy->data.generic.data = avahi_memdup(r->data.generic.data, r->data.generic.size)))
473
0
                goto fail;
474
702
            copy->data.generic.size = r->data.generic.size;
475
702
            break;
476
477
2.34k
    }
478
479
2.34k
    return copy;
480
481
0
fail:
482
0
    avahi_log_error("Failed to allocate memory");
483
484
0
    avahi_key_unref(copy->key);
485
0
    avahi_free(copy);
486
487
0
    return NULL;
488
2.34k
}
489
490
491
2.34k
size_t avahi_key_get_estimate_size(AvahiKey *k) {
492
2.34k
    assert(k);
493
494
2.34k
    return strlen(k->name)+1+4;
495
2.34k
}
496
497
2.34k
size_t avahi_record_get_estimate_size(AvahiRecord *r) {
498
2.34k
    size_t n;
499
2.34k
    assert(r);
500
501
2.34k
    n = avahi_key_get_estimate_size(r->key) + 4 + 2;
502
503
2.34k
    switch (r->key->type) {
504
103
        case AVAHI_DNS_TYPE_PTR:
505
383
        case AVAHI_DNS_TYPE_CNAME:
506
547
        case AVAHI_DNS_TYPE_NS:
507
547
            n += strlen(r->data.ptr.name) + 1;
508
547
            break;
509
510
167
        case AVAHI_DNS_TYPE_SRV:
511
167
            n += 6 + strlen(r->data.srv.name) + 1;
512
167
            break;
513
514
417
        case AVAHI_DNS_TYPE_HINFO:
515
417
            n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1;
516
417
            break;
517
518
414
        case AVAHI_DNS_TYPE_TXT:
519
414
            n += avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
520
414
            break;
521
522
62
        case AVAHI_DNS_TYPE_A:
523
62
            n += sizeof(AvahiIPv4Address);
524
62
            break;
525
526
32
        case AVAHI_DNS_TYPE_AAAA:
527
32
            n += sizeof(AvahiIPv6Address);
528
32
            break;
529
530
702
        default:
531
702
            n += r->data.generic.size;
532
2.34k
    }
533
534
2.34k
    return n;
535
2.34k
}
536
537
1.89k
static int lexicographical_memcmp(const void* a, size_t al, const void* b, size_t bl) {
538
1.89k
    size_t c;
539
1.89k
    int ret;
540
541
1.89k
    assert(a);
542
1.89k
    assert(b);
543
544
1.89k
    c = al < bl ? al : bl;
545
1.89k
    if ((ret = memcmp(a, b, c)))
546
267
        return ret;
547
548
1.62k
    if (al == bl)
549
1.58k
        return 0;
550
38
    else
551
38
        return al == c ? -1 : 1;
552
1.62k
}
553
554
13.0k
static int uint16_cmp(uint16_t a, uint16_t b) {
555
13.0k
    return a == b ? 0 : (a < b ? -1 : 1);
556
13.0k
}
557
558
6.19k
int avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b) {
559
6.19k
    int r;
560
/*      char *t1, *t2; */
561
562
6.19k
    assert(a);
563
6.19k
    assert(b);
564
565
/*     t1 = avahi_record_to_string(a); */
566
/*     t2 = avahi_record_to_string(b); */
567
/*     g_message("lexicocmp: %s %s", t1, t2); */
568
/*     avahi_free(t1); */
569
/*     avahi_free(t2); */
570
571
6.19k
    if (a == b)
572
0
        return 0;
573
574
6.19k
    if ((r = uint16_cmp(a->key->clazz, b->key->clazz)) ||
575
5.71k
        (r = uint16_cmp(a->key->type, b->key->type)))
576
535
        return r;
577
578
5.65k
    switch (a->key->type) {
579
580
257
        case AVAHI_DNS_TYPE_PTR:
581
926
        case AVAHI_DNS_TYPE_CNAME:
582
1.26k
        case AVAHI_DNS_TYPE_NS:
583
1.26k
            return avahi_binary_domain_cmp(a->data.ptr.name, b->data.ptr.name);
584
585
419
        case AVAHI_DNS_TYPE_SRV: {
586
419
            if ((r = uint16_cmp(a->data.srv.priority, b->data.srv.priority)) == 0 &&
587
395
                (r = uint16_cmp(a->data.srv.weight, b->data.srv.weight)) == 0 &&
588
367
                (r = uint16_cmp(a->data.srv.port, b->data.srv.port)) == 0)
589
339
                r = avahi_binary_domain_cmp(a->data.srv.name, b->data.srv.name);
590
591
419
            return r;
592
926
        }
593
594
1.16k
        case AVAHI_DNS_TYPE_HINFO: {
595
596
1.16k
            if ((r = strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu)) ||
597
981
                (r = strcmp(a->data.hinfo.os, b->data.hinfo.os)))
598
333
                return r;
599
600
835
            return 0;
601
602
1.16k
        }
603
604
976
        case AVAHI_DNS_TYPE_TXT: {
605
606
976
            uint8_t *ma = NULL, *mb = NULL;
607
976
            size_t asize, bsize;
608
609
976
            asize = avahi_string_list_serialize(a->data.txt.string_list, NULL, 0);
610
976
            bsize = avahi_string_list_serialize(b->data.txt.string_list, NULL, 0);
611
612
976
            if (asize > 0 && !(ma = avahi_new(uint8_t, asize)))
613
0
                goto fail;
614
615
976
            if (bsize > 0 && !(mb = avahi_new(uint8_t, bsize))) {
616
0
                avahi_free(ma);
617
0
                goto fail;
618
0
            }
619
620
976
            avahi_string_list_serialize(a->data.txt.string_list, ma, asize);
621
976
            avahi_string_list_serialize(b->data.txt.string_list, mb, bsize);
622
623
976
            if (asize && bsize)
624
976
                r = lexicographical_memcmp(ma, asize, mb, bsize);
625
0
            else if (asize && !bsize)
626
0
                r = 1;
627
0
            else if (!asize && bsize)
628
0
                r = -1;
629
0
            else
630
0
                r = 0;
631
632
976
            avahi_free(ma);
633
976
            avahi_free(mb);
634
635
976
            return r;
636
976
        }
637
638
134
        case AVAHI_DNS_TYPE_A:
639
134
            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address));
640
641
75
        case AVAHI_DNS_TYPE_AAAA:
642
75
            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address));
643
644
1.62k
        default: {
645
1.62k
            size_t asize, bsize;
646
647
1.62k
            asize = a->data.generic.size;
648
1.62k
            bsize = b->data.generic.size;
649
650
1.62k
            if (asize && bsize)
651
914
                r = lexicographical_memcmp(a->data.generic.data, asize, b->data.generic.data, bsize);
652
706
            else if (asize && !bsize)
653
29
                r = 1;
654
677
            else if (!asize && bsize)
655
10
                r = -1;
656
667
            else
657
667
                r = 0;
658
659
1.62k
            return r;
660
976
        }
661
5.65k
    }
662
663
664
0
fail:
665
0
    avahi_log_error(__FILE__": Out of memory");
666
0
    return -1; /* or whatever ... */
667
5.65k
}
668
669
2.34k
int avahi_record_is_goodbye(AvahiRecord *r) {
670
2.34k
    assert(r);
671
672
2.34k
    return r->ttl == 0;
673
2.34k
}
674
675
10.4k
int avahi_key_is_valid(AvahiKey *k) {
676
10.4k
    assert(k);
677
678
10.4k
    if (!avahi_is_valid_domain_name(k->name))
679
0
        return 0;
680
681
10.4k
    return 1;
682
10.4k
}
683
684
8.62k
int avahi_record_is_valid(AvahiRecord *r) {
685
8.62k
    assert(r);
686
687
8.62k
    if (!avahi_key_is_valid(r->key))
688
0
        return 0;
689
690
8.62k
    switch (r->key->type) {
691
692
400
        case AVAHI_DNS_TYPE_PTR:
693
1.36k
        case AVAHI_DNS_TYPE_CNAME:
694
1.90k
        case AVAHI_DNS_TYPE_NS:
695
1.90k
            return avahi_is_valid_domain_name(r->data.ptr.name);
696
697
590
        case AVAHI_DNS_TYPE_SRV:
698
590
            return avahi_is_valid_domain_name(r->data.srv.name);
699
700
1.59k
        case AVAHI_DNS_TYPE_HINFO:
701
1.59k
            return
702
1.59k
                strlen(r->data.hinfo.os) <= 255 &&
703
1.59k
                strlen(r->data.hinfo.cpu) <= 255;
704
705
1.39k
        case AVAHI_DNS_TYPE_TXT: {
706
707
1.39k
            AvahiStringList *strlst;
708
1.39k
            size_t used = 0;
709
710
182k
            for (strlst = r->data.txt.string_list; strlst; strlst = strlst->next) {
711
180k
                if (strlst->size > 255 || strlst->size <= 0)
712
0
                    return 0;
713
714
180k
                used += 1+strlst->size;
715
180k
                if (used > AVAHI_DNS_RDATA_MAX)
716
0
                    return 0;
717
180k
            }
718
719
1.39k
            return 1;
720
1.39k
        }
721
8.62k
    }
722
723
3.13k
    return 1;
724
8.62k
}
725
726
2.34k
static AvahiAddress *get_address(const AvahiRecord *r, AvahiAddress *a) {
727
2.34k
    assert(r);
728
729
2.34k
    switch (r->key->type) {
730
62
        case AVAHI_DNS_TYPE_A:
731
62
            a->proto = AVAHI_PROTO_INET;
732
62
            a->data.ipv4 = r->data.a.address;
733
62
            break;
734
735
32
        case AVAHI_DNS_TYPE_AAAA:
736
32
            a->proto = AVAHI_PROTO_INET6;
737
32
            a->data.ipv6 = r->data.aaaa.address;
738
32
            break;
739
740
2.24k
        default:
741
2.24k
            return NULL;
742
2.34k
    }
743
744
94
    return a;
745
2.34k
}
746
747
2.34k
int avahi_record_is_link_local_address(const AvahiRecord *r) {
748
2.34k
    AvahiAddress a;
749
750
2.34k
    assert(r);
751
752
2.34k
    if (!get_address(r, &a))
753
2.24k
        return 0;
754
755
94
    return avahi_address_is_link_local(&a);
756
2.34k
}