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