(root)/
glib-2.79.0/
gio/
ginetaddressmask.c
       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  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  g_inet_address_mask_set_property (GObject      *object,
      67  				  guint         prop_id,
      68  				  const GValue *value,
      69  				  GParamSpec   *pspec)
      70  {
      71    GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
      72  
      73    switch (prop_id)
      74      {
      75      case PROP_ADDRESS:
      76        if (mask->priv->addr)
      77  	g_object_unref (mask->priv->addr);
      78        mask->priv->addr = g_value_dup_object (value);
      79        break;
      80  
      81      case PROP_LENGTH:
      82        mask->priv->length = g_value_get_uint (value);
      83        break;
      84  
      85      default:
      86        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      87        break;
      88      }
      89  
      90  }
      91  
      92  static void
      93  g_inet_address_mask_get_property (GObject    *object,
      94  				  guint       prop_id,
      95  				  GValue     *value,
      96  				  GParamSpec *pspec)
      97  {
      98    GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
      99  
     100    switch (prop_id)
     101      {
     102      case PROP_FAMILY:
     103        g_value_set_enum (value, g_inet_address_get_family (mask->priv->addr));
     104        break;
     105  
     106      case PROP_ADDRESS:
     107        g_value_set_object (value, mask->priv->addr);
     108        break;
     109  
     110      case PROP_LENGTH:
     111        g_value_set_uint (value, mask->priv->length);
     112        break;
     113  
     114      default:
     115        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     116      }
     117  }
     118  
     119  static void
     120  g_inet_address_mask_dispose (GObject *object)
     121  {
     122    GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
     123  
     124    g_clear_object (&mask->priv->addr);
     125  
     126    G_OBJECT_CLASS (g_inet_address_mask_parent_class)->dispose (object);
     127  }
     128  
     129  static void
     130  g_inet_address_mask_class_init (GInetAddressMaskClass *klass)
     131  {
     132    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     133  
     134    gobject_class->set_property = g_inet_address_mask_set_property;
     135    gobject_class->get_property = g_inet_address_mask_get_property;
     136    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    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    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    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  }
     178  
     179  static gboolean
     180  g_inet_address_mask_initable_init (GInitable     *initable,
     181  				   GCancellable  *cancellable,
     182  				   GError       **error)
     183  {
     184    GInetAddressMask *mask = G_INET_ADDRESS_MASK (initable);
     185    guint addrlen, nbytes, nbits;
     186    const guint8 *bytes;
     187    gboolean ok;
     188  
     189    if (!mask->priv->addr)
     190      {
     191        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
     192  			   _("No address specified"));
     193        return FALSE;
     194      }
     195  
     196    addrlen = g_inet_address_get_native_size (mask->priv->addr);
     197    if (mask->priv->length > addrlen * 8)
     198      {
     199        g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
     200  		   _("Length %u is too long for address"),
     201  		   mask->priv->length);
     202        return FALSE;
     203      }
     204  
     205    /* Make sure all the bits after @length are 0 */
     206    bytes = g_inet_address_to_bytes (mask->priv->addr);
     207    ok = TRUE;
     208  
     209    nbytes = mask->priv->length / 8;
     210    bytes += nbytes;
     211    addrlen -= nbytes;
     212  
     213    nbits = mask->priv->length % 8;
     214    if (nbits)
     215      {
     216        if (bytes[0] & (0xFF >> nbits))
     217  	ok = FALSE;
     218        bytes++;
     219        addrlen--;
     220      }
     221  
     222    while (addrlen)
     223      {
     224        if (bytes[0])
     225  	ok = FALSE;
     226        bytes++;
     227        addrlen--;
     228      }
     229  
     230    if (!ok)
     231      {
     232        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
     233  			   _("Address has bits set beyond prefix length"));
     234        return FALSE;
     235      }
     236  
     237    return TRUE;
     238  }
     239  
     240  static void
     241  g_inet_address_mask_initable_iface_init (GInitableIface  *iface)
     242  {
     243    iface->init = g_inet_address_mask_initable_init;
     244  }
     245  
     246  static void
     247  g_inet_address_mask_init (GInetAddressMask *mask)
     248  {
     249    mask->priv = g_inet_address_mask_get_instance_private (mask);
     250  }
     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  g_inet_address_mask_new (GInetAddress  *addr,
     267  			 guint          length,
     268  			 GError       **error)
     269  {
     270    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  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    slash = strchr (mask_string, '/');
     301    if (slash)
     302      {
     303        gchar *address, *end;
     304  
     305        length = strtoul (slash + 1, &end, 10);
     306        if (*end || !*(slash + 1))
     307  	{
     308  	parse_error:
     309  	  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  	  return NULL;
     313  	}
     314  
     315        address = g_strndup (mask_string, slash - mask_string);
     316        addr = g_inet_address_new_from_string (address);
     317        g_free (address);
     318  
     319        if (!addr)
     320  	goto parse_error;
     321      }
     322    else
     323      {
     324        addr = g_inet_address_new_from_string (mask_string);
     325        if (!addr)
     326  	goto parse_error;
     327  
     328        length = g_inet_address_get_native_size (addr) * 8;
     329      }
     330  
     331    mask = g_inet_address_mask_new (addr, length, error);
     332    g_object_unref (addr);
     333  
     334    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  g_inet_address_mask_to_string (GInetAddressMask *mask)
     349  {
     350    gchar *addr_string, *mask_string;
     351  
     352    g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), NULL);
     353  
     354    addr_string = g_inet_address_to_string (mask->priv->addr);
     355  
     356    if (mask->priv->length == (g_inet_address_get_native_size (mask->priv->addr) * 8))
     357      return addr_string;
     358  
     359    mask_string = g_strdup_printf ("%s/%u", addr_string, mask->priv->length);
     360    g_free (addr_string);
     361  
     362    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  g_inet_address_mask_get_family (GInetAddressMask *mask)
     377  {
     378    g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), G_SOCKET_FAMILY_INVALID);
     379  
     380    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  g_inet_address_mask_get_address (GInetAddressMask *mask)
     395  {
     396    g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), NULL);
     397  
     398    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  g_inet_address_mask_get_length (GInetAddressMask *mask)
     413  {
     414    g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), 0);
     415  
     416    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  g_inet_address_mask_matches (GInetAddressMask *mask,
     433  			     GInetAddress     *address)
     434  {
     435    const guint8 *maskbytes, *addrbytes;
     436    int nbytes, nbits;
     437  
     438    g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), FALSE);
     439    g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
     440  
     441    if (g_inet_address_get_family (mask->priv->addr) !=
     442        g_inet_address_get_family (address))
     443      return FALSE;
     444  
     445    if (mask->priv->length == 0)
     446      return TRUE;
     447  
     448    maskbytes = g_inet_address_to_bytes (mask->priv->addr);
     449    addrbytes = g_inet_address_to_bytes (address);
     450  
     451    nbytes = mask->priv->length / 8;
     452    if (nbytes != 0 && memcmp (maskbytes, addrbytes, nbytes) != 0)
     453      return FALSE;
     454  
     455    nbits = mask->priv->length % 8;
     456    if (nbits == 0)
     457      return TRUE;
     458  
     459    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  g_inet_address_mask_equal (GInetAddressMask  *mask,
     476  			   GInetAddressMask  *mask2)
     477  {
     478    g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), FALSE);
     479    g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask2), FALSE);
     480  
     481    return ((mask->priv->length == mask2->priv->length) &&
     482  	  g_inet_address_equal (mask->priv->addr, mask2->priv->addr));
     483  }