]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
hostip: resolve *.localhost to 127.0.0.1/::1
authorDaniel Stenberg <daniel@haxx.se>
Thu, 11 Aug 2022 09:32:22 +0000 (11:32 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 11 Aug 2022 12:01:37 +0000 (14:01 +0200)
Following the footsteps of other clients like Firefox/Chrome.  RFC 6761
says clients SHOULD do this.

Add test 389 to verify.

Reported-by: TheKnarf on github
Fixes #9192
Closes #9296

lib/hostip.c
tests/data/Makefile.inc
tests/data/test389 [new file with mode: 0644]

index 1ced9d2e9ce083127f9a5e699cd2765c54ffa1c9..99779044c5f1b0fc249fe91fc5604d21f4506e0e 100644 (file)
@@ -463,12 +463,12 @@ Curl_cache_addr(struct Curl_easy *data,
 }
 
 #ifdef ENABLE_IPV6
-/* return a static IPv6 resolve for 'localhost' */
-static struct Curl_addrinfo *get_localhost6(int port)
+/* return a static IPv6 ::1 for the name */
+static struct Curl_addrinfo *get_localhost6(int port, const char *name)
 {
   struct Curl_addrinfo *ca;
   const size_t ss_size = sizeof(struct sockaddr_in6);
-  const size_t hostlen = strlen("localhost");
+  const size_t hostlen = strlen(name);
   struct sockaddr_in6 sa6;
   unsigned char ipv6[16];
   unsigned short port16 = (unsigned short)(port & 0xffff);
@@ -493,19 +493,19 @@ static struct Curl_addrinfo *get_localhost6(int port)
   ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
   memcpy(ca->ai_addr, &sa6, ss_size);
   ca->ai_canonname = (char *)ca->ai_addr + ss_size;
-  strcpy(ca->ai_canonname, "localhost");
+  strcpy(ca->ai_canonname, name);
   return ca;
 }
 #else
-#define get_localhost6(x) NULL
+#define get_localhost6(x,y) NULL
 #endif
 
-/* return a static IPv4 resolve for 'localhost' */
-static struct Curl_addrinfo *get_localhost(int port)
+/* return a static IPv4 127.0.0.1 for the given name */
+static struct Curl_addrinfo *get_localhost(int port, const char *name)
 {
   struct Curl_addrinfo *ca;
   const size_t ss_size = sizeof(struct sockaddr_in);
-  const size_t hostlen = strlen("localhost");
+  const size_t hostlen = strlen(name);
   struct sockaddr_in sa;
   unsigned int ipv4;
   unsigned short port16 = (unsigned short)(port & 0xffff);
@@ -529,8 +529,8 @@ static struct Curl_addrinfo *get_localhost(int port)
   ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
   memcpy(ca->ai_addr, &sa, ss_size);
   ca->ai_canonname = (char *)ca->ai_addr + ss_size;
-  strcpy(ca->ai_canonname, "localhost");
-  ca->ai_next = get_localhost6(port);
+  strcpy(ca->ai_canonname, name);
+  ca->ai_next = get_localhost6(port, name);
   return ca;
 }
 
@@ -583,6 +583,17 @@ bool Curl_host_is_ipnum(const char *hostname)
   return FALSE;
 }
 
+
+/* return TRUE if 'part' is a case insentive tail of 'full' */
+static bool tailmatch(const char *full, const char *part)
+{
+  size_t plen = strlen(part);
+  size_t flen = strlen(full);
+  if(plen > flen)
+    return FALSE;
+  return strncasecompare(part, &full[flen - plen], plen);
+}
+
 /*
  * Curl_resolv() is the main name resolve function within libcurl. It resolves
  * a name and returns a pointer to the entry in the 'entry' argument (if one
@@ -718,8 +729,9 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
       if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data))
         return CURLRESOLV_ERROR;
 
-      if(strcasecompare(hostname, "localhost"))
-        addr = get_localhost(port);
+      if(strcasecompare(hostname, "localhost") ||
+         tailmatch(hostname, ".localhost"))
+        addr = get_localhost(port, hostname);
 #ifndef CURL_DISABLE_DOH
       else if(allowDOH && data->set.doh && !ipnum)
         addr = Curl_doh(data, hostname, port, &respwait);
index b7bc2d41df8ac8e489c9e2879f5f13902f6c2010..cfa0ea38413cfb7369a668f917f4c0e3608315ba 100644 (file)
@@ -64,8 +64,7 @@ test343 test344 test345 test346 test347 test348 test349 test350 test351 \
 test352 test353 test354 test355 test356 test357 test358 test359 test360 \
 test361 test362 test363 test364 test365 test366 test367 test368 test369 \
 test370 test371 test372 test373 test374 test375 test376 test378 test379 \
-test380 test381 test383 test384 test385 test386 test387 test388 \
-\
+test380 test381 test383 test384 test385 test386 test387 test388 test389 \
 test390 test391 test392 test393 test394 test395 test396 test397 test398 \
 \
 test400 test401 test402 test403 test404 test405 test406 test407 test408 \
diff --git a/tests/data/test389 b/tests/data/test389
new file mode 100644 (file)
index 0000000..f805bc2
--- /dev/null
@@ -0,0 +1,57 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+.localhost
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+ <name>
+*.localhost is a local host
+ </name>
+ <command>
+http://curlmachine.localhost:%HTTPPORT/%TESTNUMBER
+</command>
+# Ensure that we're running on localhost
+<precheck>
+perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );"
+</precheck>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+GET /%TESTNUMBER HTTP/1.1\r
+Host: curlmachine.localhost:%HTTPPORT\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>