]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Use fr_ipaddr_t for prefixes in value_box_t too. Closes #1979
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 5 May 2017 23:44:50 +0000 (19:44 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 5 May 2017 23:45:19 +0000 (19:45 -0400)
Now all the IP address types use a single struct (woohoo)

src/include/pair.h
src/include/value.h
src/lib/util/value.c
src/main/client.c
src/main/pair.c
src/main/xlat_func.c
src/protocols/radius/decode.c
src/tests/keywords/base64
src/tests/keywords/cast-ipaddr
src/tests/keywords/hex

index de92af7e60c3d25bd1b9e9539b3e3340245f85d7..6ba8632629e39b204db25470737b3d962567bd73 100644 (file)
@@ -136,7 +136,6 @@ typedef struct value_pair_raw {
 #define vp_filter      data.datum.filter
 #define vp_octets      data.datum.octets
 #define vp_ifid                data.datum.ifid
-#define vp_ipv6prefix  data.datum.ipv6prefix
 #define vp_bool                data.datum.boolean
 #define vp_byte                data.datum.byte
 #define vp_short       data.datum.ushort
@@ -144,7 +143,6 @@ typedef struct value_pair_raw {
 #define vp_signed      data.datum.sinteger
 #define vp_integer64   data.datum.integer64
 #define vp_size                data.datum.size
-#define vp_ipv4prefix  data.datum.ipv4prefix
 #define vp_decimal     data.datum.decimal
 #define vp_ptr         data.datum.ptr                          //!< Either octets or strvalue
 
index 3c0fb55a8768d26780fa62e03180cc2cd9bbe20b..99baf8c6dae8c497f2c588c4d55635adad752307 100644 (file)
@@ -39,10 +39,6 @@ struct value_box {
 
                fr_ipaddr_t             ip;                     //!< IPv4/6 address/prefix.
 
-               uint8_t                 ipv4prefix[6];          //!< IPv4 prefix (should be struct?).
-               uint8_t                 ipv6prefix[18];         //!< IPv6 prefix (should be struct?).
-
-
                uint8_t                 ifid[8];                //!< IPv6 interface ID (should be struct?).
                uint8_t                 ether[6];               //!< Ethernet (MAC) address.
 
index 60d06277dd037681c0c2212d07690f1637ee4c2e..32cf41a16c97f51271d176b3114ca47ac49c08ee 100644 (file)
@@ -1,8 +1,4 @@
 /*
- * value.c     Functions to handle value_box_t
- *
- * Version:    $Id$
- *
  *   This library is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU Lesser General Public
  *   License as published by the Free Software Foundation; either
  *   You should have received a copy of the GNU Lesser General Public
  *   License along with this library; if not, write to the Free Software
  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Copyright 2014 The FreeRADIUS server project
  */
 
+/**
+ * $Id$
+ * @file value.c
+ * @brief Manipulate boxed values representing all internal data types.
+ *
+ * There are three notional data formats used in the server:
+ *
+ * - #value_box_t are the INTERNAL format.  This is usually close to the in-memory representation
+ *   of the data, though integers and IPs are always converted to/from octets with BIG ENDIAN
+ *   byte ordering for consistency.
+ *   - #value_box_cast is used to convert (cast) #value_box_t between INTERNAL formats.
+ *   - #value_box_strdup* is used to convert nul terminated strings to the INTERNAL format.
+ *   - #value_box_memdup* is used to convert binary data to the INTERNAL format.
+ *
+ * - NETWORK format is the format we receive on the wire.  It is not a perfect representation of data
+ *   packing for all protocols, so you will likely need to overload conversion for some types.
+ *   - #value_box_to_network is used to covert INTERNAL format data to generic NETWORK format data.
+ *     For integers, IP addresses etc... This means BIG ENDIAN byte ordering.
+ *   - #value_box_from_network is used to convert packet buffer fragments in NETWORK format to
+ *     INTERNAL format.
+ *
+ * - PRESENTATION format is what we print to the screen, and what we read from the user, databases
+ *   and configuration files.
+ *   - #value_box_snprint is used to convert INTERNAL format PRESENTATION format.
+ *   - #value_box_from_str is used to convert from INTERNAL to PRESENTATION format.
+ *
+ * @copyright 2014-2017 The FreeRADIUS server project
+ * @copyright 2017 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
 RCSID("$Id$")
 
 #include <freeradius-devel/libradius.h>
@@ -36,9 +59,9 @@ size_t const value_box_field_sizes[] = {
        [PW_TYPE_OCTETS]                        = SIZEOF_MEMBER(value_box_t, datum.octets),
 
        [PW_TYPE_IPV4_ADDR]                     = SIZEOF_MEMBER(value_box_t, datum.ip),
-       [PW_TYPE_IPV4_PREFIX]                   = SIZEOF_MEMBER(value_box_t, datum.ipv4prefix),
+       [PW_TYPE_IPV4_PREFIX]                   = SIZEOF_MEMBER(value_box_t, datum.ip),
        [PW_TYPE_IPV6_ADDR]                     = SIZEOF_MEMBER(value_box_t, datum.ip),
-       [PW_TYPE_IPV6_PREFIX]                   = SIZEOF_MEMBER(value_box_t, datum.ipv6prefix),
+       [PW_TYPE_IPV6_PREFIX]                   = SIZEOF_MEMBER(value_box_t, datum.ip),
        [PW_TYPE_IFID]                          = SIZEOF_MEMBER(value_box_t, datum.ifid),
        [PW_TYPE_ETHERNET]                      = SIZEOF_MEMBER(value_box_t, datum.ether),
 
@@ -70,9 +93,9 @@ size_t const value_box_offsets[] = {
        [PW_TYPE_OCTETS]                        = offsetof(value_box_t, datum.octets),
 
        [PW_TYPE_IPV4_ADDR]                     = offsetof(value_box_t, datum.ip),
-       [PW_TYPE_IPV4_PREFIX]                   = offsetof(value_box_t, datum.ipv4prefix),
+       [PW_TYPE_IPV4_PREFIX]                   = offsetof(value_box_t, datum.ip),
        [PW_TYPE_IPV6_ADDR]                     = offsetof(value_box_t, datum.ip),
-       [PW_TYPE_IPV6_PREFIX]                   = offsetof(value_box_t, datum.ipv6prefix),
+       [PW_TYPE_IPV6_PREFIX]                   = offsetof(value_box_t, datum.ip),
        [PW_TYPE_IFID]                          = offsetof(value_box_t, datum.ifid),
        [PW_TYPE_ETHERNET]                      = offsetof(value_box_t, datum.ether),
 
@@ -87,6 +110,7 @@ size_t const value_box_offsets[] = {
 
        [PW_TYPE_TIMEVAL]                       = offsetof(value_box_t, datum.timeval),
        [PW_TYPE_DECIMAL]                       = offsetof(value_box_t, datum.decimal),
+
        [PW_TYPE_DATE]                          = offsetof(value_box_t, datum.date),
 
        [PW_TYPE_ABINARY]                       = offsetof(value_box_t, datum.filter),
@@ -270,29 +294,10 @@ int value_box_cmp(value_box_t const *a, value_box_t const *b)
                break;
 
        case PW_TYPE_IPV4_ADDR:
-       {
-               uint32_t a_int, b_int;
-
-               a_int = ntohl(a->datum.ip.addr.v4.s_addr);
-               b_int = ntohl(b->datum.ip.addr.v4.s_addr);
-               if (a_int < b_int) {
-                       compare = -1;
-               } else if (a_int > b_int) {
-                       compare = +1;
-               }
-       }
-               break;
-
+       case PW_TYPE_IPV4_PREFIX:
        case PW_TYPE_IPV6_ADDR:
-               compare = memcmp(&a->datum.ip, &b->datum.ip, sizeof(a->datum.ip));
-               break;
-
        case PW_TYPE_IPV6_PREFIX:
-               compare = memcmp(a->datum.ipv6prefix, b->datum.ipv6prefix, sizeof(a->datum.ipv6prefix));
-               break;
-
-       case PW_TYPE_IPV4_PREFIX:
-               compare = memcmp(a->datum.ipv4prefix, b->datum.ipv4prefix, sizeof(a->datum.ipv4prefix));
+               compare = memcmp(&a->datum.ip, &b->datum.ip, sizeof(a->datum.ip));
                break;
 
        case PW_TYPE_IFID:
@@ -327,8 +332,8 @@ int value_box_cmp(value_box_t const *a, value_box_t const *b)
  *     reserved, prefix-len, data...
  */
 static int value_box_cidr_cmp_op(FR_TOKEN op, int bytes,
-                                 uint8_t a_net, uint8_t const *a,
-                                 uint8_t b_net, uint8_t const *b)
+                                uint8_t a_net, uint8_t const *a,
+                                uint8_t b_net, uint8_t const *b)
 {
        int i, common;
        uint32_t mask;
@@ -459,8 +464,8 @@ int value_box_cmp_op(FR_TOKEN op, value_box_t const *a, value_box_t const *b)
                        goto cmp;
 
                case PW_TYPE_IPV4_PREFIX:       /* IPv4 and IPv4 Prefix */
-                       return value_box_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->datum.ip.addr.v4,
-                                                    b->datum.ipv4prefix[1], (uint8_t const *) &b->datum.ipv4prefix[2]);
+                       return value_box_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->datum.ip.addr.v4.s_addr,
+                                                    b->datum.ip.prefix, (uint8_t const *) &b->datum.ip.addr.v4.s_addr);
 
                default:
                        fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
@@ -470,14 +475,14 @@ int value_box_cmp_op(FR_TOKEN op, value_box_t const *a, value_box_t const *b)
        case PW_TYPE_IPV4_PREFIX:               /* IPv4 and IPv4 Prefix */
                switch (b->type) {
                case PW_TYPE_IPV4_ADDR:
-                       return value_box_cidr_cmp_op(op, 4, a->datum.ipv4prefix[1],
-                                                    (uint8_t const *) &a->datum.ipv4prefix[2],
+                       return value_box_cidr_cmp_op(op, 4, a->datum.ip.prefix,
+                                                    (uint8_t const *) &a->datum.ip.addr.v4.s_addr,
                                                     32, (uint8_t const *) &b->datum.ip.addr.v4);
 
                case PW_TYPE_IPV4_PREFIX:       /* IPv4 Prefix and IPv4 Prefix */
-                       return value_box_cidr_cmp_op(op, 4, a->datum.ipv4prefix[1],
-                                                    (uint8_t const *) &a->datum.ipv4prefix[2],
-                                                    b->datum.ipv4prefix[1], (uint8_t const *) &b->datum.ipv4prefix[2]);
+                       return value_box_cidr_cmp_op(op, 4, a->datum.ip.prefix,
+                                                    (uint8_t const *) &a->datum.ip.addr.v4.s_addr,
+                                                    b->datum.ip.prefix, (uint8_t const *) &b->datum.ip.addr.v4.s_addr);
 
                default:
                        fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
@@ -491,7 +496,7 @@ int value_box_cmp_op(FR_TOKEN op, value_box_t const *a, value_box_t const *b)
 
                case PW_TYPE_IPV6_PREFIX:       /* IPv6 and IPv6 Preifx */
                        return value_box_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->datum.ip.addr.v6,
-                                                    b->datum.ipv6prefix[1], (uint8_t const *) &b->datum.ipv6prefix[2]);
+                                                    b->datum.ip.prefix, (uint8_t const *) &b->datum.ip.addr.v6);
 
                default:
                        fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
@@ -501,14 +506,14 @@ int value_box_cmp_op(FR_TOKEN op, value_box_t const *a, value_box_t const *b)
        case PW_TYPE_IPV6_PREFIX:
                switch (b->type) {
                case PW_TYPE_IPV6_ADDR:         /* IPv6 Prefix and IPv6 */
-                       return value_box_cidr_cmp_op(op, 16, a->datum.ipv6prefix[1],
-                                                    (uint8_t const *) &a->datum.ipv6prefix[2],
+                       return value_box_cidr_cmp_op(op, 16, a->datum.ip.prefix,
+                                                    (uint8_t const *) &a->datum.ip.addr.v6,
                                                     128, (uint8_t const *) &b->datum.ip.addr.v6);
 
                case PW_TYPE_IPV6_PREFIX:       /* IPv6 Prefix and IPv6 */
-                       return value_box_cidr_cmp_op(op, 16, a->datum.ipv6prefix[1],
-                                                    (uint8_t const *) &a->datum.ipv6prefix[2],
-                                                    b->datum.ipv6prefix[1], (uint8_t const *) &b->datum.ipv6prefix[2]);
+                       return value_box_cidr_cmp_op(op, 16, a->datum.ip.prefix,
+                                                    (uint8_t const *) &a->datum.ip.addr.v6,
+                                                    b->datum.ip.prefix, (uint8_t const *) &b->datum.ip.addr.v6);
 
                default:
                        fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
@@ -828,9 +833,9 @@ static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  * @param dst_enumv    unused.
  * @param src          Input data.
  */
-static inline int value_box_cast_strvalue(TALLOC_CTX *ctx, value_box_t *dst,
-                                         PW_TYPE dst_type, UNUSED fr_dict_attr_t const *dst_enumv,
-                                         value_box_t const *src)
+static inline int value_box_cast_to_strvalue(TALLOC_CTX *ctx, value_box_t *dst,
+                                            PW_TYPE dst_type, UNUSED fr_dict_attr_t const *dst_enumv,
+                                            value_box_t const *src)
 {
        if (!fr_cond_assert(dst_type == PW_TYPE_STRING)) return -1;
 
@@ -869,15 +874,15 @@ static inline int value_box_cast_strvalue(TALLOC_CTX *ctx, value_box_t *dst,
  * @param dst_enumv    unused.
  * @param src          Input data.
  */
-static inline int value_box_cast_octets(TALLOC_CTX *ctx, value_box_t *dst,
-                                       PW_TYPE dst_type, UNUSED fr_dict_attr_t const *dst_enumv,
-                                       value_box_t const *src)
+static inline int value_box_cast_to_octets(TALLOC_CTX *ctx, value_box_t *dst,
+                                          PW_TYPE dst_type, UNUSED fr_dict_attr_t const *dst_enumv,
+                                          value_box_t const *src)
 {
        if (!fr_cond_assert(dst_type == PW_TYPE_OCTETS)) return -1;
 
        switch (src->type) {
        /*
-        *      Everything but the nul byte
+        *      <string> (excluding terminating \0)
         */
        case PW_TYPE_STRING:
                dst->datum.octets = talloc_memdup(ctx, (uint8_t const *)src->datum.strvalue, src->length);
@@ -886,8 +891,7 @@ static inline int value_box_cast_octets(TALLOC_CTX *ctx, value_box_t *dst,
                break;
 
        /*
-        *      IP Addresses are weird, because the octet form isn't
-        *      quite the in-memory form.
+        *      <4 bytes address>
         */
        case PW_TYPE_IPV4_ADDR:
                dst->datum.octets = talloc_memdup(ctx,
@@ -896,6 +900,24 @@ static inline int value_box_cast_octets(TALLOC_CTX *ctx, value_box_t *dst,
                dst->length = sizeof(src->datum.ip.addr.v4.s_addr);
                break;
 
+       /*
+        *      <1 byte prefix> + <4 bytes address>
+        */
+       case PW_TYPE_IPV4_PREFIX:
+       {
+               uint8_t *bin;
+
+               bin = talloc_array(ctx, uint8_t, sizeof(src->datum.ip.addr.v4.s_addr) + 1);
+               bin[0] = src->datum.ip.prefix;
+               memcpy(&bin[1], (uint8_t const *)&src->datum.ip.addr.v4.s_addr, sizeof(src->datum.ip.addr.v4.s_addr));
+               dst->datum.octets = bin;
+               dst->length = talloc_array_length(bin);
+       }
+               break;
+
+       /*
+        *      <16 bytes address>
+        */
        case PW_TYPE_IPV6_ADDR:
                dst->datum.octets = talloc_memdup(ctx,
                                                  (uint8_t const *)src->datum.ip.addr.v6.s6_addr,
@@ -903,6 +925,21 @@ static inline int value_box_cast_octets(TALLOC_CTX *ctx, value_box_t *dst,
                dst->length = sizeof(src->datum.ip.addr.v6.s6_addr);
                break;
 
+       /*
+        *      <1 byte prefix> + <1 byte scope> + <16 bytes address>
+        */
+       case PW_TYPE_IPV6_PREFIX:
+       {
+               uint8_t *bin;
+
+               bin = talloc_array(ctx, uint8_t, sizeof(src->datum.ip.addr.v6.s6_addr) + 2);
+               bin[0] = src->datum.ip.scope_id;
+               bin[1] = src->datum.ip.prefix;
+               memcpy(&bin[2], src->datum.ip.addr.v6.s6_addr, sizeof(src->datum.ip.addr.v6.s6_addr));
+               dst->datum.octets = bin;
+               dst->length = talloc_array_length(bin);
+               break;
+       }
        /*
         *      Get the raw binary in memory representation
         */
@@ -936,9 +973,9 @@ static inline int value_box_cast_octets(TALLOC_CTX *ctx, value_box_t *dst,
  * @param dst_enumv    unused.
  * @param src          Input data.
  */
-static inline int value_box_cast_ipv4addr(TALLOC_CTX *ctx, value_box_t *dst,
-                                         PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv,
-                                         value_box_t const *src)
+static inline int value_box_cast_to_ipv4addr(TALLOC_CTX *ctx, value_box_t *dst,
+                                            PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv,
+                                            value_box_t const *src)
 {
        if (!fr_cond_assert(dst_type == PW_TYPE_IPV4_ADDR)) return -1;
 
@@ -958,28 +995,28 @@ static inline int value_box_cast_ipv4addr(TALLOC_CTX *ctx, value_box_t *dst,
                break;
 
        case PW_TYPE_IPV4_PREFIX:
-               if (src->datum.ipv4prefix[1] != 32) {
-                       fr_strerror_printf("Invalid cast from %s to %s.  Only /32 prefixes may be "
+               if (src->datum.ip.prefix != 32) {
+                       fr_strerror_printf("Invalid cast from %s to %s.  Only /32 (not %i/) prefixes may be "
                                           "cast to IP address types",
                                           fr_int2str(dict_attr_types, src->type, "<INVALID>"),
-                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+                                          src->datum.ip.prefix);
                        return -1;
                }
-               memcpy(&dst->datum.ip.addr.v4, &src->datum.ipv4prefix[2], sizeof(dst->datum.ip.addr.v4));
+               memcpy(&dst->datum.ip.addr.v4, &src->datum.ip.addr.v4, sizeof(dst->datum.ip.addr.v4));
                break;
 
        case PW_TYPE_IPV6_PREFIX:
-               if (src->datum.ipv6prefix[1] != 128) {
-                       fr_strerror_printf("Invalid cast from %s to %s.  Only /128 prefixes may be "
+               if (src->datum.ip.prefix != 128) {
+                       fr_strerror_printf("Invalid cast from %s to %s.  Only /128 (not /%i) prefixes may be "
                                           "cast to IP address types",
                                           fr_int2str(dict_attr_types, src->type, "<INVALID>"),
-                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+                                          src->datum.ip.prefix);
                        return -1;
                }
-               if (memcmp(&src->datum.ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
-                       goto bad_v6_prefix_map;
-               }
-               memcpy(&dst->datum.ip.addr.v4, &src->datum.ipv6prefix[2 + sizeof(v4_v6_map)],
+               if (memcmp(&src->datum.ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
+               memcpy(&dst->datum.ip.addr.v4, &src->datum.ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
                       sizeof(dst->datum.ip.addr.v4));
                break;
 
@@ -1039,9 +1076,109 @@ static inline int value_box_cast_ipv4addr(TALLOC_CTX *ctx, value_box_t *dst,
  * @param dst_enumv    unused.
  * @param src          Input data.
  */
-static inline int value_box_cast_ipv6addr(TALLOC_CTX *ctx, value_box_t *dst,
-                                         PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv,
-                                         value_box_t const *src)
+static inline int value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, value_box_t *dst,
+                                              PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv,
+                                              value_box_t const *src)
+{
+       if (!fr_cond_assert(dst_type == PW_TYPE_IPV4_PREFIX)) return -1;
+
+       switch (src->type) {
+       case PW_TYPE_IPV4_ADDR:
+               memcpy(&dst->datum.ip, &src->datum.ip, sizeof(dst->datum.ip));
+               break;
+
+       /*
+        *      Copy the last four bytes, to make an IPv4prefix
+        */
+       case PW_TYPE_IPV6_ADDR:
+               if (memcmp(src->datum.ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
+               bad_v6_prefix_map:
+                       fr_strerror_printf("Invalid cast from %s to %s.  No IPv4-IPv6 mapping prefix",
+                                          fr_int2str(dict_attr_types, src->type, "<INVALID>"),
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+                       return -1;
+               }
+               memcpy(&dst->datum.ip.addr.v4.s_addr, &src->datum.ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
+                      sizeof(dst->datum.ip.addr.v4.s_addr));
+               dst->datum.ip.prefix = 32;
+               break;
+
+       case PW_TYPE_IPV6_PREFIX:
+               if (memcmp(src->datum.ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
+
+               if (src->datum.ip.prefix < (sizeof(v4_v6_map) << 3)) {
+                       fr_strerror_printf("Invalid cast from %s to %s. Expected prefix >= %u bits got %u bits",
+                                          fr_int2str(dict_attr_types, src->type, "<INVALID>"),
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+                                          (unsigned int)(sizeof(v4_v6_map) << 3), src->datum.ip.prefix);
+                       return -1;
+               }
+               memcpy(&dst->datum.ip.addr.v4.s_addr, &src->datum.ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
+                      sizeof(dst->datum.ip.addr.v4.s_addr));
+
+               /*
+                *      Subtract the bits used by the v4_v6_map to get the v4 prefix bits
+                */
+               dst->datum.ip.prefix = src->datum.ip.prefix - (sizeof(v4_v6_map) << 3);
+               break;
+
+       case PW_TYPE_STRING:
+               if (value_box_from_str(ctx, dst, &dst_type, dst_enumv,
+                                      src->datum.strvalue, src->length, '\0') < 0) return -1;
+               break;
+
+
+       case PW_TYPE_OCTETS:
+               if (src->length != sizeof(dst->datum.ip.addr.v4.s_addr) + 1) {
+                       fr_strerror_printf("Invalid cast from %s to %s.  Only %zu byte octet strings "
+                                          "may be cast to IP address types",
+                                          fr_int2str(dict_attr_types, src->type, "<INVALID>"),
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+                                          sizeof(dst->datum.ip.addr.v4.s_addr) + 1);
+                       return -1;
+               }
+               dst->datum.ip.prefix = src->datum.octets[0];
+               memcpy(&dst->datum.ip.addr.v4, &src->datum.octets[1], sizeof(dst->datum.ip.addr.v4.s_addr));
+               break;
+
+       case PW_TYPE_INTEGER:
+       {
+               uint32_t net;
+
+               net = ntohl(src->datum.integer);
+               memcpy(&dst->datum.ip.addr.v4, (uint8_t *)&net, sizeof(dst->datum.ip.addr.v4.s_addr));
+               dst->datum.ip.prefix = 32;
+       }
+
+       default:
+               break;
+       }
+
+       dst->datum.ip.af = AF_INET;
+       dst->datum.ip.scope_id = 0;
+       dst->length = value_box_field_sizes[PW_TYPE_IPV6_ADDR];
+       dst->type = PW_TYPE_IPV4_PREFIX;
+
+       return 0;
+}
+
+/** Convert any supported type to an IPv6 address
+ *
+ * Allowed input types are:
+ * - PW_TYPE_IPV4_ADDR
+ * - PW_TYPE_IPV4_PREFIX (with 32bit mask).
+ * - PW_TYPE_IPV6_PREFIX (with 128bit mask).
+ * - PW_TYPE_OCTETS (of length 16).
+ *
+ * @param ctx          unused.
+ * @param dst          Where to write result of casting.
+ * @param dst_type     to cast to.
+ * @param dst_enumv    unused.
+ * @param src          Input data.
+ */
+static inline int value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, value_box_t *dst,
+                                            PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv,
+                                            value_box_t const *src)
 {
        if (!fr_cond_assert(dst_type == PW_TYPE_IPV6_ADDR)) return -1;
 
@@ -1056,8 +1193,7 @@ static inline int value_box_cast_ipv6addr(TALLOC_CTX *ctx, value_box_t *dst,
                /* Add the v4/v6 mapping prefix */
                memcpy(p, v4_v6_map, sizeof(v4_v6_map));
                p += sizeof(v4_v6_map);
-               memcpy(p, (uint8_t const *)&src->datum.ip.addr.v4.s_addr,
-                      sizeof(src->datum.ip.addr.v4.s_addr));
+               memcpy(p, (uint8_t const *)&src->datum.ip.addr.v4.s_addr, sizeof(src->datum.ip.addr.v4.s_addr));
                dst->datum.ip.scope_id = 0;
        }
                break;
@@ -1066,31 +1202,33 @@ static inline int value_box_cast_ipv6addr(TALLOC_CTX *ctx, value_box_t *dst,
        {
                uint8_t *p = dst->datum.ip.addr.v6.s6_addr;
 
-               if (src->datum.ipv4prefix[1] != 32) {
-                       fr_strerror_printf("Invalid cast from %s to %s.  Only /32 prefixes may be "
+               if (src->datum.ip.prefix != 32) {
+                       fr_strerror_printf("Invalid cast from %s to %s.  Only /32 (not /%i) prefixes may be "
                                           "cast to IP address types",
                                           fr_int2str(dict_attr_types, src->type, "<INVALID>"),
-                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+                                          src->datum.ip.prefix);
                        return -1;
                }
 
                /* Add the v4/v6 mapping prefix */
                memcpy(p, v4_v6_map, sizeof(v4_v6_map));
                p += sizeof(v4_v6_map);
-               memcpy(p, &src->datum.ipv4prefix[2], sizeof(src->datum.ipv4prefix) - 2);
+               memcpy(p, (uint8_t const *)&src->datum.ip.addr.v4.s_addr, sizeof(src->datum.ip.addr.v4.s_addr));
                dst->datum.ip.scope_id = 0;
        }
                break;
 
        case PW_TYPE_IPV6_PREFIX:
-               if (src->datum.ipv4prefix[1] != 128) {
-                       fr_strerror_printf("Invalid cast from %s to %s.  Only /128 prefixes may be "
+               if (src->datum.ip.prefix != 128) {
+                       fr_strerror_printf("Invalid cast from %s to %s.  Only /128 (not /%i) prefixes may be "
                                           "cast to IP address types",
                                           fr_int2str(dict_attr_types, src->type, "<INVALID>"),
-                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+                                          src->datum.ip.prefix);
                        return -1;
                }
-               memcpy(dst->datum.ip.addr.v6.s6_addr, &src->datum.ipv6prefix[2],
+               memcpy(dst->datum.ip.addr.v6.s6_addr, src->datum.ip.addr.v6.s6_addr,
                       sizeof(dst->datum.ip.addr.v6.s6_addr));
                dst->datum.ip.scope_id = src->datum.ip.scope_id;
                break;
@@ -1098,7 +1236,6 @@ static inline int value_box_cast_ipv6addr(TALLOC_CTX *ctx, value_box_t *dst,
        case PW_TYPE_STRING:
                if (value_box_from_str(ctx, dst, &dst_type, dst_enumv,
                                       src->datum.strvalue, src->length, '\0') < 0) return -1;
-               dst->datum.ip.scope_id = 0;
                break;
 
        case PW_TYPE_OCTETS:
@@ -1111,7 +1248,6 @@ static inline int value_box_cast_ipv6addr(TALLOC_CTX *ctx, value_box_t *dst,
                        return -1;
                }
                memcpy(&dst->datum.ip.addr.v6.s6_addr, src->datum.octets, sizeof(dst->datum.ip.addr.v6.s6_addr));
-               dst->datum.ip.scope_id = 0;
                break;
 
        default:
@@ -1129,9 +1265,94 @@ static inline int value_box_cast_ipv6addr(TALLOC_CTX *ctx, value_box_t *dst,
        return 0;
 }
 
+/** Convert any supported type to an IPv6 address
+ *
+ * Allowed input types are:
+ * - PW_TYPE_IPV4_ADDR
+ * - PW_TYPE_IPV4_PREFIX (with 32bit mask).
+ * - PW_TYPE_IPV6_PREFIX (with 128bit mask).
+ * - PW_TYPE_OCTETS (of length 16).
+ *
+ * @param ctx          unused.
+ * @param dst          Where to write result of casting.
+ * @param dst_type     to cast to.
+ * @param dst_enumv    unused.
+ * @param src          Input data.
+ */
+static inline int value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, value_box_t *dst,
+                                              PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv,
+                                              value_box_t const *src)
+{
+       switch (src->type) {
+       case PW_TYPE_IPV4_ADDR:
+       {
+               uint8_t *p = dst->datum.ip.addr.v6.s6_addr;
+
+               /* Add the v4/v6 mapping prefix */
+               memcpy(p, v4_v6_map, sizeof(v4_v6_map));
+               p += sizeof(v4_v6_map);
+               memcpy(p, (uint8_t const *)&src->datum.ip.addr.v4.s_addr, sizeof(src->datum.ip.addr.v4.s_addr));
+               dst->datum.ip.prefix = 128;
+               dst->datum.ip.scope_id = 0;
+       }
+               break;
+
+       case PW_TYPE_IPV4_PREFIX:
+       {
+               uint8_t *p = dst->datum.ip.addr.v6.s6_addr;
+
+               /* Add the v4/v6 mapping prefix */
+               memcpy(p, v4_v6_map, sizeof(v4_v6_map));
+               p += sizeof(v4_v6_map);
+               memcpy(p, (uint8_t const *)&src->datum.ip.addr.v4.s_addr, sizeof(src->datum.ip.addr.v4.s_addr));
+               dst->datum.ip.prefix = (sizeof(v4_v6_map) << 3) + src->datum.ip.prefix;
+               dst->datum.ip.scope_id = 0;
+       }
+               break;
+
+       case PW_TYPE_IPV6_ADDR:
+               memcpy(dst->datum.ip.addr.v6.s6_addr, src->datum.ip.addr.v6.s6_addr,
+                      sizeof(dst->datum.ip.addr.v6.s6_addr));
+               dst->datum.ip.prefix = 128;
+               dst->datum.ip.scope_id = src->datum.ip.scope_id;
+               break;
+
+       case PW_TYPE_STRING:
+               if (value_box_from_str(ctx, dst, &dst_type, dst_enumv,
+                                      src->datum.strvalue, src->length, '\0') < 0) return -1;
+               break;
+
+       case PW_TYPE_OCTETS:
+               if (src->length != (sizeof(dst->datum.ip.addr.v6.s6_addr) + 2)) {
+                       fr_strerror_printf("Invalid cast from %s to %s.  Only %zu byte octet strings "
+                                          "may be cast to IP address types",
+                                          fr_int2str(dict_attr_types, src->type, "<INVALID>"),
+                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+                                          sizeof(dst->datum.ip.addr.v6.s6_addr) + 2);
+                       return -1;
+               }
+               dst->datum.ip.scope_id = src->datum.octets[0];
+               dst->datum.ip.prefix = src->datum.octets[1];
+               memcpy(&dst->datum.ip.addr.v6.s6_addr, src->datum.octets, sizeof(dst->datum.ip.addr.v6.s6_addr));
+               break;
+
+       default:
+               break;
+       }
+
+       dst->datum.ip.af = AF_INET6;
+       dst->length = value_box_field_sizes[PW_TYPE_IPV6_ADDR];
+       dst->type = PW_TYPE_IPV6_PREFIX;
+
+       return 0;
+}
+
 /** Convert one type of value_box_t to another
  *
- * @note This should be the canonical function used to convert between data types.
+ * This should be the canonical function used to convert between INTERNAL data formats.
+ *
+ * - If you want to convert from PRESENTATION format, use #value_box_from_str.
+
  *
  * @param ctx          to allocate buffers in (usually the same as dst)
  * @param dst          Where to write result of casting.
@@ -1161,27 +1382,32 @@ int value_box_cast(TALLOC_CTX *ctx, value_box_t *dst,
         */
        if (dst_type == src->type) return value_box_copy(ctx, dst, src);
 
+       /*
+        *      Initialise dst
+        */
+       memset(dst, 0, sizeof(*dst));
+
        /*
         *      Dispatch to specialised cast functions
         */
        switch (dst_type) {
        case PW_TYPE_STRING:
-               return value_box_cast_strvalue(ctx, dst, dst_type, dst_enumv, src);
+               return value_box_cast_to_strvalue(ctx, dst, dst_type, dst_enumv, src);
 
        case PW_TYPE_OCTETS:
-               return value_box_cast_octets(ctx, dst, dst_type, dst_enumv, src);
+               return value_box_cast_to_octets(ctx, dst, dst_type, dst_enumv, src);
 
        case PW_TYPE_IPV4_ADDR:
-               return value_box_cast_ipv4addr(ctx, dst, dst_type, dst_enumv, src);
+               return value_box_cast_to_ipv4addr(ctx, dst, dst_type, dst_enumv, src);
 
        case PW_TYPE_IPV4_PREFIX:
-               break;  /* need func */
+               return value_box_cast_to_ipv4prefix(ctx, dst, dst_type, dst_enumv, src);
 
        case PW_TYPE_IPV6_ADDR:
-               return value_box_cast_ipv6addr(ctx, dst, dst_type, dst_enumv, src);
+               return value_box_cast_to_ipv6addr(ctx, dst, dst_type, dst_enumv, src);
 
        case PW_TYPE_IPV6_PREFIX:
-               break;  /* need func */
+               return value_box_cast_to_ipv6prefix(ctx, dst, dst_type, dst_enumv, src);
 
        /*
         *      Need func
@@ -1218,8 +1444,6 @@ int value_box_cast(TALLOC_CTX *ctx, value_box_t *dst,
        if (src->type == PW_TYPE_STRING) return value_box_from_str(ctx, dst, &dst_type, dst_enumv,
                                                                   src->datum.strvalue, src->length, '\0');
 
-
-
        if ((src->type == PW_TYPE_IFID) &&
            (dst_type == PW_TYPE_INTEGER64)) {
                memcpy(&dst->datum.integer64, src->datum.ifid, sizeof(src->datum.ifid));
@@ -1281,8 +1505,8 @@ int value_box_cast(TALLOC_CTX *ctx, value_box_t *dst,
 
                case PW_TYPE_SIGNED:
                        if (src->datum.sinteger < 0 ) {
-                               fr_strerror_printf("Invalid cast: From signed to integer.  signed value %d is negative ",
-                                                   src->datum.sinteger);
+                               fr_strerror_printf("Invalid cast: From signed to integer.  "
+                                                  "signed value %d is negative ", src->datum.sinteger);
                                return -1;
                        }
                        dst->datum.integer = (uint32_t)src->datum.sinteger;
@@ -1424,89 +1648,7 @@ int value_box_cast(TALLOC_CTX *ctx, value_box_t *dst,
                 *      10 bytes of 0x00 2 bytes of 0xff
                 */
 
-               switch (dst_type) {
-               case PW_TYPE_IPV4_PREFIX:
-                       switch (src->type) {
-                       case PW_TYPE_IPV4_ADDR:
-                               memcpy(&dst->datum.ipv4prefix[2], &src->datum.ip.addr.v4,
-                                      sizeof(src->datum.ip.addr.v4));
-                               dst->datum.ipv4prefix[0] = 0;
-                               dst->datum.ipv4prefix[1] = 32;
-                               goto fixed_length;
-
-                       case PW_TYPE_IPV6_ADDR:
-                               if (memcmp(src->datum.ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
-                               bad_v6_prefix_map:
-                                       fr_strerror_printf("Invalid cast from %s to %s.  No IPv4-IPv6 mapping prefix",
-                                                          fr_int2str(dict_attr_types, src->type, "<INVALID>"),
-                                                          fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
-                                       return -1;
-                               }
-                               memcpy(&dst->datum.ipv4prefix[2], &src->datum.ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
-                                      sizeof(dst->datum.ipv4prefix) - 2);
-                               dst->datum.ipv4prefix[0] = 0;
-                               dst->datum.ipv4prefix[1] = 32;
-                               goto fixed_length;
-
-                       case PW_TYPE_IPV6_PREFIX:
-                               if (memcmp(&src->datum.ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
-                                       goto bad_v6_prefix_map;
-                               }
-
-                               /*
-                                *      Prefix must be >= 96 bits. If it's < 96 bytes and the
-                                *      above check passed, the v6 address wasn't masked
-                                *      correctly when it was packet into a value_box_t.
-                                */
-                               if (!fr_cond_assert(src->datum.ipv6prefix[1] >= (sizeof(v4_v6_map) * 8))) return -1;
 
-                               memcpy(&dst->datum.ipv4prefix[2], &src->datum.ipv6prefix[2 + sizeof(v4_v6_map)],
-                                      sizeof(dst->datum.ipv4prefix) - 2);
-                               dst->datum.ipv4prefix[0] = 0;
-                               dst->datum.ipv4prefix[1] = src->datum.ipv6prefix[1] - (sizeof(v4_v6_map) * 8);
-                               goto fixed_length;
-
-                       default:
-                               break;
-                       }
-                       break;
-
-               case PW_TYPE_IPV6_PREFIX:
-                       switch (src->type) {
-                       case PW_TYPE_IPV4_ADDR:
-                               /* Add the v4/v6 mapping prefix */
-                               memcpy(&dst->datum.ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
-                               memcpy(&dst->datum.ipv6prefix[2 + sizeof(v4_v6_map)], &src->datum.ip.addr.v4,
-                                      sizeof(src->datum.ip.addr.v4));
-                               dst->datum.ipv6prefix[0] = 0;
-                               dst->datum.ipv6prefix[1] = 128;
-                               goto fixed_length;
-
-                       case PW_TYPE_IPV4_PREFIX:
-                               /* Add the v4/v6 mapping prefix */
-                               memcpy(&dst->datum.ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
-                               memcpy(&dst->datum.ipv6prefix[2 + sizeof(v4_v6_map)], &src->datum.ipv4prefix[2],
-                                      (sizeof(dst->datum.ipv6prefix) - 2) - sizeof(v4_v6_map));
-                               dst->datum.ipv6prefix[0] = 0;
-                               dst->datum.ipv6prefix[1] = (sizeof(v4_v6_map) * 8) + src->datum.ipv4prefix[1];
-                               goto fixed_length;
-
-                       case PW_TYPE_IPV6_ADDR:
-                               memcpy(&dst->datum.ipv6prefix[2], &src->datum.ip.addr.v6,
-                                      sizeof(dst->datum.ipv6prefix) - 2);
-                               dst->datum.ipv6prefix[0] = 0;
-                               dst->datum.ipv6prefix[1] = 128;
-                               goto fixed_length;
-
-                       default:
-                               break;
-                       }
-
-                       break;
-
-               default:
-                       break;
-               }
        }
 
        /*
@@ -2254,14 +2396,7 @@ int value_box_from_str(TALLOC_CTX *ctx, value_box_t *dst,
                goto finish;
 
        case PW_TYPE_IPV4_PREFIX:
-       {
-               fr_ipaddr_t addr;
-
-               if (fr_inet_pton4(&addr, in, inlen, fr_hostname_lookups, false, true) < 0) return -1;
-
-               dst->datum.ipv4prefix[1] = addr.prefix;
-               memcpy(&dst->datum.ipv4prefix[2], &addr.addr.v4.s_addr, sizeof(dst->datum.ipv4prefix) - 2);
-       }
+               if (fr_inet_pton4(&dst->datum.ip, in, inlen, fr_hostname_lookups, false, true) < 0) return -1;
                goto finish;
 
        case PW_TYPE_IPV6_ADDR:
@@ -2285,14 +2420,7 @@ int value_box_from_str(TALLOC_CTX *ctx, value_box_t *dst,
                goto finish;
 
        case PW_TYPE_IPV6_PREFIX:
-       {
-               fr_ipaddr_t addr;
-
-               if (fr_inet_pton6(&addr, in, inlen, fr_hostname_lookups, false, true) < 0) return -1;
-
-               dst->datum.ipv6prefix[1] = addr.prefix;
-               memcpy(&dst->datum.ipv6prefix[2], addr.addr.v6.s6_addr, sizeof(dst->datum.ipv6prefix) - 2);
-       }
+               if (fr_inet_pton6(&dst->datum.ip, in, inlen, fr_hostname_lookups, false, true) < 0) return -1;
                goto finish;
 
        /*
@@ -2919,6 +3047,12 @@ size_t value_box_snprint(char *out, size_t outlen, value_box_t const *data, char
                len = strlen(buf);
                break;
 
+       case PW_TYPE_IPV4_PREFIX:
+       case PW_TYPE_IPV6_PREFIX:
+               a = fr_inet_ntop_prefix(buf, sizeof(buf), &data->datum.ip);
+               len = strlen(buf);
+               break;
+
        case PW_TYPE_ABINARY:
 #ifdef WITH_ASCEND_BINARY
                print_abinary(buf, sizeof(buf), (uint8_t const *) data->datum.filter, data->length, quote);
@@ -2965,46 +3099,6 @@ size_t value_box_snprint(char *out, size_t outlen, value_box_t const *data, char
                len = strlen(buf);
                break;
 
-       case PW_TYPE_IPV6_PREFIX:
-       {
-               struct in6_addr addr;
-
-               /*
-                *      Alignment issues.
-                */
-               memcpy(&addr, &(data->datum.ipv6prefix[2]), sizeof(addr));
-
-               a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
-               if (a) {
-                       p = buf;
-
-                       len = strlen(buf);
-                       p += len;
-                       len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->datum.ipv6prefix[1]);
-               }
-       }
-               break;
-
-       case PW_TYPE_IPV4_PREFIX:
-       {
-               struct in_addr addr;
-
-               /*
-                *      Alignment issues.
-                */
-               memcpy(&addr, &(data->datum.ipv4prefix[2]), sizeof(addr));
-
-               a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
-               if (a) {
-                       p = buf;
-
-                       len = strlen(buf);
-                       p += len;
-                       len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->datum.ipv4prefix[1] & 0x3f));
-               }
-       }
-               break;
-
        case PW_TYPE_ETHERNET:
                return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
                                data->datum.ether[0], data->datum.ether[1],
index 7450e9d59815093892dd9670f9d2b222c2d05b42..50ba5c9abbae3c9d4d13040562e4b82949164a76 100644 (file)
@@ -1302,10 +1302,7 @@ RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request)
 
                case PW_TYPE_IPV4_PREFIX:
                        if (da->attr == PW_FREERADIUS_CLIENT_IP_PREFIX) {
-                               c->ipaddr.af = AF_INET;
-                               memcpy(&c->ipaddr.addr.v4, &vp->vp_ipv4prefix[2],
-                                      sizeof(c->ipaddr.addr.v4.s_addr));
-                               fr_ipaddr_mask(&c->ipaddr, (vp->vp_ipv4prefix[1] & 0x3f));
+                               memcpy(&c->ipaddr, &vp->vp_ip, sizeof(c->ipaddr));
                                cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
                        }
 
@@ -1313,10 +1310,7 @@ RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request)
 
                case PW_TYPE_IPV6_PREFIX:
                        if (da->attr == PW_FREERADIUS_CLIENT_IPV6_PREFIX) {
-                               c->ipaddr.af = AF_INET6;
-                               memcpy(&c->ipaddr.addr.v6, &vp->vp_ipv6prefix[2],
-                                      sizeof(c->ipaddr.addr.v6));
-                               fr_ipaddr_mask(&c->ipaddr, vp->vp_ipv6prefix[1]);
+                               memcpy(&c->ipaddr, &vp->vp_ip, sizeof(c->ipaddr));;
                                cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
                        }
 
index 601984246dee1b52865acff8c45b89ce2ceeb917..4b9f859d48c1264fbb77eb2476e5e20964899243 100644 (file)
@@ -225,11 +225,13 @@ int radius_compare_vps(UNUSED REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *v
                        break;
 
                case PW_TYPE_IPV6_ADDR:
-                       ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
+                       ret = memcmp(vp->vp_ip.addr.v6.s6_addr, check->vp_ip.addr.v6.s6_addr,
+                                    sizeof(vp->vp_ip.addr.v6.s6_addr));
                        break;
 
+               case PW_TYPE_IPV4_PREFIX:
                case PW_TYPE_IPV6_PREFIX:
-                       ret = memcmp(vp->vp_ipv6prefix, check->vp_ipv6prefix, sizeof(vp->vp_ipv6prefix));
+                       ret = memcmp(&vp->vp_ip, &check->vp_ip, sizeof(vp->vp_ip));
                        break;
 
                case PW_TYPE_IFID:
index 75d2a1cbd68c3abf85b449d8be4afe71a41df41d..97813fc4446f36c7ecbdcc64ea882c276a896490 100644 (file)
@@ -119,11 +119,9 @@ static ssize_t xlat_integer(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen,
         *      is bigendian and will convert it for us.
         */
        case PW_TYPE_IPV4_ADDR:
+       case PW_TYPE_IPV4_PREFIX:       /* Same addr field */
                return snprintf(*out, outlen, "%u", htonl(vp->vp_ipv4addr));
 
-       case PW_TYPE_IPV4_PREFIX:
-               return snprintf(*out, outlen, "%u", htonl((*(uint32_t *)(vp->vp_ipv4prefix + 2))));
-
        case PW_TYPE_INTEGER:
                return snprintf(*out, outlen, "%u", vp->vp_integer);
 
@@ -148,10 +146,8 @@ static ssize_t xlat_integer(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen,
                return snprintf(*out, outlen, "%i", vp->vp_signed);
 
        case PW_TYPE_IPV6_ADDR:
-               return fr_snprint_uint128(*out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
-
        case PW_TYPE_IPV6_PREFIX:
-               return fr_snprint_uint128(*out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6prefix[2]));
+               return fr_snprint_uint128(*out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
 
        default:
                break;
index 258c60155d52d802bfc4ecf85aca9223957053cb..916a3ae70e163abec5a5b5dbe043064eccbc77e9 100644 (file)
@@ -916,6 +916,7 @@ ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dic
        uint8_t const           *p = data;
        uint8_t                 buffer[256];
        fr_radius_ctx_t         *packet_ctx = decoder_ctx;
+       fr_ipaddr_t             tmp_prefix;
 
        if (!parent || (attr_len > packet_len) || (attr_len > 128 * 1024)) {
                fr_strerror_printf("%s: Invalid arguments", __FUNCTION__);
@@ -1082,9 +1083,48 @@ ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dic
                if (data_len != 16) goto raw;
                break;
 
+       case PW_TYPE_IPV4_PREFIX:
+               if (data_len != 6) goto raw;
+               if (p[0] != 0) goto raw;
+               if ((p[1] & 0x3f) > 32) goto raw;
+
+               memset(&tmp_prefix, 0, sizeof(tmp_prefix));
+
+               tmp_prefix.af = AF_INET;
+               memcpy((uint8_t *)&tmp_prefix.addr.v4.s_addr, p + 2, data_len - 2);
+               fr_ipaddr_mask(&tmp_prefix, p[1] & 0x3f);
+
+               /*
+                *      Check the prefix data is the same before
+                *      and after casting (it should be).
+                */
+               if (memcmp(p + 2, (uint8_t *)&tmp_prefix.addr.v4.s_addr, data_len - 2) != 0) goto raw;
+               break;
+
        case PW_TYPE_IPV6_PREFIX:
+       {
                if ((data_len < 2) || (data_len > 18)) goto raw;
+               if (p[0] != 0) goto raw;        /* First byte is always 0 */
                if (p[1] > 128) goto raw;
+
+               /*
+                *      Convert prefix bits to bytes to check that
+                *      we have sufficient data.
+                */
+               if ((p[1] >> 3) > (data_len - 2)) goto raw;
+
+               memset(&tmp_prefix, 0, sizeof(tmp_prefix));
+
+               tmp_prefix.af = AF_INET6;
+               memcpy((uint8_t *)tmp_prefix.addr.v6.s6_addr, p + 2, data_len - 2);
+               fr_ipaddr_mask(&tmp_prefix, p[1]);
+
+               /*
+                *      Check the prefix data is the same before
+                *      and after casting (it should be).
+                */
+               if (memcmp(p + 2, (uint8_t *)tmp_prefix.addr.v6.s6_addr, data_len - 2) != 0) goto raw;
+       }
                break;
 
        case PW_TYPE_BYTE:
@@ -1111,11 +1151,6 @@ ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dic
                parent = child; /* re-write it */
                break;
 
-       case PW_TYPE_IPV4_PREFIX:
-               if (data_len != 6) goto raw;
-               if ((p[1] & 0x3f) > 32) goto raw;
-               break;
-
                /*
                 *      The rest of the p types can cause
                 *      recursion!  Ask yourself, "is recursion OK?"
@@ -1363,38 +1398,9 @@ ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dic
                memcpy(&vp->vp_ipv6addr, p, 16);
                break;
 
-       case PW_TYPE_IPV6_PREFIX:
-               /*
-                *      FIXME: double-check that
-                *      (vp->vp_octets[1] >> 3) matches vp->vp_length + 2
-                */
-               memcpy(vp->vp_ipv6prefix, p, vp->vp_length);
-               if (vp->vp_length < 18) {
-                       memset(((uint8_t *)vp->vp_ipv6prefix) + vp->vp_length, 0,
-                              18 - vp->vp_length);
-               }
-               break;
-
        case PW_TYPE_IPV4_PREFIX:
-               /* FIXME: do the same double-check as for IPv6Prefix */
-               memcpy(vp->vp_ipv4prefix, p, vp->vp_length);
-
-               /*
-                *      /32 means "keep all bits".  Otherwise, mask
-                *      them out.
-                */
-               if ((p[1] & 0x3f) > 32) {
-                       uint32_t addr, mask;
-
-                       memcpy(&addr, vp->vp_octets + 2, sizeof(addr));
-                       mask = 1;
-                       mask <<= (32 - (p[1] & 0x3f));
-                       mask--;
-                       mask = ~mask;
-                       mask = htonl(mask);
-                       addr &= mask;
-                       memcpy(vp->vp_ipv4prefix + 2, &addr, sizeof(addr));
-               }
+       case PW_TYPE_IPV6_PREFIX:
+               memcpy(&vp->vp_ip, &tmp_prefix, sizeof(vp->vp_ip));
                break;
 
        case PW_TYPE_SIGNED:    /* overloaded with vp_integer */
index 582870aa7c85ed7f24c3135ce3a35898eef53c46..f4e90319dd3cb90d4afe075c3b517e402e10647f 100644 (file)
@@ -133,8 +133,8 @@ if (Tmp-String-2 != 'EAAAADk4Nz0=') {
        }
 }
 
-# ipv4prefix - bin 0x00203938373e
-if (Tmp-String-3 != 'ACA5ODc+') {
+# ipv4prefix - bin 0x203938373e
+if (Tmp-String-3 != 'IDk4Nz4=') {
        update reply {
                Filter-Id += 'fail 12'
        }
index d328c2cb71122a25791ed69ce0e7dee91f3d9256..63cc4358f42ccc32d1fd702f8e446965fdf40740 100644 (file)
@@ -207,7 +207,7 @@ redundant {
                }
        }
        group {
-               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipv6addr.  Only /128 prefixes may be cast to IP address types') {
+               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipv6addr.  Only /128 (not /32) prefixes may be cast to IP address types') {
                        update reply {
                                Filter-Id += 'Fail 14.5'
                        }
@@ -232,7 +232,7 @@ redundant {
                }
        }
        group {
-               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipaddr.  Only /128 prefixes may be cast to IP address types') {
+               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipaddr.  Only /128 (not /64) prefixes may be cast to IP address types') {
                        update reply {
                                Filter-Id += 'Fail 15.5'
                        }
@@ -282,7 +282,7 @@ redundant {
                }
        }
        group {
-               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv4prefix to ipv6addr.  Only /32 prefixes may be cast to IP address types') {
+               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv4prefix to ipv6addr.  Only /32 (not /24) prefixes may be cast to IP address types') {
                        update reply {
                                Filter-Id += 'Fail 17.5'
                        }
@@ -303,13 +303,13 @@ redundant {
                        Tmp-Cast-Ipaddr := &Tmp-Cast-IPv4Prefix
                }
                update reply {
-                       Filter-Id += 'Fail 17'
+                       Filter-Id += 'Fail 17.1'
                }
        }
        group {
-               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv4prefix to ipaddr.  Only /32 prefixes may be cast to IP address types') {
+               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv4prefix to ipaddr.  Only /32 (not 24/) prefixes may be cast to IP address types') {
                        update reply {
-                               Filter-Id += 'Fail 17.5'
+                               Filter-Id += 'Fail 17.6'
                        }
                }
                update request {
@@ -332,7 +332,7 @@ redundant {
                }
        }
        group {
-               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipaddr.  Only /128 prefixes may be cast to IP address types') {
+               if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipaddr.  Only /128 (not /32) prefixes may be cast to IP address types') {
                        update reply {
                                Filter-Id += 'Fail 18.5'
                        }
index 6693c7cc44b0e7b2612f936bd8e3d9b08d6a53a3..0ad8929c511324c1e448d6921981ce02e957bb03 100644 (file)
@@ -134,7 +134,7 @@ if (Tmp-String-2 != '100000003938373d') {
 }
 
 # ipv4prefix
-if (Tmp-String-3 != '00203938373e') {
+if (Tmp-String-3 != '203938373e') {
        update reply {
                Filter-Id += 'fail 14'
        }