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) {
62 free_address(m, i->addresses);
65 flx_cache_free(i->ipv4_cache);
67 flx_cache_free(i->ipv6_cache);
69 g_assert(i->n_ipv6_addrs == 0);
70 g_assert(i->n_ipv4_addrs == 0);
72 FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i);
73 g_hash_table_remove(m->hash_table, &i->index);
75 flx_cache_free(i->ipv4_cache);
76 flx_cache_free(i->ipv6_cache);
82 static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) {
83 flxInterfaceAddress *ia;
89 for (ia = i->addresses; ia; ia = ia->address_next)
90 if (flx_address_cmp(&ia->address, raddr) == 0)
96 static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) {
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;
109 memset(gen, 0, sizeof(struct rtgenmsg));
110 gen->rtgen_family = AF_UNSPEC;
112 return flx_netlink_send(nl, n, ret_seq);
115 static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
116 flxInterfaceMonitor *m = userdata;
120 g_assert(m->netlink == nl);
122 if (n->nlmsg_type == RTM_NEWLINK) {
123 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
125 struct rtattr *a = NULL;
129 if (ifinfomsg->ifi_family != AF_UNSPEC)
132 if ((i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
135 i = g_new(flxInterface, 1);
138 i->index = ifinfomsg->ifi_index;
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);
149 i->flags = ifinfomsg->ifi_flags;
151 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
152 a = IFLA_RTA(ifinfomsg);
154 while (RTA_OK(a, l)) {
155 switch(a->rta_type) {
158 i->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
168 update_interface_rr(m, i, 0);
169 } else if (n->nlmsg_type == RTM_DELLINK) {
170 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
173 if (ifinfomsg->ifi_family != AF_UNSPEC)
176 if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
179 update_interface_rr(m, i, 1);
180 free_interface(m, i);
182 } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
184 struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
186 struct rtattr *a = NULL;
192 if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
195 if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index)))
198 raddr.family = ifaddrmsg->ifa_family;
200 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
201 a = IFA_RTA(ifaddrmsg);
203 while (RTA_OK(a, l)) {
204 switch(a->rta_type) {
206 if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
207 (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
210 memcpy(raddr.data, RTA_DATA(a), RTA_PAYLOAD(a));
226 if (n->nlmsg_type == RTM_NEWADDR) {
227 flxInterfaceAddress *addr;
229 if ((addr = get_address(m, i, &raddr)))
232 addr = g_new(flxInterfaceAddress, 1);
233 addr->address = raddr;
236 if (raddr.family == AF_INET)
238 else if (raddr.family == AF_INET6)
243 FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr);
248 addr->flags = ifaddrmsg->ifa_flags;
249 addr->scope = ifaddrmsg->ifa_scope;
251 update_address_rr(m, addr, 0);
253 flxInterfaceAddress *addr;
255 if (!(addr = get_address(m, i, &raddr)))
258 update_address_rr(m, addr, 1);
259 free_address(m, addr);
262 } else if (n->nlmsg_type == NLMSG_DONE) {
264 if (m->list == LIST_IFACE) {
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));
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);
278 g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
282 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) {
283 flxInterfaceMonitor *m = NULL;
285 m = g_new0(flxInterfaceMonitor, 1);
287 if (!(m->netlink = flx_netlink_new(s->context, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
290 m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
291 m->interfaces = NULL;
293 if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
296 m->list = LIST_IFACE;
301 flx_interface_monitor_free(m);
305 void flx_interface_monitor_free(flxInterfaceMonitor *m) {
309 flx_netlink_free(m->netlink);
312 g_hash_table_destroy(m->hash_table);
318 flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) {
322 return g_hash_table_lookup(m->hash_table, &index);
325 flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) {
327 return m->interfaces;
330 int flx_interface_is_relevant(flxInterface *i) {
334 (i->flags & IFF_UP) &&
335 (i->flags & IFF_RUNNING) &&
336 !(i->flags & IFF_LOOPBACK);
339 int flx_address_is_relevant(flxInterfaceAddress *a) {
343 a->scope == RT_SCOPE_UNIVERSE &&
344 flx_interface_is_relevant(a->interface);
347 void flx_interface_send_packet(flxInterface *i, guchar protocol, flxDnsPacket *p) {
351 if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0 && flx_interface_is_relevant(i)) {
352 g_message("sending on '%s':IPv4", i->name);
353 flx_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->index, p);
356 if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0 && flx_interface_is_relevant(i)) {
357 g_message("sending on '%s':IPv6", i->name);
358 flx_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->index, p);
362 void flx_interface_send_query(flxInterface *i, guchar protocol, flxKey *k) {
368 p = flx_dns_packet_new();
369 flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
370 flx_dns_packet_append_key(p, k);
371 flx_dns_packet_set_field(p, DNS_FIELD_QDCOUNT, 1);
372 flx_interface_send_packet(i, protocol, p);
373 flx_dns_packet_free(p);
376 void flx_interface_send_response(flxInterface *i, guchar protocol, flxRecord *rr) {
382 p = flx_dns_packet_new();
383 flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
384 flx_dns_packet_append_record(p, rr, FALSE);
385 flx_dns_packet_set_field(p, DNS_FIELD_ANCOUNT, 1);
386 flx_interface_send_packet(i, protocol, p);
387 flx_dns_packet_free(p);
390 void flx_dump_caches(flxServer *s, FILE *f) {
394 for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next) {
395 if (!flx_interface_is_relevant(i))
398 if (i->n_ipv4_addrs > 0) {
399 fprintf(f, ";;; INTERFACE %s; IPv4 ;;;\n", i->name);
400 flx_cache_dump(i->ipv4_cache, f);
403 if (i->n_ipv6_addrs > 0) {
404 fprintf(f, ";;; INTERFACE %s; IPv6 ;;;\n", i->name);
405 flx_cache_dump(i->ipv6_cache, f);