2 #include <sys/socket.h>
4 #include <linux/netlink.h>
5 #include <linux/rtnetlink.h>
12 static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, int remove) {
16 if (!flx_address_is_relevant(a) || remove) {
18 flx_server_remove(m->server, a->rr_id);
23 a->rr_id = flx_server_get_next_id(m->server);
24 flx_server_add_address(m->server, a->rr_id, a->interface->index, AF_UNSPEC, FALSE, m->server->hostname, &a->address);
29 static void update_interface_rr(flxInterfaceMonitor *m, flxInterface *i, int remove) {
30 flxInterfaceAddress *a;
34 for (a = i->addresses; a; a = a->address_next)
35 update_address_rr(m, a, remove);
38 static void free_address(flxInterfaceMonitor *m, flxInterfaceAddress *a) {
41 g_assert(a->interface);
43 if (a->address.family == AF_INET)
44 a->interface->n_ipv4_addrs --;
45 else if (a->address.family == AF_INET6)
46 a->interface->n_ipv6_addrs --;
48 FLX_LLIST_REMOVE(flxInterfaceAddress, address, a->interface->addresses, a);
50 flx_server_remove(m->server, a->rr_id);
55 static void free_interface(flxInterfaceMonitor *m, flxInterface *i) {
60 free_address(m, i->addresses);
63 flx_cache_free(i->ipv4_cache);
65 flx_cache_free(i->ipv6_cache);
67 g_assert(i->n_ipv6_addrs == 0);
68 g_assert(i->n_ipv4_addrs == 0);
70 FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i);
71 g_hash_table_remove(m->hash_table, &i->index);
73 flx_cache_free(i->ipv4_cache);
74 flx_cache_free(i->ipv6_cache);
80 static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) {
81 flxInterfaceAddress *ia;
87 for (ia = i->addresses; ia; ia = ia->address_next)
88 if (flx_address_cmp(&ia->address, raddr) == 0)
94 static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) {
99 memset(&req, 0, sizeof(req));
100 n = (struct nlmsghdr*) req;
101 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
102 n->nlmsg_type = type;
103 n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
107 memset(gen, 0, sizeof(struct rtgenmsg));
108 gen->rtgen_family = AF_UNSPEC;
110 return flx_netlink_send(nl, n, ret_seq);
113 static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
114 flxInterfaceMonitor *m = userdata;
118 g_assert(m->netlink == nl);
120 if (n->nlmsg_type == RTM_NEWLINK) {
121 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
123 struct rtattr *a = NULL;
127 if (ifinfomsg->ifi_family != AF_UNSPEC)
130 if ((i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
133 i = g_new(flxInterface, 1);
136 i->index = ifinfomsg->ifi_index;
138 i->n_ipv4_addrs = i->n_ipv6_addrs = 0;
139 FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i);
140 g_hash_table_insert(m->hash_table, &i->index, i);
141 i->ipv4_cache = flx_cache_new(m->server, i);
142 i->ipv6_cache = flx_cache_new(m->server, i);
147 i->flags = ifinfomsg->ifi_flags;
149 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
150 a = IFLA_RTA(ifinfomsg);
152 while (RTA_OK(a, l)) {
153 switch(a->rta_type) {
156 i->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a));
166 update_interface_rr(m, i, 0);
167 } else if (n->nlmsg_type == RTM_DELLINK) {
168 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
171 if (ifinfomsg->ifi_family != AF_UNSPEC)
174 if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
177 update_interface_rr(m, i, 1);
178 free_interface(m, i);
180 } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
182 struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
184 struct rtattr *a = NULL;
190 if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
193 if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index)))
196 raddr.family = ifaddrmsg->ifa_family;
198 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
199 a = IFA_RTA(ifaddrmsg);
201 while (RTA_OK(a, l)) {
202 switch(a->rta_type) {
204 if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
205 (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
208 memcpy(raddr.data, RTA_DATA(a), RTA_PAYLOAD(a));
224 if (n->nlmsg_type == RTM_NEWADDR) {
225 flxInterfaceAddress *addr;
227 if ((addr = get_address(m, i, &raddr)))
230 addr = g_new(flxInterfaceAddress, 1);
231 addr->address = raddr;
234 if (raddr.family == AF_INET)
236 else if (raddr.family == AF_INET6)
241 FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr);
246 addr->flags = ifaddrmsg->ifa_flags;
247 addr->scope = ifaddrmsg->ifa_scope;
249 update_address_rr(m, addr, 0);
251 flxInterfaceAddress *addr;
253 if (!(addr = get_address(m, i, &raddr)))
256 update_address_rr(m, addr, 1);
257 free_address(m, addr);
260 } else if (n->nlmsg_type == NLMSG_DONE) {
262 if (m->list == LIST_IFACE) {
265 if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) {
266 g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
272 } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
273 struct nlmsgerr *e = NLMSG_DATA (n);
276 g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
280 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) {
281 flxInterfaceMonitor *m = NULL;
283 m = g_new0(flxInterfaceMonitor, 1);
285 if (!(m->netlink = flx_netlink_new(s->context, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
288 m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
289 m->interfaces = NULL;
291 if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
294 m->list = LIST_IFACE;
299 flx_interface_monitor_free(m);
303 void flx_interface_monitor_free(flxInterfaceMonitor *m) {
307 flx_netlink_free(m->netlink);
310 g_hash_table_destroy(m->hash_table);
316 flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) {
320 return g_hash_table_lookup(m->hash_table, &index);
323 flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) {
325 return m->interfaces;
328 int flx_interface_is_relevant(flxInterface *i) {
332 (i->flags & IFF_UP) &&
333 (i->flags & IFF_RUNNING) &&
334 !(i->flags & IFF_LOOPBACK);
337 int flx_address_is_relevant(flxInterfaceAddress *a) {
341 a->scope == RT_SCOPE_UNIVERSE &&
342 flx_interface_is_relevant(a->interface);
345 void flx_interface_send_query(flxInterface *i, guchar protocol, flxKey *k) {