]> git.meshlink.io Git - catta/blob - server.c
* add support for both ipv4 AND ipv6 reverse lookups
[catta] / server.c
1 #include <sys/socket.h>
2 #include <arpa/inet.h>
3 #include <string.h>
4
5 #include "server.h"
6 #include "util.h"
7
8 flxServer *flx_server_new(GMainContext *c) {
9     flxServer *s = g_new(flxServer, 1);
10
11     if (c) {
12         g_main_context_ref(c);
13         s->context = c;
14     } else
15         s->context = g_main_context_default();
16     
17     s->current_id = 1;
18     s->rrset_by_id = g_hash_table_new(g_int_hash, g_int_equal);
19     s->rrset_by_name = g_hash_table_new(g_str_hash, g_str_equal);
20     s->entries = NULL;
21
22     s->monitor = flx_interface_monitor_new(s->context);
23     
24     return s;
25 }
26
27 void flx_server_free(flxServer* s) {
28     g_assert(s);
29
30     flx_interface_monitor_free(s->monitor);
31
32     flx_server_remove(s, 0);
33     
34     g_hash_table_destroy(s->rrset_by_id);
35     g_hash_table_destroy(s->rrset_by_name);
36     g_main_context_unref(s->context);
37     g_free(s);
38 }
39
40 gint flx_server_get_next_id(flxServer *s) {
41     g_assert(s);
42
43     return s->current_id++;
44 }
45
46 void flx_server_add_rr(flxServer *s, gint id, gint interface, const flxRecord *rr) {
47     flxEntry *e;
48     g_assert(s);
49     g_assert(rr);
50     g_assert(rr->name);
51     g_assert(rr->data);
52     g_assert(rr->size);
53
54     e = g_new(flxEntry, 1);
55     flx_record_copy_normalize(&e->rr, rr);
56     e->id = id;
57     e->interface = interface;
58
59     /* Insert into linked list */
60     e->prev = NULL;
61     if ((e->next = s->entries))
62         e->next->prev = e;
63     s->entries = e;
64
65     /* Insert into hash table indexed by id */
66     e->prev_by_id = NULL;
67     if ((e->next_by_id = g_hash_table_lookup(s->rrset_by_id, &id)))
68         e->next_by_id->prev = e;
69     g_hash_table_replace(s->rrset_by_id, &e->id, e);
70
71     /* Insert into hash table indexed by name */
72     e->prev_by_name = NULL;
73     if ((e->next_by_name = g_hash_table_lookup(s->rrset_by_name, e->rr.name)))
74         e->next_by_name->prev = e;
75     g_hash_table_replace(s->rrset_by_name, e->rr.name, e);
76 }
77
78 void flx_server_add(flxServer *s, gint id, gint interface, const gchar *name, guint16 type, gconstpointer data, guint size) {
79     flxRecord rr;
80     g_assert(s);
81     g_assert(name);
82     g_assert(data);
83     g_assert(size);
84
85     rr.name = (gchar*) name;
86     rr.type = type;
87     rr.class = FLX_DNS_CLASS_IN;
88     rr.data = (gpointer) data;
89     rr.size = size;
90     rr.ttl = FLX_DEFAULT_TTL;
91     flx_server_add_rr(s, id, interface, &rr);
92 }
93
94 const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) {
95     flxEntry **e = (flxEntry**) state;
96     g_assert(s);
97     g_assert(e);
98
99     if (e)
100         *e = id > 0 ? (*e)->next_by_id : (*e)->next;
101     else
102         *e = id > 0 ? g_hash_table_lookup(s->rrset_by_id, &id) : s->entries;
103         
104     if (!*e)
105         return NULL;
106
107     return &(*e)->rr;
108 }
109
110 static void free_entry(flxServer*s, flxEntry *e) {
111     g_assert(e);
112
113     /* Remove from linked list */
114     if (e->prev)
115         e->prev->next = e->next;
116     else
117         s->entries = e->next;
118     
119     if (e->next)
120         e->next->prev = e->prev;
121
122     /* Remove from hash table indexed by id */
123     if (e->prev_by_id)
124         e->prev_by_id = e->next_by_id;
125     else {
126         if (e->next_by_id)
127             g_hash_table_replace(s->rrset_by_id, &e->next_by_id->id, e->next_by_id);
128         else
129             g_hash_table_remove(s->rrset_by_id, &e->id);
130     }
131
132     if (e->next_by_id)
133         e->next_by_id->prev_by_id = e->prev_by_id;
134
135     /* Remove from hash table indexed by name */
136     if (e->prev_by_name)
137         e->prev_by_name = e->next_by_name;
138     else {
139         if (e->next_by_name)
140             g_hash_table_replace(s->rrset_by_name, &e->next_by_name->rr.name, e->next_by_name);
141         else
142             g_hash_table_remove(s->rrset_by_name, &e->rr.name);
143     }
144     
145     if (e->next_by_name)
146         e->next_by_name->prev_by_name = e->prev_by_name;
147 }
148
149 void flx_server_remove(flxServer *s, gint id) {
150     g_assert(s);
151
152     if (id <= 0) {
153         while (s->entries)
154             free_entry(s, s->entries);
155     } else {
156         flxEntry *e;
157
158         while ((e = g_hash_table_lookup(s->rrset_by_id, &id)))
159             free_entry(s, e);
160     }
161 }
162
163 flxRecord *flx_record_copy_normalize(flxRecord *ret_dest, const flxRecord*src) {
164     g_assert(ret_dest);
165     g_assert(src);
166
167     *ret_dest = *src;
168     ret_dest->name = flx_normalize_name(src->name);
169     ret_dest->data = g_memdup(src->data, src->size);
170
171     return ret_dest;    
172 }
173
174 static const gchar *dns_class_to_string(guint16 class) {
175     if (class == FLX_DNS_CLASS_IN)
176         return "IN";
177
178     return NULL;
179 }
180
181 static const gchar *dns_type_to_string(guint16 type) {
182     switch (type) {
183         case FLX_DNS_TYPE_A:
184             return "A";
185         case FLX_DNS_TYPE_AAAA:
186             return "AAAA";
187         case FLX_DNS_TYPE_PTR:
188             return "PTR";
189         case FLX_DNS_TYPE_HINFO:
190             return "HINFO";
191         case FLX_DNS_TYPE_TXT:
192             return "TXT";
193         default:
194             return NULL;
195     }
196 }
197
198 void flx_server_dump(flxServer *s, FILE *f) {
199     flxEntry *e;
200     g_assert(s);
201     g_assert(f);
202
203     for (e = s->entries; e; e = e->next) {
204         char t[256];
205         fprintf(f, "%i: %-40s %-8s %-8s ", e->interface, e->rr.name, dns_class_to_string(e->rr.class), dns_type_to_string(e->rr.type));
206
207         t[0] = 0;
208         
209         if (e->rr.class == FLX_DNS_CLASS_IN) {
210             if (e->rr.type == FLX_DNS_TYPE_A)
211                 inet_ntop(AF_INET, e->rr.data, t, sizeof(t));
212             else if (e->rr.type == FLX_DNS_TYPE_AAAA)
213                 inet_ntop(AF_INET6, e->rr.data, t, sizeof(t));
214             else if (e->rr.type == FLX_DNS_TYPE_PTR)
215                 g_strlcpy(t, e->rr.data, sizeof(t));
216             else if (e->rr.type == FLX_DNS_TYPE_HINFO) {
217                 char *s2;
218
219                 if ((s2 = memchr(e->rr.data, 0, e->rr.size))) {
220                     s2++;
221                     if (memchr(s2, 0, e->rr.size - ((char*) s2 - (char*) e->rr.data)))
222                         snprintf(t, sizeof(t), "'%s' '%s'", (char*) e->rr.data, s2);
223                 }
224                 
225             }
226         }
227             
228         fprintf(f, "%s\n", t);
229     }
230 }
231
232 void flx_server_add_address(flxServer *s, gint id, gint interface, const gchar *name, flxAddress *a) {
233     gchar *n;
234     g_assert(s);
235     g_assert(name);
236     g_assert(a);
237
238     n = flx_normalize_name(name);
239     
240     if (a->family == AF_INET) {
241         gchar *r;
242         
243         flx_server_add(s, id, interface, n, FLX_DNS_TYPE_A, &a->ipv4, sizeof(a->ipv4));
244
245         r = flx_reverse_lookup_name_ipv4(&a->ipv4);
246         g_assert(r);
247         flx_server_add(s, id, interface, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
248         g_free(r);
249         
250     } else {
251         gchar *r;
252             
253         flx_server_add(s, id, interface, n, FLX_DNS_TYPE_AAAA, &a->ipv6, sizeof(a->ipv6));
254
255         r = flx_reverse_lookup_name_ipv6_arpa(&a->ipv6);
256         g_assert(r);
257         flx_server_add(s, id, interface, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
258         g_free(r);
259     
260         r = flx_reverse_lookup_name_ipv6_int(&a->ipv6);
261         g_assert(r);
262         flx_server_add(s, id, interface, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
263         g_free(r);
264     }
265     
266     g_free(n);
267 }