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