2 #include <sys/socket.h>
4 #include <linux/netlink.h>
5 #include <linux/rtnetlink.h>
14 static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, int remove) {
18 if (!flx_address_is_relevant(a) || remove) {
20 flx_server_remove(m->server, a->rr_id);
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);
31 static void update_interface_rr(flxInterfaceMonitor *m, flxInterface *i, int remove) {
32 flxInterfaceAddress *a;
36 for (a = i->addresses; a; a = a->address_next)
37 update_address_rr(m, a, remove);
40 static void free_address(flxInterfaceMonitor *m, flxInterfaceAddress *a) {
43 g_assert(a->interface);
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 --;
50 FLX_LLIST_REMOVE(flxInterfaceAddress, address, a->interface->addresses, a);
52 flx_server_remove(m->server, a->rr_id);
57 static void free_interface(flxInterfaceMonitor *m, flxInterface *i) {
61 if (i->ipv4_scheduler)
62 flx_packet_scheduler_free(i->ipv4_scheduler);
63 if (i->ipv6_scheduler)
64 flx_packet_scheduler_free(i->ipv6_scheduler);
67 free_address(m, i->addresses);
70 flx_cache_free(i->ipv4_cache);
72 flx_cache_free(i->ipv6_cache);
74 g_assert(i->n_ipv6_addrs == 0);
75 g_assert(i->n_ipv4_addrs == 0);
77 FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i);
78 g_hash_table_remove(m->hash_table, &i->index);
80 flx_cache_free(i->ipv4_cache);
81 flx_cache_free(i->ipv6_cache);
87 static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) {
88 flxInterfaceAddress *ia;
94 for (ia = i->addresses; ia; ia = ia->address_next)
95 if (flx_address_cmp(&ia->address, raddr) == 0)
101 static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) {
103 struct rtgenmsg *gen;
106 memset(&req, 0, sizeof(req));
107 n = (struct nlmsghdr*) req;
108 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
109 n->nlmsg_type = type;
110 n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
114 memset(gen, 0, sizeof(struct rtgenmsg));
115 gen->rtgen_family = AF_UNSPEC;
117 return flx_netlink_send(nl, n, ret_seq);
120 static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
121 flxInterfaceMonitor *m = userdata;
125 g_assert(m->netlink == nl);
127 if (n->nlmsg_type == RTM_NEWLINK) {
128 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
130 struct rtattr *a = NULL;
134 if (ifinfomsg->ifi_family != AF_UNSPEC)
137 if ((i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
140 i = g_new(flxInterface, 1);
143 i->index = ifinfomsg->ifi_index;
145 i->n_ipv4_addrs = i->n_ipv6_addrs = 0;
146 FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i);
147 g_hash_table_insert(m->hash_table, &i->index, i);
149 i->ipv4_cache = flx_cache_new(m->server, i);
150 i->ipv6_cache = flx_cache_new(m->server, i);
151 i->ipv4_scheduler = flx_packet_scheduler_new(m->server, i, AF_INET);
152 i->ipv6_scheduler = flx_packet_scheduler_new(m->server, i, AF_INET6);
157 i->flags = ifinfomsg->ifi_flags;
159 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
160 a = IFLA_RTA(ifinfomsg);
162 while (RTA_OK(a, l)) {
163 switch(a->rta_type) {
166 i->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
170 g_assert(RTA_PAYLOAD(a) == sizeof(unsigned int));
171 i->mtu = *((unsigned int*) RTA_DATA(a));
181 update_interface_rr(m, i, 0);
182 } else if (n->nlmsg_type == RTM_DELLINK) {
183 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
186 if (ifinfomsg->ifi_family != AF_UNSPEC)
189 if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
192 update_interface_rr(m, i, 1);
193 free_interface(m, i);
195 } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
197 struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
199 struct rtattr *a = NULL;
205 if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
208 if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index)))
211 raddr.family = ifaddrmsg->ifa_family;
213 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
214 a = IFA_RTA(ifaddrmsg);
216 while (RTA_OK(a, l)) {
217 switch(a->rta_type) {
219 if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
220 (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
223 memcpy(raddr.data, RTA_DATA(a), RTA_PAYLOAD(a));
239 if (n->nlmsg_type == RTM_NEWADDR) {
240 flxInterfaceAddress *addr;
242 if ((addr = get_address(m, i, &raddr)))
245 addr = g_new(flxInterfaceAddress, 1);
246 addr->address = raddr;
249 if (raddr.family == AF_INET)
251 else if (raddr.family == AF_INET6)
256 FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr);
261 addr->flags = ifaddrmsg->ifa_flags;
262 addr->scope = ifaddrmsg->ifa_scope;
264 update_address_rr(m, addr, 0);
266 flxInterfaceAddress *addr;
268 if (!(addr = get_address(m, i, &raddr)))
271 update_address_rr(m, addr, 1);
272 free_address(m, addr);
275 } else if (n->nlmsg_type == NLMSG_DONE) {
277 if (m->list == LIST_IFACE) {
280 if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) {
281 g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
287 } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
288 struct nlmsgerr *e = NLMSG_DATA (n);
291 g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
295 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) {
296 flxInterfaceMonitor *m = NULL;
298 m = g_new0(flxInterfaceMonitor, 1);
300 if (!(m->netlink = flx_netlink_new(s->context, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
303 m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
304 m->interfaces = NULL;
306 if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
309 m->list = LIST_IFACE;
314 flx_interface_monitor_free(m);
318 void flx_interface_monitor_free(flxInterfaceMonitor *m) {
322 flx_netlink_free(m->netlink);
325 g_hash_table_destroy(m->hash_table);
331 flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) {
335 return g_hash_table_lookup(m->hash_table, &index);
338 flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) {
340 return m->interfaces;
343 int flx_interface_is_relevant(flxInterface *i) {
347 (i->flags & IFF_UP) &&
348 (i->flags & IFF_RUNNING) &&
349 !(i->flags & IFF_LOOPBACK);
352 int flx_address_is_relevant(flxInterfaceAddress *a) {
356 a->scope == RT_SCOPE_UNIVERSE &&
357 flx_interface_is_relevant(a->interface);
360 void flx_interface_send_packet(flxInterface *i, guchar protocol, flxDnsPacket *p) {
364 if (!flx_interface_is_relevant(i))
367 if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0) {
368 g_message("sending on '%s':IPv4", i->name);
369 flx_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->index, p);
372 if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0) {
373 g_message("sending on '%s':IPv6", i->name);
374 flx_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->index, p);
378 void flx_interface_post_query(flxInterface *i, guchar protocol, flxKey *k) {
382 if (!flx_interface_is_relevant(i))
385 if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0)
386 flx_packet_scheduler_post_query(i->ipv4_scheduler, k);
388 if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0)
389 flx_packet_scheduler_post_query(i->ipv6_scheduler, k);
392 void flx_interface_post_response(flxInterface *i, guchar protocol, flxRecord *rr) {
396 if (!flx_interface_is_relevant(i))
399 if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0)
400 flx_packet_scheduler_post_response(i->ipv4_scheduler, rr);
402 if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0)
403 flx_packet_scheduler_post_response(i->ipv6_scheduler, rr);
406 void flx_dump_caches(flxServer *s, FILE *f) {
410 for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next) {
411 if (!flx_interface_is_relevant(i))
414 if (i->n_ipv4_addrs > 0) {
415 fprintf(f, ";;; INTERFACE %s; IPv4 ;;;\n", i->name);
416 flx_cache_dump(i->ipv4_cache, f);
419 if (i->n_ipv6_addrs > 0) {
420 fprintf(f, ";;; INTERFACE %s; IPv6 ;;;\n", i->name);
421 flx_cache_dump(i->ipv6_cache, f);