]> git.meshlink.io Git - catta/blob - rr.c
fix two memory leaks
[catta] / rr.c
1 #include <string.h>
2 #include <stdio.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <arpa/inet.h>
6
7 #include "util.h"
8 #include "rr.h"
9 #include "dns.h"
10
11 flxKey *flx_key_new(const gchar *name, guint16 class, guint16 type) {
12     flxKey *k;
13     g_assert(name);
14
15     k = g_new(flxKey, 1);
16     k->ref = 1;
17     k->name = flx_normalize_name(name);    
18     k->class = class;
19     k->type = type;
20
21 /*     g_message("%p %% ref=1", k); */
22     
23     return k;
24 }
25
26 flxKey *flx_key_ref(flxKey *k) {
27     g_assert(k);
28     g_assert(k->ref >= 1);
29
30     k->ref++;
31
32 /*     g_message("%p ++ ref=%i", k, k->ref); */
33
34     return k;
35 }
36
37 void flx_key_unref(flxKey *k) {
38     g_assert(k);
39     g_assert(k->ref >= 1);
40
41 /*     g_message("%p -- ref=%i", k, k->ref-1); */
42     
43     if ((--k->ref) <= 0) {
44         g_free(k->name);
45         g_free(k);
46     }
47 }
48
49 flxRecord *flx_record_new(flxKey *k) {
50     flxRecord *r;
51     
52     g_assert(k);
53     
54     r = g_new(flxRecord, 1);
55     r->ref = 1;
56     r->key = flx_key_ref(k);
57
58     memset(&r->data, 0, sizeof(r->data));
59
60     r->ttl = FLX_DEFAULT_TTL;
61
62     return r;
63 }
64
65 flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type) {
66     flxRecord *r;
67     flxKey *k;
68
69     g_assert(name);
70     
71     k = flx_key_new(name, class, type);
72     r = flx_record_new(k);
73     flx_key_unref(k);
74
75     return r;
76 }
77
78 flxRecord *flx_record_ref(flxRecord *r) {
79     g_assert(r);
80     g_assert(r->ref >= 1);
81
82     r->ref++;
83     return r;
84 }
85
86 void flx_record_unref(flxRecord *r) {
87     g_assert(r);
88     g_assert(r->ref >= 1);
89
90     if ((--r->ref) <= 0) {
91         switch (r->key->type) {
92
93             case FLX_DNS_TYPE_SRV:
94                 g_free(r->data.srv.name);
95                 break;
96
97             case FLX_DNS_TYPE_PTR:
98             case FLX_DNS_TYPE_CNAME:
99                 g_free(r->data.ptr.name);
100                 break;
101
102             case FLX_DNS_TYPE_HINFO:
103                 g_free(r->data.hinfo.cpu);
104                 g_free(r->data.hinfo.os);
105                 break;
106
107             case FLX_DNS_TYPE_TXT:
108                 flx_string_list_free(r->data.txt.string_list);
109                 break;
110
111             case FLX_DNS_TYPE_A:
112             case FLX_DNS_TYPE_AAAA:
113                 break;
114             
115             default:
116                 g_free(r->data.generic.data);
117         }
118         
119         flx_key_unref(r->key);
120         g_free(r);
121     }
122 }
123
124 const gchar *flx_dns_class_to_string(guint16 class) {
125     if (class & FLX_DNS_CACHE_FLUSH) 
126         return "FLUSH";
127     
128     if (class == FLX_DNS_CLASS_IN)
129         return "IN";
130
131     return NULL;
132 }
133
134 const gchar *flx_dns_type_to_string(guint16 type) {
135     switch (type) {
136         case FLX_DNS_TYPE_CNAME:
137             return "CNAME";
138         case FLX_DNS_TYPE_A:
139             return "A";
140         case FLX_DNS_TYPE_AAAA:
141             return "AAAA";
142         case FLX_DNS_TYPE_PTR:
143             return "PTR";
144         case FLX_DNS_TYPE_HINFO:
145             return "HINFO";
146         case FLX_DNS_TYPE_TXT:
147             return "TXT";
148         case FLX_DNS_TYPE_SRV:
149             return "SRV";
150         case FLX_DNS_TYPE_ANY:
151             return "ANY";
152         default:
153             return NULL;
154     }
155 }
156
157
158 gchar *flx_key_to_string(const flxKey *k) {
159     return g_strdup_printf("%s\t%s\t%s",
160                            k->name,
161                            flx_dns_class_to_string(k->class),
162                            flx_dns_type_to_string(k->type));
163 }
164
165 gchar *flx_record_to_string(const flxRecord *r) {
166     gchar *p, *s;
167     char buf[257], *t = NULL, *d = NULL;
168
169     switch (r->key->type) {
170         case FLX_DNS_TYPE_A:
171             inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
172             break;
173             
174         case FLX_DNS_TYPE_AAAA:
175             inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
176             break;
177             
178         case FLX_DNS_TYPE_PTR:
179         case FLX_DNS_TYPE_CNAME :
180
181             t = r->data.ptr.name;
182             break;
183
184         case FLX_DNS_TYPE_TXT:
185             t = d = flx_string_list_to_string(r->data.txt.string_list);
186             break;
187
188         case FLX_DNS_TYPE_HINFO:
189
190             snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os);
191             break;
192
193         case FLX_DNS_TYPE_SRV:
194
195             snprintf(t = buf, sizeof(buf), "%u %u %u %s",
196                      r->data.srv.priority,
197                      r->data.srv.weight,
198                      r->data.srv.port,
199                      r->data.srv.name);
200
201             break;
202     }
203
204     p = flx_key_to_string(r->key);
205     s = g_strdup_printf("%s %s ; ttl=%u", p, t ? t : "<unparsable>", r->ttl);
206     g_free(p);
207     g_free(d);
208     
209     return s;
210 }
211
212 gboolean flx_key_equal(const flxKey *a, const flxKey *b) {
213     g_assert(a);
214     g_assert(b);
215
216 /*     g_message("equal: %p %p", a, b); */
217     
218     return flx_domain_equal(a->name, b->name) &&
219         a->type == b->type &&
220         a->class == b->class;
221 }
222
223 gboolean flx_key_pattern_match(const flxKey *pattern, const flxKey *k) {
224     g_assert(pattern);
225     g_assert(k);
226
227 /*     g_message("equal: %p %p", a, b); */
228
229     g_assert(!flx_key_is_pattern(k));
230     
231     return flx_domain_equal(pattern->name, k->name) &&
232         (pattern->type == k->type || pattern->type == FLX_DNS_TYPE_ANY) &&
233         pattern->class == k->class;
234 }
235
236 gboolean flx_key_is_pattern(const flxKey *k) {
237     g_assert(k);
238
239     return k->type == FLX_DNS_TYPE_ANY;
240 }
241
242
243 guint flx_key_hash(const flxKey *k) {
244     g_assert(k);
245
246     return flx_domain_hash(k->name) + k->type + k->class;
247 }
248
249 static gboolean rdata_equal(const flxRecord *a, const flxRecord *b) {
250     g_assert(a);
251     g_assert(b);
252     g_assert(a->key->type == b->key->type);
253
254 /*     t = flx_record_to_string(a); */
255 /*     g_message("comparing %s", t); */
256 /*     g_free(t); */
257
258 /*     t = flx_record_to_string(b); */
259 /*     g_message("and %s", t); */
260 /*     g_free(t); */
261
262     
263     switch (a->key->type) {
264         case FLX_DNS_TYPE_SRV:
265             return
266                 a->data.srv.priority == b->data.srv.priority &&
267                 a->data.srv.weight == b->data.srv.weight &&
268                 a->data.srv.port == b->data.srv.port &&
269                 flx_domain_equal(a->data.srv.name, b->data.srv.name);
270
271         case FLX_DNS_TYPE_PTR:
272         case FLX_DNS_TYPE_CNAME:
273             return flx_domain_equal(a->data.ptr.name, b->data.ptr.name);
274
275         case FLX_DNS_TYPE_HINFO:
276             return
277                 !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) &&
278                 !strcmp(a->data.hinfo.os, b->data.hinfo.os);
279
280         case FLX_DNS_TYPE_TXT:
281             return flx_string_list_equal(a->data.txt.string_list, b->data.txt.string_list);
282
283         case FLX_DNS_TYPE_A:
284             return memcmp(&a->data.a.address, &b->data.a.address, sizeof(flxIPv4Address)) == 0;
285
286         case FLX_DNS_TYPE_AAAA:
287             return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(flxIPv6Address)) == 0;
288
289         default:
290             return a->data.generic.size == b->data.generic.size &&
291                 (a->data.generic.size == 0 || memcmp(a->data.generic.data, b->data.generic.data, a->data.generic.size) == 0);
292     }
293     
294 }
295
296 gboolean flx_record_equal_no_ttl(const flxRecord *a, const flxRecord *b) {
297     g_assert(a);
298     g_assert(b);
299
300     return
301         flx_key_equal(a->key, b->key) &&
302         rdata_equal(a, b);
303 }
304
305
306 flxRecord *flx_record_copy(flxRecord *r) {
307     flxRecord *copy;
308
309     copy = g_new(flxRecord, 1);
310     copy->ref = 1;
311     copy->key = flx_key_ref(r->key);
312     copy->ttl = r->ttl;
313
314     switch (r->key->type) {
315         case FLX_DNS_TYPE_PTR:
316         case FLX_DNS_TYPE_CNAME:
317             copy->data.ptr.name = g_strdup(r->data.ptr.name);
318             break;
319
320         case FLX_DNS_TYPE_SRV:
321             copy->data.srv.priority = r->data.srv.priority;
322             copy->data.srv.weight = r->data.srv.weight;
323             copy->data.srv.port = r->data.srv.port;
324             copy->data.srv.name = g_strdup(r->data.srv.name);
325             break;
326
327         case FLX_DNS_TYPE_HINFO:
328             copy->data.hinfo.os = g_strdup(r->data.hinfo.os);
329             copy->data.hinfo.cpu = g_strdup(r->data.hinfo.cpu);
330             break;
331
332         case FLX_DNS_TYPE_TXT:
333             copy->data.txt.string_list = flx_string_list_copy(r->data.txt.string_list);
334             break;
335
336         case FLX_DNS_TYPE_A:
337             copy->data.a.address = r->data.a.address;
338             break;
339
340         case FLX_DNS_TYPE_AAAA:
341             copy->data.aaaa.address = r->data.aaaa.address;
342             break;
343
344         default:
345             copy->data.generic.data = g_memdup(r->data.generic.data, r->data.generic.size);
346             copy->data.generic.size = r->data.generic.size;
347             break;
348                 
349     }
350
351     return copy;
352 }
353
354
355 guint flx_key_get_estimate_size(flxKey *k) {
356     g_assert(k);
357
358     return strlen(k->name)+1+4;
359 }
360
361 guint flx_record_get_estimate_size(flxRecord *r) {
362     guint n;
363     g_assert(r);
364
365     n = flx_key_get_estimate_size(r->key) + 4 + 2;
366
367     switch (r->key->type) {
368         case FLX_DNS_TYPE_PTR:
369         case FLX_DNS_TYPE_CNAME:
370             n += strlen(r->data.ptr.name) + 1;
371             break;
372
373         case FLX_DNS_TYPE_SRV:
374             n += 6 + strlen(r->data.srv.name) + 1;
375             break;
376
377         case FLX_DNS_TYPE_HINFO:
378             n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1;
379             break;
380
381         case FLX_DNS_TYPE_TXT:
382             n += flx_string_list_serialize(r->data.txt.string_list, NULL, 0);
383             break;
384
385         case FLX_DNS_TYPE_A:
386             n += sizeof(flxIPv4Address);
387             break;
388
389         case FLX_DNS_TYPE_AAAA:
390             n += sizeof(flxIPv6Address);
391             break;
392
393         default:
394             n += r->data.generic.size;
395     }
396
397     return n;
398 }
399
400 static gint lexicographical_memcmp(gconstpointer a, size_t al, gconstpointer b, size_t bl) {
401     size_t c;
402     gint ret;
403     
404     g_assert(a);
405     g_assert(b);
406
407     c = al < bl ? al : bl;
408     if ((ret = memcmp(a, b, c)) != 0)
409         return ret;
410
411     if (al == bl)
412         return 0;
413     else
414         return al == c ? 1 : -1;
415 }
416
417 static gint uint16_cmp(guint16 a, guint16 b) {
418     return a == b ? 0 : (a < b ? a : b);
419 }
420
421 static gint lexicographical_domain_cmp(const gchar *a, const gchar *b) {
422     g_assert(a);
423     g_assert(b);
424     
425
426     for (;;) {
427         gchar t1[64];
428         gchar t2[64];
429         size_t al, bl;
430         gint r;
431
432         if (!a && !b)
433             return 0;
434
435         if (a && !b)
436             return 1;
437
438         if (b && !a)
439             return -1;
440         
441         flx_unescape_label(t1, sizeof(t1), &a);
442         flx_unescape_label(t2, sizeof(t2), &b);
443
444         al = strlen(t1);
445         bl = strlen(t2);
446         
447         if (al != bl) 
448             return al < bl ? -1 : 1;
449
450         if ((r =  strcmp(t1, t2)) != 0)
451             return r;
452     }
453 }
454
455 gint flx_record_lexicographical_compare(flxRecord *a, flxRecord *b) {
456     g_assert(a);
457     g_assert(b);
458
459     if (a->key->class < b->key->class)
460         return -1;
461     else if (a->key->class > b->key->class)
462         return 1;
463
464     if (a->key->type < b->key->type)
465         return -1;
466     else if (a->key->type > b->key->type)
467         return 1;
468
469     switch (a->key->type) {
470
471         case FLX_DNS_TYPE_PTR:
472         case FLX_DNS_TYPE_CNAME:
473             return lexicographical_domain_cmp(a->data.ptr.name, b->data.ptr.name);
474
475         case FLX_DNS_TYPE_SRV: {
476             gint r;
477             if ((r = uint16_cmp(a->data.srv.priority, b->data.srv.priority)) != 0 ||
478                 (r = uint16_cmp(a->data.srv.weight, b->data.srv.weight)) != 0 ||
479                 (r = uint16_cmp(a->data.srv.port, b->data.srv.port)) != 0)
480                 return lexicographical_domain_cmp(a->data.srv.name, b->data.srv.name);
481         }
482
483         case FLX_DNS_TYPE_HINFO: {
484             size_t al = strlen(a->data.hinfo.cpu), bl = strlen(b->data.hinfo.cpu);
485             gint r;
486
487             if (al != bl)
488                 return al < bl ? -1 : 1;
489
490             if ((r = strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu)) != 0)
491                 return r;
492
493             al = strlen(a->data.hinfo.os), bl = strlen(b->data.hinfo.os);
494
495             if (al != bl)
496                 return al < bl ? -1 : 1;
497
498             if ((r = strcmp(a->data.hinfo.os, b->data.hinfo.os)) != 0)
499                 return r;
500
501             return 0;
502
503         }
504
505         case FLX_DNS_TYPE_TXT: {
506
507             guint8 *ma, *mb;
508             guint asize, bsize;
509             gint r;
510
511             ma = g_new(guint8, asize = flx_string_list_serialize(a->data.txt.string_list, NULL, 0));
512             mb = g_new(guint8, bsize = flx_string_list_serialize(b->data.txt.string_list, NULL, 0));
513             flx_string_list_serialize(a->data.txt.string_list, ma, asize);
514             flx_string_list_serialize(a->data.txt.string_list, mb, bsize);
515
516             r = lexicographical_memcmp(ma, asize, mb, bsize);
517             g_free(ma);
518             g_free(mb);
519
520             return r;
521         }
522         
523         case FLX_DNS_TYPE_A:
524             return memcmp(&a->data.a.address, &b->data.a.address, sizeof(flxIPv4Address));
525
526         case FLX_DNS_TYPE_AAAA:
527             return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(flxIPv6Address));
528
529         default:
530             return lexicographical_memcmp(a->data.generic.data, a->data.generic.size,
531                                           b->data.generic.data, b->data.generic.size);
532     }
533     
534 }