Merge branch 'mingw-statbuf-size' into 'master'
[glib.git] / gio / gnetworkmonitornetlink.c
blobb308b3b659ffcda318814c575dfe832c3830251d
1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright 2011 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "config.h"
21 #include <errno.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include "gnetworkmonitornetlink.h"
26 #include "gcredentials.h"
27 #include "ginetaddressmask.h"
28 #include "ginitable.h"
29 #include "giomodule-priv.h"
30 #include "glibintl.h"
31 #include "glib/gstdio.h"
32 #include "gnetworkingprivate.h"
33 #include "gnetworkmonitor.h"
34 #include "gsocket.h"
35 #include "gunixcredentialsmessage.h"
37 /* must come at the end to pick system includes from
38 * gnetworkingprivate.h */
39 #include <linux/netlink.h>
40 #include <linux/rtnetlink.h>
42 static GInitableIface *initable_parent_iface;
43 static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *iface);
44 static void g_network_monitor_netlink_initable_iface_init (GInitableIface *iface);
46 struct _GNetworkMonitorNetlinkPrivate
48 GSocket *sock;
49 GSource *source, *dump_source;
50 GMainContext *context;
52 GPtrArray *dump_networks;
55 static gboolean read_netlink_messages (GSocket *socket,
56 GIOCondition condition,
57 gpointer user_data);
58 static gboolean request_dump (GNetworkMonitorNetlink *nl,
59 GError **error);
61 #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
62 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink, g_network_monitor_netlink, G_TYPE_NETWORK_MONITOR_BASE,
63 G_ADD_PRIVATE (GNetworkMonitorNetlink)
64 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
65 g_network_monitor_netlink_iface_init)
66 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
67 g_network_monitor_netlink_initable_iface_init)
68 _g_io_modules_ensure_extension_points_registered ();
69 g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
70 g_define_type_id,
71 "netlink",
72 20))
74 static void
75 g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl)
77 nl->priv = g_network_monitor_netlink_get_instance_private (nl);
80 static gboolean
81 g_network_monitor_netlink_initable_init (GInitable *initable,
82 GCancellable *cancellable,
83 GError **error)
85 GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable);
86 gint sockfd;
87 struct sockaddr_nl snl;
89 /* We create the socket the old-school way because sockaddr_netlink
90 * can't be represented as a GSocketAddress
92 sockfd = g_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, NULL);
93 if (sockfd == -1)
95 int errsv = errno;
96 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
97 _("Could not create network monitor: %s"),
98 g_strerror (errsv));
99 return FALSE;
102 snl.nl_family = AF_NETLINK;
103 snl.nl_pid = snl.nl_pad = 0;
104 snl.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
105 if (bind (sockfd, (struct sockaddr *)&snl, sizeof (snl)) != 0)
107 int errsv = errno;
108 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
109 _("Could not create network monitor: %s"),
110 g_strerror (errsv));
111 (void) g_close (sockfd, NULL);
112 return FALSE;
115 nl->priv->sock = g_socket_new_from_fd (sockfd, error);
116 if (error)
118 g_prefix_error (error, "%s", _("Could not create network monitor: "));
119 (void) g_close (sockfd, NULL);
120 return FALSE;
123 if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED,
124 TRUE, NULL))
126 int errsv = errno;
127 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
128 _("Could not create network monitor: %s"),
129 g_strerror (errsv));
130 return FALSE;
133 /* Request the current state */
134 if (!request_dump (nl, error))
135 return FALSE;
137 /* And read responses; since we haven't yet marked the socket
138 * non-blocking, each call will block until a message is received.
140 while (nl->priv->dump_networks)
142 if (!read_netlink_messages (NULL, G_IO_IN, nl))
143 break;
146 g_socket_set_blocking (nl->priv->sock, FALSE);
147 nl->priv->context = g_main_context_ref_thread_default ();
148 nl->priv->source = g_socket_create_source (nl->priv->sock, G_IO_IN, NULL);
149 g_source_set_callback (nl->priv->source,
150 (GSourceFunc) read_netlink_messages, nl, NULL);
151 g_source_attach (nl->priv->source, nl->priv->context);
153 return initable_parent_iface->init (initable, cancellable, error);
156 static gboolean
157 request_dump (GNetworkMonitorNetlink *nl,
158 GError **error)
160 struct nlmsghdr *n;
161 struct rtgenmsg *gen;
162 gchar buf[NLMSG_SPACE (sizeof (*gen))];
164 memset (buf, 0, sizeof (buf));
165 n = (struct nlmsghdr*) buf;
166 n->nlmsg_len = NLMSG_LENGTH (sizeof (*gen));
167 n->nlmsg_type = RTM_GETROUTE;
168 n->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
169 n->nlmsg_pid = 0;
170 gen = NLMSG_DATA (n);
171 gen->rtgen_family = AF_UNSPEC;
173 if (g_socket_send (nl->priv->sock, buf, sizeof (buf),
174 NULL, error) < 0)
176 g_prefix_error (error, "%s", _("Could not get network status: "));
177 return FALSE;
180 nl->priv->dump_networks = g_ptr_array_new_with_free_func (g_object_unref);
181 return TRUE;
184 static gboolean
185 timeout_request_dump (gpointer user_data)
187 GNetworkMonitorNetlink *nl = user_data;
189 g_source_destroy (nl->priv->dump_source);
190 g_source_unref (nl->priv->dump_source);
191 nl->priv->dump_source = NULL;
193 request_dump (nl, NULL);
195 return FALSE;
198 static void
199 queue_request_dump (GNetworkMonitorNetlink *nl)
201 if (nl->priv->dump_networks)
202 return;
204 if (nl->priv->dump_source)
206 g_source_destroy (nl->priv->dump_source);
207 g_source_unref (nl->priv->dump_source);
210 nl->priv->dump_source = g_timeout_source_new_seconds (1);
211 g_source_set_callback (nl->priv->dump_source,
212 (GSourceFunc) timeout_request_dump, nl, NULL);
213 g_source_attach (nl->priv->dump_source, nl->priv->context);
216 static GInetAddressMask *
217 create_inet_address_mask (GSocketFamily family,
218 const guint8 *dest,
219 gsize dest_len)
221 GInetAddress *dest_addr;
222 GInetAddressMask *network;
224 if (dest)
225 dest_addr = g_inet_address_new_from_bytes (dest, family);
226 else
227 dest_addr = g_inet_address_new_any (family);
228 network = g_inet_address_mask_new (dest_addr, dest_len, NULL);
229 g_object_unref (dest_addr);
231 return network;
234 static void
235 add_network (GNetworkMonitorNetlink *nl,
236 GSocketFamily family,
237 const guint8 *dest,
238 gsize dest_len)
240 GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len);
241 g_return_if_fail (network != NULL);
243 if (nl->priv->dump_networks)
244 g_ptr_array_add (nl->priv->dump_networks, g_object_ref (network));
245 else
246 g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network);
248 g_object_unref (network);
251 static void
252 remove_network (GNetworkMonitorNetlink *nl,
253 GSocketFamily family,
254 const guint8 *dest,
255 gsize dest_len)
257 GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len);
258 g_return_if_fail (network != NULL);
260 if (nl->priv->dump_networks)
262 GInetAddressMask **dump_networks = (GInetAddressMask **)nl->priv->dump_networks->pdata;
263 int i;
265 for (i = 0; i < nl->priv->dump_networks->len; i++)
267 if (g_inet_address_mask_equal (network, dump_networks[i]))
268 g_ptr_array_remove_index_fast (nl->priv->dump_networks, i--);
271 else
273 g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl), network);
276 g_object_unref (network);
279 static void
280 finish_dump (GNetworkMonitorNetlink *nl)
282 g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl),
283 (GInetAddressMask **)nl->priv->dump_networks->pdata,
284 nl->priv->dump_networks->len);
285 g_ptr_array_free (nl->priv->dump_networks, TRUE);
286 nl->priv->dump_networks = NULL;
289 static gboolean
290 read_netlink_messages (GSocket *socket,
291 GIOCondition condition,
292 gpointer user_data)
294 GNetworkMonitorNetlink *nl = user_data;
295 GInputVector iv;
296 gssize len;
297 gint flags;
298 GError *error = NULL;
299 GSocketAddress *addr = NULL;
300 struct nlmsghdr *msg;
301 struct rtmsg *rtmsg;
302 struct rtattr *attr;
303 struct sockaddr_nl source_sockaddr;
304 gsize attrlen;
305 guint8 *dest, *gateway, *oif;
306 gboolean retval = TRUE;
308 iv.buffer = NULL;
309 iv.size = 0;
311 flags = MSG_PEEK | MSG_TRUNC;
312 len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1,
313 NULL, NULL, &flags, NULL, &error);
314 if (len < 0)
316 g_warning ("Error on netlink socket: %s", error->message);
317 g_clear_error (&error);
318 retval = FALSE;
319 goto done;
322 iv.buffer = g_malloc (len);
323 iv.size = len;
324 len = g_socket_receive_message (nl->priv->sock, &addr, &iv, 1,
325 NULL, NULL, NULL, NULL, &error);
326 if (len < 0)
328 g_warning ("Error on netlink socket: %s", error->message);
329 g_clear_error (&error);
330 retval = FALSE;
331 goto done;
334 if (!g_socket_address_to_native (addr, &source_sockaddr, sizeof (source_sockaddr), &error))
336 g_warning ("Error on netlink socket: %s", error->message);
337 g_clear_error (&error);
338 retval = FALSE;
339 goto done;
342 /* If the sender port id is 0 (not fakeable) then the message is from the kernel */
343 if (source_sockaddr.nl_pid != 0)
344 goto done;
346 msg = (struct nlmsghdr *) iv.buffer;
347 for (; len > 0; msg = NLMSG_NEXT (msg, len))
349 if (!NLMSG_OK (msg, (size_t) len))
351 g_warning ("netlink message was truncated; shouldn't happen...");
352 retval = FALSE;
353 goto done;
356 switch (msg->nlmsg_type)
358 case RTM_NEWROUTE:
359 case RTM_DELROUTE:
360 rtmsg = NLMSG_DATA (msg);
362 if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6)
363 continue;
364 if (rtmsg->rtm_type == RTN_UNREACHABLE)
365 continue;
367 attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg));
368 attr = RTM_RTA (rtmsg);
369 dest = gateway = oif = NULL;
370 while (RTA_OK (attr, attrlen))
372 if (attr->rta_type == RTA_DST)
373 dest = RTA_DATA (attr);
374 else if (attr->rta_type == RTA_GATEWAY)
375 gateway = RTA_DATA (attr);
376 else if (attr->rta_type == RTA_OIF)
377 oif = RTA_DATA (attr);
378 attr = RTA_NEXT (attr, attrlen);
381 if (dest || gateway || oif)
383 /* Unless we're processing the results of a dump, ignore
384 * IPv6 link-local multicast routes, which are added and
385 * removed all the time for some reason.
387 #define UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL(a) \
388 ((a[0] == 0xff) && ((a[1] & 0xf) == 0x2))
390 if (!nl->priv->dump_networks &&
391 rtmsg->rtm_family == AF_INET6 &&
392 rtmsg->rtm_dst_len != 0 &&
393 UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL (dest))
394 continue;
396 if (msg->nlmsg_type == RTM_NEWROUTE)
397 add_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
398 else
399 remove_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
400 queue_request_dump (nl);
402 break;
404 case NLMSG_DONE:
405 finish_dump (nl);
406 goto done;
408 case NLMSG_ERROR:
410 struct nlmsgerr *e = NLMSG_DATA (msg);
412 g_warning ("netlink error: %s", g_strerror (-e->error));
414 retval = FALSE;
415 goto done;
417 default:
418 g_warning ("unexpected netlink message %d", msg->nlmsg_type);
419 retval = FALSE;
420 goto done;
424 done:
425 g_free (iv.buffer);
426 g_clear_object (&addr);
428 if (!retval && nl->priv->dump_networks)
429 finish_dump (nl);
430 return retval;
433 static void
434 g_network_monitor_netlink_finalize (GObject *object)
436 GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object);
438 if (nl->priv->sock)
440 g_socket_close (nl->priv->sock, NULL);
441 g_object_unref (nl->priv->sock);
444 if (nl->priv->source)
446 g_source_destroy (nl->priv->source);
447 g_source_unref (nl->priv->source);
450 if (nl->priv->dump_source)
452 g_source_destroy (nl->priv->dump_source);
453 g_source_unref (nl->priv->dump_source);
456 g_clear_pointer (&nl->priv->context, g_main_context_unref);
457 g_clear_pointer (&nl->priv->dump_networks, g_ptr_array_unref);
459 G_OBJECT_CLASS (g_network_monitor_netlink_parent_class)->finalize (object);
462 static void
463 g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class)
465 GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
467 gobject_class->finalize = g_network_monitor_netlink_finalize;
470 static void
471 g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface)
475 static void
476 g_network_monitor_netlink_initable_iface_init (GInitableIface *iface)
478 initable_parent_iface = g_type_interface_peek_parent (iface);
480 iface->init = g_network_monitor_netlink_initable_init;