Coverage Report

Created: 2025-12-10 06:32

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
121k
AvahiKey *avahi_key_new(const char *name, uint16_t class, uint16_t type) {
45
121k
    AvahiKey *k;
46
121k
    assert(name);
47
48
121k
    if (!(k = avahi_new(AvahiKey, 1))) {
49
0
        avahi_log_error("avahi_new() failed.");
50
0
        return NULL;
51
0
    }
52
53
121k
    if (!(k->name = avahi_normalize_name_strdup(name))) {
54
202
        avahi_log_error("avahi_normalize_name() failed.");
55
202
        avahi_free(k);
56
202
        return NULL;
57
202
    }
58
59
121k
    k->ref = 1;
60
121k
    k->clazz = class;
61
121k
    k->type = type;
62
63
121k
    return k;
64
121k
}
65
66
609
AvahiKey *avahi_key_new_cname(AvahiKey *key) {
67
609
    assert(key);
68
69
609
    if (key->clazz != AVAHI_DNS_CLASS_IN)
70
539
        return NULL;
71
72
70
    if (key->type == AVAHI_DNS_TYPE_CNAME)
73
2
        return NULL;
74
75
68
    return avahi_key_new(key->name, key->clazz, AVAHI_DNS_TYPE_CNAME);
76
70
}
77
78
36.6k
AvahiKey *avahi_key_ref(AvahiKey *k) {
79
36.6k
    assert(k);
80
36.6k
    assert(k->ref >= 1);
81
82
36.6k
    k->ref++;
83
84
36.6k
    return k;
85
36.6k
}
86
87
157k
void avahi_key_unref(AvahiKey *k) {
88
157k
    assert(k);
89
157k
    assert(k->ref >= 1);
90
91
157k
    if ((--k->ref) <= 0) {
92
121k
        avahi_free(k->name);
93
121k
        avahi_free(k);
94
121k
    }
95
157k
}
96
97
34.5k
AvahiRecord *avahi_record_new(AvahiKey *k, uint32_t ttl) {
98
34.5k
    AvahiRecord *r;
99
100
34.5k
    assert(k);
101
102
34.5k
    if (!(r = avahi_new(AvahiRecord, 1))) {
103
0
        avahi_log_error("avahi_new() failed.");
104
0
        return NULL;
105
0
    }
106
107
34.5k
    r->ref = 1;
108
34.5k
    r->key = avahi_key_ref(k);
109
110
34.5k
    memset(&r->data, 0, sizeof(r->data));
111
112
34.5k
    r->ttl = ttl != (uint32_t) -1 ? ttl : AVAHI_DEFAULT_TTL;
113
114
34.5k
    return r;
115
34.5k
}
116
117
34.6k
AvahiRecord *avahi_record_new_full(const char *name, uint16_t class, uint16_t type, uint32_t ttl) {
118
34.6k
    AvahiRecord *r;
119
34.6k
    AvahiKey *k;
120
121
34.6k
    assert(name);
122
123
34.6k
    if (!(k = avahi_key_new(name, class, type))) {
124
33
        avahi_log_error("avahi_key_new() failed.");
125
33
        return NULL;
126
33
    }
127
128
34.5k
    r = avahi_record_new(k, ttl);
129
34.5k
    avahi_key_unref(k);
130
131
34.5k
    if (!r) {
132
0
        avahi_log_error("avahi_record_new() failed.");
133
0
        return NULL;
134
0
    }
135
136
34.5k
    return r;
137
34.5k
}
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
36.6k
void avahi_record_unref(AvahiRecord *r) {
148
36.6k
    assert(r);
149
36.6k
    assert(r->ref >= 1);
150
151
36.6k
    if ((--r->ref) <= 0) {
152
36.6k
        switch (r->key->type) {
153
154
1.80k
            case AVAHI_DNS_TYPE_SRV:
155
1.80k
                avahi_free(r->data.srv.name);
156
1.80k
                break;
157
158
4.83k
            case AVAHI_DNS_TYPE_PTR:
159
6.18k
            case AVAHI_DNS_TYPE_CNAME:
160
7.94k
            case AVAHI_DNS_TYPE_NS:
161
7.94k
                avahi_free(r->data.ptr.name);
162
7.94k
                break;
163
164
3.83k
            case AVAHI_DNS_TYPE_HINFO:
165
3.83k
                avahi_free(r->data.hinfo.cpu);
166
3.83k
                avahi_free(r->data.hinfo.os);
167
3.83k
                break;
168
169
3.27k
            case AVAHI_DNS_TYPE_TXT:
170
3.27k
                avahi_string_list_free(r->data.txt.string_list);
171
3.27k
                break;
172
173
1.29k
            case AVAHI_DNS_TYPE_A:
174
2.32k
            case AVAHI_DNS_TYPE_AAAA:
175
2.32k
                break;
176
177
17.5k
            default:
178
17.5k
                avahi_free(r->data.generic.data);
179
36.6k
        }
180
181
36.6k
        avahi_key_unref(r->key);
182
36.6k
        avahi_free(r);
183
36.6k
    }
184
36.6k
}
185
186
116k
const char *avahi_dns_class_to_string(uint16_t class) {
187
116k
    if (class & AVAHI_DNS_CACHE_FLUSH)
188
0
        return "FLUSH";
189
190
116k
    switch (class) {
191
4.43k
        case AVAHI_DNS_CLASS_IN:
192
4.43k
            return "IN";
193
107
        case AVAHI_DNS_CLASS_ANY:
194
107
            return "ANY";
195
112k
        default:
196
112k
            return NULL;
197
116k
    }
198
116k
}
199
200
116k
const char *avahi_dns_type_to_string(uint16_t type) {
201
116k
    switch (type) {
202
946
        case AVAHI_DNS_TYPE_CNAME:
203
946
            return "CNAME";
204
1.47k
        case AVAHI_DNS_TYPE_A:
205
1.47k
            return "A";
206
1.08k
        case AVAHI_DNS_TYPE_AAAA:
207
1.08k
            return "AAAA";
208
4.81k
        case AVAHI_DNS_TYPE_PTR:
209
4.81k
            return "PTR";
210
2.84k
        case AVAHI_DNS_TYPE_HINFO:
211
2.84k
            return "HINFO";
212
2.62k
        case AVAHI_DNS_TYPE_TXT:
213
2.62k
            return "TXT";
214
1.47k
        case AVAHI_DNS_TYPE_SRV:
215
1.47k
            return "SRV";
216
782
        case AVAHI_DNS_TYPE_ANY:
217
782
            return "ANY";
218
327
        case AVAHI_DNS_TYPE_SOA:
219
327
            return "SOA";
220
1.61k
        case AVAHI_DNS_TYPE_NS:
221
1.61k
            return "NS";
222
98.7k
        default:
223
98.7k
            return NULL;
224
116k
    }
225
116k
}
226
227
116k
char *avahi_key_to_string(const AvahiKey *k) {
228
116k
    char class[16], type[16];
229
116k
    const char *c, *t;
230
231
116k
    assert(k);
232
116k
    assert(k->ref >= 1);
233
234
    /* According to RFC3597 */
235
236
116k
    if (!(c = avahi_dns_class_to_string(k->clazz))) {
237
112k
        snprintf(class, sizeof(class), "CLASS%u", k->clazz);
238
112k
        c = class;
239
112k
    }
240
241
116k
    if (!(t = avahi_dns_type_to_string(k->type))) {
242
98.7k
        snprintf(type, sizeof(type), "TYPE%u", k->type);
243
98.7k
        t = type;
244
98.7k
    }
245
246
116k
    return avahi_strdup_printf("%s\t%s\t%s", k->name, c, t);
247
116k
}
248
249
30.6k
char *avahi_record_to_string(const AvahiRecord *r) {
250
30.6k
    char *p, *s;
251
30.6k
    char buf[1024], *t = NULL, *d = NULL;
252
253
30.6k
    assert(r);
254
30.6k
    assert(r->ref >= 1);
255
256
30.6k
    switch (r->key->type) {
257
1.13k
        case AVAHI_DNS_TYPE_A:
258
1.13k
            inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
259
1.13k
            break;
260
261
874
        case AVAHI_DNS_TYPE_AAAA:
262
874
            inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
263
874
            break;
264
265
4.58k
        case AVAHI_DNS_TYPE_PTR:
266
5.32k
        case AVAHI_DNS_TYPE_CNAME:
267
6.68k
        case AVAHI_DNS_TYPE_NS:
268
269
6.68k
            t = r->data.ptr.name;
270
6.68k
            break;
271
272
2.42k
        case AVAHI_DNS_TYPE_TXT:
273
2.42k
            t = d = avahi_string_list_to_string(r->data.txt.string_list);
274
2.42k
            break;
275
276
2.63k
        case AVAHI_DNS_TYPE_HINFO:
277
278
2.63k
            snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os);
279
2.63k
            break;
280
281
1.27k
        case AVAHI_DNS_TYPE_SRV:
282
283
1.27k
            snprintf(t = buf, sizeof(buf), "%u %u %u %s",
284
1.27k
                     r->data.srv.priority,
285
1.27k
                     r->data.srv.weight,
286
1.27k
                     r->data.srv.port,
287
1.27k
                     r->data.srv.name);
288
289
1.27k
            break;
290
291
15.5k
        default: {
292
293
15.5k
            uint8_t *c;
294
15.5k
            uint16_t n;
295
15.5k
            int i;
296
15.5k
            char *e;
297
298
            /* According to RFC3597 */
299
300
15.5k
            snprintf(t = buf, sizeof(buf), "\\# %u", r->data.generic.size);
301
302
15.5k
            e = strchr(t, 0);
303
304
15.5k
            for (c = r->data.generic.data, n = r->data.generic.size, i = 0;
305
57.4k
                 n > 0 && i < 20;
306
41.8k
                 c ++, n --, i++) {
307
308
41.8k
                sprintf(e, " %02X", *c);
309
41.8k
                e = strchr(e, 0);
310
41.8k
            }
311
312
15.5k
            break;
313
5.32k
        }
314
30.6k
    }
315
316
30.6k
    p = avahi_key_to_string(r->key);
317
30.6k
    s = avahi_strdup_printf("%s %s ; ttl=%u", p, t, r->ttl);
318
30.6k
    avahi_free(p);
319
30.6k
    avahi_free(d);
320
321
30.6k
    return s;
322
30.6k
}
323
324
5.57k
int avahi_key_equal(const AvahiKey *a, const AvahiKey *b) {
325
5.57k
    assert(a);
326
5.57k
    assert(b);
327
328
5.57k
    if (a == b)
329
2.11k
        return 1;
330
331
3.45k
    return avahi_domain_equal(a->name, b->name) &&
332
2.96k
        a->type == b->type &&
333
2.88k
        a->clazz == b->clazz;
334
5.57k
}
335
336
287
int avahi_key_pattern_match(const AvahiKey *pattern, const AvahiKey *k) {
337
287
    assert(pattern);
338
287
    assert(k);
339
340
287
    assert(!avahi_key_is_pattern(k));
341
342
287
    if (pattern == k)
343
0
        return 1;
344
345
287
    return avahi_domain_equal(pattern->name, k->name) &&
346
111
        (pattern->type == k->type || pattern->type == AVAHI_DNS_TYPE_ANY) &&
347
46
        (pattern->clazz == k->clazz || pattern->clazz == AVAHI_DNS_CLASS_ANY);
348
287
}
349
350
579
int avahi_key_is_pattern(const AvahiKey *k) {
351
579
    assert(k);
352
353
579
    return
354
579
        k->type == AVAHI_DNS_TYPE_ANY ||
355
577
        k->clazz == AVAHI_DNS_CLASS_ANY;
356
579
}
357
358
609
unsigned avahi_key_hash(const AvahiKey *k) {
359
609
    assert(k);
360
361
609
    return
362
609
        avahi_domain_hash(k->name) +
363
609
        k->type +
364
609
        k->clazz;
365
609
}
366
367
4.97k
static int rdata_equal(const AvahiRecord *a, const AvahiRecord *b) {
368
4.97k
    assert(a);
369
4.97k
    assert(b);
370
4.97k
    assert(a->key->type == b->key->type);
371
372
4.97k
    switch (a->key->type) {
373
397
        case AVAHI_DNS_TYPE_SRV:
374
397
            return
375
397
                a->data.srv.priority == b->data.srv.priority &&
376
372
                a->data.srv.weight == b->data.srv.weight &&
377
348
                a->data.srv.port == b->data.srv.port &&
378
325
                avahi_domain_equal(a->data.srv.name, b->data.srv.name);
379
380
186
        case AVAHI_DNS_TYPE_PTR:
381
711
        case AVAHI_DNS_TYPE_CNAME:
382
1.03k
        case AVAHI_DNS_TYPE_NS:
383
1.03k
            return avahi_domain_equal(a->data.ptr.name, b->data.ptr.name);
384
385
1.05k
        case AVAHI_DNS_TYPE_HINFO:
386
1.05k
            return
387
1.05k
                !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) &&
388
904
                !strcmp(a->data.hinfo.os, b->data.hinfo.os);
389
390
790
        case AVAHI_DNS_TYPE_TXT:
391
790
            return avahi_string_list_equal(a->data.txt.string_list, b->data.txt.string_list);
392
393
130
        case AVAHI_DNS_TYPE_A:
394
130
            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address)) == 0;
395
396
112
        case AVAHI_DNS_TYPE_AAAA:
397
112
            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address)) == 0;
398
399
1.45k
        default:
400
1.45k
            return a->data.generic.size == b->data.generic.size &&
401
1.38k
                (a->data.generic.size == 0 || memcmp(a->data.generic.data, b->data.generic.data, a->data.generic.size) == 0);
402
4.97k
    }
403
404
4.97k
}
405
406
5.57k
int avahi_record_equal_no_ttl(const AvahiRecord *a, const AvahiRecord *b) {
407
5.57k
    assert(a);
408
5.57k
    assert(b);
409
410
5.57k
    if (a == b)
411
0
        return 1;
412
413
5.57k
    return
414
5.57k
        avahi_key_equal(a->key, b->key) &&
415
4.97k
        rdata_equal(a, b);
416
5.57k
}
417
418
419
2.11k
AvahiRecord *avahi_record_copy(AvahiRecord *r) {
420
2.11k
    AvahiRecord *copy;
421
422
2.11k
    if (!(copy = avahi_new(AvahiRecord, 1))) {
423
0
        avahi_log_error("avahi_new() failed.");
424
0
        return NULL;
425
0
    }
426
427
2.11k
    copy->ref = 1;
428
2.11k
    copy->key = avahi_key_ref(r->key);
429
2.11k
    copy->ttl = r->ttl;
430
2.11k
    memset(&copy->data, 0, sizeof(copy->data));
431
432
2.11k
    switch (r->key->type) {
433
78
        case AVAHI_DNS_TYPE_PTR:
434
335
        case AVAHI_DNS_TYPE_CNAME:
435
492
        case AVAHI_DNS_TYPE_NS:
436
492
            if (!(copy->data.ptr.name = avahi_strdup(r->data.ptr.name)))
437
0
                goto fail;
438
492
            break;
439
440
492
        case AVAHI_DNS_TYPE_SRV:
441
162
            copy->data.srv.priority = r->data.srv.priority;
442
162
            copy->data.srv.weight = r->data.srv.weight;
443
162
            copy->data.srv.port = r->data.srv.port;
444
162
            if (!(copy->data.srv.name = avahi_strdup(r->data.srv.name)))
445
0
                goto fail;
446
162
            break;
447
448
377
        case AVAHI_DNS_TYPE_HINFO:
449
377
            if (!(copy->data.hinfo.os = avahi_strdup(r->data.hinfo.os)))
450
0
                goto fail;
451
452
377
            if (!(copy->data.hinfo.cpu = avahi_strdup(r->data.hinfo.cpu))) {
453
0
                avahi_free(r->data.hinfo.os);
454
0
                goto fail;
455
0
            }
456
377
            break;
457
458
377
        case AVAHI_DNS_TYPE_TXT:
459
340
            copy->data.txt.string_list = avahi_string_list_copy(r->data.txt.string_list);
460
340
            break;
461
462
61
        case AVAHI_DNS_TYPE_A:
463
61
            copy->data.a.address = r->data.a.address;
464
61
            break;
465
466
52
        case AVAHI_DNS_TYPE_AAAA:
467
52
            copy->data.aaaa.address = r->data.aaaa.address;
468
52
            break;
469
470
630
        default:
471
630
            if (r->data.generic.size && !(copy->data.generic.data = avahi_memdup(r->data.generic.data, r->data.generic.size)))
472
0
                goto fail;
473
630
            copy->data.generic.size = r->data.generic.size;
474
630
            break;
475
476
2.11k
    }
477
478
2.11k
    return copy;
479
480
0
fail:
481
0
    avahi_log_error("Failed to allocate memory");
482
483
0
    avahi_key_unref(copy->key);
484
0
    avahi_free(copy);
485
486
0
    return NULL;
487
2.11k
}
488
489
490
2.11k
size_t avahi_key_get_estimate_size(AvahiKey *k) {
491
2.11k
    assert(k);
492
493
2.11k
    return strlen(k->name)+1+4;
494
2.11k
}
495
496
2.11k
size_t avahi_record_get_estimate_size(AvahiRecord *r) {
497
2.11k
    size_t n;
498
2.11k
    assert(r);
499
500
2.11k
    n = avahi_key_get_estimate_size(r->key) + 4 + 2;
501
502
2.11k
    switch (r->key->type) {
503
78
        case AVAHI_DNS_TYPE_PTR:
504
335
        case AVAHI_DNS_TYPE_CNAME:
505
492
        case AVAHI_DNS_TYPE_NS:
506
492
            n += strlen(r->data.ptr.name) + 1;
507
492
            break;
508
509
162
        case AVAHI_DNS_TYPE_SRV:
510
162
            n += 6 + strlen(r->data.srv.name) + 1;
511
162
            break;
512
513
377
        case AVAHI_DNS_TYPE_HINFO:
514
377
            n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1;
515
377
            break;
516
517
340
        case AVAHI_DNS_TYPE_TXT:
518
340
            n += avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
519
340
            break;
520
521
61
        case AVAHI_DNS_TYPE_A:
522
61
            n += sizeof(AvahiIPv4Address);
523
61
            break;
524
525
52
        case AVAHI_DNS_TYPE_AAAA:
526
52
            n += sizeof(AvahiIPv6Address);
527
52
            break;
528
529
630
        default:
530
630
            n += r->data.generic.size;
531
2.11k
    }
532
533
2.11k
    return n;
534
2.11k
}
535
536
1.57k
static int lexicographical_memcmp(const void* a, size_t al, const void* b, size_t bl) {
537
1.57k
    size_t c;
538
1.57k
    int ret;
539
540
1.57k
    assert(a);
541
1.57k
    assert(b);
542
543
1.57k
    c = al < bl ? al : bl;
544
1.57k
    if ((ret = memcmp(a, b, c)))
545
215
        return ret;
546
547
1.36k
    if (al == bl)
548
1.32k
        return 0;
549
37
    else
550
37
        return al == c ? -1 : 1;
551
1.36k
}
552
553
11.8k
static int uint16_cmp(uint16_t a, uint16_t b) {
554
11.8k
    return a == b ? 0 : (a < b ? -1 : 1);
555
11.8k
}
556
557
5.57k
int avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b) {
558
5.57k
    int r;
559
/*      char *t1, *t2; */
560
561
5.57k
    assert(a);
562
5.57k
    assert(b);
563
564
/*     t1 = avahi_record_to_string(a); */
565
/*     t2 = avahi_record_to_string(b); */
566
/*     g_message("lexicocmp: %s %s", t1, t2); */
567
/*     avahi_free(t1); */
568
/*     avahi_free(t2); */
569
570
5.57k
    if (a == b)
571
0
        return 0;
572
573
5.57k
    if ((r = uint16_cmp(a->key->clazz, b->key->clazz)) ||
574
5.13k
        (r = uint16_cmp(a->key->type, b->key->type)))
575
478
        return r;
576
577
5.09k
    switch (a->key->type) {
578
579
201
        case AVAHI_DNS_TYPE_PTR:
580
801
        case AVAHI_DNS_TYPE_CNAME:
581
1.12k
        case AVAHI_DNS_TYPE_NS:
582
1.12k
            return avahi_binary_domain_cmp(a->data.ptr.name, b->data.ptr.name);
583
584
401
        case AVAHI_DNS_TYPE_SRV: {
585
401
            if ((r = uint16_cmp(a->data.srv.priority, b->data.srv.priority)) == 0 &&
586
374
                (r = uint16_cmp(a->data.srv.weight, b->data.srv.weight)) == 0 &&
587
350
                (r = uint16_cmp(a->data.srv.port, b->data.srv.port)) == 0)
588
326
                r = avahi_binary_domain_cmp(a->data.srv.name, b->data.srv.name);
589
590
401
            return r;
591
801
        }
592
593
1.06k
        case AVAHI_DNS_TYPE_HINFO: {
594
595
1.06k
            if ((r = strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu)) ||
596
908
                (r = strcmp(a->data.hinfo.os, b->data.hinfo.os)))
597
313
                return r;
598
599
756
            return 0;
600
601
1.06k
        }
602
603
791
        case AVAHI_DNS_TYPE_TXT: {
604
605
791
            uint8_t *ma = NULL, *mb = NULL;
606
791
            size_t asize, bsize;
607
608
791
            asize = avahi_string_list_serialize(a->data.txt.string_list, NULL, 0);
609
791
            bsize = avahi_string_list_serialize(b->data.txt.string_list, NULL, 0);
610
611
791
            if (asize > 0 && !(ma = avahi_new(uint8_t, asize)))
612
0
                goto fail;
613
614
791
            if (bsize > 0 && !(mb = avahi_new(uint8_t, bsize))) {
615
0
                avahi_free(ma);
616
0
                goto fail;
617
0
            }
618
619
791
            avahi_string_list_serialize(a->data.txt.string_list, ma, asize);
620
791
            avahi_string_list_serialize(b->data.txt.string_list, mb, bsize);
621
622
791
            if (asize && bsize)
623
791
                r = lexicographical_memcmp(ma, asize, mb, bsize);
624
0
            else if (asize && !bsize)
625
0
                r = 1;
626
0
            else if (!asize && bsize)
627
0
                r = -1;
628
0
            else
629
0
                r = 0;
630
631
791
            avahi_free(ma);
632
791
            avahi_free(mb);
633
634
791
            return r;
635
791
        }
636
637
130
        case AVAHI_DNS_TYPE_A:
638
130
            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address));
639
640
112
        case AVAHI_DNS_TYPE_AAAA:
641
112
            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address));
642
643
1.46k
        default: {
644
1.46k
            size_t asize, bsize;
645
646
1.46k
            asize = a->data.generic.size;
647
1.46k
            bsize = b->data.generic.size;
648
649
1.46k
            if (asize && bsize)
650
788
                r = lexicographical_memcmp(a->data.generic.data, asize, b->data.generic.data, bsize);
651
675
            else if (asize && !bsize)
652
24
                r = 1;
653
651
            else if (!asize && bsize)
654
18
                r = -1;
655
633
            else
656
633
                r = 0;
657
658
1.46k
            return r;
659
791
        }
660
5.09k
    }
661
662
663
0
fail:
664
0
    avahi_log_error(__FILE__": Out of memory");
665
0
    return -1; /* or whatever ... */
666
5.09k
}
667
668
2.11k
int avahi_record_is_goodbye(AvahiRecord *r) {
669
2.11k
    assert(r);
670
671
2.11k
    return r->ttl == 0;
672
2.11k
}
673
674
123k
int avahi_key_is_valid(AvahiKey *k) {
675
123k
    assert(k);
676
677
123k
    if (!avahi_is_valid_domain_name(k->name))
678
0
        return 0;
679
680
123k
    return 1;
681
123k
}
682
683
36.2k
int avahi_record_is_valid(AvahiRecord *r) {
684
36.2k
    assert(r);
685
686
36.2k
    if (!avahi_key_is_valid(r->key))
687
0
        return 0;
688
689
36.2k
    switch (r->key->type) {
690
691
4.82k
        case AVAHI_DNS_TYPE_PTR:
692
6.16k
        case AVAHI_DNS_TYPE_CNAME:
693
7.90k
        case AVAHI_DNS_TYPE_NS:
694
7.90k
            return avahi_is_valid_domain_name(r->data.ptr.name);
695
696
1.68k
        case AVAHI_DNS_TYPE_SRV:
697
1.68k
            return avahi_is_valid_domain_name(r->data.srv.name);
698
699
3.70k
        case AVAHI_DNS_TYPE_HINFO:
700
3.70k
            return
701
3.70k
                strlen(r->data.hinfo.os) <= 255 &&
702
3.70k
                strlen(r->data.hinfo.cpu) <= 255;
703
704
3.21k
        case AVAHI_DNS_TYPE_TXT: {
705
706
3.21k
            AvahiStringList *strlst;
707
3.21k
            size_t used = 0;
708
709
188k
            for (strlst = r->data.txt.string_list; strlst; strlst = strlst->next) {
710
184k
                if (strlst->size > 255 || strlst->size <= 0)
711
0
                    return 0;
712
713
184k
                used += 1+strlst->size;
714
184k
                if (used > AVAHI_DNS_RDATA_MAX)
715
0
                    return 0;
716
184k
            }
717
718
3.21k
            return 1;
719
3.21k
        }
720
36.2k
    }
721
722
19.7k
    return 1;
723
36.2k
}
724
725
2.11k
static AvahiAddress *get_address(const AvahiRecord *r, AvahiAddress *a) {
726
2.11k
    assert(r);
727
728
2.11k
    switch (r->key->type) {
729
61
        case AVAHI_DNS_TYPE_A:
730
61
            a->proto = AVAHI_PROTO_INET;
731
61
            a->data.ipv4 = r->data.a.address;
732
61
            break;
733
734
52
        case AVAHI_DNS_TYPE_AAAA:
735
52
            a->proto = AVAHI_PROTO_INET6;
736
52
            a->data.ipv6 = r->data.aaaa.address;
737
52
            break;
738
739
2.00k
        default:
740
2.00k
            return NULL;
741
2.11k
    }
742
743
113
    return a;
744
2.11k
}
745
746
2.11k
int avahi_record_is_link_local_address(const AvahiRecord *r) {
747
2.11k
    AvahiAddress a;
748
749
2.11k
    assert(r);
750
751
2.11k
    if (!get_address(r, &a))
752
2.00k
        return 0;
753
754
113
    return avahi_address_is_link_local(&a);
755
2.11k
}