From 0bc4938eecccefdf8906bf9c488e4cd9c8467e99 Mon Sep 17 00:00:00 2001
From: Paul Marks <pmarks@google.com>
Date: Sun, 30 Mar 2014 07:50:37 +0200
Subject: [PATCH] curl: stop interpreting IPv6 literals as glob patterns.

This makes it possible to fetch from an IPv6 literal without specifying
the -g option.  Globbing remains available elsehwere in the URL.

For example:
  curl http://[::1]/file[1-3].txt

This creates no ambiguity, because there is no overlap between the
syntax of valid globs and valid IPv6 literals.  Globs contain hyphens
and at most 1 colon, while IPv6 literals have no hyphens, and at least 2
colons.

The peek_ipv6() parser simply whitelists a set of characters and counts
colons, because the real validation happens later on.  The character set
includes A-Z, in case someone decides to implement support for scopes
like [fe80::1%25eth0] in the future.

Signed-off-by: Paul Marks <pmarks@google.com>
---
 src/tool_urlglob.c  | 48 ++++++++++++++++++++++++++++++++++++++++++---
 tests/data/test1230 |  2 +-
 2 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/src/tool_urlglob.c b/src/tool_urlglob.c
index ec5014b973..943e0ab88c 100644
--- a/src/tool_urlglob.c
+++ b/src/tool_urlglob.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -302,6 +302,36 @@ static GlobCode glob_range(URLGlob *glob, char **patternp,
   return GLOB_OK;
 }
 
+static bool peek_ipv6(const char *str, size_t *skip)
+{
+  /*
+   * Scan for a potential IPv6 literal.
+   * - Valid globs contain a hyphen and <= 1 colon.
+   * - IPv6 literals contain no hyphens and >= 2 colons.
+   */
+  size_t i = 0;
+  size_t colons = 0;
+  if(str[i++] != '[') {
+    return FALSE;
+  }
+  for(;;) {
+    const char c = str[i++];
+    if(ISALNUM(c) || c == '.' || c == '%') {
+      /* ok */
+    }
+    else if(c == ':') {
+      colons++;
+    }
+    else if(c == ']') {
+      *skip = i;
+      return colons >= 2;
+    }
+    else {
+      return FALSE;
+    }
+  }
+}
+
 static GlobCode glob_parse(URLGlob *glob, char *pattern,
                            size_t pos, unsigned long *amount)
 {
@@ -315,8 +345,20 @@ static GlobCode glob_parse(URLGlob *glob, char *pattern,
 
   while(*pattern && !res) {
     char *buf = glob->glob_buffer;
-    int sublen = 0;
-    while(*pattern && *pattern != '{' && *pattern != '[') {
+    size_t sublen = 0;
+    while(*pattern && *pattern != '{') {
+      if(*pattern == '[') {
+        /* Skip over potential IPv6 literals. */
+        size_t skip;
+        if(peek_ipv6(pattern, &skip)) {
+          memcpy(buf, pattern, skip);
+          buf += skip;
+          pattern += skip;
+          sublen += skip;
+          continue;
+        }
+        break;
+      }
       if(*pattern == '}' || *pattern == ']')
         return GLOBERROR("unmatched close brace/bracket", pos, GLOB_ERROR);
 
diff --git a/tests/data/test1230 b/tests/data/test1230
index b16269d2dc..3c1d3d448a 100644
--- a/tests/data/test1230
+++ b/tests/data/test1230
@@ -56,7 +56,7 @@ HTTP CONNECT to IPv6 numerical address
  </name>
 # 0x4ce == 1230, the test number
  <command>
--g http://[1234:1234:1234::4ce]:%HTTPPORT/wanted/page/1230 -p -x %HOSTIP:%HTTPPORT
+http://[1234:1234:1234::4ce]:%HTTPPORT/wanted/page/1230 -p -x %HOSTIP:%HTTPPORT
 </command>
 </client>
 
-- 
GitLab