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