From: Arran Cudbard-Bell Date: Mon, 20 Jul 2015 18:03:44 +0000 (-0400) Subject: Allow an af to be specified for fr_pton X-Git-Tag: release_3_0_10~313 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d2759c57452842a43115b845afaf43301653dd1b;p=thirdparty%2Ffreeradius-server.git Allow an af to be specified for fr_pton This controls which record we use if the address doesn't look like a v4 or v6 address. Additionally inet_pton doesn't like addresses being wrapped in [], so strip them off in fr_pton_port. --- diff --git a/src/include/libradius.h b/src/include/libradius.h index a42426796fc..a6d20f782fc 100644 --- a/src/include/libradius.h +++ b/src/include/libradius.h @@ -706,8 +706,9 @@ char const *fr_inet_ntop(int af, void const *src); char const *ip_ntoa(char *, uint32_t); int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback); int fr_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback); -int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve); -int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, bool resolve); +int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve); +int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, + bool resolve); int fr_ntop(char *out, size_t outlen, fr_ipaddr_t *addr); char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid); uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid); diff --git a/src/lib/misc.c b/src/lib/misc.c index c80c36b7712..a4b92a44168 100644 --- a/src/lib/misc.c +++ b/src/lib/misc.c @@ -397,25 +397,29 @@ int fr_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b /** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser. * - * @param out Where to write the ip address value. - * @param value to parse. - * @param inlen Length of value, if value is \0 terminated inlen may be -1. - * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname. - * @return 0 if ip address was parsed successfully, else -1 on error. + * @param[out] out Where to write the ip address value. + * @param[in] value to parse. + * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1. + * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a + * hostname. + * @param[in] af If the address type is not obvious from the format, and resolve is true, the DNS + * record (A or AAAA) we require. Also controls which parser we pass the address to if + * we have no idea what it is. + * @return + * - 0 if ip address was parsed successfully. + * - -1 on failure. */ -int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve) +int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve) { size_t len, i; len = (inlen >= 0) ? (size_t)inlen : strlen(value); for (i = 0; i < len; i++) switch (value[i]) { /* - * Chars illegal in domain names and IPv4 addresses. + * ':' is illegal in domain names and IPv4 addresses. * Must be v6 and cannot be a domain. */ case ':': - case '[': - case ']': return fr_pton6(out, value, inlen, false, false); /* @@ -435,7 +439,20 @@ int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve) fr_strerror_printf("Not IPv4/6 address, and asked not to resolve"); return -1; } - return fr_pton4(out, value, inlen, true, true); + switch (af) { + case AF_UNSPEC: + return fr_pton4(out, value, inlen, resolve, true); + + case AF_INET: + return fr_pton4(out, value, inlen, resolve, false); + + case AF_INET6: + return fr_pton6(out, value, inlen, resolve, false); + + default: + fr_strerror_printf("Invalid address family %i", af); + return -1; + } } break; } @@ -453,10 +470,13 @@ int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve) * @param[out] port_out Where to write the port (0 if no port found). * @param[in] value to parse. * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1. + * @param[in] af If the address type is not obvious from the format, and resolve is true, the DNS + * record (A or AAAA) we require. Also controls which parser we pass the address to if + * we have no idea what it is. * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a * hostname. */ -int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, bool resolve) +int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve) { char const *p = value, *q; char *end; @@ -474,7 +494,10 @@ int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_ return -1; } - if (fr_pton6(out, p, (q - p) + 1, false, false) < 0) return -1; + /* + * inet_pton doesn't like the address being wrapped in [] + */ + if (fr_pton6(out, p + 1, (q - p) - 1, false, false) < 0) return -1; if (q[1] == ':') { q++; @@ -485,18 +508,15 @@ int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_ } /* - * IPv4 or host, with no port + * Host, IPv4 or IPv6 with no port */ q = memchr(p, ':', len); - if (!q) { - if (fr_pton(out, p, len, resolve) < 0) return -1; - return 0; - } + if (!q || !memchr(p, '.', len)) return fr_pton(out, p, len, af, resolve); /* * IPv4 or host, with port */ - if (fr_pton(out, p, (q - p), true) < 0) return -1; + if (fr_pton(out, p, (q - p), af, resolve) < 0) return -1; do_port: /* * Valid ports are a maximum of 5 digits, so if the diff --git a/src/main/client.c b/src/main/client.c index 408ea74be19..8f42ffc143e 100644 --- a/src/main/client.c +++ b/src/main/client.c @@ -1156,7 +1156,7 @@ RADCLIENT *client_afrom_query(TALLOC_CTX *ctx, char const *identifier, char cons c = talloc_zero(ctx, RADCLIENT); - if (fr_pton(&c->ipaddr, identifier, -1, true) < 0) { + if (fr_pton(&c->ipaddr, identifier, -1, AF_UNSPEC, true) < 0) { ERROR("%s", fr_strerror()); talloc_free(c); diff --git a/src/main/conffile.c b/src/main/conffile.c index e15416433b2..904b65ed2ff 100644 --- a/src/main/conffile.c +++ b/src/main/conffile.c @@ -1668,7 +1668,7 @@ int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *d case PW_TYPE_COMBO_IP_PREFIX: ipaddr = data; - if (fr_pton(ipaddr, value, -1, true) < 0) { + if (fr_pton(ipaddr, value, -1, AF_UNSPEC, true) < 0) { ERROR("%s", fr_strerror()); return -1; } diff --git a/src/main/mainconfig.c b/src/main/mainconfig.c index ca2a811c116..a082d6c0c0e 100644 --- a/src/main/mainconfig.c +++ b/src/main/mainconfig.c @@ -423,7 +423,7 @@ static ssize_t xlat_getclient(UNUSED void *instance, REQUEST *request, char cons } strlcpy(buffer, p, (q + 1) - p); - if (fr_pton(&ip, buffer, -1, false) < 0) { + if (fr_pton(&ip, buffer, -1, AF_UNSPEC, false) < 0) { REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", buffer); goto error; }