1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Add proper detection of numeric IPv6 addresses.

By Mauro Tortonesi.
This commit is contained in:
hniksic 2003-09-05 13:36:17 -07:00
parent 564f6aa349
commit 05715ed4d6
2 changed files with 167 additions and 25 deletions

View File

@ -1,3 +1,15 @@
2003-09-05 Hrvoje Niksic <hniksic@xemacs.org>
* url.c (is_valid_ipv6_address): Modified to not require
zero-terminated strings.
(is_valid_ipv4_address): Ditto.
2003-09-05 Mauro Tortonesi <mauro@deepspace6.net>
src/url.c: added RFC 2732 compliance for URL parsing. The
functions is_*_address valid are a modified version of
glibc 2.3.2 inet_pton's code.
2003-09-03 Ahmon Dancy <dancy@dancysoft.com>
* main.c init.c options.h: Added --retry-connrefused option so

180
src/url.c
View File

@ -58,6 +58,11 @@ extern int errno;
/* Is X ".."? */
#define DDOTP(x) ((*(x) == '.') && (*(x + 1) == '.') && (!*(x + 2)))
static const int NS_INADDRSZ = 4;
static const int NS_IN6ADDRSZ = 16;
static const int NS_INT16SZ = 2;
struct scheme_data
{
char *leading_string;
@ -645,7 +650,7 @@ static char *parse_errors[] = {
#define PE_UNTERMINATED_IPV6_ADDRESS 5
"Unterminated IPv6 numeric address",
#define PE_INVALID_IPV6_ADDRESS 6
"Invalid char in IPv6 numeric address"
"Invalid IPv6 numeric address"
};
#define SETERR(p, v) do { \
@ -653,6 +658,137 @@ static char *parse_errors[] = {
*(p) = (v); \
} while (0)
/* The following two functions were adapted from glibc. */
static int
is_valid_ipv4_address (const char *str, const char *end)
{
int saw_digit, octets;
int val;
saw_digit = 0;
octets = 0;
val = 0;
while (str < end) {
int ch = *str++;
if (ch >= '0' && ch <= '9') {
val = val * 10 + (ch - '0');
if (val > 255)
return 0;
if (saw_digit == 0) {
if (++octets > 4)
return 0;
saw_digit = 1;
}
} else if (ch == '.' && saw_digit == 1) {
if (octets == 4)
return 0;
val = 0;
saw_digit = 0;
} else
return 0;
}
if (octets < 4)
return 0;
return 1;
}
static int
is_valid_ipv6_address (const char *str, const char *end)
{
static const char xdigits[] = "0123456789abcdef";
const char *curtok;
int tp;
const char *colonp;
int saw_xdigit;
unsigned int val;
tp = 0;
colonp = NULL;
if (str == end)
return 0;
/* Leading :: requires some special handling. */
if (*str == ':')
{
++str;
if (str == end || *str != ':')
return 0;
}
curtok = str;
saw_xdigit = 0;
val = 0;
while (str < end) {
int ch = *str++;
const char *pch;
/* if ch is a number, add it to val. */
pch = strchr(xdigits, ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return 0;
saw_xdigit = 1;
continue;
}
/* if ch is a colon ... */
if (ch == ':') {
curtok = str;
if (saw_xdigit == 0) {
if (colonp != NULL)
return 0;
colonp = str + tp;
continue;
} else if (str == end) {
return 0;
}
if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
return 0;
tp += NS_INT16SZ;
saw_xdigit = 0;
val = 0;
continue;
}
/* if ch is a dot ... */
if (ch == '.' && (tp <= NS_IN6ADDRSZ - NS_INADDRSZ) &&
is_valid_ipv4_address(curtok, end) == 1) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
break;
}
return 0;
}
if (saw_xdigit == 1) {
if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
return 0;
tp += NS_INT16SZ;
}
if (colonp != NULL) {
if (tp == NS_IN6ADDRSZ)
return 0;
tp = NS_IN6ADDRSZ;
}
if (tp != NS_IN6ADDRSZ)
return 0;
return 1;
}
/* Parse a URL.
Return a new struct url if successful, NULL on error. In case of
@ -710,36 +846,29 @@ url_parse (const char *url, int *error)
if (*p == '[')
{
/* Support http://[::1]/ used by IPv6. */
int invalid = 0;
++p;
while (1)
/* Handle IPv6 address inside square brackets. Ideally we'd
just look for the terminating ']', but rfc2732 mandates
rejecting invalid IPv6 addresses. */
/* The address begins after '['. */
host_b = p + 1;
host_e = strchr (host_b, ']');
if (!host_e)
{
char c = *p++;
switch (c)
{
case ']':
goto out;
case '\0':
SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS);
return NULL;
case ':': case '.':
break;
default:
if (ISXDIGIT (c))
break;
invalid = 1;
}
SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS);
return NULL;
}
out:
if (invalid)
/* Check if the IPv6 address is valid. */
if (!is_valid_ipv6_address(host_b, host_e))
{
SETERR (error, PE_INVALID_IPV6_ADDRESS);
return NULL;
}
/* Don't include brackets in [host_b, host_p). */
++host_b;
host_e = p - 1;
/* Continue parsing after the closing ']'. */
p = host_e + 1;
}
else
{
@ -782,6 +911,7 @@ url_parse (const char *url, int *error)
SETERR (error, PE_BAD_PORT_NUMBER);
return NULL;
}
port = 10 * port + (*pp - '0');
}
}