]> git.meshlink.io Git - catta/blob - iface.c
some more inomcplete work
[catta] / iface.c
1 #include <string.h>
2 #include <sys/socket.h>
3 #include <asm/types.h>
4 #include <linux/netlink.h>
5 #include <linux/rtnetlink.h>
6 #include <errno.h>
7 #include <net/if.h>
8
9 #include "iface.h"
10 #include "netlink.h"
11 #include "dns.h"
12 #include "socket.h"
13
14 static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, int remove) {
15     g_assert(m);
16     g_assert(a);
17
18     if (!flx_address_is_relevant(a) || remove) {
19         if (a->rr_id >= 0) {
20             flx_server_remove(m->server, a->rr_id);
21             a->rr_id = -1;
22         }
23     } else {
24         if (a->rr_id < 0) {
25             a->rr_id = flx_server_get_next_id(m->server);
26             flx_server_add_address(m->server, a->rr_id, a->interface->index, AF_UNSPEC, FALSE, m->server->hostname, &a->address);
27         }
28     }
29 }
30
31 static void update_interface_rr(flxInterfaceMonitor *m, flxInterface *i, int remove) {
32     flxInterfaceAddress *a;
33     g_assert(m);
34     g_assert(i);
35
36     for (a = i->addresses; a; a = a->address_next)
37         update_address_rr(m, a, remove);
38 }
39
40 static void free_address(flxInterfaceMonitor *m, flxInterfaceAddress *a) {
41     g_assert(m);
42     g_assert(a);
43     g_assert(a->interface);
44
45     if (a->address.family == AF_INET)
46         a->interface->n_ipv4_addrs --;
47     else if (a->address.family == AF_INET6)
48         a->interface->n_ipv6_addrs --;
49
50     FLX_LLIST_REMOVE(flxInterfaceAddress, address, a->interface->addresses, a);
51
52     flx_server_remove(m->server, a->rr_id);
53     
54     g_free(a);
55 }
56
57 static void free_interface(flxInterfaceMonitor *m, flxInterface *i) {
58     g_assert(m);
59     g_assert(i);
60
61     while (i->addresses)
62         free_address(m, i->addresses);
63
64     if (i->ipv4_cache)
65         flx_cache_free(i->ipv4_cache);
66     if (i->ipv6_cache)
67         flx_cache_free(i->ipv6_cache);
68     
69     g_assert(i->n_ipv6_addrs == 0);
70     g_assert(i->n_ipv4_addrs == 0);
71
72     FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i);
73     g_hash_table_remove(m->hash_table, &i->index);
74
75     flx_cache_free(i->ipv4_cache);
76     flx_cache_free(i->ipv6_cache);
77     
78     g_free(i->name);
79     g_free(i);
80 }
81
82 static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) {
83     flxInterfaceAddress *ia;
84     
85     g_assert(m);
86     g_assert(i);
87     g_assert(raddr);
88
89     for (ia = i->addresses; ia; ia = ia->address_next)
90         if (flx_address_cmp(&ia->address, raddr) == 0)
91             return ia;
92
93     return NULL;
94 }
95
96 static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) {
97     struct nlmsghdr *n;
98     struct rtgenmsg *gen;
99     guint8 req[1024];
100     
101     memset(&req, 0, sizeof(req));
102     n = (struct nlmsghdr*) req;
103     n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
104     n->nlmsg_type = type;
105     n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
106     n->nlmsg_pid = 0;
107
108     gen = NLMSG_DATA(n);
109     memset(gen, 0, sizeof(struct rtgenmsg));
110     gen->rtgen_family = AF_UNSPEC;
111
112     return flx_netlink_send(nl, n, ret_seq);
113 }
114
115 static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
116     flxInterfaceMonitor *m = userdata;
117     
118     g_assert(m);
119     g_assert(n);
120     g_assert(m->netlink == nl);
121
122     if (n->nlmsg_type == RTM_NEWLINK) {
123         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
124         flxInterface *i;
125         struct rtattr *a = NULL;
126         size_t l;
127         int changed;
128
129         if (ifinfomsg->ifi_family != AF_UNSPEC)
130             return;
131
132         if ((i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
133             changed = 1;
134         else {
135             i = g_new(flxInterface, 1);
136             i->monitor = m;
137             i->name = NULL;
138             i->index = ifinfomsg->ifi_index;
139             i->addresses = NULL;
140             i->n_ipv4_addrs = i->n_ipv6_addrs = 0;
141             FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i);
142             g_hash_table_insert(m->hash_table, &i->index, i);
143             i->ipv4_cache = flx_cache_new(m->server, i);
144             i->ipv6_cache = flx_cache_new(m->server, i);
145             
146             changed = 0;
147         }
148         
149         i->flags = ifinfomsg->ifi_flags;
150
151         l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
152         a = IFLA_RTA(ifinfomsg);
153
154         while (RTA_OK(a, l)) {
155             switch(a->rta_type) {
156                 case IFLA_IFNAME:
157                     g_free(i->name);
158                     i->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
159                     break;
160                     
161                 default:
162                     ;
163             }
164
165             a = RTA_NEXT(a, l);
166         }
167
168         update_interface_rr(m, i, 0);
169     } else if (n->nlmsg_type == RTM_DELLINK) {
170         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
171         flxInterface *i;
172
173         if (ifinfomsg->ifi_family != AF_UNSPEC)
174             return;
175         
176         if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
177             return;
178
179         update_interface_rr(m, i, 1);
180         free_interface(m, i);
181         
182     } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
183
184         struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
185         flxInterface *i;
186         struct rtattr *a = NULL;
187         size_t l;
188         int changed;
189         flxAddress raddr;
190         int raddr_valid = 0;
191
192         if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
193             return;
194
195         if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index)))
196             return;
197
198         raddr.family = ifaddrmsg->ifa_family;
199
200         l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
201         a = IFA_RTA(ifaddrmsg);
202
203         while (RTA_OK(a, l)) {
204             switch(a->rta_type) {
205                 case IFA_ADDRESS:
206                     if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
207                         (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
208                         return;
209
210                     memcpy(raddr.data, RTA_DATA(a), RTA_PAYLOAD(a));
211                     raddr_valid = 1;
212
213                     break;
214                     
215                 default:
216                     ;
217             }
218
219             a = RTA_NEXT(a, l);
220         }
221
222
223         if (!raddr_valid)
224             return;
225
226         if (n->nlmsg_type == RTM_NEWADDR) {
227             flxInterfaceAddress *addr;
228             
229             if ((addr = get_address(m, i, &raddr)))
230                 changed = 1;
231             else {
232                 addr = g_new(flxInterfaceAddress, 1);
233                 addr->address = raddr;
234                 addr->interface = i;
235
236                 if (raddr.family == AF_INET)
237                     i->n_ipv4_addrs++;
238                 else if (raddr.family == AF_INET6)
239                     i->n_ipv6_addrs++;
240
241                 addr->rr_id = -1;
242
243                 FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr);
244                 
245                 changed = 0;
246             }
247             
248             addr->flags = ifaddrmsg->ifa_flags;
249             addr->scope = ifaddrmsg->ifa_scope;
250
251             update_address_rr(m, addr, 0);
252         } else {
253             flxInterfaceAddress *addr;
254             
255             if (!(addr = get_address(m, i, &raddr)))
256                 return;
257
258             update_address_rr(m, addr, 1);
259             free_address(m, addr);
260         }
261                 
262     } else if (n->nlmsg_type == NLMSG_DONE) {
263
264         if (m->list == LIST_IFACE) {
265             m->list = LIST_DONE;
266             
267             if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) {
268                 g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
269             } else
270                 m->list = LIST_ADDR;
271         } else
272             m->list = LIST_DONE;
273         
274     } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
275         struct nlmsgerr *e = NLMSG_DATA (n);
276                     
277         if (e->error)
278             g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
279     }
280 }
281
282 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) {
283     flxInterfaceMonitor *m = NULL;
284
285     m = g_new0(flxInterfaceMonitor, 1);
286     m->server = s;
287     if (!(m->netlink = flx_netlink_new(s->context, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
288         goto fail;
289
290     m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
291     m->interfaces = NULL;
292
293     if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
294         goto fail;
295
296     m->list = LIST_IFACE;
297     
298     return m;
299
300 fail:
301     flx_interface_monitor_free(m);
302     return NULL;
303 }
304
305 void flx_interface_monitor_free(flxInterfaceMonitor *m) {
306     g_assert(m);
307
308     if (m->netlink)
309         flx_netlink_free(m->netlink);
310
311     if (m->hash_table)
312         g_hash_table_destroy(m->hash_table);
313
314     g_free(m);
315 }
316
317
318 flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) {
319     g_assert(m);
320     g_assert(index > 0);
321
322     return g_hash_table_lookup(m->hash_table, &index);
323 }
324
325 flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) {
326     g_assert(m);
327     return m->interfaces;
328 }
329
330 int flx_interface_is_relevant(flxInterface *i) {
331     g_assert(i);
332
333     return
334         (i->flags & IFF_UP) &&
335         (i->flags & IFF_RUNNING) &&
336         !(i->flags & IFF_LOOPBACK);
337 }
338
339 int flx_address_is_relevant(flxInterfaceAddress *a) {
340     g_assert(a);
341
342     return
343         a->scope == RT_SCOPE_UNIVERSE &&
344         flx_interface_is_relevant(a->interface);
345 }
346
347 void flx_interface_send_query(flxInterface *i, guchar protocol, flxKey *k) {
348     flxDnsPacket *p;
349     g_assert(i);
350     g_assert(k);
351
352     p = flx_dns_packet_new();
353     flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
354
355     flx_dns_packet_append_name(p, k->name);
356     flx_dns_packet_append_uint16(p, k->type);
357     flx_dns_packet_append_uint16(p, k->class);
358
359     flx_dns_packet_set_field(p, DNS_FIELD_QDCOUNT, 1);
360
361     if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0 && flx_interface_is_relevant(i)) {
362         g_message("sending on '%s':IPv4", i->name);
363         flx_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->index, p);
364     }
365
366     if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0 && flx_interface_is_relevant(i)) {
367         g_message("sending on '%s':IPv6", i->name);
368         flx_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->index, p);
369     }
370     
371     flx_dns_packet_free(p);
372 }
373
374 void flx_interface_send_response(flxinterface *i, guchar protocol, flxRecord *rr) {
375     flxDnsPacket+p;
376     
377     g_assert(i);
378     g_assert(rr);
379
380     p = flx_dns_packet_new();
381     flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
382
383     flx_dns_packet_append_name(p, rr->key->name);
384     flx_dns_packet_append_uint16(p, rr->key->type);
385     flx_dns_packet_append_uint16(p, rr->key->class);
386     flx_dns_packet_append_uint16
387 }
388
389
390
391 void flx_dump_caches(flxServer *s, FILE *f) {
392     flxInterface *i;
393     g_assert(s);
394
395     for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next) {
396         if (!flx_interface_is_relevant(i))
397             continue;
398         
399         if (i->n_ipv4_addrs > 0) {
400             fprintf(f, ";;; INTERFACE %s; IPv4 ;;;\n", i->name);
401             flx_cache_dump(i->ipv4_cache, f);
402         }
403
404         if (i->n_ipv6_addrs > 0) {
405             fprintf(f, ";;; INTERFACE %s; IPv6 ;;;\n", i->name);
406             flx_cache_dump(i->ipv6_cache, f);
407         }
408     }
409 }