Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright 2011 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include "config.h"
22 : :
23 : : #include <errno.h>
24 : : #include <string.h>
25 : : #include <unistd.h>
26 : : #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
27 : : #include <sys/sysctl.h>
28 : : #endif
29 : :
30 : : #include "gnetworkmonitornetlink.h"
31 : : #include "gcredentials.h"
32 : : #include "ginetaddressmask.h"
33 : : #include "ginitable.h"
34 : : #include "giomodule-priv.h"
35 : : #include "glibintl.h"
36 : : #include "glib/gstdio.h"
37 : : #include "gnetworkingprivate.h"
38 : : #include "gnetworkmonitor.h"
39 : : #include "gsocket.h"
40 : : #include "gunixcredentialsmessage.h"
41 : :
42 : : /* must come at the end to pick system includes from
43 : : * gnetworkingprivate.h */
44 : : #ifdef HAVE_LINUX_NETLINK_H
45 : : #include <linux/netlink.h>
46 : : #include <linux/rtnetlink.h>
47 : : #endif
48 : : #if defined(HAVE_NETLINK_NETLINK_H) && defined(HAVE_NETLINK_NETLINK_ROUTE_H)
49 : : #include <netlink/netlink.h>
50 : : #include <netlink/netlink_route.h>
51 : : #endif
52 : :
53 : : static GInitableIface *initable_parent_iface;
54 : : static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *iface);
55 : : static void g_network_monitor_netlink_initable_iface_init (GInitableIface *iface);
56 : :
57 : : struct _GNetworkMonitorNetlinkPrivate
58 : : {
59 : : GSocket *sock;
60 : : GSource *source, *dump_source;
61 : : GMainContext *context;
62 : :
63 : : GPtrArray *dump_networks;
64 : : };
65 : :
66 : : static gboolean read_netlink_messages (GNetworkMonitorNetlink *nl,
67 : : GError **error);
68 : : static gboolean read_netlink_messages_callback (GSocket *socket,
69 : : GIOCondition condition,
70 : : gpointer user_data);
71 : : static gboolean request_dump (GNetworkMonitorNetlink *nl,
72 : : GError **error);
73 : :
74 : : #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
75 : 549 : G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink, g_network_monitor_netlink, G_TYPE_NETWORK_MONITOR_BASE,
76 : : G_ADD_PRIVATE (GNetworkMonitorNetlink)
77 : : G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
78 : : g_network_monitor_netlink_iface_init)
79 : : G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
80 : : g_network_monitor_netlink_initable_iface_init)
81 : : _g_io_modules_ensure_extension_points_registered ();
82 : : g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
83 : : g_define_type_id,
84 : : "netlink",
85 : : 20))
86 : :
87 : : static void
88 : 44 : g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl)
89 : : {
90 : 44 : nl->priv = g_network_monitor_netlink_get_instance_private (nl);
91 : 44 : }
92 : :
93 : : static gboolean
94 : 44 : g_network_monitor_netlink_initable_init (GInitable *initable,
95 : : GCancellable *cancellable,
96 : : GError **error)
97 : : {
98 : 44 : GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable);
99 : : gint sockfd;
100 : : struct sockaddr_nl snl;
101 : :
102 : : /* We create the socket the old-school way because sockaddr_netlink
103 : : * can't be represented as a GSocketAddress
104 : : */
105 : 44 : sockfd = g_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, NULL);
106 : 44 : if (sockfd == -1)
107 : : {
108 : 0 : int errsv = errno;
109 : 0 : g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
110 : : _("Could not create network monitor: %s"),
111 : : g_strerror (errsv));
112 : 0 : return FALSE;
113 : : }
114 : :
115 : 44 : snl.nl_family = AF_NETLINK;
116 : 44 : snl.nl_pid = snl.nl_pad = 0;
117 : 44 : snl.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
118 : 44 : if (bind (sockfd, (struct sockaddr *)&snl, sizeof (snl)) != 0)
119 : : {
120 : 0 : int errsv = errno;
121 : 0 : g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
122 : : _("Could not create network monitor: %s"),
123 : : g_strerror (errsv));
124 : 0 : (void) g_close (sockfd, NULL);
125 : 0 : return FALSE;
126 : : }
127 : :
128 : 44 : nl->priv->sock = g_socket_new_from_fd (sockfd, error);
129 : 44 : if (!nl->priv->sock)
130 : : {
131 : 0 : g_prefix_error (error, "%s", _("Could not create network monitor: "));
132 : 0 : (void) g_close (sockfd, NULL);
133 : 0 : return FALSE;
134 : : }
135 : :
136 : : #ifdef SO_PASSCRED
137 : 44 : if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED,
138 : : TRUE, NULL))
139 : : {
140 : 0 : int errsv = errno;
141 : 0 : g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
142 : : _("Could not create network monitor: %s"),
143 : : g_strerror (errsv));
144 : 0 : return FALSE;
145 : : }
146 : : #endif
147 : :
148 : : /* Request the current state */
149 : 44 : if (!request_dump (nl, error))
150 : 0 : return FALSE;
151 : :
152 : : /* And read responses; since we haven't yet marked the socket
153 : : * non-blocking, each call will block until a message is received.
154 : : */
155 : 132 : while (nl->priv->dump_networks)
156 : : {
157 : 88 : GError *local_error = NULL;
158 : 88 : if (!read_netlink_messages (nl, &local_error))
159 : : {
160 : 0 : g_warning ("%s", local_error->message);
161 : 0 : g_clear_error (&local_error);
162 : 0 : break;
163 : : }
164 : : }
165 : :
166 : 44 : g_socket_set_blocking (nl->priv->sock, FALSE);
167 : 44 : nl->priv->context = g_main_context_ref_thread_default ();
168 : 44 : nl->priv->source = g_socket_create_source (nl->priv->sock, G_IO_IN, NULL);
169 : 44 : g_source_set_callback (nl->priv->source,
170 : : (GSourceFunc) read_netlink_messages_callback, nl, NULL);
171 : 44 : g_source_attach (nl->priv->source, nl->priv->context);
172 : :
173 : 44 : return initable_parent_iface->init (initable, cancellable, error);
174 : : }
175 : :
176 : : static gboolean
177 : 44 : request_dump (GNetworkMonitorNetlink *nl,
178 : : GError **error)
179 : : {
180 : : struct nlmsghdr *n;
181 : : struct rtgenmsg *gen;
182 : : gchar buf[NLMSG_SPACE (sizeof (*gen))];
183 : :
184 : 44 : memset (buf, 0, sizeof (buf));
185 : 44 : n = (struct nlmsghdr*) buf;
186 : 44 : n->nlmsg_len = NLMSG_LENGTH (sizeof (*gen));
187 : 44 : n->nlmsg_type = RTM_GETROUTE;
188 : 44 : n->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
189 : 44 : n->nlmsg_pid = 0;
190 : 44 : gen = NLMSG_DATA (n);
191 : 44 : gen->rtgen_family = AF_UNSPEC;
192 : :
193 : 44 : if (g_socket_send (nl->priv->sock, buf, sizeof (buf),
194 : : NULL, error) < 0)
195 : : {
196 : 0 : g_prefix_error (error, "%s", _("Could not get network status: "));
197 : 0 : return FALSE;
198 : : }
199 : :
200 : 44 : nl->priv->dump_networks = g_ptr_array_new_with_free_func (g_object_unref);
201 : 44 : return TRUE;
202 : : }
203 : :
204 : : static gboolean
205 : 0 : timeout_request_dump (gpointer user_data)
206 : : {
207 : 0 : GNetworkMonitorNetlink *nl = user_data;
208 : :
209 : 0 : g_source_destroy (nl->priv->dump_source);
210 : 0 : g_source_unref (nl->priv->dump_source);
211 : 0 : nl->priv->dump_source = NULL;
212 : :
213 : 0 : request_dump (nl, NULL);
214 : :
215 : 0 : return FALSE;
216 : : }
217 : :
218 : : static void
219 : 484 : queue_request_dump (GNetworkMonitorNetlink *nl)
220 : : {
221 : 484 : if (nl->priv->dump_networks)
222 : 484 : return;
223 : :
224 : 0 : if (nl->priv->dump_source)
225 : : {
226 : 0 : g_source_destroy (nl->priv->dump_source);
227 : 0 : g_source_unref (nl->priv->dump_source);
228 : : }
229 : :
230 : 0 : nl->priv->dump_source = g_timeout_source_new_seconds (1);
231 : 0 : g_source_set_callback (nl->priv->dump_source,
232 : : (GSourceFunc) timeout_request_dump, nl, NULL);
233 : 0 : g_source_attach (nl->priv->dump_source, nl->priv->context);
234 : : }
235 : :
236 : : static GInetAddressMask *
237 : 484 : create_inet_address_mask (GSocketFamily family,
238 : : const guint8 *dest,
239 : : gsize dest_len)
240 : : {
241 : : GInetAddress *dest_addr;
242 : : GInetAddressMask *network;
243 : :
244 : 484 : if (dest)
245 : 440 : dest_addr = g_inet_address_new_from_bytes (dest, family);
246 : : else
247 : 44 : dest_addr = g_inet_address_new_any (family);
248 : 484 : network = g_inet_address_mask_new (dest_addr, dest_len, NULL);
249 : 484 : g_object_unref (dest_addr);
250 : :
251 : 484 : return network;
252 : : }
253 : :
254 : : static void
255 : 484 : add_network (GNetworkMonitorNetlink *nl,
256 : : GSocketFamily family,
257 : : const guint8 *dest,
258 : : gsize dest_len)
259 : : {
260 : 484 : GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len);
261 : 484 : g_return_if_fail (network != NULL);
262 : :
263 : 484 : if (nl->priv->dump_networks)
264 : 484 : g_ptr_array_add (nl->priv->dump_networks, g_object_ref (network));
265 : : else
266 : 0 : g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network);
267 : :
268 : 484 : g_object_unref (network);
269 : : }
270 : :
271 : : static void
272 : 0 : remove_network (GNetworkMonitorNetlink *nl,
273 : : GSocketFamily family,
274 : : const guint8 *dest,
275 : : gsize dest_len)
276 : : {
277 : 0 : GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len);
278 : 0 : g_return_if_fail (network != NULL);
279 : :
280 : 0 : if (nl->priv->dump_networks)
281 : : {
282 : 0 : GInetAddressMask **dump_networks = (GInetAddressMask **)nl->priv->dump_networks->pdata;
283 : : guint i;
284 : :
285 : 0 : for (i = 0; i < nl->priv->dump_networks->len; i++)
286 : : {
287 : 0 : if (g_inet_address_mask_equal (network, dump_networks[i]))
288 : 0 : g_ptr_array_remove_index_fast (nl->priv->dump_networks, i--);
289 : : }
290 : : }
291 : : else
292 : : {
293 : 0 : g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl), network);
294 : : }
295 : :
296 : 0 : g_object_unref (network);
297 : : }
298 : :
299 : : static void
300 : 44 : finish_dump (GNetworkMonitorNetlink *nl)
301 : : {
302 : 44 : g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl),
303 : 44 : (GInetAddressMask **)nl->priv->dump_networks->pdata,
304 : 44 : nl->priv->dump_networks->len);
305 : 44 : g_ptr_array_free (nl->priv->dump_networks, TRUE);
306 : 44 : nl->priv->dump_networks = NULL;
307 : :
308 : : /* FreeBSD features "jailing" functionality, which can be approximated to
309 : : * Linux namespaces. A jail may or may not share the host's network stack,
310 : : * which includes routing tables.
311 : : * When jail runs in non-vnet mode and has a shared stack with the host,
312 : : * the kernel prevents jailed processes from getting full view on a routing
313 : : * table. This makes GNetworkManager believe that we're offline and return
314 : : * FALSE for the "available" property.
315 : : * To workaround this problem, do the same thing as GNetworkMonitorBase -
316 : : * add a fake network of 0 length.
317 : : */
318 : : #ifdef __FreeBSD__
319 : : gboolean is_jailed = FALSE;
320 : : gsize len = sizeof (is_jailed);
321 : :
322 : : if (sysctlbyname ("security.jail.jailed", &is_jailed, &len, NULL, 0) != 0)
323 : : return;
324 : :
325 : : if (!is_jailed)
326 : : return;
327 : :
328 : : if (is_jailed && !g_network_monitor_get_network_available (G_NETWORK_MONITOR (nl)))
329 : : {
330 : : GInetAddressMask *network;
331 : : network = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
332 : : g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network);
333 : : g_object_unref (network);
334 : : }
335 : : #endif
336 : 44 : }
337 : :
338 : : static gboolean
339 : 88 : read_netlink_messages (GNetworkMonitorNetlink *nl,
340 : : GError **error)
341 : : {
342 : : GInputVector iv;
343 : : gssize len;
344 : : gint flags;
345 : 88 : GError *local_error = NULL;
346 : 88 : GSocketAddress *addr = NULL;
347 : : struct nlmsghdr *msg;
348 : : struct rtmsg *rtmsg;
349 : : struct rtattr *attr;
350 : : struct sockaddr_nl source_sockaddr;
351 : : gsize attrlen;
352 : : guint8 *dest, *gateway, *oif;
353 : :
354 : 88 : iv.buffer = NULL;
355 : 88 : iv.size = 0;
356 : :
357 : 88 : flags = MSG_PEEK | MSG_TRUNC;
358 : 88 : len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1,
359 : : NULL, NULL, &flags, NULL, &local_error);
360 : 88 : if (len < 0)
361 : 0 : goto done;
362 : :
363 : 88 : iv.buffer = g_malloc (len);
364 : 88 : iv.size = len;
365 : 88 : len = g_socket_receive_message (nl->priv->sock, &addr, &iv, 1,
366 : : NULL, NULL, NULL, NULL, &local_error);
367 : 88 : if (len < 0)
368 : 0 : goto done;
369 : :
370 : 88 : if (!g_socket_address_to_native (addr, &source_sockaddr, sizeof (source_sockaddr), &local_error))
371 : 0 : goto done;
372 : :
373 : : /* If the sender port id is 0 (not fakeable) then the message is from the kernel */
374 : 88 : if (source_sockaddr.nl_pid != 0)
375 : 0 : goto done;
376 : :
377 : 88 : msg = (struct nlmsghdr *) iv.buffer;
378 : 572 : for (; len > 0; msg = NLMSG_NEXT (msg, len))
379 : : {
380 : 528 : if (!NLMSG_OK (msg, (size_t) len))
381 : : {
382 : 0 : g_set_error_literal (&local_error,
383 : : G_IO_ERROR,
384 : : G_IO_ERROR_PARTIAL_INPUT,
385 : : "netlink message was truncated; shouldn't happen...");
386 : 0 : goto done;
387 : : }
388 : :
389 : 528 : switch (msg->nlmsg_type)
390 : : {
391 : 484 : case RTM_NEWROUTE:
392 : : case RTM_DELROUTE:
393 : 484 : rtmsg = NLMSG_DATA (msg);
394 : :
395 : 484 : if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6)
396 : 0 : continue;
397 : 484 : if (rtmsg->rtm_type == RTN_UNREACHABLE)
398 : 0 : continue;
399 : :
400 : 484 : attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg));
401 : 484 : attr = RTM_RTA (rtmsg);
402 : 484 : dest = gateway = oif = NULL;
403 : 2772 : while (RTA_OK (attr, attrlen))
404 : : {
405 : 2288 : if (attr->rta_type == RTA_DST)
406 : 440 : dest = RTA_DATA (attr);
407 : 1848 : else if (attr->rta_type == RTA_GATEWAY)
408 : 44 : gateway = RTA_DATA (attr);
409 : 1804 : else if (attr->rta_type == RTA_OIF)
410 : 484 : oif = RTA_DATA (attr);
411 : 2288 : attr = RTA_NEXT (attr, attrlen);
412 : : }
413 : :
414 : 484 : if (dest || gateway || oif)
415 : : {
416 : : /* Unless we're processing the results of a dump, ignore
417 : : * IPv6 link-local multicast routes, which are added and
418 : : * removed all the time for some reason.
419 : : */
420 : : #define UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL(a) \
421 : : ((a[0] == 0xff) && ((a[1] & 0xf) == 0x2))
422 : :
423 : 484 : if (!nl->priv->dump_networks &&
424 : 0 : rtmsg->rtm_family == AF_INET6 &&
425 : 0 : rtmsg->rtm_dst_len != 0 &&
426 : 0 : (dest && UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL (dest)))
427 : 0 : continue;
428 : :
429 : 484 : if (msg->nlmsg_type == RTM_NEWROUTE)
430 : 484 : add_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
431 : : else
432 : 0 : remove_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
433 : 484 : queue_request_dump (nl);
434 : : }
435 : 484 : break;
436 : :
437 : 44 : case NLMSG_DONE:
438 : 44 : finish_dump (nl);
439 : 44 : goto done;
440 : :
441 : 0 : case NLMSG_ERROR:
442 : : {
443 : 0 : struct nlmsgerr *e = NLMSG_DATA (msg);
444 : :
445 : 0 : g_set_error (&local_error,
446 : : G_IO_ERROR,
447 : 0 : g_io_error_from_errno (-e->error),
448 : : "netlink error: %s",
449 : 0 : g_strerror (-e->error));
450 : : }
451 : 0 : goto done;
452 : :
453 : 0 : default:
454 : 0 : g_set_error (&local_error,
455 : : G_IO_ERROR,
456 : : G_IO_ERROR_INVALID_DATA,
457 : : "unexpected netlink message %d",
458 : 0 : msg->nlmsg_type);
459 : 0 : goto done;
460 : : }
461 : : }
462 : :
463 : 44 : done:
464 : 88 : g_free (iv.buffer);
465 : 88 : g_clear_object (&addr);
466 : :
467 : 88 : if (local_error != NULL && nl->priv->dump_networks)
468 : 0 : finish_dump (nl);
469 : :
470 : 88 : if (local_error != NULL)
471 : : {
472 : 0 : g_propagate_prefixed_error (error, local_error, "Error on netlink socket: ");
473 : 0 : return FALSE;
474 : : }
475 : : else
476 : : {
477 : 88 : return TRUE;
478 : : }
479 : : }
480 : :
481 : : static void
482 : 22 : g_network_monitor_netlink_finalize (GObject *object)
483 : : {
484 : 22 : GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object);
485 : :
486 : 22 : if (nl->priv->source)
487 : : {
488 : 22 : g_source_destroy (nl->priv->source);
489 : 22 : g_source_unref (nl->priv->source);
490 : : }
491 : :
492 : 22 : if (nl->priv->dump_source)
493 : : {
494 : 0 : g_source_destroy (nl->priv->dump_source);
495 : 0 : g_source_unref (nl->priv->dump_source);
496 : : }
497 : :
498 : 22 : if (nl->priv->sock)
499 : : {
500 : 22 : g_socket_close (nl->priv->sock, NULL);
501 : 22 : g_object_unref (nl->priv->sock);
502 : : }
503 : :
504 : 22 : g_clear_pointer (&nl->priv->context, g_main_context_unref);
505 : 22 : g_clear_pointer (&nl->priv->dump_networks, g_ptr_array_unref);
506 : :
507 : 22 : G_OBJECT_CLASS (g_network_monitor_netlink_parent_class)->finalize (object);
508 : 22 : }
509 : :
510 : : static gboolean
511 : 0 : read_netlink_messages_callback (GSocket *socket,
512 : : GIOCondition condition,
513 : : gpointer user_data)
514 : : {
515 : 0 : GError *error = NULL;
516 : 0 : GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (user_data);
517 : :
518 : 0 : if (!read_netlink_messages (nl, &error))
519 : : {
520 : 0 : g_warning ("Error reading netlink message: %s", error->message);
521 : 0 : g_clear_error (&error);
522 : 0 : return FALSE;
523 : : }
524 : :
525 : 0 : return TRUE;
526 : : }
527 : :
528 : : static void
529 : 22 : g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class)
530 : : {
531 : 22 : GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
532 : :
533 : 22 : gobject_class->finalize = g_network_monitor_netlink_finalize;
534 : 22 : }
535 : :
536 : : static void
537 : 22 : g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface)
538 : : {
539 : 22 : }
540 : :
541 : : static void
542 : 22 : g_network_monitor_netlink_initable_iface_init (GInitableIface *iface)
543 : : {
544 : 22 : initable_parent_iface = g_type_interface_peek_parent (iface);
545 : :
546 : 22 : iface->init = g_network_monitor_netlink_initable_init;
547 : 22 : }
|