Coverage Report

Created: 2025-06-13 06:55

/src/glib/gio/ginetaddressmask.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 <stdlib.h>
24
#include <string.h>
25
26
#include "ginetaddressmask.h"
27
#include "ginetaddress.h"
28
#include "ginitable.h"
29
#include "gioerror.h"
30
#include "gioenumtypes.h"
31
#include "glibintl.h"
32
33
/**
34
 * SECTION:ginetaddressmask
35
 * @short_description: An IPv4/IPv6 address mask
36
 * @include: gio/gio.h
37
 *
38
 * #GInetAddressMask represents a range of IPv4 or IPv6 addresses
39
 * described by a base address and a length indicating how many bits
40
 * of the base address are relevant for matching purposes. These are
41
 * often given in string form. Eg, "10.0.0.0/8", or "fe80::/10".
42
 */
43
44
/**
45
 * GInetAddressMask:
46
 *
47
 * A combination of an IPv4 or IPv6 base address and a length,
48
 * representing a range of IP addresses.
49
 *
50
 * Since: 2.32
51
 */
52
53
struct _GInetAddressMaskPrivate
54
{
55
  GInetAddress *addr;
56
  guint         length;
57
};
58
59
static void     g_inet_address_mask_initable_iface_init (GInitableIface  *iface);
60
61
G_DEFINE_TYPE_WITH_CODE (GInetAddressMask, g_inet_address_mask, G_TYPE_OBJECT,
62
                         G_ADD_PRIVATE (GInetAddressMask)
63
       G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
64
            g_inet_address_mask_initable_iface_init))
65
66
enum
67
{
68
  PROP_0,
69
  PROP_FAMILY,
70
  PROP_ADDRESS,
71
  PROP_LENGTH
72
};
73
74
static void
75
g_inet_address_mask_set_property (GObject      *object,
76
          guint         prop_id,
77
          const GValue *value,
78
          GParamSpec   *pspec)
79
0
{
80
0
  GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
81
82
0
  switch (prop_id)
83
0
    {
84
0
    case PROP_ADDRESS:
85
0
      if (mask->priv->addr)
86
0
  g_object_unref (mask->priv->addr);
87
0
      mask->priv->addr = g_value_dup_object (value);
88
0
      break;
89
90
0
    case PROP_LENGTH:
91
0
      mask->priv->length = g_value_get_uint (value);
92
0
      break;
93
94
0
    default:
95
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
96
0
      break;
97
0
    }
98
99
0
}
100
101
static void
102
g_inet_address_mask_get_property (GObject    *object,
103
          guint       prop_id,
104
          GValue     *value,
105
          GParamSpec *pspec)
106
0
{
107
0
  GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
108
109
0
  switch (prop_id)
110
0
    {
111
0
    case PROP_FAMILY:
112
0
      g_value_set_enum (value, g_inet_address_get_family (mask->priv->addr));
113
0
      break;
114
115
0
    case PROP_ADDRESS:
116
0
      g_value_set_object (value, mask->priv->addr);
117
0
      break;
118
119
0
    case PROP_LENGTH:
120
0
      g_value_set_uint (value, mask->priv->length);
121
0
      break;
122
123
0
    default:
124
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
125
0
    }
126
0
}
127
128
static void
129
g_inet_address_mask_dispose (GObject *object)
130
0
{
131
0
  GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
132
133
0
  g_clear_object (&mask->priv->addr);
134
135
0
  G_OBJECT_CLASS (g_inet_address_mask_parent_class)->dispose (object);
136
0
}
137
138
static void
139
g_inet_address_mask_class_init (GInetAddressMaskClass *klass)
140
0
{
141
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
142
143
0
  gobject_class->set_property = g_inet_address_mask_set_property;
144
0
  gobject_class->get_property = g_inet_address_mask_get_property;
145
0
  gobject_class->dispose = g_inet_address_mask_dispose;
146
147
0
  g_object_class_install_property (gobject_class, PROP_FAMILY,
148
0
                                   g_param_spec_enum ("family",
149
0
                  P_("Address family"),
150
0
                  P_("The address family (IPv4 or IPv6)"),
151
0
                  G_TYPE_SOCKET_FAMILY,
152
0
                  G_SOCKET_FAMILY_INVALID,
153
0
                  G_PARAM_READABLE |
154
0
                                                      G_PARAM_STATIC_STRINGS));
155
0
  g_object_class_install_property (gobject_class, PROP_ADDRESS,
156
0
                                   g_param_spec_object ("address",
157
0
              P_("Address"),
158
0
              P_("The base address"),
159
0
              G_TYPE_INET_ADDRESS,
160
0
              G_PARAM_READWRITE |
161
0
              G_PARAM_STATIC_STRINGS));
162
0
  g_object_class_install_property (gobject_class, PROP_LENGTH,
163
0
                                   g_param_spec_uint ("length",
164
0
                  P_("Length"),
165
0
                  P_("The prefix length"),
166
0
                  0, 128, 0,
167
0
                  G_PARAM_READWRITE |
168
0
                  G_PARAM_STATIC_STRINGS));
169
0
}
170
171
static gboolean
172
g_inet_address_mask_initable_init (GInitable     *initable,
173
           GCancellable  *cancellable,
174
           GError       **error)
175
0
{
176
0
  GInetAddressMask *mask = G_INET_ADDRESS_MASK (initable);
177
0
  guint addrlen, nbytes, nbits;
178
0
  const guint8 *bytes;
179
0
  gboolean ok;
180
181
0
  if (!mask->priv->addr)
182
0
    {
183
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
184
0
         _("No address specified"));
185
0
      return FALSE;
186
0
    }
187
188
0
  addrlen = g_inet_address_get_native_size (mask->priv->addr);
189
0
  if (mask->priv->length > addrlen * 8)
190
0
    {
191
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
192
0
       _("Length %u is too long for address"),
193
0
       mask->priv->length);
194
0
      return FALSE;
195
0
    }
196
197
  /* Make sure all the bits after @length are 0 */
198
0
  bytes = g_inet_address_to_bytes (mask->priv->addr);
199
0
  ok = TRUE;
200
201
0
  nbytes = mask->priv->length / 8;
202
0
  bytes += nbytes;
203
0
  addrlen -= nbytes;
204
205
0
  nbits = mask->priv->length % 8;
206
0
  if (nbits)
207
0
    {
208
0
      if (bytes[0] & (0xFF >> nbits))
209
0
  ok = FALSE;
210
0
      bytes++;
211
0
      addrlen--;
212
0
    }
213
214
0
  while (addrlen)
215
0
    {
216
0
      if (bytes[0])
217
0
  ok = FALSE;
218
0
      bytes++;
219
0
      addrlen--;
220
0
    }
221
222
0
  if (!ok)
223
0
    {
224
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
225
0
         _("Address has bits set beyond prefix length"));
226
0
      return FALSE;
227
0
    }
228
229
0
  return TRUE;
230
0
}
231
232
static void
233
g_inet_address_mask_initable_iface_init (GInitableIface  *iface)
234
0
{
235
0
  iface->init = g_inet_address_mask_initable_init;
236
0
}
237
238
static void
239
g_inet_address_mask_init (GInetAddressMask *mask)
240
0
{
241
0
  mask->priv = g_inet_address_mask_get_instance_private (mask);
242
0
}
243
244
/**
245
 * g_inet_address_mask_new:
246
 * @addr: a #GInetAddress
247
 * @length: number of bits of @addr to use
248
 * @error: return location for #GError, or %NULL
249
 *
250
 * Creates a new #GInetAddressMask representing all addresses whose
251
 * first @length bits match @addr.
252
 *
253
 * Returns: a new #GInetAddressMask, or %NULL on error
254
 *
255
 * Since: 2.32
256
 */
257
GInetAddressMask *
258
g_inet_address_mask_new (GInetAddress  *addr,
259
       guint          length,
260
       GError       **error)
261
0
{
262
0
  return g_initable_new (G_TYPE_INET_ADDRESS_MASK, NULL, error,
263
0
       "address", addr,
264
0
       "length", length,
265
0
       NULL);
266
0
}
267
268
/**
269
 * g_inet_address_mask_new_from_string:
270
 * @mask_string: an IP address or address/length string
271
 * @error: return location for #GError, or %NULL
272
 *
273
 * Parses @mask_string as an IP address and (optional) length, and
274
 * creates a new #GInetAddressMask. The length, if present, is
275
 * delimited by a "/". If it is not present, then the length is
276
 * assumed to be the full length of the address.
277
 *
278
 * Returns: a new #GInetAddressMask corresponding to @string, or %NULL
279
 * on error.
280
 *
281
 * Since: 2.32
282
 */
283
GInetAddressMask *
284
g_inet_address_mask_new_from_string (const gchar  *mask_string,
285
             GError      **error)
286
0
{
287
0
  GInetAddressMask *mask;
288
0
  GInetAddress *addr;
289
0
  gchar *slash;
290
0
  guint length;
291
292
0
  slash = strchr (mask_string, '/');
293
0
  if (slash)
294
0
    {
295
0
      gchar *address, *end;
296
297
0
      length = strtoul (slash + 1, &end, 10);
298
0
      if (*end || !*(slash + 1))
299
0
  {
300
0
  parse_error:
301
0
    g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
302
0
           _("Could not parse ā€œ%sā€ as IP address mask"),
303
0
           mask_string);
304
0
    return NULL;
305
0
  }
306
307
0
      address = g_strndup (mask_string, slash - mask_string);
308
0
      addr = g_inet_address_new_from_string (address);
309
0
      g_free (address);
310
311
0
      if (!addr)
312
0
  goto parse_error;
313
0
    }
314
0
  else
315
0
    {
316
0
      addr = g_inet_address_new_from_string (mask_string);
317
0
      if (!addr)
318
0
  goto parse_error;
319
320
0
      length = g_inet_address_get_native_size (addr) * 8;
321
0
    }
322
323
0
  mask = g_inet_address_mask_new (addr, length, error);
324
0
  g_object_unref (addr);
325
326
0
  return mask;
327
0
}
328
329
/**
330
 * g_inet_address_mask_to_string:
331
 * @mask: a #GInetAddressMask
332
 *
333
 * Converts @mask back to its corresponding string form.
334
 *
335
 * Returns: a string corresponding to @mask.
336
 *
337
 * Since: 2.32
338
 */
339
gchar *
340
g_inet_address_mask_to_string (GInetAddressMask *mask)
341
0
{
342
0
  gchar *addr_string, *mask_string;
343
344
0
  g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), NULL);
345
346
0
  addr_string = g_inet_address_to_string (mask->priv->addr);
347
348
0
  if (mask->priv->length == (g_inet_address_get_native_size (mask->priv->addr) * 8))
349
0
    return addr_string;
350
351
0
  mask_string = g_strdup_printf ("%s/%u", addr_string, mask->priv->length);
352
0
  g_free (addr_string);
353
354
0
  return mask_string;
355
0
}
356
357
/**
358
 * g_inet_address_mask_get_family:
359
 * @mask: a #GInetAddressMask
360
 *
361
 * Gets the #GSocketFamily of @mask's address
362
 *
363
 * Returns: the #GSocketFamily of @mask's address
364
 *
365
 * Since: 2.32
366
 */
367
GSocketFamily
368
g_inet_address_mask_get_family (GInetAddressMask *mask)
369
0
{
370
0
  g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), G_SOCKET_FAMILY_INVALID);
371
372
0
  return g_inet_address_get_family (mask->priv->addr);
373
0
}
374
375
/**
376
 * g_inet_address_mask_get_address:
377
 * @mask: a #GInetAddressMask
378
 *
379
 * Gets @mask's base address
380
 *
381
 * Returns: (transfer none): @mask's base address
382
 *
383
 * Since: 2.32
384
 */
385
GInetAddress *
386
g_inet_address_mask_get_address (GInetAddressMask *mask)
387
0
{
388
0
  g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), NULL);
389
390
0
  return mask->priv->addr;
391
0
}
392
393
/**
394
 * g_inet_address_mask_get_length:
395
 * @mask: a #GInetAddressMask
396
 *
397
 * Gets @mask's length
398
 *
399
 * Returns: @mask's length
400
 *
401
 * Since: 2.32
402
 */
403
guint
404
g_inet_address_mask_get_length (GInetAddressMask *mask)
405
0
{
406
0
  g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), 0);
407
408
0
  return mask->priv->length;
409
0
}
410
411
/**
412
 * g_inet_address_mask_matches:
413
 * @mask: a #GInetAddressMask
414
 * @address: a #GInetAddress
415
 *
416
 * Tests if @address falls within the range described by @mask.
417
 *
418
 * Returns: whether @address falls within the range described by
419
 * @mask.
420
 *
421
 * Since: 2.32
422
 */
423
gboolean
424
g_inet_address_mask_matches (GInetAddressMask *mask,
425
           GInetAddress     *address)
426
0
{
427
0
  const guint8 *maskbytes, *addrbytes;
428
0
  int nbytes, nbits;
429
430
0
  g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), FALSE);
431
0
  g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
432
433
0
  if (g_inet_address_get_family (mask->priv->addr) !=
434
0
      g_inet_address_get_family (address))
435
0
    return FALSE;
436
437
0
  if (mask->priv->length == 0)
438
0
    return TRUE;
439
440
0
  maskbytes = g_inet_address_to_bytes (mask->priv->addr);
441
0
  addrbytes = g_inet_address_to_bytes (address);
442
443
0
  nbytes = mask->priv->length / 8;
444
0
  if (nbytes != 0 && memcmp (maskbytes, addrbytes, nbytes) != 0)
445
0
    return FALSE;
446
447
0
  nbits = mask->priv->length % 8;
448
0
  if (nbits == 0)
449
0
    return TRUE;
450
451
0
  return maskbytes[nbytes] == (addrbytes[nbytes] & (0xFF << (8 - nbits)));
452
0
}
453
454
455
/**
456
 * g_inet_address_mask_equal:
457
 * @mask: a #GInetAddressMask
458
 * @mask2: another #GInetAddressMask
459
 *
460
 * Tests if @mask and @mask2 are the same mask.
461
 *
462
 * Returns: whether @mask and @mask2 are the same mask
463
 *
464
 * Since: 2.32
465
 */
466
gboolean
467
g_inet_address_mask_equal (GInetAddressMask  *mask,
468
         GInetAddressMask  *mask2)
469
0
{
470
0
  g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), FALSE);
471
0
  g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask2), FALSE);
472
473
0
  return ((mask->priv->length == mask2->priv->length) &&
474
0
    g_inet_address_equal (mask->priv->addr, mask2->priv->addr));
475
0
}