mirror of
https://github.com/curl/curl.git
synced 2026-07-26 05:07:22 +03:00
urlapi: detect and error on illegal IPv4 addresses
Using bad numbers in an IPv4 numerical address now returns CURLUE_BAD_HOSTNAME. I noticed while working on trurl and it was originally reported here: https://github.com/curl/trurl/issues/78 Updated test 1560 accordingly. Closes #10894
This commit is contained in:
parent
98fac31b06
commit
17a15d8846
2 changed files with 48 additions and 34 deletions
69
lib/urlapi.c
69
lib/urlapi.c
|
|
@ -649,7 +649,12 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
|
||||||
* Output the "normalized" version of that input string in plain quad decimal
|
* Output the "normalized" version of that input string in plain quad decimal
|
||||||
* integers and return TRUE.
|
* integers and return TRUE.
|
||||||
*/
|
*/
|
||||||
static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
|
|
||||||
|
#define IPV4_NOTANIP 1
|
||||||
|
#define IPV4_BAD 2
|
||||||
|
#define IPV4_CLEANED 3
|
||||||
|
|
||||||
|
static int ipv4_normalize(const char *hostname, char *outp, size_t olen)
|
||||||
{
|
{
|
||||||
bool done = FALSE;
|
bool done = FALSE;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
@ -659,28 +664,18 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
|
||||||
while(!done) {
|
while(!done) {
|
||||||
char *endp;
|
char *endp;
|
||||||
unsigned long l;
|
unsigned long l;
|
||||||
if((*c < '0') || (*c > '9'))
|
if(!ISDIGIT(*c))
|
||||||
/* most importantly this doesn't allow a leading plus or minus */
|
/* most importantly this doesn't allow a leading plus or minus */
|
||||||
return FALSE;
|
return n ? IPV4_BAD :IPV4_NOTANIP;
|
||||||
l = strtoul(c, &endp, 0);
|
l = strtoul(c, &endp, 0);
|
||||||
|
|
||||||
/* overflow or nothing parsed at all */
|
|
||||||
if(((l == ULONG_MAX) && (errno == ERANGE)) || (endp == c))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
#if SIZEOF_LONG > 4
|
|
||||||
/* a value larger than 32 bits */
|
|
||||||
if(l > UINT_MAX)
|
|
||||||
return FALSE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
parts[n] = l;
|
parts[n] = l;
|
||||||
c = endp;
|
c = endp;
|
||||||
|
|
||||||
switch (*c) {
|
switch (*c) {
|
||||||
case '.' :
|
case '.' :
|
||||||
if(n == 3)
|
if(n == 3)
|
||||||
return FALSE;
|
return IPV4_BAD;
|
||||||
n++;
|
n++;
|
||||||
c++;
|
c++;
|
||||||
break;
|
break;
|
||||||
|
|
@ -690,8 +685,18 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return n ? IPV4_BAD : IPV4_NOTANIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* overflow */
|
||||||
|
if((l == ULONG_MAX) && (errno == ERANGE))
|
||||||
|
return IPV4_BAD;
|
||||||
|
|
||||||
|
#if SIZEOF_LONG > 4
|
||||||
|
/* a value larger than 32 bits */
|
||||||
|
if(l > UINT_MAX)
|
||||||
|
return IPV4_BAD;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is deemed a valid IPv4 numerical address */
|
/* this is deemed a valid IPv4 numerical address */
|
||||||
|
|
@ -704,14 +709,14 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
|
||||||
break;
|
break;
|
||||||
case 1: /* a.b -- 8.24 bits */
|
case 1: /* a.b -- 8.24 bits */
|
||||||
if((parts[0] > 0xff) || (parts[1] > 0xffffff))
|
if((parts[0] > 0xff) || (parts[1] > 0xffffff))
|
||||||
return FALSE;
|
return IPV4_BAD;
|
||||||
msnprintf(outp, olen, "%u.%u.%u.%u",
|
msnprintf(outp, olen, "%u.%u.%u.%u",
|
||||||
parts[0], (parts[1] >> 16) & 0xff,
|
parts[0], (parts[1] >> 16) & 0xff,
|
||||||
(parts[1] >> 8) & 0xff, parts[1] & 0xff);
|
(parts[1] >> 8) & 0xff, parts[1] & 0xff);
|
||||||
break;
|
break;
|
||||||
case 2: /* a.b.c -- 8.8.16 bits */
|
case 2: /* a.b.c -- 8.8.16 bits */
|
||||||
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff))
|
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff))
|
||||||
return FALSE;
|
return IPV4_BAD;
|
||||||
msnprintf(outp, olen, "%u.%u.%u.%u",
|
msnprintf(outp, olen, "%u.%u.%u.%u",
|
||||||
parts[0], parts[1], (parts[2] >> 8) & 0xff,
|
parts[0], parts[1], (parts[2] >> 8) & 0xff,
|
||||||
parts[2] & 0xff);
|
parts[2] & 0xff);
|
||||||
|
|
@ -719,12 +724,12 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
|
||||||
case 3: /* a.b.c.d -- 8.8.8.8 bits */
|
case 3: /* a.b.c.d -- 8.8.8.8 bits */
|
||||||
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) ||
|
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) ||
|
||||||
(parts[3] > 0xff))
|
(parts[3] > 0xff))
|
||||||
return FALSE;
|
return IPV4_BAD;
|
||||||
msnprintf(outp, olen, "%u.%u.%u.%u",
|
msnprintf(outp, olen, "%u.%u.%u.%u",
|
||||||
parts[0], parts[1], parts[2], parts[3]);
|
parts[0], parts[1], parts[2], parts[3]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return IPV4_CLEANED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if necessary, replace the host content with a URL decoded version */
|
/* if necessary, replace the host content with a URL decoded version */
|
||||||
|
|
@ -1247,6 +1252,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
|
||||||
|
|
||||||
if(Curl_dyn_len(&host)) {
|
if(Curl_dyn_len(&host)) {
|
||||||
char normalized_ipv4[sizeof("255.255.255.255") + 1];
|
char normalized_ipv4[sizeof("255.255.255.255") + 1];
|
||||||
|
int norm;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the login details and strip them out of the host name.
|
* Parse the login details and strip them out of the host name.
|
||||||
|
|
@ -1262,21 +1268,28 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ipv4_normalize(Curl_dyn_ptr(&host),
|
norm = ipv4_normalize(Curl_dyn_ptr(&host),
|
||||||
normalized_ipv4, sizeof(normalized_ipv4))) {
|
normalized_ipv4, sizeof(normalized_ipv4));
|
||||||
|
switch(norm) {
|
||||||
|
case IPV4_CLEANED:
|
||||||
Curl_dyn_reset(&host);
|
Curl_dyn_reset(&host);
|
||||||
if(Curl_dyn_add(&host, normalized_ipv4)) {
|
if(Curl_dyn_add(&host, normalized_ipv4))
|
||||||
result = CURLUE_OUT_OF_MEMORY;
|
result = CURLUE_OUT_OF_MEMORY;
|
||||||
goto fail;
|
break;
|
||||||
}
|
|
||||||
}
|
case IPV4_NOTANIP:
|
||||||
else {
|
|
||||||
result = decode_host(&host);
|
result = decode_host(&host);
|
||||||
if(!result)
|
if(!result)
|
||||||
result = hostname_check(u, Curl_dyn_ptr(&host), Curl_dyn_len(&host));
|
result = hostname_check(u, Curl_dyn_ptr(&host), Curl_dyn_len(&host));
|
||||||
if(result)
|
break;
|
||||||
goto fail;
|
|
||||||
|
case IPV4_BAD:
|
||||||
|
default:
|
||||||
|
result = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if(result)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if((flags & CURLU_GUESS_SCHEME) && !schemep) {
|
if((flags & CURLU_GUESS_SCHEME) && !schemep) {
|
||||||
const char *hostname = Curl_dyn_ptr(&host);
|
const char *hostname = Curl_dyn_ptr(&host);
|
||||||
|
|
|
||||||
|
|
@ -531,13 +531,14 @@ static const struct urltestcase get_url_list[] = {
|
||||||
{"https://a127.0.0.1", "https://a127.0.0.1/", 0, 0, CURLUE_OK},
|
{"https://a127.0.0.1", "https://a127.0.0.1/", 0, 0, CURLUE_OK},
|
||||||
{"https://\xff.127.0.0.1", "https://%FF.127.0.0.1/", 0, CURLU_URLENCODE,
|
{"https://\xff.127.0.0.1", "https://%FF.127.0.0.1/", 0, CURLU_URLENCODE,
|
||||||
CURLUE_OK},
|
CURLUE_OK},
|
||||||
{"https://127.-0.0.1", "https://127.-0.0.1/", 0, 0, CURLUE_OK},
|
{"https://127.-0.0.1", "https://127.-0.0.1/", 0, 0, CURLUE_BAD_HOSTNAME},
|
||||||
{"https://127.0. 1", "https://127.0.0.1/", 0, 0, CURLUE_BAD_HOSTNAME},
|
{"https://127.0. 1", "https://127.0.0.1/", 0, 0, CURLUE_BAD_HOSTNAME},
|
||||||
{"https://1.0x1000000", "https://1.0x1000000/", 0, 0, CURLUE_OK},
|
{"https://1.0x1000000", "https://1.0x1000000/", 0, 0, CURLUE_BAD_HOSTNAME},
|
||||||
{"https://1.2.3.256", "https://1.2.3.256/", 0, 0, CURLUE_OK},
|
{"https://1.2.3.256", "https://1.2.3.256/", 0, 0, CURLUE_BAD_HOSTNAME},
|
||||||
{"https://1.2.3.4.5", "https://1.2.3.4.5/", 0, 0, CURLUE_OK},
|
{"https://1.2.3.4.5", "https://1.2.3.4.5/", 0, 0, CURLUE_BAD_HOSTNAME},
|
||||||
{"https://1.2.0x100.3", "https://1.2.0x100.3/", 0, 0, CURLUE_OK},
|
{"https://1.2.0x100.3", "https://1.2.0x100.3/", 0, 0, CURLUE_BAD_HOSTNAME},
|
||||||
{"https://4294967296", "https://4294967296/", 0, 0, CURLUE_OK},
|
{"https://4294967296", "https://4294967296/", 0, 0, CURLUE_BAD_HOSTNAME},
|
||||||
|
{"https://123host", "https://123host/", 0, 0, CURLUE_OK},
|
||||||
/* 40 bytes scheme is the max allowed */
|
/* 40 bytes scheme is the max allowed */
|
||||||
{"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA://hostname/path",
|
{"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA://hostname/path",
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa://hostname/path",
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa://hostname/path",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue