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 "ginetaddress.h"
33 : : #include "ginetaddressmask.h"
34 : : #include "ginetsocketaddress.h"
35 : : #include "ginitable.h"
36 : : #include "giomodule-priv.h"
37 : : #include "gioerror.h"
38 : : #include "glibintl.h"
39 : : #include "glib/gstdio.h"
40 : : #include "gnetworkingprivate.h"
41 : : #include "gnetworkmonitor.h"
42 : : #include "gsocket.h"
43 : : #include "gsocketaddressenumerator.h"
44 : : #include "gsocketconnectable.h"
45 : : #include "gtask.h"
46 : : #include "gunixcredentialsmessage.h"
47 : :
48 : : /* must come at the end to pick system includes from
49 : : * gnetworkingprivate.h */
50 : : #ifdef HAVE_LINUX_NETLINK_H
51 : : #include <linux/netlink.h>
52 : : #include <linux/rtnetlink.h>
53 : : /* <linux/netlink.h> defines NETLINK_GET_STRICT_CHK but not its setsockopt
54 : : * level SOL_NETLINK. */
55 : : #ifndef SOL_NETLINK
56 : : #define SOL_NETLINK 270
57 : : #endif
58 : : #endif
59 : : #if defined(HAVE_NETLINK_NETLINK_H) && defined(HAVE_NETLINK_NETLINK_ROUTE_H)
60 : : #include <netlink/netlink.h>
61 : : #include <netlink/netlink_route.h>
62 : : #endif
63 : :
64 : : /* GNetworkMonitorNetlink is the default GNetworkMonitor on Linux when neither
65 : : * NetworkManager nor systemd-networkd is in charge.
66 : : *
67 : : * The kernel routing table (FIB) can be enormous on routers and network-facing
68 : : * servers (millions of routes), so this backend must never mirror or re-dump the
69 : : * whole table. It deliberately ignores non-default routes:
70 : : *
71 : : * - network-available is derived only from default routes. A single streaming
72 : : * dump at construction records just the default routes (every route with
73 : : * rtm_dst_len != 0 is skipped), and the set is then maintained incrementally
74 : : * from RTM_NEWROUTE/RTM_DELROUTE deltas. The table is re-dumped only to resync
75 : : * after an ENOBUFS overflow.
76 : : *
77 : : * - can_reach() uses an on-demand per-destination RTM_GETROUTE lookup (the
78 : : * "ip route get" primitive), which is O(prefix length) and independent of the
79 : : * table size.
80 : : *
81 : : * If you change this code, keep it that way: never enumerate or cache the full
82 : : * FIB. */
83 : :
84 : : static GInitableIface *initable_parent_iface;
85 : : static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *iface);
86 : : static void g_network_monitor_netlink_initable_iface_init (GInitableIface *iface);
87 : :
88 : : struct _GNetworkMonitorNetlinkPrivate
89 : : {
90 : : GSocket *query_sock; /* (mutex query_lock) */
91 : : guint query_seq; /* (mutex query_lock) */
92 : : GMutex query_lock;
93 : :
94 : : GMainContext *context;
95 : :
96 : : /* Availability tracking from the kernel routing table. These members are set
97 : : * up only by setup_monitor(), which runs solely for the plain
98 : : * GNetworkMonitorNetlink type. Subclasses (NetworkManager, systemd) source
99 : : * availability elsewhere (e.g. D-Bus) and inherit only can_reach(), so for
100 : : * them these stay NULL/empty: any code touching them must handle that. */
101 : : GSocket *monitor_sock; /* (nullable) */
102 : : GSource *source; /* (nullable) */
103 : : GSource *dump_source; /* (nullable) */
104 : : gboolean dumping;
105 : : GHashTable *ipv4_defaults; /* (element-type utf8) (owned) (nullable) */
106 : : GHashTable *ipv6_defaults; /* (element-type utf8) (owned) (nullable) */
107 : : GHashTable *dump_ipv4_defaults; /* (element-type utf8) (owned) (nullable) */
108 : : GHashTable *dump_ipv6_defaults; /* (element-type utf8) (owned) (nullable) */
109 : : GInetAddressMask *ipv4_default_mask; /* (nullable) */
110 : : GInetAddressMask *ipv6_default_mask; /* (nullable) */
111 : : };
112 : :
113 : : static gboolean read_netlink_messages (GNetworkMonitorNetlink *nl,
114 : : GError **error);
115 : : static gboolean read_netlink_messages_callback (GSocket *socket,
116 : : GIOCondition condition,
117 : : gpointer user_data);
118 : : static gboolean request_dump (GNetworkMonitorNetlink *nl,
119 : : GError **error);
120 : :
121 : : #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
122 : 812 : G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink, g_network_monitor_netlink, G_TYPE_NETWORK_MONITOR_BASE,
123 : : G_ADD_PRIVATE (GNetworkMonitorNetlink)
124 : : G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
125 : : g_network_monitor_netlink_iface_init)
126 : : G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
127 : : g_network_monitor_netlink_initable_iface_init)
128 : : _g_io_modules_ensure_extension_points_registered ();
129 : : g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
130 : : g_define_type_id,
131 : : "netlink",
132 : : 20))
133 : :
134 : : static void
135 : 63 : g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl)
136 : : {
137 : 63 : nl->priv = g_network_monitor_netlink_get_instance_private (nl);
138 : 63 : }
139 : :
140 : : /* Create a NETLINK_ROUTE socket bound to the given multicast groups (0 for a
141 : : * request/response socket that is not interested in unsolicited events). */
142 : : static GSocket *
143 : 84 : create_netlink_socket (guint32 groups,
144 : : GError **error)
145 : : {
146 : : gint sockfd;
147 : : struct sockaddr_nl snl;
148 : : GSocket *sock;
149 : 84 : const int rcvbuf = 1024 * 1024;
150 : :
151 : : /* We create the socket the old-school way because sockaddr_netlink
152 : : * can't be represented as a GSocketAddress
153 : : */
154 : 84 : sockfd = g_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, NULL);
155 : 84 : if (sockfd == -1)
156 : : {
157 : 0 : int errsv = errno;
158 : 0 : g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
159 : : _("Could not create network monitor: %s"),
160 : : g_strerror (errsv));
161 : 0 : return NULL;
162 : : }
163 : :
164 : : /* A host running dynamic routing protocols such as BGP can generate many
165 : : * route events in a short time; a larger buffer reduces ENOBUFS overflows
166 : : * that force running the full route enumeration again. */
167 : 84 : if (setsockopt (sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof (rcvbuf)) != 0)
168 : 0 : g_debug ("Could not enlarge netlink receive buffer: %s", g_strerror (errno));
169 : :
170 : 84 : snl.nl_family = AF_NETLINK;
171 : 84 : snl.nl_pid = snl.nl_pad = 0;
172 : 84 : snl.nl_groups = groups;
173 : 84 : if (bind (sockfd, (struct sockaddr *)&snl, sizeof (snl)) != 0)
174 : : {
175 : 0 : int errsv = errno;
176 : 0 : g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
177 : : _("Could not create network monitor: %s"),
178 : : g_strerror (errsv));
179 : 0 : (void) g_close (sockfd, NULL);
180 : 0 : return NULL;
181 : : }
182 : :
183 : 84 : sock = g_socket_new_from_fd (sockfd, error);
184 : 84 : if (!sock)
185 : : {
186 : 0 : g_prefix_error (error, "%s", _("Could not create network monitor: "));
187 : 0 : (void) g_close (sockfd, NULL);
188 : 0 : return NULL;
189 : : }
190 : :
191 : 84 : return sock;
192 : : }
193 : :
194 : : static gboolean
195 : 21 : setup_monitor (GNetworkMonitorNetlink *nl,
196 : : GError **error)
197 : : {
198 : 21 : nl->priv->monitor_sock = create_netlink_socket (RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE,
199 : : error);
200 : 21 : if (!nl->priv->monitor_sock)
201 : 0 : return FALSE;
202 : :
203 : : #ifdef SO_PASSCRED
204 : 21 : if (!g_socket_set_option (nl->priv->monitor_sock, SOL_SOCKET, SO_PASSCRED,
205 : : TRUE, NULL))
206 : : {
207 : 0 : int errsv = errno;
208 : 0 : g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
209 : : _("Could not create network monitor: %s"),
210 : : g_strerror (errsv));
211 : 0 : return FALSE;
212 : : }
213 : : #endif
214 : :
215 : 21 : nl->priv->ipv4_defaults = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
216 : 21 : nl->priv->ipv6_defaults = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
217 : :
218 : : /* Request the current state to find existing default routes */
219 : 21 : if (!request_dump (nl, error))
220 : 0 : return FALSE;
221 : :
222 : : /* And read responses; since we haven't yet marked the socket
223 : : * non-blocking, each call will block until a message is received.
224 : : */
225 : 63 : while (nl->priv->dumping)
226 : : {
227 : 42 : GError *local_error = NULL;
228 : 42 : if (!read_netlink_messages (nl, &local_error))
229 : : {
230 : 0 : g_warning ("%s", local_error->message);
231 : 0 : g_clear_error (&local_error);
232 : 0 : break;
233 : : }
234 : : }
235 : :
236 : 21 : g_socket_set_blocking (nl->priv->monitor_sock, FALSE);
237 : 21 : nl->priv->source = g_socket_create_source (nl->priv->monitor_sock, G_IO_IN, NULL);
238 : 21 : g_source_set_callback (nl->priv->source,
239 : : (GSourceFunc) read_netlink_messages_callback, nl, NULL);
240 : 21 : g_source_attach (nl->priv->source, nl->priv->context);
241 : :
242 : 21 : return TRUE;
243 : : }
244 : :
245 : : static gboolean
246 : 63 : g_network_monitor_netlink_initable_init (GInitable *initable,
247 : : GCancellable *cancellable,
248 : : GError **error)
249 : : {
250 : 63 : GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable);
251 : :
252 : 63 : g_mutex_init (&nl->priv->query_lock);
253 : 63 : nl->priv->context = g_main_context_ref_thread_default ();
254 : :
255 : : /* A socket for on-demand per-destination route lookups, used by can_reach()
256 : : * for this backend and every subclass. */
257 : 63 : nl->priv->query_sock = create_netlink_socket (0, error);
258 : 63 : if (!nl->priv->query_sock)
259 : 0 : return FALSE;
260 : :
261 : : /* Availability tracking is set up only for the plain netlink type; see the
262 : : * GNetworkMonitorNetlinkPrivate definition. Subclasses inherit can_reach(). */
263 : 84 : if (G_OBJECT_TYPE (nl) == G_TYPE_NETWORK_MONITOR_NETLINK &&
264 : 21 : !setup_monitor (nl, error))
265 : 0 : return FALSE;
266 : :
267 : 63 : return initable_parent_iface->init (initable, cancellable, error);
268 : : }
269 : :
270 : : static gboolean
271 : 21 : request_dump (GNetworkMonitorNetlink *nl,
272 : : GError **error)
273 : : {
274 : : struct nlmsghdr *n;
275 : : struct rtmsg *rtm;
276 : : gchar buf[NLMSG_SPACE (sizeof (*rtm))];
277 : :
278 : : #ifdef NETLINK_GET_STRICT_CHK
279 : : /* Strict checking with rtm_flags == 0 lets the kernel dump faster by
280 : : * skipping unnecessary data, e.g. the route-cache exceptions. */
281 : : {
282 : 21 : const int strict = 1;
283 : 21 : if (setsockopt (g_socket_get_fd (nl->priv->monitor_sock), SOL_NETLINK,
284 : : NETLINK_GET_STRICT_CHK, &strict, sizeof (strict)) != 0)
285 : 0 : g_debug ("Could not set NETLINK_GET_STRICT_CHK: %s", g_strerror (errno));
286 : : }
287 : : #endif
288 : :
289 : 21 : memset (buf, 0, sizeof (buf));
290 : 21 : n = (struct nlmsghdr*) buf;
291 : 21 : n->nlmsg_len = NLMSG_LENGTH (sizeof (*rtm));
292 : 21 : n->nlmsg_type = RTM_GETROUTE;
293 : 21 : n->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
294 : 21 : n->nlmsg_pid = 0;
295 : 21 : rtm = NLMSG_DATA (n);
296 : 21 : rtm->rtm_family = AF_UNSPEC;
297 : : /* Keep this request minimal: a strict dump requires the selector fields to
298 : : * stay zero, and extra attributes can also hurt dump performance. */
299 : :
300 : 21 : if (g_socket_send (nl->priv->monitor_sock, buf, sizeof (buf),
301 : : NULL, error) < 0)
302 : : {
303 : 0 : g_prefix_error (error, "%s", _("Could not get network status: "));
304 : 0 : return FALSE;
305 : : }
306 : :
307 : 21 : nl->priv->dumping = TRUE;
308 : 21 : nl->priv->dump_ipv4_defaults = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
309 : 21 : nl->priv->dump_ipv6_defaults = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
310 : 21 : return TRUE;
311 : : }
312 : :
313 : : static gboolean
314 : 0 : timeout_request_dump (gpointer user_data)
315 : : {
316 : 0 : GNetworkMonitorNetlink *nl = user_data;
317 : :
318 : 0 : g_source_destroy (nl->priv->dump_source);
319 : 0 : g_source_unref (nl->priv->dump_source);
320 : 0 : nl->priv->dump_source = NULL;
321 : :
322 : 0 : request_dump (nl, NULL);
323 : :
324 : 0 : return FALSE;
325 : : }
326 : :
327 : : /* Schedule a full re-dump to rebuild default-route state after the monitor
328 : : * socket overflows (ENOBUFS). Normal default-route changes are tracked
329 : : * incrementally and do not trigger a dump. */
330 : : static void
331 : 0 : queue_request_dump (GNetworkMonitorNetlink *nl)
332 : : {
333 : 0 : if (nl->priv->dumping)
334 : 0 : return;
335 : :
336 : 0 : if (nl->priv->dump_source)
337 : : {
338 : 0 : g_source_destroy (nl->priv->dump_source);
339 : 0 : g_source_unref (nl->priv->dump_source);
340 : : }
341 : :
342 : 0 : nl->priv->dump_source = g_timeout_source_new_seconds (1);
343 : 0 : g_source_set_callback (nl->priv->dump_source,
344 : : (GSourceFunc) timeout_request_dump, nl, NULL);
345 : 0 : g_source_attach (nl->priv->dump_source, nl->priv->context);
346 : : }
347 : :
348 : : static GInetAddressMask *
349 : 21 : default_route_mask (GNetworkMonitorNetlink *nl,
350 : : int family)
351 : : {
352 : : GInetAddressMask **maskp;
353 : : GSocketFamily socket_family;
354 : :
355 : 21 : if (family == AF_INET)
356 : : {
357 : 21 : maskp = &nl->priv->ipv4_default_mask;
358 : 21 : socket_family = G_SOCKET_FAMILY_IPV4;
359 : : }
360 : 0 : else if (family == AF_INET6)
361 : : {
362 : 0 : maskp = &nl->priv->ipv6_default_mask;
363 : 0 : socket_family = G_SOCKET_FAMILY_IPV6;
364 : : }
365 : : else
366 : : {
367 : : g_assert_not_reached ();
368 : : }
369 : :
370 : 21 : if (*maskp == NULL)
371 : : {
372 : 21 : GInetAddress *any = g_inet_address_new_any (socket_family);
373 : 21 : *maskp = g_inet_address_mask_new (any, 0, NULL);
374 : 21 : g_object_unref (any);
375 : : }
376 : :
377 : 21 : return *maskp;
378 : : }
379 : :
380 : : /* Reflect presence of a default route for @family into the base monitor's
381 : : * network set, which drives the network-available property. */
382 : : static void
383 : 21 : update_default_route_available (GNetworkMonitorNetlink *nl,
384 : : int family,
385 : : gboolean available)
386 : : {
387 : 21 : GInetAddressMask *mask = default_route_mask (nl, family);
388 : :
389 : 21 : if (mask == NULL)
390 : 0 : return;
391 : :
392 : 21 : if (available)
393 : 21 : g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), mask);
394 : : else
395 : 0 : g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl), mask);
396 : : }
397 : :
398 : : static void
399 : 21 : add_default_route (GNetworkMonitorNetlink *nl,
400 : : int family,
401 : : gchar *stolen_key /* (transfer full) */)
402 : : {
403 : : GHashTable *set;
404 : :
405 : 21 : if (nl->priv->dumping)
406 : 21 : set = (family == AF_INET) ? nl->priv->dump_ipv4_defaults : nl->priv->dump_ipv6_defaults;
407 : : else
408 : 0 : set = (family == AF_INET) ? nl->priv->ipv4_defaults : nl->priv->ipv6_defaults;
409 : :
410 : 21 : if (!nl->priv->dumping && g_hash_table_size (set) == 0)
411 : 0 : update_default_route_available (nl, family, TRUE);
412 : :
413 : 21 : g_hash_table_add (set, g_steal_pointer (&stolen_key));
414 : 21 : }
415 : :
416 : : static void
417 : 0 : remove_default_route (GNetworkMonitorNetlink *nl,
418 : : int family,
419 : : const gchar *key)
420 : : {
421 : : GHashTable *set;
422 : :
423 : : /* An RTM_DELROUTE is always a multicast event and can interleave with a
424 : : * (re-)dump, so this may run while dumping; update the live set, which
425 : : * finish_dump() then reconciles against the freshly dumped set. */
426 : 0 : set = (family == AF_INET) ? nl->priv->ipv4_defaults : nl->priv->ipv6_defaults;
427 : :
428 : 0 : if (g_hash_table_remove (set, key) &&
429 : 0 : g_hash_table_size (set) == 0)
430 : 0 : update_default_route_available (nl, family, FALSE);
431 : 0 : }
432 : :
433 : : static void
434 : 21 : finish_dump (GNetworkMonitorNetlink *nl)
435 : : {
436 : 21 : int families[2] = { AF_INET, AF_INET6 };
437 : : size_t i;
438 : :
439 : : /* Reconcile the freshly-dumped default routes with the live state, emitting
440 : : * an availability change only when the per-family presence actually flips. */
441 : 63 : for (i = 0; i < G_N_ELEMENTS (families); i++)
442 : : {
443 : 42 : int family = families[i];
444 : 42 : GHashTable **livep = (family == AF_INET) ? &nl->priv->ipv4_defaults : &nl->priv->ipv6_defaults;
445 : 42 : GHashTable **dumpp = (family == AF_INET) ? &nl->priv->dump_ipv4_defaults : &nl->priv->dump_ipv6_defaults;
446 : 42 : gboolean was_available = g_hash_table_size (*livep) > 0;
447 : 42 : gboolean now_available = g_hash_table_size (*dumpp) > 0;
448 : :
449 : 42 : g_hash_table_unref (*livep);
450 : 42 : *livep = g_steal_pointer (dumpp);
451 : :
452 : 42 : if (was_available != now_available)
453 : 21 : update_default_route_available (nl, family, now_available);
454 : : }
455 : :
456 : 21 : nl->priv->dumping = FALSE;
457 : :
458 : : /* FreeBSD features "jailing" functionality, which can be approximated to
459 : : * Linux namespaces. A jail may or may not share the host's network stack,
460 : : * which includes routing tables.
461 : : * When jail runs in non-vnet mode and has a shared stack with the host,
462 : : * the kernel prevents jailed processes from getting full view on a routing
463 : : * table. This makes GNetworkManager believe that we're offline and return
464 : : * FALSE for the "available" property.
465 : : * To workaround this problem, do the same thing as GNetworkMonitorBase -
466 : : * add a fake network of 0 length.
467 : : */
468 : : #ifdef __FreeBSD__
469 : : gboolean is_jailed = FALSE;
470 : : gsize len = sizeof (is_jailed);
471 : :
472 : : if (sysctlbyname ("security.jail.jailed", &is_jailed, &len, NULL, 0) != 0)
473 : : return;
474 : :
475 : : if (!is_jailed)
476 : : return;
477 : :
478 : : if (is_jailed && !g_network_monitor_get_network_available (G_NETWORK_MONITOR (nl)))
479 : : {
480 : : GInetAddressMask *network;
481 : : network = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
482 : : g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network);
483 : : g_object_unref (network);
484 : : }
485 : : #endif
486 : 21 : }
487 : :
488 : : /* A route whose type does not actually deliver packets to the destination
489 : : * (unreachable, blackhole, prohibit, throw) does not count as reachable. */
490 : : static gboolean
491 : 25 : route_type_is_reachable (unsigned char rtm_type)
492 : : {
493 : 25 : return (rtm_type != RTN_UNREACHABLE &&
494 : 25 : rtm_type != RTN_BLACKHOLE &&
495 : 50 : rtm_type != RTN_PROHIBIT &&
496 : : rtm_type != RTN_THROW);
497 : : }
498 : :
499 : : /* Sane upper bound on a single netlink datagram before g_malloc(): a route-get
500 : : * reply is one message (<= NLMSG_GOODSIZE, < 8 KiB), while a dump datagram packs
501 : : * many messages and is hard-capped by the kernel at SKB_WITH_OVERHEAD(32768)
502 : : * (~32 KiB, see netlink_recvmsg()). 64 KiB leaves headroom over both. */
503 : : #define NETLINK_MESSAGE_MAX_SIZE (64 * 1024)
504 : :
505 : : static gboolean
506 : 42 : read_netlink_messages (GNetworkMonitorNetlink *nl,
507 : : GError **error)
508 : : {
509 : : GInputVector iv;
510 : : gssize len;
511 : : gint flags;
512 : 42 : GError *local_error = NULL;
513 : 42 : GSocketAddress *addr = NULL;
514 : : struct nlmsghdr *msg;
515 : : struct rtmsg *rtmsg;
516 : : struct rtattr *attr;
517 : : struct sockaddr_nl source_sockaddr;
518 : : gsize attrlen;
519 : : guint32 table, metric, oif;
520 : : gboolean have_nexthop;
521 : :
522 : : /* The kernel is aware of the read buffer size, so a larger buffer lets it
523 : : * deliver more data per datagram. */
524 : 42 : iv.buffer = g_malloc (NETLINK_MESSAGE_MAX_SIZE);
525 : 42 : iv.size = NETLINK_MESSAGE_MAX_SIZE;
526 : 42 : flags = 0;
527 : 42 : len = g_socket_receive_message (nl->priv->monitor_sock, &addr, &iv, 1,
528 : : NULL, NULL, &flags, NULL, &local_error);
529 : 42 : if (len < 0)
530 : 0 : goto done;
531 : 42 : if (len == 0 || (flags & MSG_TRUNC))
532 : : {
533 : 0 : g_set_error_literal (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
534 : : "netlink message length is invalid");
535 : 0 : goto done;
536 : : }
537 : :
538 : 42 : if (!g_socket_address_to_native (addr, &source_sockaddr, sizeof (source_sockaddr), &local_error))
539 : 0 : goto done;
540 : :
541 : : /* If the sender port id is 0 (not fakeable) then the message is from the kernel */
542 : 42 : if (source_sockaddr.nl_pid != 0)
543 : 0 : goto done;
544 : :
545 : 42 : msg = (struct nlmsghdr *) iv.buffer;
546 : 273 : for (; len > 0; msg = NLMSG_NEXT (msg, len))
547 : : {
548 : 252 : if (!NLMSG_OK (msg, (size_t) len))
549 : : {
550 : 0 : g_set_error_literal (&local_error,
551 : : G_IO_ERROR,
552 : : G_IO_ERROR_PARTIAL_INPUT,
553 : : "netlink message was truncated; shouldn't happen...");
554 : 0 : goto done;
555 : : }
556 : :
557 : 252 : switch (msg->nlmsg_type)
558 : : {
559 : 231 : case RTM_NEWROUTE:
560 : : case RTM_DELROUTE:
561 : 231 : rtmsg = NLMSG_DATA (msg);
562 : :
563 : 231 : if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6)
564 : 0 : continue;
565 : : /* Only default routes (0-length prefix) affect network-available. */
566 : 231 : if (rtmsg->rtm_dst_len != 0)
567 : 210 : continue;
568 : 21 : if (!route_type_is_reachable (rtmsg->rtm_type))
569 : 0 : continue;
570 : :
571 : 21 : table = rtmsg->rtm_table;
572 : 21 : metric = 0;
573 : 21 : oif = 0;
574 : 21 : have_nexthop = FALSE;
575 : :
576 : 21 : attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg));
577 : 21 : attr = RTM_RTA (rtmsg);
578 : 105 : while (RTA_OK (attr, attrlen))
579 : : {
580 : 84 : if (attr->rta_type == RTA_GATEWAY)
581 : 21 : have_nexthop = TRUE;
582 : 63 : else if (attr->rta_type == RTA_OIF)
583 : : {
584 : 21 : oif = *(guint32 *) RTA_DATA (attr);
585 : 21 : have_nexthop = TRUE;
586 : : }
587 : 42 : else if (attr->rta_type == RTA_PRIORITY)
588 : 21 : metric = *(guint32 *) RTA_DATA (attr);
589 : 21 : else if (attr->rta_type == RTA_TABLE)
590 : 21 : table = *(guint32 *) RTA_DATA (attr);
591 : 0 : else if (attr->rta_type == RTA_MULTIPATH)
592 : 0 : have_nexthop = TRUE;
593 : 84 : attr = RTA_NEXT (attr, attrlen);
594 : : }
595 : :
596 : : /* A default route reaches a nexthop: a gateway, an output interface,
597 : : * or a set of multipath nexthops. */
598 : 21 : if (have_nexthop)
599 : : {
600 : : /* Key by attributes that survive "ip route replace" (which emits
601 : : * RTM_NEWROUTE with no matching RTM_DELROUTE), so the set tracks
602 : : * distinct default routes without drifting. */
603 : 21 : gchar *key = g_strdup_printf ("%u:%u:%u", table, metric, oif);
604 : :
605 : 21 : if (msg->nlmsg_type == RTM_NEWROUTE)
606 : 21 : add_default_route (nl, rtmsg->rtm_family, g_steal_pointer (&key));
607 : : else
608 : 0 : remove_default_route (nl, rtmsg->rtm_family, key);
609 : 21 : g_free (key);
610 : : }
611 : 21 : break;
612 : :
613 : 21 : case NLMSG_DONE:
614 : 21 : finish_dump (nl);
615 : 21 : goto done;
616 : :
617 : 0 : case NLMSG_ERROR:
618 : : {
619 : 0 : struct nlmsgerr *e = NLMSG_DATA (msg);
620 : :
621 : : /* ENOBUFS means the socket buffer overflowed and we may have missed
622 : : * default-route changes; resync by re-dumping. */
623 : 0 : if (e->error == -ENOBUFS)
624 : : {
625 : 0 : queue_request_dump (nl);
626 : 0 : goto done;
627 : : }
628 : :
629 : 0 : g_set_error (&local_error,
630 : : G_IO_ERROR,
631 : 0 : g_io_error_from_errno (-e->error),
632 : : "netlink error: %s",
633 : 0 : g_strerror (-e->error));
634 : : }
635 : 0 : goto done;
636 : :
637 : 0 : default:
638 : 0 : g_set_error (&local_error,
639 : : G_IO_ERROR,
640 : : G_IO_ERROR_INVALID_DATA,
641 : : "unexpected netlink message %d",
642 : 0 : msg->nlmsg_type);
643 : 0 : goto done;
644 : : }
645 : : }
646 : :
647 : 21 : done:
648 : 42 : g_free (iv.buffer);
649 : 42 : g_clear_object (&addr);
650 : :
651 : 42 : if (local_error != NULL && nl->priv->dumping)
652 : 0 : finish_dump (nl);
653 : :
654 : 42 : if (local_error != NULL)
655 : : {
656 : 0 : g_propagate_prefixed_error (error, local_error, "Error on netlink socket: ");
657 : 0 : return FALSE;
658 : : }
659 : : else
660 : : {
661 : 42 : return TRUE;
662 : : }
663 : : }
664 : :
665 : : static gboolean
666 : 0 : read_netlink_messages_callback (GSocket *socket,
667 : : GIOCondition condition,
668 : : gpointer user_data)
669 : : {
670 : 0 : GError *error = NULL;
671 : 0 : GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (user_data);
672 : :
673 : 0 : if (!read_netlink_messages (nl, &error))
674 : : {
675 : 0 : g_warning ("Error reading netlink message: %s", error->message);
676 : 0 : g_clear_error (&error);
677 : 0 : return FALSE;
678 : : }
679 : :
680 : 0 : return TRUE;
681 : : }
682 : :
683 : : /* Map a GSocketFamily to its AF_* address family constant. */
684 : : static int
685 : 4 : socket_family_to_af_family (GSocketFamily socket_family)
686 : : {
687 : 4 : switch (socket_family)
688 : : {
689 : 2 : case G_SOCKET_FAMILY_IPV4:
690 : 2 : return AF_INET;
691 : 2 : case G_SOCKET_FAMILY_IPV6:
692 : 2 : return AF_INET6;
693 : 0 : default:
694 : : g_assert_not_reached ();
695 : : }
696 : : }
697 : :
698 : : /* Map a kernel route-lookup errno to the GIOError reported by can_reach(). */
699 : : static GIOErrorEnum
700 : 0 : route_get_error_from_errno (int err)
701 : : {
702 : 0 : switch (err)
703 : : {
704 : 0 : case ENETUNREACH:
705 : : case ENETDOWN:
706 : 0 : return G_IO_ERROR_NETWORK_UNREACHABLE;
707 : 0 : case EHOSTUNREACH:
708 : : case EHOSTDOWN:
709 : : case EACCES:
710 : 0 : return G_IO_ERROR_HOST_UNREACHABLE;
711 : 0 : default:
712 : 0 : return g_io_error_from_errno (err);
713 : : }
714 : : }
715 : :
716 : : /* Perform a single per-destination route lookup ("ip route get"). Returns TRUE
717 : : * if @addr is reachable, otherwise FALSE with @error set. The error is usually
718 : : * G_IO_ERROR_HOST_UNREACHABLE or G_IO_ERROR_NETWORK_UNREACHABLE, but any other
719 : : * GIOError that route_get_error_from_errno() maps from the kernel's errno is
720 : : * possible. Blocking, and safe to call from a worker thread. */
721 : : static gboolean
722 : 4 : route_get (GNetworkMonitorNetlink *nl,
723 : : GInetAddress *addr,
724 : : GCancellable *cancellable,
725 : : GError **error)
726 : : {
727 : 4 : GSocketFamily socket_family = g_inet_address_get_family (addr);
728 : 4 : int family = socket_family_to_af_family (socket_family);
729 : 4 : gsize addrlen = g_inet_address_get_native_size (addr);
730 : 4 : const guint8 *addrbytes = g_inet_address_to_bytes (addr);
731 : : struct {
732 : : struct nlmsghdr n;
733 : : struct rtmsg r;
734 : : gchar buf[64];
735 : : } req;
736 : : struct nlmsghdr *msg;
737 : : struct rtmsg *rtmsg;
738 : : struct rtattr *rta;
739 : 4 : GInputVector iv = { NULL, 0 };
740 : : struct sockaddr_nl source_sockaddr;
741 : 4 : GSocketAddress *src_addr = NULL;
742 : 4 : GError *local_error = NULL;
743 : : gssize len;
744 : : gint flags;
745 : : guint seq;
746 : 4 : gboolean reachable = FALSE;
747 : 4 : gboolean got_reply = FALSE;
748 : :
749 : 4 : memset (&req, 0, sizeof (req));
750 : 4 : req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
751 : 4 : req.n.nlmsg_type = RTM_GETROUTE;
752 : 4 : req.n.nlmsg_flags = NLM_F_REQUEST;
753 : 4 : req.r.rtm_family = family;
754 : 4 : req.r.rtm_dst_len = addrlen * 8; /* this field is a CIDR length in bits */
755 : :
756 : : /* We want the kernel to resolve the route to @addr. RTM_F_FIB_MATCH
757 : : * (Linux 4.11+) makes it return the matching FIB entry; without the flag the
758 : : * kernel returns a per-destination cloned route instead, which still works
759 : : * as we are currently interested in a route existence. */
760 : : #ifdef RTM_F_FIB_MATCH
761 : 4 : req.r.rtm_flags = RTM_F_FIB_MATCH;
762 : : #endif
763 : :
764 : 4 : rta = (struct rtattr *) (((char *) &req) + NLMSG_ALIGN (req.n.nlmsg_len));
765 : 4 : rta->rta_type = RTA_DST;
766 : 4 : rta->rta_len = RTA_LENGTH (addrlen);
767 : 4 : g_assert ((char *) rta + rta->rta_len <= (char *) &req + sizeof (req));
768 : 4 : memcpy (RTA_DATA (rta), addrbytes, addrlen);
769 : 4 : req.n.nlmsg_len = NLMSG_ALIGN (req.n.nlmsg_len) + rta->rta_len;
770 : :
771 : 4 : g_mutex_lock (&nl->priv->query_lock);
772 : :
773 : 4 : seq = ++nl->priv->query_seq;
774 : 4 : req.n.nlmsg_seq = seq;
775 : :
776 : 4 : if (g_socket_send (nl->priv->query_sock, (const gchar *) &req, req.n.nlmsg_len,
777 : : cancellable, &local_error) < 0)
778 : 0 : goto done;
779 : :
780 : 4 : flags = MSG_PEEK | MSG_TRUNC;
781 : 4 : len = g_socket_receive_message (nl->priv->query_sock, NULL, &iv, 1,
782 : : NULL, NULL, &flags, cancellable, &local_error);
783 : 4 : if (len < 0)
784 : 0 : goto done;
785 : 4 : if (len == 0 || len > NETLINK_MESSAGE_MAX_SIZE)
786 : : {
787 : 0 : g_set_error_literal (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
788 : : "netlink route reply length is invalid");
789 : 0 : goto done;
790 : : }
791 : :
792 : 4 : iv.buffer = g_malloc (len);
793 : 4 : iv.size = len;
794 : 4 : len = g_socket_receive_message (nl->priv->query_sock, &src_addr, &iv, 1,
795 : : NULL, NULL, NULL, cancellable, &local_error);
796 : 4 : if (len < 0)
797 : 0 : goto done;
798 : :
799 : : /* Only trust messages from the kernel (sender port id 0). */
800 : 4 : if (!g_socket_address_to_native (src_addr, &source_sockaddr, sizeof (source_sockaddr), &local_error))
801 : 0 : goto done;
802 : 4 : if (source_sockaddr.nl_pid != 0)
803 : 0 : goto done;
804 : :
805 : 4 : msg = (struct nlmsghdr *) iv.buffer;
806 : 4 : for (; len > 0; msg = NLMSG_NEXT (msg, len))
807 : : {
808 : 4 : if (!NLMSG_OK (msg, (size_t) len))
809 : : break;
810 : 4 : if (msg->nlmsg_seq != seq)
811 : 0 : continue;
812 : :
813 : 4 : if (msg->nlmsg_type == NLMSG_ERROR)
814 : : {
815 : 0 : struct nlmsgerr *e = NLMSG_DATA (msg);
816 : :
817 : 0 : got_reply = TRUE;
818 : : /* error == 0 is a success acknowledgement, which the kernel never sends for our request. */
819 : 0 : if (e->error != 0)
820 : 0 : g_set_error_literal (&local_error, G_IO_ERROR,
821 : 0 : route_get_error_from_errno (-e->error),
822 : 0 : g_strerror (-e->error));
823 : 0 : break;
824 : : }
825 : 4 : else if (msg->nlmsg_type == RTM_NEWROUTE)
826 : : {
827 : 4 : rtmsg = NLMSG_DATA (msg);
828 : 4 : got_reply = TRUE;
829 : 4 : reachable = route_type_is_reachable (rtmsg->rtm_type);
830 : 4 : if (!reachable)
831 : 0 : g_set_error_literal (&local_error, G_IO_ERROR,
832 : : G_IO_ERROR_HOST_UNREACHABLE,
833 : : _("Host unreachable"));
834 : 4 : break;
835 : : }
836 : : }
837 : :
838 : 0 : done:
839 : 4 : g_mutex_unlock (&nl->priv->query_lock);
840 : :
841 : 4 : g_free (iv.buffer);
842 : 4 : g_clear_object (&src_addr);
843 : :
844 : 4 : if (reachable)
845 : : {
846 : 4 : g_assert (local_error == NULL);
847 : 4 : return TRUE;
848 : : }
849 : :
850 : 0 : if (local_error != NULL)
851 : 0 : g_propagate_error (error, g_steal_pointer (&local_error));
852 : 0 : else if (!got_reply)
853 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
854 : : _("Host unreachable"));
855 : 0 : return FALSE;
856 : : }
857 : :
858 : : static gboolean
859 : 4 : g_network_monitor_netlink_can_reach (GNetworkMonitor *monitor,
860 : : GSocketConnectable *connectable,
861 : : GCancellable *cancellable,
862 : : GError **error)
863 : : {
864 : 4 : GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (monitor);
865 : : GSocketAddressEnumerator *enumerator;
866 : : GSocketAddress *addr;
867 : 4 : GError *local_error = NULL;
868 : :
869 : 4 : enumerator = g_socket_connectable_proxy_enumerate (connectable);
870 : :
871 : : /* Try each resolved address; the host is reachable if any of them is. A
872 : : * failed route_get() is cleared so the next g_socket_address_enumerator_next()
873 : : * sees a clean @local_error, except on cancellation, which we propagate. */
874 : 4 : while ((addr = g_socket_address_enumerator_next (enumerator, cancellable, &local_error)))
875 : : {
876 : 4 : if (G_IS_INET_SOCKET_ADDRESS (addr))
877 : : {
878 : : GInetAddress *iaddr;
879 : :
880 : 4 : iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
881 : 4 : if (route_get (nl, iaddr, cancellable, &local_error))
882 : : {
883 : 4 : g_object_unref (addr);
884 : 4 : g_object_unref (enumerator);
885 : 4 : return TRUE;
886 : : }
887 : :
888 : 0 : if (g_cancellable_is_cancelled (cancellable))
889 : : {
890 : 0 : g_object_unref (addr);
891 : 0 : break;
892 : : }
893 : 0 : g_clear_error (&local_error);
894 : : }
895 : :
896 : 0 : g_object_unref (addr);
897 : : }
898 : 0 : g_object_unref (enumerator);
899 : :
900 : : /* An enumeration failure (DNS) or cancellation is reported as-is. */
901 : 0 : if (local_error != NULL)
902 : : {
903 : 0 : g_propagate_error (error, g_steal_pointer (&local_error));
904 : 0 : return FALSE;
905 : : }
906 : :
907 : : /* Reached when no address was routable (each route_get() error was cleared to
908 : : * try the next one) or none were `GInetSocketAddress`es; either way report a
909 : : * generic error, matching the base monitor. */
910 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
911 : : _("Host unreachable"));
912 : 0 : return FALSE;
913 : : }
914 : :
915 : : static void
916 : 2 : can_reach_thread (GTask *task,
917 : : gpointer source_object,
918 : : gpointer task_data,
919 : : GCancellable *cancellable)
920 : : {
921 : 2 : GNetworkMonitor *monitor = G_NETWORK_MONITOR (source_object);
922 : 2 : GSocketConnectable *connectable = G_SOCKET_CONNECTABLE (task_data);
923 : 2 : GError *error = NULL;
924 : :
925 : 2 : if (g_network_monitor_netlink_can_reach (monitor, connectable, cancellable, &error))
926 : 2 : g_task_return_boolean (task, TRUE);
927 : : else
928 : 0 : g_task_return_error (task, g_steal_pointer (&error));
929 : 2 : }
930 : :
931 : : static void
932 : 2 : g_network_monitor_netlink_can_reach_async (GNetworkMonitor *monitor,
933 : : GSocketConnectable *connectable,
934 : : GCancellable *cancellable,
935 : : GAsyncReadyCallback callback,
936 : : gpointer user_data)
937 : : {
938 : : GTask *task;
939 : :
940 : 2 : task = g_task_new (monitor, cancellable, callback, user_data);
941 : 2 : g_task_set_source_tag (task, g_network_monitor_netlink_can_reach_async);
942 : 2 : g_task_set_static_name (task, "[gio] network monitor can_reach");
943 : 2 : g_task_set_task_data (task, g_object_ref (connectable), g_object_unref);
944 : :
945 : : /* A route lookup is a quick kernel round-trip, so the shared GTask thread
946 : : * pool is fine here. */
947 : 2 : g_task_run_in_thread (task, can_reach_thread);
948 : 2 : g_object_unref (task);
949 : 2 : }
950 : :
951 : : static gboolean
952 : 2 : g_network_monitor_netlink_can_reach_finish (GNetworkMonitor *monitor,
953 : : GAsyncResult *result,
954 : : GError **error)
955 : : {
956 : 2 : g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
957 : :
958 : 2 : return g_task_propagate_boolean (G_TASK (result), error);
959 : : }
960 : :
961 : : static void
962 : 21 : g_network_monitor_netlink_finalize (GObject *object)
963 : : {
964 : 21 : GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object);
965 : :
966 : 21 : if (nl->priv->source)
967 : : {
968 : 0 : g_source_destroy (nl->priv->source);
969 : 0 : g_source_unref (nl->priv->source);
970 : : }
971 : :
972 : 21 : if (nl->priv->dump_source)
973 : : {
974 : 0 : g_source_destroy (nl->priv->dump_source);
975 : 0 : g_source_unref (nl->priv->dump_source);
976 : : }
977 : :
978 : 21 : if (nl->priv->query_sock)
979 : : {
980 : 21 : g_socket_close (nl->priv->query_sock, NULL);
981 : 21 : g_object_unref (nl->priv->query_sock);
982 : : }
983 : :
984 : 21 : if (nl->priv->monitor_sock)
985 : : {
986 : 0 : g_socket_close (nl->priv->monitor_sock, NULL);
987 : 0 : g_object_unref (nl->priv->monitor_sock);
988 : : }
989 : :
990 : 21 : g_mutex_clear (&nl->priv->query_lock);
991 : :
992 : 21 : g_clear_pointer (&nl->priv->context, g_main_context_unref);
993 : 21 : g_clear_pointer (&nl->priv->ipv4_defaults, g_hash_table_unref);
994 : 21 : g_clear_pointer (&nl->priv->ipv6_defaults, g_hash_table_unref);
995 : 21 : g_clear_pointer (&nl->priv->dump_ipv4_defaults, g_hash_table_unref);
996 : 21 : g_clear_pointer (&nl->priv->dump_ipv6_defaults, g_hash_table_unref);
997 : 21 : g_clear_object (&nl->priv->ipv4_default_mask);
998 : 21 : g_clear_object (&nl->priv->ipv6_default_mask);
999 : :
1000 : 21 : G_OBJECT_CLASS (g_network_monitor_netlink_parent_class)->finalize (object);
1001 : 21 : }
1002 : :
1003 : : static void
1004 : 22 : g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class)
1005 : : {
1006 : 22 : GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
1007 : :
1008 : 22 : gobject_class->finalize = g_network_monitor_netlink_finalize;
1009 : 22 : }
1010 : :
1011 : : static void
1012 : 22 : g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface)
1013 : : {
1014 : 22 : monitor_iface->can_reach = g_network_monitor_netlink_can_reach;
1015 : 22 : monitor_iface->can_reach_async = g_network_monitor_netlink_can_reach_async;
1016 : 22 : monitor_iface->can_reach_finish = g_network_monitor_netlink_can_reach_finish;
1017 : 22 : }
1018 : :
1019 : : static void
1020 : 22 : g_network_monitor_netlink_initable_iface_init (GInitableIface *iface)
1021 : : {
1022 : 22 : initable_parent_iface = g_type_interface_peek_parent (iface);
1023 : :
1024 : 22 : iface->init = g_network_monitor_netlink_initable_init;
1025 : 22 : }
|