← Commit list

4be7143ba1

Joshua Rogers
Joshua Rogers
2026-09-22
SUCCESS Duration: 401s

Subject

urlapi: normalize legacy numeric IPv4 hosts set via CURLUPART_HOST

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

docs/libcurl/curl_url_set.md+4 -0
@@ -131,6 +131,10 @@ you also set the CURLU_URLENCODE flag.
Unless *CURLU_NO_AUTHORITY* is set, a blank hostname is not allowed to set.
+A numeric IPv4 address (in dotted decimal or a legacy form such as a single
+decimal, octal or hexadecimal number) is normalized to dotted decimal, the
+same way it is when libcurl parses a full URL.
+
## CURLUPART_ZONEID
If the hostname is a numeric IPv6 address, this field can also be set.
lib/urlapi.c+17 -1
@@ -2056,10 +2056,24 @@ static CURLUcode url_sethost(CURLU *u, struct dynbuf *encp,
CURLcode result = Curl_urldecode(newp, n, &decoded, &dlen, REJECT_CTRL);
if(result || hostname_check6(u, decoded, dlen))
bad = TRUE;
+ else {
+ struct dynbuf dbuf;
+ curlx_dyn_init(&dbuf, CURL_MAX_INPUT_LENGTH);
+ if(curlx_dyn_addn(&dbuf, decoded, dlen))
+ bad = TRUE;
+ else if(ipv4_normalize(&dbuf) == HOST_IPV4) {
+ curlx_dyn_reset(encp);
+ if(curlx_dyn_addn(encp, curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf)))
+ bad = TRUE;
+ }
+ curlx_dyn_free(&dbuf);
+ }
curlx_free(decoded);
}
else if(hostname_check6(u, newp, n))
bad = TRUE;
+ else if(ipv4_normalize(encp) == HOST_ERROR)
+ bad = TRUE;
if(bad) {
curlx_dyn_free(encp);
return CURLUE_BAD_HOSTNAME;
@@ -2143,7 +2157,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
const char *newp = NULL;
struct dynbuf enc;
CURLUcode status;
- curlx_dyn_init(&enc, (nalloc * 3) + 1 + leadingslash);
+ curlx_dyn_init(&enc, (what == CURLUPART_HOST) ?
+ CURLMAX((nalloc * 3) + 1 + leadingslash, 16) :
+ (nalloc * 3) + 1 + leadingslash);
if(leadingslash && (part[0] != '/')) {
CURLcode result = curlx_dyn_addn(&enc, "/", 1);
tests/libtest/lib1560.c+1 -1
@@ -1297,7 +1297,7 @@ static const struct setcase set_parts_list[] = {
{"https://example.com/",
"host=0xff,", /* '++' there is no automatic URL decode when setting this
part */
- "https://0xff/",
+ "https://0.0.0.255/",
0, /* get */
0, /* set */
CURLUE_OK, CURLUE_OK},
tests/unit/unit1675.c+68 -0
@@ -438,5 +438,73 @@ loop_end:
abort_if(fails, "parse_hostname_login tests failed");
}
+ /* Test that CURLUPART_HOST normalizes legacy numeric IPv4 forms the
+ same way the full URL parser does */
+ {
+ int fails = 0;
+ unsigned int i;
+ struct host_test {
+ const char *host;
+ const char *out;
+ };
+ static const struct host_test tests[] = {
+ { "2130706433", "127.0.0.1" },
+ { "0177.1", "127.0.0.1" },
+ { "0x7f.1", "127.0.0.1" },
+ { "0xc0a80001", "192.168.0.1" },
+ { "127.0.0.1", "127.0.0.1" },
+ { "example.com", "example.com" },
+ { "0", "0.0.0.0" },
+ { "1", "0.0.0.1" },
+ { "7", "0.0.0.7" },
+ { "9", "0.0.0.9" },
+ { "00", "0.0.0.0" },
+ };
+
+ for(i = 0; i < CURL_ARRAYSIZE(tests); i++) {
+ CURLU *viaurl = curl_url();
+ CURLU *viahost = curl_url();
+ CURLUcode uc1, uc2;
+ char *urlbuf = curl_maprintf("http://%s/", tests[i].host);
+ char *gothost1 = NULL;
+ char *gothost2 = NULL;
+
+ if(!viaurl || !viahost || !urlbuf) {
+ curl_mfprintf(stderr, "%u: failed to allocate memory\n", i);
+ fails++;
+ goto host_loop_end;
+ }
+
+ uc1 = curl_url_set(viaurl, CURLUPART_URL, urlbuf, 0);
+ if(!uc1)
+ uc1 = curl_url_get(viaurl, CURLUPART_HOST, &gothost1, 0);
+
+ curl_url_set(viahost, CURLUPART_SCHEME, "http", 0);
+ uc2 = curl_url_set(viahost, CURLUPART_HOST, tests[i].host, 0);
+ if(!uc2)
+ uc2 = curl_url_get(viahost, CURLUPART_HOST, &gothost2, 0);
+
+ if(uc1 || uc2 ||
+ strcmp(gothost1, tests[i].out) ||
+ strcmp(gothost2, tests[i].out)) {
+ curl_mfprintf(stderr, "host '%s' mismatch: full-URL -> '%s' (%d), "
+ "CURLUPART_HOST -> '%s' (%d), expected '%s'\n",
+ tests[i].host,
+ uc1 ? "error" : gothost1, (int)uc1,
+ uc2 ? "error" : gothost2, (int)uc2,
+ tests[i].out);
+ fails++;
+ }
+
+host_loop_end:
+ curl_free(gothost1);
+ curl_free(gothost2);
+ curl_free(urlbuf);
+ curl_url_cleanup(viaurl);
+ curl_url_cleanup(viahost);
+ }
+ abort_if(fails, "CURLUPART_HOST ipv4 normalization parity tests failed");
+ }
+
UNITTEST_END_SIMPLE
}