]> git.meshlink.io Git - catta/blob - rr.c
* improve dns.c testing program
[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
10 flxKey *flx_key_new(const gchar *name, guint16 class, guint16 type) {
11     flxKey *k;
12     g_assert(name);
13
14     k = g_new(flxKey, 1);
15     k->ref = 1;
16     k->name = flx_normalize_name(name);    
17     k->class = class;
18     k->type = type;
19
20 /*     g_message("%p %% ref=1", k); */
21     
22     return k;
23 }
24
25 flxKey *flx_key_ref(flxKey *k) {
26     g_assert(k);
27     g_assert(k->ref >= 1);
28
29     k->ref++;
30
31 /*     g_message("%p ++ ref=%i", k, k->ref); */
32
33     return k;
34 }
35
36 void flx_key_unref(flxKey *k) {
37     g_assert(k);
38     g_assert(k->ref >= 1);
39
40 /*     g_message("%p -- ref=%i", k, k->ref-1); */
41     
42     if ((--k->ref) <= 0) {
43         g_free(k->name);
44         g_free(k);
45     }
46 }
47
48 flxRecord *flx_record_new(flxKey *k) {
49     flxRecord *r;
50     
51     g_assert(k);
52     
53     r = g_new(flxRecord, 1);
54     r->ref = 1;
55     r->key = flx_key_ref(k);
56
57     memset(&r->data, 0, sizeof(r->data));
58
59     r->ttl = FLX_DEFAULT_TTL;
60
61     return r;
62 }
63
64 flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type) {
65     flxRecord *r;
66     flxKey *k;
67
68     g_assert(name);
69     
70     k = flx_key_new(name, class, type);
71     r = flx_record_new(k);
72     flx_key_unref(k);
73
74     return r;
75 }
76
77 flxRecord *flx_record_ref(flxRecord *r) {
78     g_assert(r);
79     g_assert(r->ref >= 1);
80
81     r->ref++;
82     return r;
83 }
84
85 void flx_record_unref(flxRecord *r) {
86     g_assert(r);
87     g_assert(r->ref >= 1);
88
89     if ((--r->ref) <= 0) {
90         switch (r->key->type) {
91
92             case FLX_DNS_TYPE_SRV:
93                 g_free(r->data.srv.name);
94                 break;
95
96             case FLX_DNS_TYPE_PTR:
97             case FLX_DNS_TYPE_CNAME:
98                 g_free(r->data.ptr.name);
99                 break;
100
101             case FLX_DNS_TYPE_HINFO:
102                 g_free(r->data.hinfo.cpu);
103                 g_free(r->data.hinfo.os);
104                 break;
105
106             case FLX_DNS_TYPE_TXT:
107                 flx_string_list_free(r->data.txt.string_list);
108                 break;
109
110             case FLX_DNS_TYPE_A:
111             case FLX_DNS_TYPE_AAAA:
112                 break;
113             
114             default:
115                 g_free(r->data.generic.data);
116         }
117         
118         flx_key_unref(r->key);
119         g_free(r);
120     }
121 }
122
123 const gchar *flx_dns_class_to_string(guint16 class) {
124     if (class & FLX_DNS_CACHE_FLUSH) 
125         return "FLUSH";
126     
127     if (class == FLX_DNS_CLASS_IN)
128         return "IN";
129
130     return NULL;
131 }
132
133 const gchar *flx_dns_type_to_string(guint16 type) {
134     switch (type) {
135         case FLX_DNS_TYPE_CNAME:
136             return "CNAME";
137         case FLX_DNS_TYPE_A:
138             return "A";
139         case FLX_DNS_TYPE_AAAA:
140             return "AAAA";
141         case FLX_DNS_TYPE_PTR:
142             return "PTR";
143         case FLX_DNS_TYPE_HINFO:
144             return "HINFO";
145         case FLX_DNS_TYPE_TXT:
146             return "TXT";
147         case FLX_DNS_TYPE_SRV:
148             return "SRV";
149         case FLX_DNS_TYPE_ANY:
150             return "ANY";
151         default:
152             return NULL;
153     }
154 }
155
156
157 gchar *flx_key_to_string(const flxKey *k) {
158     return g_strdup_printf("%s\t%s\t%s",
159                            k->name,
160                            flx_dns_class_to_string(k->class),
161                            flx_dns_type_to_string(k->type));
162 }
163
164 gchar *flx_record_to_string(const flxRecord *r) {
165     gchar *p, *s;
166     char buf[257], *t = NULL, *d = NULL;
167
168     switch (r->key->type) {
169         case FLX_DNS_TYPE_A:
170             inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
171             break;
172             
173         case FLX_DNS_TYPE_AAAA:
174             inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
175             break;
176             
177         case FLX_DNS_TYPE_PTR:
178         case FLX_DNS_TYPE_CNAME :
179
180             t = r->data.ptr.name;
181             break;
182
183         case FLX_DNS_TYPE_TXT:
184             t = d = flx_string_list_to_string(r->data.txt.string_list);
185             break;
186
187         case FLX_DNS_TYPE_HINFO:
188
189             snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os);
190             break;
191
192         case FLX_DNS_TYPE_SRV:
193
194             snprintf(t = buf, sizeof(buf), "%u %u %u %s",
195                      r->data.srv.priority,
196                      r->data.srv.weight,
197                      r->data.srv.port,
198                      r->data.srv.name);
199
200             break;
201     }
202
203     p = flx_key_to_string(r->key);
204     s = g_strdup_printf("%s %s ; ttl=%u", p, t ? t : "<unparsable>", r->ttl);
205     g_free(p);
206     g_free(d);
207     
208     return s;
209 }
210
211 gboolean flx_key_equal(const flxKey *a, const flxKey *b) {
212     g_assert(a);
213     g_assert(b);
214
215 /*     g_message("equal: %p %p", a, b); */
216     
217     return flx_domain_equal(a->name, b->name) &&
218         a->type == b->type &&
219         a->class == b->class;
220 }
221
222 gboolean flx_key_pattern_match(const flxKey *pattern, const flxKey *k) {
223     g_assert(pattern);
224     g_assert(k);
225
226 /*     g_message("equal: %p %p", a, b); */
227
228     g_assert(!flx_key_is_pattern(k));
229     
230     return flx_domain_equal(pattern->name, k->name) &&
231         (pattern->type == k->type || pattern->type == FLX_DNS_TYPE_ANY) &&
232         pattern->class == k->class;
233 }
234
235 gboolean flx_key_is_pattern(const flxKey *k) {
236     g_assert(k);
237
238     return k->type == FLX_DNS_TYPE_ANY;
239 }
240
241
242 guint flx_key_hash(const flxKey *k) {
243     g_assert(k);
244
245     return flx_domain_hash(k->name) + k->type + k->class;
246 }
247
248 static gboolean rdata_equal(const flxRecord *a, const flxRecord *b) {
249     g_assert(a);
250     g_assert(b);
251     g_assert(a->key->type == b->key->type);
252
253 /*     t = flx_record_to_string(a); */
254 /*     g_message("comparing %s", t); */
255 /*     g_free(t); */
256
257 /*     t = flx_record_to_string(b); */
258 /*     g_message("and %s", t); */
259 /*     g_free(t); */
260
261     
262     switch (a->key->type) {
263         case FLX_DNS_TYPE_SRV:
264             return
265                 a->data.srv.priority == b->data.srv.priority &&
266                 a->data.srv.weight == b->data.srv.weight &&
267                 a->data.srv.port == b->data.srv.port &&
268                 flx_domain_equal(a->data.srv.name, b->data.srv.name);
269
270         case FLX_DNS_TYPE_PTR:
271         case FLX_DNS_TYPE_CNAME:
272             return flx_domain_equal(a->data.ptr.name, b->data.ptr.name);
273
274         case FLX_DNS_TYPE_HINFO:
275             return
276                 !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) &&
277                 !strcmp(a->data.hinfo.os, b->data.hinfo.os);
278
279         case FLX_DNS_TYPE_TXT:
280             return flx_string_list_equal(a->data.txt.string_list, b->data.txt.string_list);
281
282         case FLX_DNS_TYPE_A:
283             return memcmp(&a->data.a.address, &b->data.a.address, sizeof(flxIPv4Address)) == 0;
284
285         case FLX_DNS_TYPE_AAAA:
286             return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(flxIPv6Address)) == 0;
287
288         default:
289             return a->data.generic.size == b->data.generic.size &&
290                 (a->data.generic.size == 0 || memcmp(a->data.generic.data, b->data.generic.data, a->data.generic.size) == 0);
291     }
292     
293 }
294
295 gboolean flx_record_equal_no_ttl(const flxRecord *a, const flxRecord *b) {
296     g_assert(a);
297     g_assert(b);
298
299     return
300         flx_key_equal(a->key, b->key) &&
301         rdata_equal(a, b);
302 }
303
304
305 flxRecord *flx_record_copy(flxRecord *r) {
306     flxRecord *copy;
307
308     copy = g_new(flxRecord, 1);
309     copy->ref = 1;
310     copy->key = flx_key_ref(r->key);
311     copy->ttl = r->ttl;
312
313     switch (r->key->type) {
314         case FLX_DNS_TYPE_PTR:
315         case FLX_DNS_TYPE_CNAME:
316             copy->data.ptr.name = g_strdup(r->data.ptr.name);
317             break;
318
319         case FLX_DNS_TYPE_SRV:
320             copy->data.srv.priority = r->data.srv.priority;
321             copy->data.srv.weight = r->data.srv.weight;
322             copy->data.srv.port = r->data.srv.port;
323             copy->data.srv.name = g_strdup(r->data.srv.name);
324             break;
325
326         case FLX_DNS_TYPE_HINFO:
327             copy->data.hinfo.os = g_strdup(r->data.hinfo.os);
328             copy->data.hinfo.cpu = g_strdup(r->data.hinfo.cpu);
329             break;
330
331         case FLX_DNS_TYPE_TXT:
332             copy->data.txt.string_list = flx_string_list_copy(r->data.txt.string_list);
333             break;
334
335         case FLX_DNS_TYPE_A:
336             copy->data.a.address = r->data.a.address;
337             break;
338
339         case FLX_DNS_TYPE_AAAA:
340             copy->data.aaaa.address = r->data.aaaa.address;
341             break;
342
343         default:
344             copy->data.generic.data = g_memdup(r->data.generic.data, r->data.generic.size);
345             copy->data.generic.size = r->data.generic.size;
346             break;
347                 
348     }
349
350     return copy;
351 }
352
353
354 guint flx_key_get_estimate_size(flxKey *k) {
355     g_assert(k);
356
357     return strlen(k->name)+1+4;
358 }
359
360 guint flx_record_get_estimate_size(flxRecord *r) {
361     guint n;
362     g_assert(r);
363
364     n = flx_key_get_estimate_size(r->key) + 4 + 2;
365
366     switch (r->key->type) {
367         case FLX_DNS_TYPE_PTR:
368         case FLX_DNS_TYPE_CNAME:
369             n += strlen(r->data.ptr.name) + 1;
370             break;
371
372         case FLX_DNS_TYPE_SRV:
373             n += 6 + strlen(r->data.srv.name) + 1;
374             break;
375
376         case FLX_DNS_TYPE_HINFO:
377             n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1;
378             break;
379
380         case FLX_DNS_TYPE_TXT:
381             n += flx_string_list_serialize(r->data.txt.string_list, NULL, 0);
382             break;
383
384         case FLX_DNS_TYPE_A:
385             n += sizeof(flxIPv4Address);
386             break;
387
388         case FLX_DNS_TYPE_AAAA:
389             n += sizeof(flxIPv6Address);
390             break;
391
392         default:
393             n += r->data.generic.size;
394     }
395
396     return n;
397 }