Welcome! Log In Create A New Profile

Advanced

Implementation of parsing URL to IPv6

February 28, 2011 06:39AM
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) 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;
}
Subject Author Posted

Implementation of parsing URL to IPv6

speedfirst February 28, 2011 06:39AM

Re: Implementation of parsing URL to IPv6

Maxim Dounin February 28, 2011 06:58AM

Re: Implementation of parsing URL to IPv6

speedfirst February 28, 2011 09:44PM

Re: Implementation of parsing URL to IPv6

speedfirst February 28, 2011 09:57PM

Re: Implementation of parsing URL to IPv6

Igor Sysoev March 01, 2011 01:04AM

Re: Implementation of parsing URL to IPv6

Igor Sysoev March 01, 2011 01:06AM



Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 273
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready