Coverage Report

Created: 2025-07-01 07:09

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