From: Alan T. DeKok Date: Thu, 20 Dec 2012 14:18:41 +0000 (-0500) Subject: Add IPv4prefix data type for RFC 6572 X-Git-Tag: release_3_0_0_beta1~1354 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2b8b811c3e0487899128af489ec07b6ab190e14e;p=thirdparty%2Ffreeradius-server.git Add IPv4prefix data type for RFC 6572 --- diff --git a/share/dictionary.rfc6572 b/share/dictionary.rfc6572 index be10316cecf..d30f328522d 100644 --- a/share/dictionary.rfc6572 +++ b/share/dictionary.rfc6572 @@ -17,10 +17,8 @@ ATTRIBUTE PMIP6-Home-HN-Prefix 151 ipv6prefix ATTRIBUTE PMIP6-Visited-HN-Prefix 152 ipv6prefix ATTRIBUTE PMIP6-Home-Interface-ID 153 ifid ATTRIBUTE PMIP6-Visited-Interface-ID 154 ifid -# ipv4 prefix? -ATTRIBUTE PMIP6-Home-IPv4-HoA 155 octets -# ipv4 prefix? -ATTRIBUTE PMIP6-Visited-IPv4-HoA 156 octets +ATTRIBUTE PMIP6-Home-IPv4-HoA 155 ipv4prefix +ATTRIBUTE PMIP6-Visited-IPv4-HoA 156 ipv4prefix ATTRIBUTE PMIP6-Home-DHCP4-Server-Address 157 ipaddr ATTRIBUTE PMIP6-Visited-DHCP4-Server-Address 158 ipaddr ATTRIBUTE PMIP6-Home-DHCP6-Server-Address 159 ipv6addr diff --git a/src/include/libradius.h b/src/include/libradius.h index bd8e9d15ca7..41c50db456b 100644 --- a/src/include/libradius.h +++ b/src/include/libradius.h @@ -170,6 +170,7 @@ typedef union value_pair_data { uint8_t filter[32]; uint8_t ifid[8]; /* struct? */ uint8_t ipv6prefix[18]; /* struct? */ + uint8_t ipv4prefix[6]; /* struct? */ uint8_t ether[6]; uint8_t *tlv; } VALUE_PAIR_DATA; @@ -206,6 +207,7 @@ typedef struct value_pair { #define vp_ipv6addr data.ipv6addr #define vp_ifid data.ifid #define vp_ipv6prefix data.ipv6prefix +#define vp_ipv4prefix data.ipv4prefix #define vp_filter data.filter #define vp_ether data.ether #define vp_signed data.sinteger diff --git a/src/include/radius.h b/src/include/radius.h index 9fe596e6c73..02842b2e734 100644 --- a/src/include/radius.h +++ b/src/include/radius.h @@ -25,6 +25,7 @@ #define PW_TYPE_LONG_EXTENDED 16 #define PW_TYPE_EVS 17 #define PW_TYPE_INTEGER64 18 +#define PW_TYPE_IPV4PREFIX 19 #define PW_FLAG_LONG (1 << 8) diff --git a/src/lib/dict.c b/src/lib/dict.c index e225451d375..0a7af5c2799 100644 --- a/src/lib/dict.c +++ b/src/lib/dict.c @@ -108,6 +108,7 @@ const FR_NAME_NUMBER dict_attr_types[] = { { "int32", PW_TYPE_SIGNED }, { "integer64", PW_TYPE_INTEGER64 }, { "uint64", PW_TYPE_INTEGER64 }, + { "ipv4prefix", PW_TYPE_IPV4PREFIX }, { NULL, 0 } }; diff --git a/src/lib/print.c b/src/lib/print.c index c36e0477060..81e29ea537b 100644 --- a/src/lib/print.c +++ b/src/lib/print.c @@ -334,6 +334,24 @@ int vp_prints_value(char * out, size_t outlen, const VALUE_PAIR *vp, int delimit } break; + case PW_TYPE_IPV4PREFIX: + { + struct in_addr addr; + + /* + * Alignment issues. + */ + memcpy(&addr, &(vp->vp_ipv4prefix[2]), sizeof(addr)); + + a = inet_ntop(AF_INET, &addr, buf, sizeof(buf)); + if (a) { + char *p = buf + strlen(buf); + snprintf(p, buf + sizeof(buf) - p - 1, "/%u", + (unsigned int) (vp->vp_octets[1] & 0x3f)); + } + } + break; + case PW_TYPE_ETHERNET: snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", vp->vp_ether[0], vp->vp_ether[1], diff --git a/src/lib/radius.c b/src/lib/radius.c index a7c7fa3c51b..ae7801921f3 100644 --- a/src/lib/radius.c +++ b/src/lib/radius.c @@ -848,6 +848,7 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet, case PW_TYPE_IFID: case PW_TYPE_IPV6ADDR: case PW_TYPE_IPV6PREFIX: + case PW_TYPE_IPV4PREFIX: case PW_TYPE_ABINARY: /* nothing more to do */ break; @@ -3082,6 +3083,14 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet, } break; + case PW_TYPE_IPV4PREFIX: + if (vp->length != sizeof(vp->vp_ipv4prefix)) goto raw; + + if ((buffer[1] & 0x3f) > 32) goto raw; + + memcpy(&vp->vp_ipv4prefix, buffer, sizeof(vp->vp_ipv4prefix)); + break; + case PW_TYPE_SIGNED: if (vp->length != 4) goto raw; @@ -3901,6 +3910,7 @@ ssize_t rad_vp2data(const VALUE_PAIR *vp, uint8_t *out, size_t outlen) case PW_TYPE_IPADDR: case PW_TYPE_IPV6ADDR: case PW_TYPE_IPV6PREFIX: + case PW_TYPE_IPV4PREFIX: case PW_TYPE_ABINARY: case PW_TYPE_TLV: do_raw: diff --git a/src/lib/valuepair.c b/src/lib/valuepair.c index 918b9d28e9e..7b79f6eb7e4 100644 --- a/src/lib/valuepair.c +++ b/src/lib/valuepair.c @@ -130,6 +130,10 @@ VALUE_PAIR *pairalloc(const DICT_ATTR *da) vp->length = sizeof(vp->vp_ipv6prefix); break; + case PW_TYPE_IPV4PREFIX: + vp->length = sizeof(vp->vp_ipv4prefix); + break; + case PW_TYPE_ETHERNET: vp->length = sizeof(vp->vp_ether); break; @@ -1202,10 +1206,54 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value) } vp->vp_octets[1] = prefix; } - vp->vp_octets[0] = '\0'; + vp->vp_octets[0] = 0; vp->length = 16 + 2; break; + case PW_TYPE_IPV4PREFIX: + p = strchr(value, '/'); + if (!p || ((p - value) >= 256)) { + fr_strerror_printf("invalid IPv4 prefix " + "string \"%s\"", value); + return NULL; + } else { + unsigned int prefix; + char buffer[256], *eptr; + + memcpy(buffer, value, p - value); + buffer[p - value] = '\0'; + + if (inet_pton(AF_INET, buffer, vp->vp_octets + 2) <= 0) { + fr_strerror_printf("failed to parse IPv6 address " + "string \"%s\"", value); + return NULL; + } + + prefix = strtoul(p + 1, &eptr, 10); + if ((prefix > 32) || *eptr) { + fr_strerror_printf("failed to parse IPv6 address " + "string \"%s\"", value); + return NULL; + } + vp->vp_octets[1] = prefix; + + if (prefix < 32) { + uint32_t addr, mask; + + memcpy(&addr, vp->vp_octets + 2, sizeof(addr)); + mask = 1; + mask <<= (32 - prefix); + mask--; + mask = ~mask; + mask = htonl(mask); + addr &= mask; + memcpy(vp->vp_octets + 2, &addr, sizeof(addr)); + } + } + vp->vp_octets[0] = 0; + vp->length = 8; + break; + case PW_TYPE_ETHERNET: { const char *c1, *c2; @@ -2164,6 +2212,14 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two) sizeof(two->vp_ipv6prefix)); break; + /* + * FIXME: do a smarter comparison... + */ + case PW_TYPE_IPV4PREFIX: + compare = memcmp(&two->vp_ipv4prefix, &one->vp_ipv4prefix, + sizeof(two->vp_ipv4prefix)); + break; + case PW_TYPE_IFID: compare = memcmp(&two->vp_ifid, &one->vp_ifid, sizeof(two->vp_ifid));