# Implementation of parsing URL to IPv6

**URL:** <https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835>\
**Category:** NGINX\
**Created:** [February 28, 2011, 12:40pm UTC](https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835 "2011-02-28T12:40:46Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![luislavena](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/0ea827/32.png) [@luislavena](https://www.ruby-forum.com/u/luislavena)\
**Post date:** [February 28, 2011, 12:40pm UTC](https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835/1 "2011-02-28T12:40:46Z")

</div>

Hey, guys. I’ve implement a parse URL to IPv6 function which is  
discussed in “[Re: Does url resolve support ipv6?](http://forum.nginx.org/read.php?2,177146,177190)”. I change  
“ngx\_parse\_url” and add an function “ngx\_parse\_host” to resolve a host  
(IP or text) to either IPv4 or IPv6 functions. And I change  
“ngx\_inet\_resolve\_host” to let it accept IPv4/IPv6. Besides I add  
another function “ngx\_inet\_sock\_addr” to parse string with format  
“ipv4:port” and “[ipv6]:port” to the addr structure. Seems I can’t  
upload the attachment so I past them here. I’ve do the unit test to  
them. Hope you can take regression test and merge them to the nginx main  
branch.

If u wish, I can also past the unit test I write. (I think send via  
email would be more convenient)

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;

#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;
    }

    if (q < last - 2 && *(q + 1) == ':') {
        port = q + 2;
    } else {
        return NGX_ERROR;
    }

    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_addr.s_addr = ngx_inet_addr (p, port - p);

    if (sin->sin_addr.s_addr == INADDR_NONE) {
        return NGX_ERROR;
    }

    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\_int\_t  
ngx\_parse\_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 sockaddr\_in \*sin;

#if (NGX\_HAVE\_INET6)  
struct sockaddr\_in6 \*sin6;  
ngx\_flag\_t ipv6 = 0;  
#endif

```
p = u->url.data;

if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
    return ngx_parse_unix_domain_url(pool, u);
}

if ((p[0] == ':' || p[0] == '/') && !u->listen) {
    u->err = "invalid host";
    return NGX_ERROR;
}

host = u->url.data;

last = host + u->url.len;

len = 0;

```

#if (NGX\_HAVE\_INET6)  
if (host[0] == ‘[’) {

```
    ipv6 = 1;

    host = u->url.data + 1;

    p = ngx_strlchr(host, last, ']');

    if (p == NULL) {
        u->err = "invalid host";
        return NGX_ERROR;
    }

    u->family = AF_INET6;

}

```

#endif

```
port = ngx_strlchr(p, last, ':');

uri = ngx_strlchr(p, last, '/');

args = ngx_strlchr(p, last, '?');

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

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

    u->uri.len = last - uri;
    u->uri.data = uri;

    last = uri;

    if (uri < port) {
        port = NULL;
    }
}

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;
    u->port_text.len = len;
    u->port_text.data = port;

    last = port - 1;

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

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

        if (n < 1 || n > 65536) {
            u->err = "invalid port";
            return NGX_ERROR;
        }

        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;

        return NGX_OK;

    } else {
        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 == 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;
u->host.data = host;

if (u->no_resolve) {
    return NGX_OK;
}

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;
}

```

#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) {
    return NGX_OK;
}

if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
    return NGX_ERROR;
}

return NGX_OK;

```

}

///////////////////////////////////////////////////////////////////////////////////////////////////////  
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)  
{  
u\_char \*p, \*host;  
size\_t len;  
in\_port\_t port;  
in\_addr\_t inaddr;  
ngx\_uint\_t i, n;  
struct addrinfo hints, \*addrinfo, \*item;  
struct sockaddr\_in \*sin;

#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);

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

if (inaddr != INADDR_NONE) {
    /* MP: ngx_shared_palloc() */

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

    sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
    if (sin == NULL) {
        return NGX_ERROR;
    }

    u->naddrs = 1;

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

    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;
    }

    u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
                                       &u->host, ntohs(port)) - p;
    u->addrs[0].name.data = p;

    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;  
}

```
    sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6));
    if (sin6 == NULL) {
        return NGX_ERROR;
    }

    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->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;
}

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;
        }

        sin->sin_family = AF_INET;
        sin->sin_port = port;
        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 *) 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;  
}  
}

```
return NGX_OK;

```

}

Posted at Nginx Forum:

> **[Implementation of parsing URL to IPv6](https://forum.nginx.org/read.php?2,179085,179085#msg-179085)**
>
> Hey, guys. I've implement a parse URL to IPv6 function which is discussed in "http://forum.nginx.org/read.php?2,177146,177190". I change "ngx\_parse\_url" and add an function "ngx\_parse\_host" to resolve a host (IP or text)...

---

<div class="post-metadata">

**Author:** ![speedfirst](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e19adc/32.png) [@speedfirst](https://www.ruby-forum.com/u/speedfirst)\
**Post date:** [February 28, 2011, 12:55pm UTC](https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835/2 "2011-02-28T12:55:49Z")

</div>

Hello!

On Mon, Feb 28, 2011 at 06:39:00AM -0500, speedfirst wrote:

> If u wish, I can also past the unit test I write. (I think send via  
> email would be more convenient)

1. Please use nginx-devel@ mailing list instead.

2. Please post diffs in unified format, not chunks of code.

Maxim D.

---

<div class="post-metadata">

**Author:** ![speedfirst](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e19adc/32.png) [@speedfirst](https://www.ruby-forum.com/u/speedfirst)\
**Post date:** [March 1, 2011, 3:45am UTC](https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835/3 "2011-03-01T03:45:37Z")

</div>

never try to use a mail list before. I try to send the diff to  
removed\_email\_address@domain.invalid through email. Is that OK? sorry this is naive.

Posted at Nginx Forum:

> **[Re: Implementation of parsing URL to IPv6](https://forum.nginx.org/read.php?2,179085,179339#msg-179339)**
>
> Hey, guys. I've implement a parse URL to IPv6 function which is discussed in "http://forum.nginx.org/read.php?2,177146,177190". I change "ngx\_parse\_url" and add an function "ngx\_parse\_host" to resolve a host (IP or text)...

---

<div class="post-metadata">

**Author:** ![speedfirst](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e19adc/32.png) [@speedfirst](https://www.ruby-forum.com/u/speedfirst)\
**Post date:** [March 1, 2011, 3:58am UTC](https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835/4 "2011-03-01T03:58:45Z")

</div>

what I mean is, in Web, nginx-devel@ is readonly. And after I send mail,  
my message doesn’t show in the list. Is it alright?

Posted at Nginx Forum:

> **[Re: Implementation of parsing URL to IPv6](https://forum.nginx.org/read.php?2,179085,179342#msg-179342)**
>
> Hey, guys. I've implement a parse URL to IPv6 function which is discussed in "http://forum.nginx.org/read.php?2,177146,177190". I change "ngx\_parse\_url" and add an function "ngx\_parse\_host" to resolve a host (IP or text)...

---

<div class="post-metadata">

**Author:** ![speedfirst](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e19adc/32.png) [@speedfirst](https://www.ruby-forum.com/u/speedfirst)\
**Post date:** [March 1, 2011, 7:04am UTC](https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835/5 "2011-03-01T07:04:59Z")

</div>

On Mon, Feb 28, 2011 at 09:44:24PM -0500, speedfirst wrote:

> never try to use a mail list before. I try to send the diff to  
> [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) through email. Is that OK? sorry this is naive.

Please send the patch in “diff -u” format.  
The default diff format is intended for aliens.

–  
Igor S.

> **[Igor Sysoev](http://sysoev.ru/en/)**

---

<div class="post-metadata">

**Author:** ![speedfirst](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e19adc/32.png) [@speedfirst](https://www.ruby-forum.com/u/speedfirst)\
**Post date:** [March 1, 2011, 7:01am UTC](https://www.ruby-forum.com/t/implementation-of-parsing-url-to-ipv6/203835/6 "2011-03-01T07:01:51Z")

</div>

On Mon, Feb 28, 2011 at 09:57:21PM -0500, speedfirst wrote:

> what I mean is, in Web, nginx-devel@ is readonly. And after I send mail,  
> my message doesn’t show in the list. Is it alright?

To write in the list you have to subscribe to.  
Now I have added your two addresses in the write only mode.

–  
Igor S.

> **[Igor Sysoev](http://sysoev.ru/en/)**
