bug-wget
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Bug-wget] Wget and IPv6 link local addresses


From: Petr Pisar
Subject: Re: [Bug-wget] Wget and IPv6 link local addresses
Date: Mon, 1 Jun 2009 21:09:10 +0200
User-agent: Mutt/1.5.16 (2007-06-09)

On Sat, May 30, 2009 at 12:18:02PM +0100, Fabian Hugelshofer wrote:
> 
> Wget 1.11.4 does not support IPv6 link local addresses. Addresses with a
> zone identifier are being rejected with "Invalid IPv6 numeric address".
> 
> e.g.:
> $ wget http://[fe80::1%25eth0]/
> http://[fe80::1%25eth0]/: Invalid IPv6 numeric address.
> 
> "%25" is encoded for '%', the delimiter for the zone identifier.
> 
> Such an URL gets rejected by is_valid_ipv6_address() in host.c.

Fix is not easy because the zone identifier should be considered only during
making local sockets. It should be avoided in upper layer (HTTP, SSL, FTP)
processing.

You can try following patch which is quick and dirty hack only for HTTP.
Propper patch would require significant changes over all the code.

-- Petr

commit cd898b30ae67881df842f35e844c99afd7e9585b
Author: Petr Písař <address@hidden>
Date:   Mon Jun 1 20:58:38 2009 +0200

    Naive IPv6 zone identifier implementation for HTTP.

diff --git a/src/host.c b/src/host.c
index fb5a2cb..48756d5 100644
--- a/src/host.c
+++ b/src/host.c
@@ -478,7 +478,12 @@ is_valid_ipv6_address (const char *str, const char *end)
 
   if (str == end)
     return false;
-  
+ 
+  /* RFC 4007: link scope address with zone identifier */
+  const char *realend = strchr(str, '%');
+  if (realend > end)
+      realend = end;
+
   /* Leading :: requires some special handling. */
   if (*str == ':')
     {
@@ -491,7 +496,7 @@ is_valid_ipv6_address (const char *str, const char *end)
   saw_xdigit = false;
   val = 0;
 
-  while (str < end)
+  while (str < realend)
     {
       int ch = *str++;
 
@@ -517,7 +522,7 @@ is_valid_ipv6_address (const char *str, const char *end)
               colonp = str + tp;
               continue;
             }
-          else if (str == end)
+          else if (str == realend)
             return false;
           if (tp > ns_in6addrsz - ns_int16sz)
             return false;
@@ -529,13 +534,13 @@ is_valid_ipv6_address (const char *str, const char *end)
 
       /* if ch is a dot ... */
       if (ch == '.' && (tp <= ns_in6addrsz - ns_inaddrsz)
-          && is_valid_ipv4_address (curtok, end) == 1)
+          && is_valid_ipv4_address (curtok, realend) == 1)
         {
           tp += ns_inaddrsz;
           saw_xdigit = false;
           break;
         }
-    
+
       return false;
     }
 
@@ -556,6 +561,16 @@ is_valid_ipv6_address (const char *str, const char *end)
   if (tp != ns_in6addrsz)
     return false;
 
+  /* Zone identifier has to be only decimal natural number in nummerical
+   * address. Othewise, it's plarform specific zone string (e.g. interface
+   * number) a and it has to be resolved. */
+  const char *ch;
+  for (ch = realend + 1; ch < end; ch++)
+    {
+      if (*ch < '0' || *ch > '9')
+          return false;
+    }
+
   return true;
 }
 
diff --git a/src/http.c b/src/http.c
index bdfe100..e6ee993 100644
--- a/src/http.c
+++ b/src/http.c
@@ -1508,6 +1508,13 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, 
struct url *proxy)
        becomes ambiguous and needs to be rewritten as "Host:
        [3ffe:8100:200:2::2]:1234".  */
   {
+    /* Hide IPv6 zone identifier. Currently it has only meaning on link local
+     * connections and the idetifier is local node specific.
+     * XXX: This ugly hack mangles data inside struct url *u. Not thread-safe! 
*/
+    char *zone_delimiter = strchr(u->host, '%');
+    if (zone_delimiter)
+      *zone_delimiter = '\0';
+
     /* Formats arranged for hfmt[add_port][add_squares].  */
     static const char *hfmt[][2] = {
       { "%s", "[%s]" }, { "%s:%d", "[%s]:%d" }
@@ -1517,6 +1524,9 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, 
struct url *proxy)
     request_set_header (req, "Host",
                         aprintf (hfmt[add_port][add_squares], u->host, 
u->port),
                         rel_value);
+    /* Unhide zone delimiter */
+    if (zone_delimiter)
+      *zone_delimiter = '%';
   }
 
   if (!inhibit_keep_alive)
diff --git a/src/url.c b/src/url.c
index 5f61e35..de5e43e 100644
--- a/src/url.c
+++ b/src/url.c
@@ -717,7 +717,14 @@ url_parse (const char *url, int *error)
 
 #ifdef ENABLE_IPV6
       /* Check if the IPv6 address is valid. */
-      if (!is_valid_ipv6_address(host_b, host_e))
+      /* XXX: The host_b is not decoded yet. This is not perfect check for
+       * zone delimiter '%'. */
+      p = strchr(host_b, '%');
+      if (p > host_e)
+        {
+          p = NULL;
+        }
+      if (!is_valid_ipv6_address(host_b, p ? p : host_e))
         {
           error_code = PE_INVALID_IPV6_ADDRESS;
           goto error;

Attachment: pgpD9MgEqjFTN.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]