[PATCH] parse URL to ipv6

Speed First speedfirst at gmail.com
Tue Mar 1 15:22:59 MSK 2011


Two files are affected "ngx_inet.c" and "ngx_inet.h". I remove the original
"ngx_parse_inet_url" and "ngx_parse_inet6_url" because they have many
duplicated code and "ngx_pare_inet_url" this name won't describe what it
does comprehensively (it may generate IPv6 too).

So I use "ngx_parse_url" to split the url to "host", "port", "uri" and
create a function "ngx_parse_host" to convert host to IP address. Besides, I
also change "ngx_inet_resolve_host" to make it accept IPv6.

At last I add a function "ngx_inet_sock_addr" to convert "ipv4:port" and
"[ipv6]:port" to sockaddr_in and sockaddr_in6.

The following test has been done to verify the functionality of url parse
(Here ip = ipv4 and ipv6).

1. only port   ==> only accept IPv4
2. *:port ==> same as 1
3. [::]:port ==> accept both ipv4 and ipv6 if not set ipv6only=on
4. ip:port
5. ip:port/uri
6. ip:port/uri?arg
7: ip/uri?arg
8. text:port   (text url can be resolved to 1 IPv6 addr)
9. text:port   (text url can be resolved to many addr, some are IPv4 and
some IPv6. The url->sockaddr always be the first IP address)

--------------------------------------------------------ngx_inet.c-------------------------------------------

--- nginx-0.9.3/src/core/ngx_inet.c 2009-12-07 07:13:46.000000000 -0800
+++
/home/speedfirst/p4/zimbra/main/ThirdParty/nginx/nginx-0.9-zimbra/src/core/ngx_inet.c
2011-02-28
02:17:31.187902103 -0800
@@ -9,8 +9,7 @@


 static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
-static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
-static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u);
+static ngx_int_t ngx_parse_host(ngx_pool_t *pool, ngx_url_t *u);


 in_addr_t
@@ -446,7 +445,6 @@
     }
 }

-
 ngx_int_t
 ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t
len)
 {
@@ -506,11 +504,18 @@
     return NGX_OK;
 }

-
 ngx_int_t
 ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
 {
-    u_char  *p;
+    u_char   *p, *host, *port, *last, *uri, *args;
+    size_t    len;
+    ngx_int_t n;
+    struct sockaddr_in  *sin;
+
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6 *sin6;
+    ngx_flag_t           ipv6 = 0;
+#endif

     p = u->url.data;

@@ -523,129 +528,44 @@
         return NGX_ERROR;
     }

-    if (p[0] == '[') {
-        return ngx_parse_inet6_url(pool, u);
-    }
+    host = u->url.data;

-    return ngx_parse_inet_url(pool, u);
-}
+    last = host + u->url.len;

+    len = 0;

-static ngx_int_t
-ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
-{
-#if (NGX_HAVE_UNIX_DOMAIN)
-    u_char              *path, *uri, *last;
-    size_t               len;
-    struct sockaddr_un  *saun;
-
-    len = u->url.len;
-    path = u->url.data;
+#if (NGX_HAVE_INET6)
+    if (host[0] == '[') {

-    path += 5;
-    len -= 5;
+        ipv6 = 1;

-    if (u->uri_part) {
+        host = u->url.data + 1;

-        last = path + len;
-        uri = ngx_strlchr(path, last, ':');
+        p = ngx_strlchr(host, last, ']');

-        if (uri) {
-            len = uri - path;
-            uri++;
-            u->uri.len = last - uri;
-            u->uri.data = uri;
+        if (p == NULL) {
+            u->err = "invalid host";
+            return NGX_ERROR;
         }
-    }
-
-    if (len == 0) {
-        u->err = "no path in the unix domain socket";
-        return NGX_ERROR;
-    }
-
-    u->host.len = len++;
-    u->host.data = path;
-
-    if (len > sizeof(saun->sun_path)) {
-        u->err = "too long path in the unix domain socket";
-        return NGX_ERROR;
-    }
-
-    u->socklen = sizeof(struct sockaddr_un);
-    saun = (struct sockaddr_un *) &u->sockaddr;
-    saun->sun_family = AF_UNIX;
-    (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);

-    u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
-    if (u->addrs == NULL) {
-        return NGX_ERROR;
-    }
+        u->family = AF_INET6;

-    saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
-    if (saun == NULL) {
-        return NGX_ERROR;
     }
-
-    u->family = AF_UNIX;
-    u->naddrs = 1;
-
-    saun->sun_family = AF_UNIX;
-    (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
-
-    u->addrs[0].sockaddr = (struct sockaddr *) saun;
-    u->addrs[0].socklen = sizeof(struct sockaddr_un);
-    u->addrs[0].name.len = len + 4;
-    u->addrs[0].name.data = u->url.data;
-
-    return NGX_OK;
-
-#else
-
-    u->err = "the unix domain sockets are not supported on this platform";
-
-    return NGX_ERROR;
-
 #endif
-}
-
-
-static ngx_int_t
-ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
-{
-    u_char              *p, *host, *port, *last, *uri, *args;
-    size_t               len;
-    ngx_int_t            n;
-    struct hostent      *h;
-    struct sockaddr_in  *sin;
-
-    u->socklen = sizeof(struct sockaddr_in);
-    sin = (struct sockaddr_in *) &u->sockaddr;
-    sin->sin_family = AF_INET;
-
-    u->family = AF_INET;
-
-    host = u->url.data;
-
-    last = host + u->url.len;
-
-    port = ngx_strlchr(host, last, ':');

-    uri = ngx_strlchr(host, last, '/');
+    port = ngx_strlchr(p, last, ':');

-    args = ngx_strlchr(host, last, '?');
+    uri = ngx_strlchr(p, last, '/');

-    if (args) {
-        if (uri == NULL) {
-            uri = args;
+    args = ngx_strlchr(p, last, '?');

-        } else if (args < uri) {
-            uri = args;
-        }
+    if (args && (uri == NULL || args < uri)) {
+        uri = args;
     }

     if (uri) {
         if (u->listen || !u->uri_part) {
-            u->err = "invalid host";
+            u->err = "invalid url to listen";
             return NGX_ERROR;
         }

@@ -677,54 +597,61 @@
         }

         u->port = (in_port_t) n;
-        sin->sin_port = htons((in_port_t) n);
-
         u->port_text.len = len;
         u->port_text.data = port;

         last = port - 1;

     } else {
-        if (uri == NULL) {
-
-            if (u->listen) {
-
-                /* test value as port only */
+        if (uri == NULL && u->listen) {
+            /* test value as port only */

-                n = ngx_atoi(host, last - host);
+            n = ngx_atoi(u->url.data, u->url.len);

-                if (n != NGX_ERROR) {
-
-                    if (n < 1 || n > 65536) {
-                        u->err = "invalid port";
-                        return NGX_ERROR;
-                    }
-
-                    u->port = (in_port_t) n;
-                    sin->sin_port = htons((in_port_t) n);
+            if (n < 1 || n > 65536) {
+                u->err = "invalid port";
+                return NGX_ERROR;
+            }

-                    u->port_text.len = last - host;
-                    u->port_text.data = host;
+            u->family = AF_INET;
+            u->port = (in_port_t) n;
+            sin = (struct sockaddr_in *)u->sockaddr;
+            sin->sin_family = AF_INET;
+            sin->sin_addr.s_addr = INADDR_ANY;
+            sin->sin_port = htons((in_port_t) n);
+            u->port_text.len = len;
+            u->port_text.data = port;
+            u->socklen = sizeof (struct sockaddr_in);
+            u->wildcard = 1;

-                    u->wildcard = 1;
+            return NGX_OK;

-                    return NGX_OK;
-                }
-            }
+        } else {
+            u->no_port = 1;
         }
+    }

-        u->no_port = 1;
+#if (NGX_HAVE_INET6)
+    if (ipv6) {
+        if (*(last - 1) == ']' && last > host) {
+            last--;
+        } else {
+            u->err = "invalid host";
+            return NGX_ERROR;
+        }
     }
+#endif

     len = last - host;

-    if (len == 0) {
-        u->err = "no host";
-        return NGX_ERROR;
-    }
-
     if (len == 1 && *host == '*') {
         len = 0;
+        u->family = AF_INET;
+        u->socklen = sizeof (struct sockaddr_in);
+        u->wildcard = 1;
+        sin = (struct sockaddr_in *)u->sockaddr;
+        sin->sin_family = AF_INET;
+        sin->sin_addr.s_addr = INADDR_ANY;
     }

     u->host.len = len;
@@ -734,41 +661,26 @@
         return NGX_OK;
     }

-    if (len) {
-        sin->sin_addr.s_addr = ngx_inet_addr(host, len);
-
-        if (sin->sin_addr.s_addr == INADDR_NONE) {
-            p = ngx_alloc(++len, pool->log);
-            if (p == NULL) {
-                return NGX_ERROR;
-            }
-
-            (void) ngx_cpystrn(p, host, len);
-
-            h = gethostbyname((const char *) p);
-
-            ngx_free(p);
-
-            if (h == NULL || h->h_addr_list[0] == NULL) {
-                u->err = "host not found";
-                return NGX_ERROR;
-            }
-
-            sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]);
-        }
-
-        if (sin->sin_addr.s_addr == INADDR_ANY) {
-            u->wildcard = 1;
-        }
-
-    } else {
-        sin->sin_addr.s_addr = INADDR_ANY;
-        u->wildcard = 1;
+    if(u->host.len > 0 && ngx_parse_host(pool, u) == NGX_ERROR) {
+        u->err = "invalid host";
+        return NGX_ERROR;
     }

     if (u->no_port) {
         u->port = u->default_port;
-        sin->sin_port = htons(u->default_port);
+    }
+
+#if (NGX_HAVE_INET6)
+    if (u->family == AF_INET6) {
+        sin6 = (struct sockaddr_in6 *)u->sockaddr;
+        sin6->sin6_port = htons (u->port);
+
+    }
+    else
+#endif
+    {
+        sin = (struct sockaddr_in *)u->sockaddr;
+        sin->sin_port = htons (u->port);
     }

     if (u->listen) {
@@ -784,114 +696,199 @@


 static ngx_int_t
-ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
+ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
 {
-#if (NGX_HAVE_INET6)
-    u_char               *p, *host, *port, *last, *uri;
-    size_t                len;
-    ngx_int_t             n;
-    struct sockaddr_in6  *sin6;
-
-    u->socklen = sizeof(struct sockaddr_in6);
-    sin6 = (struct sockaddr_in6 *) &u->sockaddr;
-    sin6->sin6_family = AF_INET6;
-
-    host = u->url.data + 1;
-
-    last = u->url.data + u->url.len;
-
-    p = ngx_strlchr(host, last, ']');
+#if (NGX_HAVE_UNIX_DOMAIN)
+    u_char              *path, *uri, *last;
+    size_t               len;
+    struct sockaddr_un  *saun;

-    if (p == NULL) {
-        u->err = "invalid host";
-        return NGX_ERROR;
-    }
+    len = u->url.len;
+    path = u->url.data;

-    if (last - p) {
+    path += 5;
+    len -= 5;

-        port = p + 1;
+    if (u->uri_part) {

-        uri = ngx_strlchr(port, last, '/');
+        last = path + len;
+        uri = ngx_strlchr(path, last, ':');

         if (uri) {
-            if (u->listen || !u->uri_part) {
-                u->err = "invalid host";
-                return NGX_ERROR;
-            }
-
+            len = uri - path;
+            uri++;
             u->uri.len = last - uri;
             u->uri.data = uri;
         }
+    }

-        if (*port == ':') {
-            port++;
-
-            len = last - port;
-
-            if (len == 0) {
-                u->err = "invalid port";
-                return NGX_ERROR;
-            }
-
-            n = ngx_atoi(port, len);
-
-            if (n < 1 || n > 65536) {
-                u->err = "invalid port";
-                return NGX_ERROR;
-            }
-
-            u->port = (in_port_t) n;
-            sin6->sin6_port = htons((in_port_t) n);
-
-            u->port_text.len = len;
-            u->port_text.data = port;
-
-        } else {
-            u->no_port = 1;
-        }
+    if (len == 0) {
+        u->err = "no path in the unix domain socket";
+        return NGX_ERROR;
     }

-    len = p - host;
+    u->host.len = len++;
+    u->host.data = path;

-    if (len == 0) {
-        u->err = "no host";
+    if (len > sizeof(saun->sun_path)) {
+        u->err = "too long path in the unix domain socket";
         return NGX_ERROR;
     }

-    u->host.len = len;
-    u->host.data = host;
+    u->socklen = sizeof(struct sockaddr_un);
+    saun = (struct sockaddr_un *) &u->sockaddr;
+    saun->sun_family = AF_UNIX;
+    (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);

-    if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) {
 -        u->err = "invalid IPv6 address";
+    u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+    if (u->addrs == NULL) {
         return NGX_ERROR;
     }

-    if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
-        u->wildcard = 1;
+    saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
+    if (saun == NULL) {
+        return NGX_ERROR;
     }

-    u->family = AF_INET6;
+    u->family = AF_UNIX;
+    u->naddrs = 1;

-    if (u->no_resolve) {
-        return NGX_OK;
-    }
+    saun->sun_family = AF_UNIX;
+    (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);

-    if (u->no_port) {
-        u->port = u->default_port;
-        sin6->sin6_port = htons(u->default_port);
-    }
+    u->addrs[0].sockaddr = (struct sockaddr *) saun;
+    u->addrs[0].socklen = sizeof(struct sockaddr_un);
+    u->addrs[0].name.len = len + 4;
+    u->addrs[0].name.data = u->url.data;

     return NGX_OK;

 #else

-    u->err = "the INET6 sockets are not supported on this platform";
+    u->err = "the unix domain sockets are not supported on this platform";

     return NGX_ERROR;

 #endif
 }

+static ngx_int_t
+ngx_parse_host(ngx_pool_t *pool, ngx_url_t *u) {
+    u_char                *p;
+    ngx_uint_t            family, n;
+    in_addr_t             inaddr;
+    struct sockaddr_in   *sin;
+    struct addrinfo       hints, *addrinfo;
+
+#if (NGX_HAVE_INET6)
+    struct in6_addr       inaddr6;
+    struct sockaddr_in6  *sin6;
+
+   if (u->family == AF_INET6) {
+       /* u->family has been set to AF_INET6 means the host
+        * to be parsed should be IPv6 address so no need to parse
+        * it as IPv4 or resolve host
+        */
+       ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr));
+       if (ngx_inet6_addr(u->host.data, u->host.len, inaddr6.s6_addr) ==
NGX_OK) {
+           family = AF_INET6;
+           goto done;
+       } else {
+           u->err = "invalid host";
+           return NGX_ERROR;
+       }
+   }
+#endif
+
+   inaddr = ngx_inet_addr(u->host.data, u->host.len);
+
+   if (inaddr != INADDR_NONE) {
+       family = AF_INET;
+
+#if (NGX_HAVE_INET6)
+   } else if (ngx_inet6_addr(u->host.data, u->host.len, inaddr6.s6_addr) ==
NGX_OK) {
+       family = AF_INET6;
+
+#endif
+   } else {
+       /* resolve the IP address through host name
+          only the first IP address will be used   */
+       p = ngx_alloc(u->host.len + 1, pool->log);
+       if (p == NULL) {
+          return NGX_ERROR;
+       }
+       ngx_cpystrn(p, u->host.data, u->host.len + 1);
+
+       ngx_memzero (&hints, sizeof (struct addrinfo));
+
+       if (u->listen) {
+           hints.ai_flags = AI_PASSIVE;
+       } else {
+           hints.ai_flags = AI_CANONNAME;
+       }
+
+       hints.ai_protocol = IPPROTO_TCP;
+
+       n = getaddrinfo((const char *) p,
+               NULL, &hints, &addrinfo);
+
+       ngx_free (p);
+
+       if (n != NGX_OK) {
+           u->err = "error in host resolve";
+           return NGX_ERROR;
+       }
+
+       if (addrinfo->ai_family == AF_INET) {
+           family = AF_INET;
+           inaddr = ((struct sockaddr_in *)
addrinfo->ai_addr)->sin_addr.s_addr;
+
+#if (NGX_HAVE_INET6)
+       } else if (addrinfo->ai_family == AF_INET6) {
+           family = AF_INET6;
+           inaddr6 = ((struct sockaddr_in6 *)
addrinfo->ai_addr)->sin6_addr;
+
+#endif
+       } else {
+           u->err = "unknown address family";
+           return NGX_ERROR;
+       }
+   }
+
+#if (NGX_HAVE_INET6)
+   done:
+#endif
+
+   switch (family) {
+
+#if (NGX_HAVE_INET6)
+   case AF_INET6:
+       sin6 = (struct sockaddr_in6 *) u->sockaddr;
+       sin6->sin6_family = AF_INET6;
+       u->family = AF_INET6;
+       u->socklen = sizeof (struct sockaddr_in6);
+       ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
+
+       if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+           u->wildcard = 1;
+       }
+       break;
+#endif
+
+   default: /* AF_INET */
+       sin = (struct sockaddr_in *) u->sockaddr;
+       sin->sin_family = AF_INET;
+       u->family = AF_INET;
+       u->socklen = sizeof (struct sockaddr_in);
+       sin->sin_addr.s_addr = inaddr;
+       if (sin->sin_addr.s_addr == INADDR_ANY) {
+           u->wildcard = 1;
+       }
+       break;
+   }
+
+   return NGX_OK;
+}

 ngx_int_t
 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
@@ -899,52 +896,138 @@
     u_char              *p, *host;
     size_t               len;
     in_port_t            port;
-    in_addr_t            in_addr;
-    ngx_uint_t           i;
-    struct hostent      *h;
+    in_addr_t            inaddr;
+    ngx_uint_t           i, n;
+    struct addrinfo      hints, *addrinfo, *item;
     struct sockaddr_in  *sin;

-    /* AF_INET only */
+#if (NGX_HAVE_INET6)
+    struct in6_addr      inaddr6;
+    struct sockaddr_in6 *sin6;
+
+    /*
+     * prevent MSVC8 waring:
+     *    potentially uninitialized local variable 'inaddr6' used
+     */
+    ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr));
+#endif

     port = htons(u->port);

-    in_addr = ngx_inet_addr(u->host.data, u->host.len);
+    inaddr = ngx_inet_addr(u->host.data, u->host.len);

-    if (in_addr == INADDR_NONE) {
-        host = ngx_alloc(u->host.len + 1, pool->log);
-        if (host == NULL) {
+    if (inaddr != INADDR_NONE) {
+        /* MP: ngx_shared_palloc() */
+
+        u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+        if (u->addrs == NULL) {
             return NGX_ERROR;
         }

-        (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
+        sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
+        if (sin == NULL) {
+            return NGX_ERROR;
+        }

-        h = gethostbyname((char *) host);
+        u->naddrs = 1;

-        ngx_free(host);
+        sin->sin_family = AF_INET;
+        sin->sin_port = port;
+        sin->sin_addr.s_addr = inaddr;

-        if (h == NULL || h->h_addr_list[0] == NULL) {
-            u->err = "host not found";
+        u->addrs[0].sockaddr = (struct sockaddr *) sin;
+        u->addrs[0].socklen = sizeof(struct sockaddr_in);
+
+        p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
+        if (p == NULL) {
             return NGX_ERROR;
         }

-        if (u->one_addr == 0) {
-            for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
+        u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
+                                           &u->host, ntohs(port)) - p;
+        u->addrs[0].name.data = p;

-        } else {
-            i = 1;
+        return NGX_OK;
+    }
+
+#if (NGX_HAVE_INET6)
+    if(ngx_inet6_addr(u->host.data, u->host.len, inaddr6.s6_addr) ==
NGX_OK) {
+        u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+        if (u->addrs == NULL) {
+            return NGX_ERROR;
         }

-        /* MP: ngx_shared_palloc() */
+        sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6));
+        if (sin6 == NULL) {
+            return NGX_ERROR;
+        }

-        u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
-        if (u->addrs == NULL) {
+        u->naddrs = 1;
+
+        sin6->sin6_family = AF_INET6;
+        sin6->sin6_port = port;
+        ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
+        u->addrs[0].sockaddr = (struct sockaddr *) sin6;
+        u->addrs[0].socklen = sizeof(struct sockaddr_in6);
+
+        p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
+        if (p == NULL) {
             return NGX_ERROR;
         }

-        u->naddrs = i;
+        u->addrs[0].name.len = ngx_sprintf(p, "[%V]:%d",
+                                           &u->host, ntohs(port)) - p;
+        u->addrs[0].name.data = p;
+
+        return NGX_OK;
+    }
+#endif
+
+    /* resolve all the IP address for this host */
+    host = ngx_alloc(u->host.len + 1, pool->log);
+    if (host == NULL) {
+        return NGX_ERROR;
+    }
+    ngx_cpystrn(host, u->host.data, u->host.len + 1);
+
+    ngx_memzero (&hints, sizeof (struct addrinfo));
+
+    /* if the address is for listen, it won't enter this reslove function
*/
+    hints.ai_flags = AI_CANONNAME;
+    hints.ai_protocol = IPPROTO_TCP;
+
+    n = getaddrinfo((const char *) host,
+          NULL, &hints, &addrinfo);
+
+    ngx_free (host);
+
+    if (n != NGX_OK) {
+      u->err = "error in host resolve";
+      return NGX_ERROR;
+    }

-        for (i = 0; h->h_addr_list[i] != NULL; i++) {
+    i = 0;

+    if (u->one_addr == 0) {
+        item = addrinfo;
+        for (i = 0; item != NULL; i++, item = item->ai_next) { /* void */ }
+
+    } else {
+        i = 1;
+    }
+
+    /* MP: ngx_shared_palloc() */
+
+    u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
+    if (u->addrs == NULL) {
+        return NGX_ERROR;
+    }
+
+    u->naddrs = i;
+
+    for (i = 0; i < u->naddrs; i++, addrinfo = addrinfo->ai_next) {
+
+        if (addrinfo->ai_family == AF_INET) {
             sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
             if (sin == NULL) {
                 return NGX_ERROR;
@@ -952,55 +1035,140 @@

             sin->sin_family = AF_INET;
             sin->sin_port = port;
-            sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
-
+            inaddr = ((struct sockaddr_in *)
addrinfo->ai_addr)->sin_addr.s_addr;
+            sin->sin_addr.s_addr = inaddr;
             u->addrs[i].sockaddr = (struct sockaddr *) sin;
             u->addrs[i].socklen = sizeof(struct sockaddr_in);

             len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
+            p = ngx_pnalloc(pool, len);
+            if (p == NULL) {
+                return NGX_ERROR;
+            }
+
+            len = ngx_sock_ntop((struct sockaddr *) sin, p, len,
sin->sin_port);
+
+            u->addrs[i].name.len = len;
+            u->addrs[i].name.data = p;

+#if (NGX_HAVE_INET6)
+        } else if (addrinfo->ai_family == AF_INET6) {
+            sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6));
+            if (sin6 == NULL) {
+                return NGX_ERROR;
+            }
+
+            sin6->sin6_family = AF_INET6;
+            sin6->sin6_port = port;
+            inaddr6 = ((struct sockaddr_in6 *)
addrinfo->ai_addr)->sin6_addr;
+            ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
+            u->addrs[i].sockaddr = (struct sockaddr *) sin6;
+            u->addrs[i].socklen = sizeof(struct sockaddr_in6);
+
+            len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1;
             p = ngx_pnalloc(pool, len);
             if (p == NULL) {
                 return NGX_ERROR;
             }

-            len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
+            len = ngx_sock_ntop((struct sockaddr *) sin6, p, len,
sin6->sin6_port);

             u->addrs[i].name.len = len;
             u->addrs[i].name.data = p;
+#endif
+        } else {
+            u->err = "unknown address family";
+            return NGX_ERROR;
         }
+    }

-    } else {
+    return NGX_OK;
+}

-        /* MP: ngx_shared_palloc() */
+ngx_int_t
+ngx_inet_sock_addr (u_char * p, size_t len, struct sockaddr * sockaddr)
+{
+    u_char               *port, *last;
+    ngx_int_t             n;
+    struct sockaddr_in   *sin;

-        u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
-        if (u->addrs == NULL) {
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6  *sin6;
+    u_char               *q;
+#endif
+
+    if (len == 0) {
+        return NGX_ERROR;
+    }
+
+    last = p + len;
+
+    port = NULL;
+
+#if (NGX_HAVE_INET6)
+
+    if (*p == '[') {
+
+        p++;
+
+        q = ngx_strlchr(p, last, ']');
+
+        if (q == NULL) {
             return NGX_ERROR;
         }

-        sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
-        if (sin == NULL) {
+        if (q < last - 2 && *(q + 1) == ':') {
 +            port = q + 2;
+        } else {
             return NGX_ERROR;
         }

-        u->naddrs = 1;
+        sin6 = (struct sockaddr_in6 *)sockaddr;
+
+        sin6->sin6_family = AF_INET6;
+
+        if (ngx_inet6_addr(p, q - p, sin6->sin6_addr.s6_addr) == NGX_ERROR)
{
+            return NGX_ERROR;
+        }
+
+        n = ngx_atoi(port, last - port);
+
+        if (n == NGX_ERROR || n < 1 || n > 65535) {
+            return NGX_ERROR;
+        }
+
+        sin6->sin6_port = htons(n);
+
+    }
+    else
+#endif
+    {
+        port = ngx_strlchr(p, last, ':');
+
+        if (port == NULL) {
+            return NGX_ERROR;
+        }
+
+        sin = (struct sockaddr_in *)sockaddr;

         sin->sin_family = AF_INET;
-        sin->sin_port = port;
-        sin->sin_addr.s_addr = in_addr;

-        u->addrs[0].sockaddr = (struct sockaddr *) sin;
-        u->addrs[0].socklen = sizeof(struct sockaddr_in);
+        sin->sin_addr.s_addr = ngx_inet_addr (p, port - p);

-        p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
-        if (p == NULL) {
+        if (sin->sin_addr.s_addr == INADDR_NONE) {
             return NGX_ERROR;
         }

-        u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
-                                           &u->host, ntohs(port)) - p;
-        u->addrs[0].name.data = p;
+        port++;
+
+        n = ngx_atoi(port, last - port);
+
+        if (n == NGX_ERROR || n < 1 || n > 65535) {
+            return NGX_ERROR;
+        }
+
+        sin->sin_port = htons(n);
+
     }

     return NGX_OK;
--------------------------------------------------------ngx_inet.h-------------------------------------------

--- nginx-0.9.3/src/core/ngx_inet.h 2009-11-03 04:44:55.000000000 -0800
+++
/home/speedfirst/p4/zimbra/main/ThirdParty/nginx/nginx-0.9-zimbra/src/core/ngx_inet.h
2011-02-25
01:45:37.133302528 -0800
@@ -108,6 +108,8 @@
 #endif
 size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len,
     ngx_uint_t port);
+ngx_int_t ngx_inet_sock_addr (u_char * p, size_t len,
+    struct sockaddr * sockaddr);
 size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
 ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr);
 ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://nginx.org/pipermail/nginx-devel/attachments/20110301/81715d80/attachment-0001.html>


More information about the nginx-devel mailing list