Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/gnetworkmonitornetlink.c
Line
Count
Source (jump to first uncovered line)
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
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
g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl)
89
0
{
90
0
  nl->priv = g_network_monitor_netlink_get_instance_private (nl);
91
0
}
92
93
static gboolean
94
g_network_monitor_netlink_initable_init (GInitable     *initable,
95
                                         GCancellable  *cancellable,
96
                                         GError       **error)
97
0
{
98
0
  GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable);
99
0
  gint sockfd;
100
0
  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
0
  sockfd = g_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, NULL);
106
0
  if (sockfd == -1)
107
0
    {
108
0
      int errsv = errno;
109
0
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
110
0
                   _("Could not create network monitor: %s"),
111
0
                   g_strerror (errsv));
112
0
      return FALSE;
113
0
    }
114
115
0
  snl.nl_family = AF_NETLINK;
116
0
  snl.nl_pid = snl.nl_pad = 0;
117
0
  snl.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
118
0
  if (bind (sockfd, (struct sockaddr *)&snl, sizeof (snl)) != 0)
119
0
    {
120
0
      int errsv = errno;
121
0
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
122
0
                   _("Could not create network monitor: %s"),
123
0
                   g_strerror (errsv));
124
0
      (void) g_close (sockfd, NULL);
125
0
      return FALSE;
126
0
    }
127
128
0
  nl->priv->sock = g_socket_new_from_fd (sockfd, error);
129
0
  if (!nl->priv->sock)
130
0
    {
131
0
      g_prefix_error (error, "%s", _("Could not create network monitor: "));
132
0
      (void) g_close (sockfd, NULL);
133
0
      return FALSE;
134
0
    }
135
136
0
#ifdef SO_PASSCRED
137
0
  if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED,
138
0
          TRUE, NULL))
139
0
    {
140
0
      int errsv = errno;
141
0
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
142
0
                   _("Could not create network monitor: %s"),
143
0
                   g_strerror (errsv));
144
0
      return FALSE;
145
0
    }
146
0
#endif
147
148
  /* Request the current state */
149
0
  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
0
  while (nl->priv->dump_networks)
156
0
    {
157
0
      GError *local_error = NULL;
158
0
      if (!read_netlink_messages (nl, &local_error))
159
0
        {
160
0
          g_warning ("%s", local_error->message);
161
0
          g_clear_error (&local_error);
162
0
          break;
163
0
        }
164
0
    }
165
166
0
  g_socket_set_blocking (nl->priv->sock, FALSE);
167
0
  nl->priv->context = g_main_context_ref_thread_default ();
168
0
  nl->priv->source = g_socket_create_source (nl->priv->sock, G_IO_IN, NULL);
169
0
  g_source_set_callback (nl->priv->source,
170
0
                         (GSourceFunc) read_netlink_messages_callback, nl, NULL);
171
0
  g_source_attach (nl->priv->source, nl->priv->context);
172
173
0
  return initable_parent_iface->init (initable, cancellable, error);
174
0
}
175
176
static gboolean
177
request_dump (GNetworkMonitorNetlink  *nl,
178
              GError                 **error)
179
0
{
180
0
  struct nlmsghdr *n;
181
0
  struct rtgenmsg *gen;
182
0
  gchar buf[NLMSG_SPACE (sizeof (*gen))];
183
184
0
  memset (buf, 0, sizeof (buf));
185
0
  n = (struct nlmsghdr*) buf;
186
0
  n->nlmsg_len = NLMSG_LENGTH (sizeof (*gen));
187
0
  n->nlmsg_type = RTM_GETROUTE;
188
0
  n->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
189
0
  n->nlmsg_pid = 0;
190
0
  gen = NLMSG_DATA (n);
191
0
  gen->rtgen_family = AF_UNSPEC;
192
193
0
  if (g_socket_send (nl->priv->sock, buf, sizeof (buf),
194
0
                     NULL, error) < 0)
195
0
    {
196
0
      g_prefix_error (error, "%s", _("Could not get network status: "));
197
0
      return FALSE;
198
0
    }
199
200
0
  nl->priv->dump_networks = g_ptr_array_new_with_free_func (g_object_unref);
201
0
  return TRUE;
202
0
}
203
204
static gboolean
205
timeout_request_dump (gpointer user_data)
206
0
{
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
0
}
217
218
static void
219
queue_request_dump (GNetworkMonitorNetlink *nl)
220
0
{
221
0
  if (nl->priv->dump_networks)
222
0
    return;
223
224
0
  if (nl->priv->dump_source)
225
0
    {
226
0
      g_source_destroy (nl->priv->dump_source);
227
0
      g_source_unref (nl->priv->dump_source);
228
0
    }
229
230
0
  nl->priv->dump_source = g_timeout_source_new_seconds (1);
231
0
  g_source_set_callback (nl->priv->dump_source,
232
0
                         (GSourceFunc) timeout_request_dump, nl, NULL);
233
0
  g_source_attach (nl->priv->dump_source, nl->priv->context);
234
0
}
235
236
static GInetAddressMask *
237
create_inet_address_mask (GSocketFamily  family,
238
                          const guint8  *dest,
239
                          gsize          dest_len)
240
0
{
241
0
  GInetAddress *dest_addr;
242
0
  GInetAddressMask *network;
243
244
0
  if (dest)
245
0
    dest_addr = g_inet_address_new_from_bytes (dest, family);
246
0
  else
247
0
    dest_addr = g_inet_address_new_any (family);
248
0
  network = g_inet_address_mask_new (dest_addr, dest_len, NULL);
249
0
  g_object_unref (dest_addr);
250
251
0
  return network;
252
0
}
253
254
static void
255
add_network (GNetworkMonitorNetlink *nl,
256
             GSocketFamily           family,
257
             const guint8           *dest,
258
             gsize                   dest_len)
259
0
{
260
0
  GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len);
261
0
  g_return_if_fail (network != NULL);
262
263
0
  if (nl->priv->dump_networks)
264
0
    g_ptr_array_add (nl->priv->dump_networks, g_object_ref (network));
265
0
  else
266
0
    g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network);
267
268
0
  g_object_unref (network);
269
0
}
270
271
static void
272
remove_network (GNetworkMonitorNetlink *nl,
273
                GSocketFamily           family,
274
                const guint8           *dest,
275
                gsize                   dest_len)
276
0
{
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
0
    {
282
0
      GInetAddressMask **dump_networks = (GInetAddressMask **)nl->priv->dump_networks->pdata;
283
0
      guint i;
284
285
0
      for (i = 0; i < nl->priv->dump_networks->len; i++)
286
0
        {
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
0
        }
290
0
    }
291
0
  else
292
0
    {
293
0
      g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl), network);
294
0
    }
295
296
0
  g_object_unref (network);
297
0
}
298
299
static void
300
finish_dump (GNetworkMonitorNetlink *nl)
301
0
{
302
0
  g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl),
303
0
                                       (GInetAddressMask **)nl->priv->dump_networks->pdata,
304
0
                                       nl->priv->dump_networks->len);
305
0
  g_ptr_array_free (nl->priv->dump_networks, TRUE);
306
0
  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
0
}
337
338
static gboolean
339
read_netlink_messages (GNetworkMonitorNetlink  *nl,
340
                       GError                 **error)
341
0
{
342
0
  GInputVector iv;
343
0
  gssize len;
344
0
  gint flags;
345
0
  GError *local_error = NULL;
346
0
  GSocketAddress *addr = NULL;
347
0
  struct nlmsghdr *msg;
348
0
  struct rtmsg *rtmsg;
349
0
  struct rtattr *attr;
350
0
  struct sockaddr_nl source_sockaddr;
351
0
  gsize attrlen;
352
0
  guint8 *dest, *gateway, *oif;
353
354
0
  iv.buffer = NULL;
355
0
  iv.size = 0;
356
357
0
  flags = MSG_PEEK | MSG_TRUNC;
358
0
  len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1,
359
0
                                  NULL, NULL, &flags, NULL, &local_error);
360
0
  if (len < 0)
361
0
    goto done;
362
363
0
  iv.buffer = g_malloc (len);
364
0
  iv.size = len;
365
0
  len = g_socket_receive_message (nl->priv->sock, &addr, &iv, 1,
366
0
                                  NULL, NULL, NULL, NULL, &local_error);
367
0
  if (len < 0)
368
0
    goto done;
369
370
0
  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
0
  if (source_sockaddr.nl_pid != 0)
375
0
    goto done;
376
377
0
  msg = (struct nlmsghdr *) iv.buffer;
378
0
  for (; len > 0; msg = NLMSG_NEXT (msg, len))
379
0
    {
380
0
      if (!NLMSG_OK (msg, (size_t) len))
381
0
        {
382
0
          g_set_error_literal (&local_error,
383
0
                               G_IO_ERROR,
384
0
                               G_IO_ERROR_PARTIAL_INPUT,
385
0
                               "netlink message was truncated; shouldn't happen...");
386
0
          goto done;
387
0
        }
388
389
0
      switch (msg->nlmsg_type)
390
0
        {
391
0
        case RTM_NEWROUTE:
392
0
        case RTM_DELROUTE:
393
0
          rtmsg = NLMSG_DATA (msg);
394
395
0
          if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6)
396
0
            continue;
397
0
          if (rtmsg->rtm_type == RTN_UNREACHABLE)
398
0
            continue;
399
400
0
          attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg));
401
0
          attr = RTM_RTA (rtmsg);
402
0
          dest = gateway = oif = NULL;
403
0
          while (RTA_OK (attr, attrlen))
404
0
            {
405
0
              if (attr->rta_type == RTA_DST)
406
0
                dest = RTA_DATA (attr);
407
0
              else if (attr->rta_type == RTA_GATEWAY)
408
0
                gateway = RTA_DATA (attr);
409
0
              else if (attr->rta_type == RTA_OIF)
410
0
                oif = RTA_DATA (attr);
411
0
              attr = RTA_NEXT (attr, attrlen);
412
0
            }
413
414
0
          if (dest || gateway || oif)
415
0
            {
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
0
#define UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL(a)           \
421
0
              ((a[0] == 0xff) && ((a[1] & 0xf) == 0x2))
422
423
0
              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
0
              if (msg->nlmsg_type == RTM_NEWROUTE)
430
0
                add_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
431
0
              else
432
0
                remove_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
433
0
              queue_request_dump (nl);
434
0
            }
435
0
          break;
436
437
0
        case NLMSG_DONE:
438
0
          finish_dump (nl);
439
0
          goto done;
440
441
0
        case NLMSG_ERROR:
442
0
          {
443
0
            struct nlmsgerr *e = NLMSG_DATA (msg);
444
445
0
            g_set_error (&local_error,
446
0
                         G_IO_ERROR,
447
0
                         g_io_error_from_errno (-e->error),
448
0
                         "netlink error: %s",
449
0
                         g_strerror (-e->error));
450
0
          }
451
0
          goto done;
452
453
0
        default:
454
0
          g_set_error (&local_error,
455
0
                       G_IO_ERROR,
456
0
                       G_IO_ERROR_INVALID_DATA,
457
0
                       "unexpected netlink message %d",
458
0
                       msg->nlmsg_type);
459
0
          goto done;
460
0
        }
461
0
    }
462
463
0
 done:
464
0
  g_free (iv.buffer);
465
0
  g_clear_object (&addr);
466
467
0
  if (local_error != NULL && nl->priv->dump_networks)
468
0
    finish_dump (nl);
469
470
0
  if (local_error != NULL)
471
0
    {
472
0
      g_propagate_prefixed_error (error, local_error, "Error on netlink socket: ");
473
0
      return FALSE;
474
0
    }
475
0
  else
476
0
    {
477
0
      return TRUE;
478
0
    }
479
0
}
480
481
static void
482
g_network_monitor_netlink_finalize (GObject *object)
483
0
{
484
0
  GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object);
485
486
0
  if (nl->priv->source)
487
0
    {
488
0
      g_source_destroy (nl->priv->source);
489
0
      g_source_unref (nl->priv->source);
490
0
    }
491
492
0
  if (nl->priv->dump_source)
493
0
    {
494
0
      g_source_destroy (nl->priv->dump_source);
495
0
      g_source_unref (nl->priv->dump_source);
496
0
    }
497
498
0
  if (nl->priv->sock)
499
0
    {
500
0
      g_socket_close (nl->priv->sock, NULL);
501
0
      g_object_unref (nl->priv->sock);
502
0
    }
503
504
0
  g_clear_pointer (&nl->priv->context, g_main_context_unref);
505
0
  g_clear_pointer (&nl->priv->dump_networks, g_ptr_array_unref);
506
507
0
  G_OBJECT_CLASS (g_network_monitor_netlink_parent_class)->finalize (object);
508
0
}
509
510
static gboolean
511
read_netlink_messages_callback (GSocket      *socket,
512
                                GIOCondition  condition,
513
                                gpointer      user_data)
514
0
{
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
0
    {
520
0
      g_warning ("Error reading netlink message: %s", error->message);
521
0
      g_clear_error (&error);
522
0
      return FALSE;
523
0
    }
524
525
0
  return TRUE;
526
0
}
527
528
static void
529
g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class)
530
0
{
531
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
532
533
0
  gobject_class->finalize = g_network_monitor_netlink_finalize;
534
0
}
535
536
static void
537
g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface)
538
0
{
539
0
}
540
541
static void
542
g_network_monitor_netlink_initable_iface_init (GInitableIface *iface)
543
0
{
544
0
  initable_parent_iface = g_type_interface_peek_parent (iface);
545
546
0
  iface->init = g_network_monitor_netlink_initable_init;
547
0
}