summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2023-05-18 00:31:17 +0200
committerDaniel Stenberg <daniel@haxx.se>2023-05-18 00:31:17 +0200
commita2815af63a3ab1bfcdff4acc4269c0e7d05e96e8 (patch)
tree9416c77de3424c5bdfa9351b93c3392a6003dffa
parenta9f8fe28481fef7c28d85b4a12a3a35521408eaf (diff)
downloadcurl-bagder/url-digits-hostname.tar.gz
urlapi: allow numerical parts in the host namebagder/url-digits-hostname
It can only be an IPv4 address if the last part is all digits, otherwise it is a host name. Extended test 1560 accordingly. Reported-by: Pavel Kalyugin Fixes #11129
-rw-r--r--lib/curl_ctype.h1
-rw-r--r--lib/urlapi.c57
-rw-r--r--tests/libtest/lib1560.c15
3 files changed, 69 insertions, 4 deletions
diff --git a/lib/curl_ctype.h b/lib/curl_ctype.h
index 1d1d60c28..f4603ae5f 100644
--- a/lib/curl_ctype.h
+++ b/lib/curl_ctype.h
@@ -41,6 +41,7 @@
#define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
#define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))
#define ISDIGIT(x) (((x) >= '0') && ((x) <= '9'))
+#define ISOCTAL(x) (((x) >= '0') && ((x) <= '7'))
#define ISBLANK(x) (((x) == ' ') || ((x) == '\t'))
#define ISSPACE(x) (ISBLANK(x) || (((x) >= 0xa) && ((x) <= 0x0d)))
diff --git a/lib/urlapi.c b/lib/urlapi.c
index 83e4ceda3..4c2d01b1b 100644
--- a/lib/urlapi.c
+++ b/lib/urlapi.c
@@ -34,6 +34,7 @@
#include "inet_ntop.h"
#include "strdup.h"
#include "idn.h"
+#include "curl_memrchr.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -656,6 +657,54 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
#define HOST_IPV4 2
#define HOST_IPV6 3
+static bool finetld(const char *c, size_t len)
+{
+ const char *ldot;
+ const char *end = &c[len];
+ int i;
+
+ for(i = 0; i < 2; i++) {
+ ldot = memrchr(c, '.', len);
+ if(!ldot)
+ ldot = c;
+ else {
+ ldot++;
+ if(!*ldot) {
+ /* this is a trailing dot, we rather want the one before */
+ len--;
+ end = &c[len];
+ /* now loop */
+ continue;
+ }
+ }
+ break;
+ }
+
+ /* this is the last part of the host name, if not only digits it is a
+ host name, otherwise a bad IPv4 address */
+ if(*ldot == '0') {
+ /* hex or octal */
+
+ ldot++;
+ if(Curl_raw_tolower(*ldot) == 'x')
+ /* hex */
+ ldot++;
+ else {
+ /* octal */
+ while(*ldot && ISOCTAL(*ldot))
+ ldot++;
+ }
+ while(*ldot && ISXDIGIT(*ldot))
+ ldot++;
+ }
+ else {
+ /* decimal */
+ while(*ldot && ISDIGIT(*ldot))
+ ldot++;
+ }
+ return (ldot != end) ? TRUE : FALSE;
+}
+
static int ipv4_normalize(struct dynbuf *host)
{
bool done = FALSE;
@@ -667,12 +716,15 @@ static int ipv4_normalize(struct dynbuf *host)
if(*c == '[')
return HOST_IPV6;
+ if(finetld(c, Curl_dyn_len(host)))
+ return HOST_NAME;
+
while(!done) {
char *endp;
unsigned long l;
if(!ISDIGIT(*c))
/* most importantly this doesn't allow a leading plus or minus */
- return n ? HOST_BAD : HOST_NAME;
+ return HOST_BAD;
l = strtoul(c, &endp, 0);
parts[n] = l;
@@ -793,6 +845,9 @@ static CURLUcode parse_authority(struct Curl_URL *u,
if(result)
goto out;
+ if(!Curl_dyn_len(host))
+ return CURLUE_NO_HOST;
+
switch(ipv4_normalize(host)) {
case HOST_IPV4:
break;
diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c
index 8d7b4e966..3120a63ab 100644
--- a/tests/libtest/lib1560.c
+++ b/tests/libtest/lib1560.c
@@ -474,6 +474,12 @@ static const struct testcase get_parts_list[] ={
};
static const struct urltestcase get_url_list[] = {
+ {"https://0x7f.1", "https://127.0.0.1/", 0, 0, CURLUE_OK},
+ {"https://1.2.3.256.com", "https://1.2.3.256.com/", 0, 0, CURLUE_OK},
+ {"https://10.com", "https://10.com/", 0, 0, CURLUE_OK},
+ {"https://1.2.com", "https://1.2.com/", 0, 0, CURLUE_OK},
+ {"https://1.2.3.com", "https://1.2.3.com/", 0, 0, CURLUE_OK},
+ {"https://1.2.com.99", "https://1.2.com.99/", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://[fe80::0000:20c:29ff:fe9c:409b]:80/moo",
"https://[fe80::20c:29ff:fe9c:409b]:80/moo",
0, 0, CURLUE_OK},
@@ -522,19 +528,22 @@ static const struct urltestcase get_url_list[] = {
/* IPv4 trickeries */
{"https://16843009", "https://1.1.1.1/", 0, 0, CURLUE_OK},
- {"https://0x7f.1", "https://127.0.0.1/", 0, 0, CURLUE_OK},
{"https://0177.1", "https://127.0.0.1/", 0, 0, CURLUE_OK},
{"https://0111.02.0x3", "https://73.2.0.3/", 0, 0, CURLUE_OK},
+ {"https://0111.02.0x3.", "https://73.2.0.3./", 0, 0, CURLUE_BAD_HOSTNAME},
+ {"https://0111.02.030", "https://73.2.0.24/", 0, 0, CURLUE_OK},
+ {"https://0111.02.030.", "https://73.2.0.24./", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://0xff.0xff.0377.255", "https://255.255.255.255/", 0, 0, CURLUE_OK},
{"https://1.0xffffff", "https://1.255.255.255/", 0, 0, CURLUE_OK},
/* IPv4 numerical overflows or syntax errors will not normalize */
- {"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_BAD_HOSTNAME},
{"https://\xff.127.0.0.1", "https://%FF.127.0.0.1/", 0, CURLU_URLENCODE,
- CURLUE_OK},
+ CURLUE_BAD_HOSTNAME},
{"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_MALFORMED_INPUT},
{"https://1.0x1000000", "https://1.0x1000000/", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://1.2.3.256", "https://1.2.3.256/", 0, 0, CURLUE_BAD_HOSTNAME},
+ {"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_BAD_HOSTNAME},
{"https://1.2.0x100.3", "https://1.2.0x100.3/", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://4294967296", "https://4294967296/", 0, 0, CURLUE_BAD_HOSTNAME},