]> git.meshlink.io Git - catta/blob - iface.c
add client part of known answer suppresion
[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 #include "announce.h"
14
15 static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, int remove) {
16     g_assert(m);
17     g_assert(a);
18
19     if (!flx_interface_address_relevant(a) || remove) {
20         if (a->rr_id >= 0) {
21             flx_server_remove(m->server, a->rr_id);
22             a->rr_id = -1;
23         }
24     } else {
25         if (a->rr_id < 0) {
26             a->rr_id = flx_server_get_next_id(m->server);
27             flx_server_add_address(m->server, a->rr_id, a->interface->hardware->index, AF_UNSPEC, FALSE, m->server->hostname, &a->address);
28         }
29     }
30 }
31
32 static void update_interface_rr(flxInterfaceMonitor *m, flxInterface *i, int remove) {
33     flxInterfaceAddress *a;
34     g_assert(m);
35     g_assert(i);
36
37     for (a = i->addresses; a; a = a->address_next)
38         update_address_rr(m, a, remove);
39 }
40
41 static void update_hw_interface_rr(flxInterfaceMonitor *m, flxHwInterface *hw, int remove) {
42     flxInterface *i;
43
44     g_assert(m);
45     g_assert(hw);
46
47     for (i = hw->interfaces; i; i = i->by_hardware_next)
48         update_interface_rr(m, i, remove);
49 }
50
51 static void free_address(flxInterfaceMonitor *m, flxInterfaceAddress *a) {
52     g_assert(m);
53     g_assert(a);
54     g_assert(a->interface);
55
56     FLX_LLIST_REMOVE(flxInterfaceAddress, address, a->interface->addresses, a);
57     flx_server_remove(m->server, a->rr_id);
58     
59     g_free(a);
60 }
61
62 static void free_interface(flxInterfaceMonitor *m, flxInterface *i, gboolean send_goodbye) {
63     g_assert(m);
64     g_assert(i);
65
66     g_message("removing interface %s.%i", i->hardware->name, i->protocol);
67     flx_goodbye_interface(m->server, i, send_goodbye);
68     g_message("flushing...");
69     flx_packet_scheduler_flush_responses(i->scheduler);
70     g_message("done");
71     
72     g_assert(!i->announcements);
73
74     while (i->addresses)
75         free_address(m, i->addresses);
76
77     flx_packet_scheduler_free(i->scheduler);
78     flx_cache_free(i->cache);
79     
80     FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i);
81     FLX_LLIST_REMOVE(flxInterface, by_hardware, i->hardware->interfaces, i);
82     
83     g_free(i);
84 }
85
86 static void free_hw_interface(flxInterfaceMonitor *m, flxHwInterface *hw, gboolean send_goodbye) {
87     g_assert(m);
88     g_assert(hw);
89
90     while (hw->interfaces)
91         free_interface(m, hw->interfaces, send_goodbye);
92
93     FLX_LLIST_REMOVE(flxHwInterface, hardware, m->hw_interfaces, hw);
94     g_hash_table_remove(m->hash_table, &hw->index);
95
96     g_free(hw->name);
97     g_free(hw);
98 }
99
100 static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) {
101     flxInterfaceAddress *ia;
102     
103     g_assert(m);
104     g_assert(i);
105     g_assert(raddr);
106
107     for (ia = i->addresses; ia; ia = ia->address_next)
108         if (flx_address_cmp(&ia->address, raddr) == 0)
109             return ia;
110
111     return NULL;
112 }
113
114 static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) {
115     struct nlmsghdr *n;
116     struct rtgenmsg *gen;
117     guint8 req[1024];
118     
119     memset(&req, 0, sizeof(req));
120     n = (struct nlmsghdr*) req;
121     n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
122     n->nlmsg_type = type;
123     n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
124     n->nlmsg_pid = 0;
125
126     gen = NLMSG_DATA(n);
127     memset(gen, 0, sizeof(struct rtgenmsg));
128     gen->rtgen_family = AF_UNSPEC;
129
130     return flx_netlink_send(nl, n, ret_seq);
131 }
132
133 static void new_interface(flxInterfaceMonitor *m, flxHwInterface *hw, guchar protocol) {
134     flxInterface *i;
135     
136     g_assert(m);
137     g_assert(hw);
138     g_assert(protocol != AF_UNSPEC);
139
140     i = g_new(flxInterface, 1);
141     i->monitor = m;
142     i->hardware = hw;
143     i->protocol = protocol;
144     i->announcing = FALSE;
145
146     FLX_LLIST_HEAD_INIT(flxInterfaceAddress, i->addresses);
147     FLX_LLIST_HEAD_INIT(flxAnnouncement, i->announcements);
148
149     i->cache = flx_cache_new(m->server, i);
150     i->scheduler = flx_packet_scheduler_new(m->server, i);
151
152     FLX_LLIST_PREPEND(flxInterface, by_hardware, hw->interfaces, i);
153     FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i);
154 }
155
156 static void check_interface_relevant(flxInterfaceMonitor *m, flxInterface *i) {
157     gboolean b;
158     g_assert(m);
159     g_assert(i);
160
161     b = flx_interface_relevant(i);
162
163     if (b && !i->announcing) {
164         g_message("New relevant interface %s.%i", i->hardware->name, i->protocol);
165
166         i->announcing = TRUE;
167         flx_announce_interface(m->server, i);
168     } else if (!b && i->announcing) {
169         g_message("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
170
171         i->announcing = FALSE;
172         flx_goodbye_interface(m->server, i, FALSE);
173     }
174 }
175
176 static void check_hw_interface_relevant(flxInterfaceMonitor *m, flxHwInterface *hw) {
177     flxInterface *i;
178     
179     g_assert(m);
180     g_assert(hw);
181
182     for (i = hw->interfaces; i; i = i->by_hardware_next)
183         check_interface_relevant(m, i);
184 }
185
186 static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
187     flxInterfaceMonitor *m = userdata;
188     
189     g_assert(m);
190     g_assert(n);
191     g_assert(m->netlink == nl);
192
193     if (n->nlmsg_type == RTM_NEWLINK) {
194         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
195         flxHwInterface *hw;
196         struct rtattr *a = NULL;
197         size_t l;
198
199         if (ifinfomsg->ifi_family != AF_UNSPEC)
200             return;
201
202         if (!(hw = g_hash_table_lookup(m->hash_table, &ifinfomsg->ifi_index))) {
203             hw = g_new(flxHwInterface, 1);
204             hw->monitor = m;
205             hw->name = NULL;
206             hw->flags = 0;
207             hw->mtu = 1500;
208             hw->index = ifinfomsg->ifi_index;
209
210             FLX_LLIST_HEAD_INIT(flxInterface, hw->interfaces);
211             FLX_LLIST_PREPEND(flxHwInterface, hardware, m->hw_interfaces, hw);
212             
213             g_hash_table_insert(m->hash_table, &hw->index, hw);
214
215             if (m->server->fd_ipv4 >= 0)
216                 new_interface(m, hw, AF_INET);
217             if (m->server->fd_ipv6 >= 0)
218                 new_interface(m, hw, AF_INET6);
219         }
220         
221         hw->flags = ifinfomsg->ifi_flags;
222
223         l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
224         a = IFLA_RTA(ifinfomsg);
225
226         while (RTA_OK(a, l)) {
227             switch(a->rta_type) {
228                 case IFLA_IFNAME:
229                     g_free(hw->name);
230                     hw->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
231                     break;
232
233                 case IFLA_MTU:
234                     g_assert(RTA_PAYLOAD(a) == sizeof(unsigned int));
235                     hw->mtu = *((unsigned int*) RTA_DATA(a));
236                     break;
237                     
238                 default:
239                     ;
240             }
241
242             a = RTA_NEXT(a, l);
243         }
244
245         update_hw_interface_rr(m, hw, FALSE);
246         check_hw_interface_relevant(m, hw);
247         
248     } else if (n->nlmsg_type == RTM_DELLINK) {
249         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
250         flxHwInterface *hw;
251         flxInterface *i;
252
253         if (ifinfomsg->ifi_family != AF_UNSPEC)
254             return;
255         
256         if (!(hw = flx_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index)))
257             return;
258
259         update_hw_interface_rr(m, hw, TRUE);
260         free_hw_interface(m, hw, FALSE);
261         
262     } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
263
264         struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
265         flxInterface *i;
266         struct rtattr *a = NULL;
267         size_t l;
268         flxAddress raddr;
269         int raddr_valid = 0;
270
271         if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
272             return;
273
274         if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index, ifaddrmsg->ifa_family)))
275             return;
276
277         raddr.family = ifaddrmsg->ifa_family;
278
279         l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
280         a = IFA_RTA(ifaddrmsg);
281
282         while (RTA_OK(a, l)) {
283             switch(a->rta_type) {
284                 case IFA_ADDRESS:
285                     if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
286                         (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
287                         return;
288
289                     memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
290                     raddr_valid = 1;
291
292                     break;
293                     
294                 default:
295                     ;
296             }
297             
298             a = RTA_NEXT(a, l);
299         }
300
301         
302         if (!raddr_valid)
303             return;
304
305         if (n->nlmsg_type == RTM_NEWADDR) {
306             flxInterfaceAddress *addr;
307             
308             if (!(addr = get_address(m, i, &raddr))) {
309                 addr = g_new(flxInterfaceAddress, 1);
310                 addr->monitor = m;
311                 addr->address = raddr;
312                 addr->interface = i;
313                 addr->rr_id = -1;
314
315                 FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr);
316             }
317             
318             addr->flags = ifaddrmsg->ifa_flags;
319             addr->scope = ifaddrmsg->ifa_scope;
320
321             update_address_rr(m, addr, FALSE);
322             check_interface_relevant(m, i);
323         } else {
324             flxInterfaceAddress *addr;
325             
326             if (!(addr = get_address(m, i, &raddr)))
327                 return;
328
329             update_address_rr(m, addr, TRUE);
330             free_address(m, addr);
331
332             check_interface_relevant(m, i);
333         }
334                 
335     } else if (n->nlmsg_type == NLMSG_DONE) {
336         
337         if (m->list == LIST_IFACE) {
338             m->list = LIST_DONE;
339             
340             if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0)
341                 g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
342             else
343                 m->list = LIST_ADDR;
344         } else {
345             m->list = LIST_DONE;
346             g_message("Enumeration complete");
347         }
348         
349     } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
350         struct nlmsgerr *e = NLMSG_DATA (n);
351                     
352         if (e->error)
353             g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
354     }
355 }
356
357 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) {
358     flxInterfaceMonitor *m = NULL;
359
360     m = g_new0(flxInterfaceMonitor, 1);
361     m->server = s;
362     if (!(m->netlink = flx_netlink_new(s->context, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
363         goto fail;
364
365     m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
366
367     FLX_LLIST_HEAD_INIT(flxInterface, m->interfaces);
368     FLX_LLIST_HEAD_INIT(flxHwInterface, m->hw_interfaces);
369
370     if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
371         goto fail;
372
373     m->list = LIST_IFACE;
374     
375     return m;
376
377 fail:
378     flx_interface_monitor_free(m);
379     return NULL;
380 }
381
382 void flx_interface_monitor_free(flxInterfaceMonitor *m) {
383     g_assert(m);
384
385     while (m->hw_interfaces)
386         free_hw_interface(m, m->hw_interfaces, TRUE);
387
388     g_assert(!m->interfaces);
389
390     
391     if (m->netlink)
392         flx_netlink_free(m->netlink);
393     
394     if (m->hash_table)
395         g_hash_table_destroy(m->hash_table);
396
397     g_free(m);
398 }
399
400
401 flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index, guchar protocol) {
402     flxHwInterface *hw;
403     flxInterface *i;
404     
405     g_assert(m);
406     g_assert(index > 0);
407     g_assert(protocol != AF_UNSPEC);
408
409     if (!(hw = flx_interface_monitor_get_hw_interface(m, index)))
410         return NULL;
411
412     for (i = hw->interfaces; i; i = i->by_hardware_next)
413         if (i->protocol == protocol)
414             return i;
415
416     return NULL;
417 }
418
419 flxHwInterface* flx_interface_monitor_get_hw_interface(flxInterfaceMonitor *m, gint index) {
420     g_assert(m);
421     g_assert(index > 0);
422
423     return g_hash_table_lookup(m->hash_table, &index);
424 }
425
426
427 void flx_interface_send_packet(flxInterface *i, flxDnsPacket *p) {
428     g_assert(i);
429     g_assert(p);
430
431     if (flx_interface_relevant(i)) {
432         g_message("sending on '%s.%i'", i->hardware->name, i->protocol);
433
434         if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
435             flx_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p);
436         else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0)
437             flx_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p);
438     }
439 }
440
441 void flx_interface_post_query(flxInterface *i, flxKey *key, gboolean immediately) {
442     g_assert(i);
443     g_assert(key);
444
445     if (flx_interface_relevant(i))
446         flx_packet_scheduler_post_query(i->scheduler, key, immediately);
447 }
448
449
450 void flx_interface_post_response(flxInterface *i, flxRecord *record, gboolean immediately) {
451     g_assert(i);
452     g_assert(record);
453
454     if (flx_interface_relevant(i))
455         flx_packet_scheduler_post_response(i->scheduler, record, immediately);
456 }
457
458 void flx_dump_caches(flxInterfaceMonitor *m, FILE *f) {
459     flxInterface *i;
460     g_assert(m);
461
462     for (i = m->interfaces; i; i = i->interface_next) {
463         if (flx_interface_relevant(i)) {
464             fprintf(f, "\n;;; INTERFACE %s.%i ;;;\n", i->hardware->name, i->protocol);
465             flx_cache_dump(i->cache, f);
466         }
467     }
468     fprintf(f, "\n");
469 }
470
471 gboolean flx_interface_relevant(flxInterface *i) {
472     g_assert(i);
473
474     return
475         (i->hardware->flags & IFF_UP) &&
476         (i->hardware->flags & IFF_RUNNING) &&
477         !(i->hardware->flags & IFF_LOOPBACK) &&
478         (i->hardware->flags & IFF_MULTICAST) &&
479         i->addresses;
480 }
481
482 gboolean flx_interface_address_relevant(flxInterfaceAddress *a) { 
483     g_assert(a);
484
485     return a->scope == RT_SCOPE_UNIVERSE;
486 }
487
488
489 gboolean flx_interface_match(flxInterface *i, gint index, guchar protocol) {
490     g_assert(i);
491     
492     if (index > 0 && index != i->hardware->index)
493         return FALSE;
494
495     if (protocol != AF_UNSPEC && protocol != i->protocol)
496         return FALSE;
497
498     return TRUE;
499 }
500
501
502 void flx_interface_monitor_walk(flxInterfaceMonitor *m, gint interface, guchar protocol, flxInterfaceMonitorWalkCallback callback, gpointer userdata) {
503     g_assert(m);
504     g_assert(callback);
505     
506     if (interface > 0) {
507         if (protocol != AF_UNSPEC) {
508             flxInterface *i;
509             
510             if ((i = flx_interface_monitor_get_interface(m, interface, protocol)))
511                 callback(m, i, userdata);
512             
513         } else {
514             flxHwInterface *hw;
515             flxInterface *i;
516
517             if ((hw = flx_interface_monitor_get_hw_interface(m, interface)))
518                 for (i = hw->interfaces; i; i = i->by_hardware_next)
519                     if (flx_interface_match(i, interface, protocol))
520                         callback(m, i, userdata);
521         }
522         
523     } else {
524         flxInterface *i;
525         
526         for (i = m->interfaces; i; i = i->interface_next)
527             if (flx_interface_match(i, interface, protocol))
528                 callback(m, i, userdata);
529     }
530 }