Coverage Report

Created: 2025-07-01 07:09

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