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