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, 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->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 --;
49 a->prev->next = a->next;
51 a->interface->addresses = a->next;
54 a->next->prev = a->prev;
59 static void free_interface(flxInterfaceMonitor *m, flxInterface *i) {
64 free_address(m, i->addresses);
66 g_assert(i->n_ipv6_addrs == 0);
67 g_assert(i->n_ipv4_addrs == 0);
70 i->prev->next = i->next;
72 m->interfaces = i->next;
75 i->next->prev = i->prev;
77 g_hash_table_remove(m->hash_table, &i->index);
83 static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) {
84 flxInterfaceAddress *ia;
90 for (ia = i->addresses; ia; ia = ia->next)
91 if (flx_address_cmp(&ia->address, raddr) == 0)
97 static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) {
102 memset(&req, 0, sizeof(req));
103 n = (struct nlmsghdr*) req;
104 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
105 n->nlmsg_type = type;
106 n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
110 memset(gen, 0, sizeof(struct rtgenmsg));
111 gen->rtgen_family = AF_UNSPEC;
113 return flx_netlink_send(nl, n, ret_seq);
116 static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
117 flxInterfaceMonitor *m = userdata;
121 g_assert(m->netlink == nl);
123 if (n->nlmsg_type == RTM_NEWLINK) {
124 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
126 struct rtattr *a = NULL;
130 if (ifinfomsg->ifi_family != AF_UNSPEC)
133 if ((i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index)))
136 i = g_new(flxInterface, 1);
138 i->index = ifinfomsg->ifi_index;
140 i->n_ipv4_addrs = i->n_ipv6_addrs = 0;
141 if ((i->next = m->interfaces))
145 g_hash_table_insert(m->hash_table, &i->index, 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;
235 if (raddr.family == AF_INET)
237 else if (raddr.family == AF_INET6)
241 if ((addr->next = i->addresses))
242 addr->next->prev = addr;
250 addr->flags = ifaddrmsg->ifa_flags;
251 addr->scope = ifaddrmsg->ifa_scope;
253 update_address_rr(m, addr, 0);
255 flxInterfaceAddress *addr;
257 if (!(addr = get_address(m, i, &raddr)))
260 update_address_rr(m, addr, 1);
261 free_address(m, addr);
264 } else if (n->nlmsg_type == NLMSG_DONE) {
266 if (m->list == LIST_IFACE) {
269 if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) {
270 g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
276 } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
277 struct nlmsgerr *e = NLMSG_DATA (n);
280 g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
284 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) {
285 flxInterfaceMonitor *m = NULL;
287 m = g_new0(flxInterfaceMonitor, 1);
289 if (!(m->netlink = flx_netlink_new(s->context, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
292 m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
293 m->interfaces = NULL;
295 if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
298 m->list = LIST_IFACE;
303 flx_interface_monitor_free(m);
307 void flx_interface_monitor_free(flxInterfaceMonitor *m) {
311 flx_netlink_free(m->netlink);
314 g_hash_table_destroy(m->hash_table);
320 const flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) {
324 return g_hash_table_lookup(m->hash_table, &index);
327 const flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) {
329 return m->interfaces;
332 int flx_interface_is_relevant(flxInterface *i) {
336 (i->flags & IFF_UP) &&
337 (i->flags & IFF_RUNNING) &&
338 !(i->flags & IFF_LOOPBACK);
341 int flx_address_is_relevant(flxInterfaceAddress *a) {
345 a->scope == RT_SCOPE_UNIVERSE &&
346 flx_interface_is_relevant(a->interface);