# HG changeset patch # User Ruslan Ermilov # Date 1355746133 0 # Node ID eaf95350d75c3c5a4b5af23074f9d3fe0b698fa4 # Parent ed2219d58518dd47faded31af73e0ffd7e6e83f6 Implemented IPv6 support for URLs specified using domain names. This includes "debug_connection", upstreams, "proxy_pass", etc. (ticket #92) To preserve compatibility, "listen" specified with a domain name selects the first IPv4 address, if available. If not available, the first IPv6 address will be used (ticket #186). diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -778,3 +778,17 @@ ngx_feature_test="struct stat sb; openat(AT_FDCWD, \".\", O_RDONLY|O_NOFOLLOW); fstatat(AT_FDCWD, \".\", &sb, AT_SYMLINK_NOFOLLOW);" . auto/feature + + +ngx_feature="getaddrinfo()" +ngx_feature_name="NGX_HAVE_GETADDRINFO" +ngx_feature_run=no +ngx_feature_incs="#include + #include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test='struct addrinfo *res; + if (getaddrinfo("localhost", NULL, NULL, &res) != 0) return 1; + freeaddrinfo(res)' +. auto/feature diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -611,11 +611,13 @@ ngx_parse_unix_domain_url(ngx_pool_t *po 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_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; +#endif u->socklen = sizeof(struct sockaddr_in); sin = (struct sockaddr_in *) &u->sockaddr; @@ -728,41 +730,79 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx return NGX_OK; } - if (u->no_resolve) { - return NGX_OK; - } - 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 (sin->sin_addr.s_addr != INADDR_NONE) { + + if (sin->sin_addr.s_addr == INADDR_ANY) { + u->wildcard = 1; + } + + u->naddrs = 1; + + 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; + } + + ngx_memcpy(sin, u->sockaddr, sizeof(struct sockaddr_in)); + + 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; } - (void) ngx_cpystrn(p, host, len); - - h = gethostbyname((const char *) p); - - ngx_free(p); + u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", + &u->host, u->port) - p; + u->addrs[0].name.data = 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]); + return NGX_OK; } - if (sin->sin_addr.s_addr == INADDR_ANY) { - u->wildcard = 1; - } - - if (u->listen) { + if (u->no_resolve) { return NGX_OK; } - return ngx_inet_resolve_host(pool, u); + if (ngx_inet_resolve_host(pool, u) != NGX_OK) { + return NGX_ERROR; + } + + u->family = u->addrs[0].sockaddr->sa_family; + u->socklen = u->addrs[0].socklen; + ngx_memcpy(u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); + + switch (u->family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) &u->sockaddr; + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + u->wildcard = 1; + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) &u->sockaddr; + + if (sin->sin_addr.s_addr == INADDR_ANY) { + u->wildcard = 1; + } + + break; + } + + return NGX_OK; } @@ -894,6 +934,150 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng } +#if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6) + +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; + ngx_uint_t i; + struct addrinfo hints, *res, *rp; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + port = htons(u->port); + + host = ngx_alloc(u->host.len + 1, pool->log); + if (host == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + + ngx_memzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) { + u->err = "host not found"; + ngx_free(host); + return NGX_ERROR; + } + + ngx_free(host); + + for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) { + + switch (rp->ai_family) { + + case AF_INET: + case AF_INET6: + break; + + default: + continue; + } + + i++; + } + + if (i == 0) { + u->err = "host not found"; + goto failed; + } + + /* MP: ngx_shared_palloc() */ + + u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + goto failed; + } + + u->naddrs = i; + + i = 0; + + /* AF_INET addresses first */ + + for (rp = res; rp != NULL; rp = rp->ai_next) { + + if (rp->ai_family != AF_INET) { + continue; + } + + sin = ngx_pcalloc(pool, rp->ai_addrlen); + if (sin == NULL) { + goto failed; + } + + ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen); + + sin->sin_port = port; + + u->addrs[i].sockaddr = (struct sockaddr *) sin; + u->addrs[i].socklen = rp->ai_addrlen; + + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + goto failed; + } + + len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); + + u->addrs[i].name.len = len; + u->addrs[i].name.data = p; + + i++; + } + + for (rp = res; rp != NULL; rp = rp->ai_next) { + + if (rp->ai_family != AF_INET6) { + continue; + } + + sin6 = ngx_pcalloc(pool, rp->ai_addrlen); + if (sin6 == NULL) { + goto failed; + } + + ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen); + + sin6->sin6_port = port; + + u->addrs[i].sockaddr = (struct sockaddr *) sin6; + u->addrs[i].socklen = rp->ai_addrlen; + + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + goto failed; + } + + len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1); + + u->addrs[i].name.len = len; + u->addrs[i].name.data = p; + + i++; + } + + freeaddrinfo(res); + return NGX_OK; + +failed: + + freeaddrinfo(res); + return NGX_ERROR; +} + +#else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */ + ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { @@ -928,12 +1112,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, return NGX_ERROR; } - if (u->one_addr == 0) { - for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } - - } else { - i = 1; - } + for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } /* MP: ngx_shared_palloc() */ @@ -1006,3 +1185,5 @@ ngx_inet_resolve_host(ngx_pool_t *pool, return NGX_OK; } + +#endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */ diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -87,7 +87,7 @@ typedef struct { unsigned listen:1; unsigned uri_part:1; unsigned no_resolve:1; - unsigned one_addr:1; + unsigned one_addr:1; /* compatibility */ unsigned no_port:1; unsigned wildcard:1; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1388,7 +1388,6 @@ ngx_mail_auth_http(ngx_conf_t *cf, ngx_c u.url = value[1]; u.default_port = 80; u.uri_part = 1; - u.one_addr = 1; if (ngx_strncmp(u.url.data, "http://", 7) == 0) { u.url.len -= 7; diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -182,6 +182,7 @@ typedef int sig_atomic_t #define NGX_HAVE_SO_SNDLOWAT 0 #endif +#define NGX_HAVE_GETADDRINFO 1 #define ngx_random rand #define ngx_debug_init()