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