]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
urlapi: deny hostnames with more than one trailing dot
authorDaniel Stenberg <daniel@haxx.se>
Fri, 15 May 2026 08:14:36 +0000 (10:14 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 15 May 2026 09:44:20 +0000 (11:44 +0200)
Or consisting of just a single dot.

Such names cannot be resolved with DNS.

While they *can* still be resolved with /etc/hosts or --resolve tricks,
they easily cause internal problems because their trailing dots.

Let's not allow them anymore.

Closes #21622

lib/urlapi.c
tests/http/test_17_ssl_use.py
tests/libtest/lib1560.c

index 24b8bc244a5347165b96594302ecea06aafcd69b..a3111f9db6e8a79dd562b16137118f5d0609fa12 100644 (file)
@@ -475,6 +475,13 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
     if(hlen != len)
       /* hostname with bad content */
       return CURLUE_BAD_HOSTNAME;
+    else if((hlen >= 2) &&
+            (hostname[hlen - 1] == '.') && (hostname[hlen - 2] == '.'))
+      /* more than one trailing dot is not allowed */
+      return CURLUE_BAD_HOSTNAME;
+    else if((hlen == 1) && (hostname[0] == '.'))
+      /* just a single dot is not allowed */
+      return CURLUE_BAD_HOSTNAME;
   }
   return CURLUE_OK;
 }
index b2339dab5165794abf3f8d65512e8a72e998bc11..4a4dd0bf7e04d1b523e6f5bbc3f03b678346a8e1 100644 (file)
@@ -127,7 +127,7 @@ class TestSSLUse:
             # the SNI the server received is without trailing dot
             assert r.json['SSL_TLS_SNI'] == env.domain1, f'{r.json}'
 
-    # use hostname with double trailing dot, verify handshake
+    # use hostname with double trailing dot
     @pytest.mark.parametrize("proto", Env.http_protos())
     def test_17_04_double_dot(self, env: Env, proto, httpd, nghttpx):
         curl = CurlClient(env=env)
@@ -142,10 +142,8 @@ class TestSSLUse:
             if proto != 'h3':  # we proxy h3
                 assert r.json['SSL_TLS_SNI'] == env.domain1, f'{r.json}'
             assert False, f'should not have succeeded: {r.json}'
-        # 7 - Rustls rejects a servername with .. during setup
-        # 35 - LibreSSL rejects setting an SNI name with trailing dot
-        # 60 - peer name matching failed against certificate
-        assert r.exit_code in [7, 35, 60], f'{r}'
+        # 3 - not allowed in the URL
+        assert r.exit_code in [3], f'{r}'
 
     # use ip address for connect
     @pytest.mark.parametrize("proto", Env.http_protos())
index 6c3fff9bc9992dc46c128a788ce28480779b44b3..e833c304e3719c05f669a7c9b25346aa20ed3eaf 100644 (file)
@@ -196,20 +196,19 @@ static const struct testcase get_parts_list[] = {
     "http://host:00080/",
     "http | [11] | [12] | [13] | host | 80 | / | [16] | [17]",
     0, 0, CURLUE_OK },
-  { /* Single dot host - technically valid in some contexts but often
-       rejected */
+  { /* Single dot host - not ok */
     "http://./",
-    "http | [11] | [12] | [13] | . | [15] | / | [16] | [17]",
-    0, 0, CURLUE_OK },
+    "",
+    0, 0, CURLUE_BAD_HOSTNAME },
   { /* Host starting with a dash (RFC 1123 technically allows it, but many
        parsers don't) */
     "http://-atest/",
     "http | [11] | [12] | [13] | -atest | [15] | / | [16] | [17]",
     0, 0, CURLUE_OK },
-  { /* Multiple trailing dots, not okay in DNS but works in /etc/hosts */
+  { /* Multiple trailing dots is not okey */
     "http://example.com../",
-    "http | [11] | [12] | [13] | example.com.. | [15] | / | [16] | [17]",
-    0, 0, CURLUE_OK },
+    "",
+    0, 0, CURLUE_BAD_HOSTNAME },
   {  /* Empty IPv6 Zone ID */
     "http://[fe80::1%]/",
     "", 0, 0, CURLUE_BAD_IPV6 },
@@ -626,6 +625,13 @@ static const struct testcase get_parts_list[] = {
 };
 
 static const struct urltestcase get_url_list[] = {
+  {"http://hej./", "http://hej./", 0, 0, CURLUE_OK},
+  {"http://hej../", "", 0, 0, CURLUE_BAD_HOSTNAME},
+  {"http://hej.../", "", 0, 0, CURLUE_BAD_HOSTNAME},
+  {"http://hej..../index.html", "", 0, 0, CURLUE_BAD_HOSTNAME},
+  {"http://.", "", 0, 0, CURLUE_BAD_HOSTNAME},
+  {"http://..", "", 0, 0, CURLUE_BAD_HOSTNAME},
+  {"http://...", "", 0, 0, CURLUE_BAD_HOSTNAME},
   {"018.0.0.0", "http://018.0.0.0/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
   {"08", "http://08/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
   {"0", "http://0.0.0.0/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},