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