Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
clean up fr_inet_pton()
Walk over the *whole* string, checking
*all* of the characters.  The issue with the earlier code was
that it bailed too early, and forced IPv4 even when the address
was IPv6.

manual port of 5452b13
  • Loading branch information
alandekok committed Feb 13, 2018
1 parent 2745376 commit 7d3b172
Showing 1 changed file with 121 additions and 36 deletions.
157 changes: 121 additions & 36 deletions src/lib/util/inet.c
Expand Up @@ -631,56 +631,141 @@ int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resol
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
{
size_t len, i;
bool hostname = true;
bool ipv4 = true;
bool ipv6 = true;

len = (inlen >= 0) ? (size_t)inlen : strlen(value);
for (i = 0; i < len; i++) switch (value[i]) {
/*
* ':' is illegal in domain names and IPv4 addresses.
* Must be v6 and cannot be a domain.
*/
case ':':
return fr_inet_pton6(out, value, inlen, false, false, mask);

for (i = 0; i < len; i++) {
/*
* These are valid for IPv4, IPv6, and host names.
*/
if ((value[i] >= '0') && (value[i] <= '9')) {
continue;
}

/*
* These are invalid for IPv4, but OK for IPv6
* and host names.
*/
if ((value[i] >= 'a') && (value[i] <= 'f')) {
ipv4 = false;
continue;
}

/*
* These are invalid for IPv4, but OK for IPv6
* and host names.
*/
if ((value[i] >= 'A') && (value[i] <= 'F')) {
ipv4 = false;
continue;
}

/*
* This is only valid for IPv6 addresses.
*/
if (value[i] == ':') {
ipv4 = false;
hostname = false;
continue;
}

/*
* Valid for IPv4 and host names, not for IPv6.
*/
if (value[i] == '.') {
ipv6 = false;
continue;
}

/*
* Netmasks are allowed by us, and MUST come at
* the end of the address.
*/
if (value[i] == '/') {
break;
}

/*
* Any characters other than what are checked for
* above can't be IPv4 or IPv6 addresses.
*/
ipv4 = false;
ipv6 = false;
}

/*
* Chars which don't really tell us anything
* It's not an IPv4 or IPv6 address. It MUST be a host
* name.
*/
case '.':
case '/':
continue;

default:
if (!ipv4 && !ipv6) {
/*
* Outside the range of IPv4 chars, must be a domain
* Use A record in preference to AAAA record.
* Not an IPv4 or IPv6 address, and we weren't
* asked to do DNS resolution, we can't do it.
*/
if ((value[i] < '0') || (value[i] > '9')) {
if (!resolve) {
fr_strerror_printf("Not IPv4/6 address, and asked not to resolve");
return -1;
}
switch (af) {
case AF_UNSPEC:
return fr_inet_pton4(out, value, inlen, resolve, true, mask);
if (!resolve) {
fr_strerror_printf("Not IPv4/6 address, and asked not to resolve");
return -1;
}

case AF_INET:
return fr_inet_pton4(out, value, inlen, resolve, false, mask);
/*
* It's not a hostname, either, so bail out
* early.
*/
if (!hostname) {
fr_strerror_printf("Invalid address");
return -1;
}

case AF_INET6:
return fr_inet_pton6(out, value, inlen, resolve, false, mask);
/*
* Fall through to resolving the address, using
* whatever address family they prefer. If they
* don't specify an address family, force IPv4.
*/
if (af == AF_UNSPEC) af = AF_INET;
}

default:
fr_strerror_printf("Invalid address family %i", af);
return -1;
}
/*
* The name has a ':' in it. Therefore it must be an
* IPv6 address. Error out if the caller specified IPv4.
* Otherwise, force IPv6.
*/
if (ipv6 && !hostname) {
if (af == AF_INET) {
fr_strerror_printf("Invalid address");
return -1;
}

af = AF_INET6;
}

fprintf(stderr, "AF %d %s\n", af, value);

/*
* Use whatever the caller specified, OR what we
* insinuated above from looking at the name string.
*/
switch (af) {
case AF_UNSPEC:
return fr_inet_pton4(out, value, inlen, resolve, true, mask);

case AF_INET:
return fr_inet_pton4(out, value, inlen, resolve, false, mask);

case AF_INET6:
return fr_inet_pton6(out, value, inlen, resolve, false, mask);

default:
break;
}

/*
* All chars were in the IPv4 set [0-9/.], must be an IPv4
* address.
*/
return fr_inet_pton4(out, value, inlen, false, false, mask);
/*
* No idea what it is...
*/
fr_strerror_printf("Invalid address family %i", af);
return -1;
}

/** Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Expand Down

0 comments on commit 7d3b172

Please sign in to comment.