From: Alan T. DeKok Date: Sat, 17 Oct 2015 14:46:06 +0000 (-0400) Subject: Parse ipv4prefix correctly X-Git-Tag: release_3_0_11~248 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=606935272e1ca9b29ea73a39e8653c56dfa4c126;p=thirdparty%2Ffreeradius-server.git Parse ipv4prefix correctly --- diff --git a/src/lib/misc.c b/src/lib/misc.c index c0938983e88..91184c90e15 100644 --- a/src/lib/misc.c +++ b/src/lib/misc.c @@ -198,6 +198,66 @@ char const *ip_ntoa(char *buffer, uint32_t ipaddr) return buffer; } +/* + * Parse decimal digits until we run out of decimal digits. + */ +static int ip_octet_from_str(char const *str, uint32_t *poctet) +{ + uint32_t octet; + char const *p = str; + + if ((*p < '0') || (*p > '9')) { + return -1; + } + + octet = 0; + + while ((*p >= '0') && (*p <= '9')) { + octet *= 10; + octet += *p - '0'; + p++; + + if (octet > 255) return -1; + } + + + *poctet = octet; + return p - str; +} + +static int ip_prefix_from_str(char const *str, uint32_t *paddr) +{ + int shift, length; + uint32_t octet; + uint32_t addr; + char const *p = str; + + addr = 0; + + for (shift = 24; shift >= 0; shift -= 8) { + length = ip_octet_from_str(p, &octet); + if (length <= 0) return -1; + + addr |= octet << shift; + p += length; + + /* + * EOS or / means we're done. + */ + if (!*p || (*p == '/')) break; + + /* + * We require dots between octets. + */ + if (*p != '.') return -1; + p++; + } + + *paddr = htonl(addr); + return p - str; +} + + /** Parse an IPv4 address or IPv4 prefix in presentation format (and others) * * @param out Where to write the ip address value. @@ -210,7 +270,7 @@ char const *ip_ntoa(char *buffer, uint32_t ipaddr) int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback) { char *p; - unsigned int prefix; + unsigned int mask; char *eptr; /* Dotted quad + / + [0-9]{1,2} */ @@ -230,6 +290,7 @@ int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b } p = strchr(value, '/'); + /* * 192.0.2.2 is parsed as if it was /32 */ @@ -242,6 +303,7 @@ int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b */ if ((value[0] == '*') && (value[1] == '\0')) { out->ipaddr.ip4addr.s_addr = htonl(INADDR_ANY); + /* * Convert things which are obviously integers to IP addresses * @@ -250,53 +312,45 @@ int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b */ } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) { out->ipaddr.ip4addr.s_addr = htonl(strtoul(value, NULL, 0)); + } else if (!resolve) { if (inet_pton(AF_INET, value, &out->ipaddr.ip4addr.s_addr) <= 0) { - fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value); + fr_strerror_printf("Failed to parse IPv4 addreess string \"%s\"", value); return -1; } } else if (ip_hton(out, AF_INET, value, fallback) < 0) return -1; return 0; } - - /* - * Otherwise parse the prefix - */ - if ((size_t)(p - value) >= INET_ADDRSTRLEN) { - fr_strerror_printf("Invalid IPv4 address string \"%s\"", value); - return -1; - } - + /* * Copy the IP portion into a temporary buffer if we haven't already. */ if (inlen < 0) memcpy(buffer, value, p - value); buffer[p - value] = '\0'; - if (!resolve) { - if (inet_pton(AF_INET, buffer, &out->ipaddr.ip4addr.s_addr) <= 0) { - fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value); - return -1; - } - } else if (ip_hton(out, AF_INET, buffer, fallback) < 0) return -1; + if (ip_prefix_from_str(buffer, &out->ipaddr.ip4addr.s_addr) <= 0) { + fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value); + return -1; + } - prefix = strtoul(p + 1, &eptr, 10); - if (prefix > 32) { + mask = strtoul(p + 1, &eptr, 10); + if (mask > 32) { fr_strerror_printf("Invalid IPv4 mask length \"%s\". Should be between 0-32", p); return -1; } + if (eptr[0] != '\0') { fr_strerror_printf("Failed to parse IPv4 address string \"%s\", " "got garbage after mask length \"%s\"", value, eptr); return -1; } - if (prefix < 32) { - out->ipaddr.ip4addr = fr_inaddr_mask(&out->ipaddr.ip4addr, prefix); + if (mask < 32) { + out->ipaddr.ip4addr = fr_inaddr_mask(&out->ipaddr.ip4addr, mask); } - out->prefix = (uint8_t) prefix; + out->prefix = (uint8_t) mask; out->af = AF_INET; return 0; diff --git a/src/tests/unit/rfc.txt b/src/tests/unit/rfc.txt index d89b1742c45..00247940bb0 100644 --- a/src/tests/unit/rfc.txt +++ b/src/tests/unit/rfc.txt @@ -120,6 +120,9 @@ data Framed-IP-Address = 0.0.0.0 attribute Framed-IP-Address = 127 data Framed-IP-Address = 0.0.0.127 +attribute Framed-IP-Address = 127.0 +data Framed-IP-Address = 127.0.0.0 + attribute Framed-IPv6-Prefix = ::1 data Framed-IPv6-Prefix = ::1/128 @@ -135,6 +138,46 @@ data Framed-IPv6-Prefix = 11:22:33:44:55:66:77:88/128 attribute Framed-IPv6-Prefix = * data Framed-IPv6-Prefix = ::/128 +attribute PMIP6-Home-IPv4-HoA = 127/8 +data PMIP6-Home-IPv4-HoA = 127.0.0.0/8 + +attribute PMIP6-Home-IPv4-HoA = 127/8 +data PMIP6-Home-IPv4-HoA = 127.0.0.0/8 + +# +# Octets outside of the mask are OK, but +# are mashed to zero. +# +attribute PMIP6-Home-IPv4-HoA = 127.63/8 +data PMIP6-Home-IPv4-HoA = 127.0.0.0/8 + +# +# Unless you give a good mask. +# +attribute PMIP6-Home-IPv4-HoA = 127.63/16 +data PMIP6-Home-IPv4-HoA = 127.63.0.0/16 + +attribute PMIP6-Home-IPv4-HoA = 127.999/16 +data Failed to parse IPv4 address string "127.999/16" + +attribute PMIP6-Home-IPv4-HoA = 127.bob/16 +data Failed to parse IPv4 address string "127.bob/16" + +attribute PMIP6-Home-IPv4-HoA = 127.63/15 +data PMIP6-Home-IPv4-HoA = 127.62.0.0/15 + +attribute PMIP6-Home-IPv4-HoA = 127.63.1/24 +data PMIP6-Home-IPv4-HoA = 127.63.1.0/24 + +attribute PMIP6-Home-IPv4-HoA = 127.63.1.6 +data PMIP6-Home-IPv4-HoA = 127.63.1.6/32 + +attribute PMIP6-Home-IPv4-HoA = 256/8 +data Failed to parse IPv4 address string "256/8" + +attribute PMIP6-Home-IPv4-HoA = bob/8 +data Failed to parse IPv4 address string "bob/8" + $INCLUDE tunnel.txt $INCLUDE errors.txt $INCLUDE extended.txt