2 #include <sys/socket.h>
4 #include <linux/netlink.h>
5 #include <linux/rtnetlink.h>
15 static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, int remove) {
19 if (!flx_interface_address_relevant(a) || remove) {
21 flx_server_remove(m->server, a->rr_id);
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);
32 static void update_interface_rr(flxInterfaceMonitor *m, flxInterface *i, int remove) {
33 flxInterfaceAddress *a;
37 for (a = i->addresses; a; a = a->address_next)
38 update_address_rr(m, a, remove);
41 static void update_hw_interface_rr(flxInterfaceMonitor *m, flxHwInterface *hw, int remove) {
47 for (i = hw->interfaces; i; i = i->by_hardware_next)
48 update_interface_rr(m, i, remove);
51 static void free_address(flxInterfaceMonitor *m, flxInterfaceAddress *a) {
54 g_assert(a->interface);
56 FLX_LLIST_REMOVE(flxInterfaceAddress, address, a->interface->addresses, a);
57 flx_server_remove(m->server, a->rr_id);
62 static void free_interface(flxInterfaceMonitor *m, flxInterface *i) {
66 flx_goodbye_interface(m->server, i, FALSE);
67 g_assert(!i->announcements);
70 free_address(m, i->addresses);
72 flx_packet_scheduler_free(i->scheduler);
73 flx_cache_free(i->cache);
75 FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i);
76 FLX_LLIST_REMOVE(flxInterface, by_hardware, i->hardware->interfaces, i);
81 static void free_hw_interface(flxInterfaceMonitor *m, flxHwInterface *hw) {
85 while (hw->interfaces)
86 free_interface(m, hw->interfaces);
88 FLX_LLIST_REMOVE(flxHwInterface, hardware, m->hw_interfaces, hw);
89 g_hash_table_remove(m->hash_table, &hw->index);
95 static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) {
96 flxInterfaceAddress *ia;
102 for (ia = i->addresses; ia; ia = ia->address_next)
103 if (flx_address_cmp(&ia->address, raddr) == 0)
109 static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) {
111 struct rtgenmsg *gen;
114 memset(&req, 0, sizeof(req));
115 n = (struct nlmsghdr*) req;
116 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
117 n->nlmsg_type = type;
118 n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
122 memset(gen, 0, sizeof(struct rtgenmsg));
123 gen->rtgen_family = AF_UNSPEC;
125 return flx_netlink_send(nl, n, ret_seq);
128 static void new_interface(flxInterfaceMonitor *m, flxHwInterface *hw, guchar protocol) {
133 g_assert(protocol != AF_UNSPEC);
135 i = g_new(flxInterface, 1);
138 i->protocol = protocol;
141 FLX_LLIST_HEAD_INIT(flxInterfaceAddress, i->addresses);
142 FLX_LLIST_HEAD_INIT(flxAnnouncement, i->announcements);
144 i->cache = flx_cache_new(m->server, i);
145 i->scheduler = flx_packet_scheduler_new(m->server, i);
147 FLX_LLIST_PREPEND(flxInterface, by_hardware, hw->interfaces, i);
148 FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i);
151 static void check_interface_relevant(flxInterfaceMonitor *m, flxInterface *i) {
156 b = flx_interface_relevant(i);
158 if (b && !i->relevant) {
159 g_message("New relevant interface %s.%i", i->hardware->name, i->protocol);
161 flx_announce_interface(m->server, i);
162 } else if (!b && i->relevant) {
163 g_message("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
165 flx_goodbye_interface(m->server, i, FALSE);
171 static void check_hw_interface_relevant(flxInterfaceMonitor *m, flxHwInterface *hw) {
177 for (i = hw->interfaces; i; i = i->by_hardware_next)
178 check_interface_relevant(m, i);
181 static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
182 flxInterfaceMonitor *m = userdata;
186 g_assert(m->netlink == nl);
188 if (n->nlmsg_type == RTM_NEWLINK) {
189 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
191 struct rtattr *a = NULL;
194 if (ifinfomsg->ifi_family != AF_UNSPEC)
197 if (!(hw = g_hash_table_lookup(m->hash_table, &ifinfomsg->ifi_index))) {
198 hw = g_new(flxHwInterface, 1);
203 hw->index = ifinfomsg->ifi_index;
205 FLX_LLIST_HEAD_INIT(flxInterface, hw->interfaces);
206 FLX_LLIST_PREPEND(flxHwInterface, hardware, m->hw_interfaces, hw);
208 g_hash_table_insert(m->hash_table, &hw->index, hw);
210 if (m->server->fd_ipv4 >= 0)
211 new_interface(m, hw, AF_INET);
212 if (m->server->fd_ipv6 >= 0)
213 new_interface(m, hw, AF_INET6);
216 hw->flags = ifinfomsg->ifi_flags;
218 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
219 a = IFLA_RTA(ifinfomsg);
221 while (RTA_OK(a, l)) {
222 switch(a->rta_type) {
225 hw->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
229 g_assert(RTA_PAYLOAD(a) == sizeof(unsigned int));
230 hw->mtu = *((unsigned int*) RTA_DATA(a));
240 update_hw_interface_rr(m, hw, FALSE);
241 check_hw_interface_relevant(m, hw);
243 } else if (n->nlmsg_type == RTM_DELLINK) {
244 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
248 if (ifinfomsg->ifi_family != AF_UNSPEC)
251 if (!(hw = flx_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index)))
254 update_hw_interface_rr(m, hw, TRUE);
255 free_hw_interface(m, hw);
257 } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
259 struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
261 struct rtattr *a = NULL;
266 if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
269 if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index, ifaddrmsg->ifa_family)))
272 raddr.family = ifaddrmsg->ifa_family;
274 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
275 a = IFA_RTA(ifaddrmsg);
277 while (RTA_OK(a, l)) {
278 switch(a->rta_type) {
280 if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
281 (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
284 memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
300 if (n->nlmsg_type == RTM_NEWADDR) {
301 flxInterfaceAddress *addr;
303 if (!(addr = get_address(m, i, &raddr))) {
304 addr = g_new(flxInterfaceAddress, 1);
306 addr->address = raddr;
310 FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr);
313 addr->flags = ifaddrmsg->ifa_flags;
314 addr->scope = ifaddrmsg->ifa_scope;
316 update_address_rr(m, addr, FALSE);
317 check_interface_relevant(m, i);
319 flxInterfaceAddress *addr;
321 if (!(addr = get_address(m, i, &raddr)))
324 update_address_rr(m, addr, TRUE);
325 free_address(m, addr);
327 check_interface_relevant(m, i);
330 } else if (n->nlmsg_type == NLMSG_DONE) {
332 if (m->list == LIST_IFACE) {
335 if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0)
336 g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
342 } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
343 struct nlmsgerr *e = NLMSG_DATA (n);
346 g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
350 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) {
351 flxInterfaceMonitor *m = NULL;
353 m = g_new0(flxInterfaceMonitor, 1);
355 if (!(m->netlink = flx_netlink_new(s->context, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
358 m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
360 FLX_LLIST_HEAD_INIT(flxInterface, m->interfaces);
361 FLX_LLIST_HEAD_INIT(flxHwInterface, m->hw_interfaces);
363 if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
366 m->list = LIST_IFACE;
371 flx_interface_monitor_free(m);
375 void flx_interface_monitor_free(flxInterfaceMonitor *m) {
379 flx_netlink_free(m->netlink);
381 while (m->hw_interfaces)
382 free_hw_interface(m, m->hw_interfaces);
384 g_assert(!m->interfaces);
387 g_hash_table_destroy(m->hash_table);
393 flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index, guchar protocol) {
399 g_assert(protocol != AF_UNSPEC);
401 if (!(hw = flx_interface_monitor_get_hw_interface(m, index)))
404 for (i = hw->interfaces; i; i = i->by_hardware_next)
405 if (i->protocol == protocol)
411 flxHwInterface* flx_interface_monitor_get_hw_interface(flxInterfaceMonitor *m, gint index) {
415 return g_hash_table_lookup(m->hash_table, &index);
419 void flx_interface_send_packet(flxInterface *i, flxDnsPacket *p) {
424 g_message("sending on '%s.%i'", i->hardware->name, i->protocol);
426 if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
427 flx_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p);
428 else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0)
429 flx_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p);
433 void flx_interface_post_query(flxInterface *i, flxKey *key) {
438 flx_packet_scheduler_post_query(i->scheduler, key);
442 void flx_interface_post_response(flxInterface *i, flxRecord *record) {
447 flx_packet_scheduler_post_response(i->scheduler, record);
450 void flx_dump_caches(flxInterfaceMonitor *m, FILE *f) {
454 for (i = m->interfaces; i; i = i->interface_next) {
456 fprintf(f, ";;; INTERFACE %s.%i ;;;\n", i->hardware->name, i->protocol);
457 flx_cache_dump(i->cache, f);
462 gboolean flx_interface_relevant(flxInterface *i) {
466 (i->hardware->flags & IFF_UP) &&
467 (i->hardware->flags & IFF_RUNNING) &&
468 !(i->hardware->flags & IFF_LOOPBACK) &&
469 (i->hardware->flags & IFF_MULTICAST) &&
473 gboolean flx_interface_address_relevant(flxInterfaceAddress *a) {
476 return a->scope == RT_SCOPE_UNIVERSE;
480 gboolean flx_interface_match(flxInterface *i, gint index, guchar protocol) {
483 if (index > 0 && index != i->hardware->index)
486 if (protocol != AF_UNSPEC && protocol != i->protocol)