Mercurial > hg > nginx
changeset 4623:ed3d0cc6de5a
New function ngx_http_get_forwarded_addr() to look up real client address.
On input it takes an original address, string in the X-Forwarded-For format
and its length, list of trusted proxies, and a flag indicating to perform
the recursive search. On output it returns NGX_OK and the "deepest" valid
address in a chain, or NGX_DECLINED. It supports AF_INET and AF_INET6.
Additionally, original address and/or proxy may be specified as AF_UNIX.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Mon, 14 May 2012 12:27:41 +0000 |
parents | 0dfdc3f732cb |
children | df93068953c0 |
files | src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h |
diffstat | 2 files changed, 99 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/http/ngx_http_core_module.c Mon May 14 09:58:07 2012 +0000 +++ b/src/http/ngx_http_core_module.c Mon May 14 12:27:41 2012 +0000 @@ -2699,6 +2699,102 @@ } +ngx_int_t +ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, + u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive) +{ + u_char *p; + in_addr_t *inaddr; + ngx_addr_t paddr; + ngx_cidr_t *cidr; + ngx_uint_t family, i; +#if (NGX_HAVE_INET6) + ngx_uint_t n; + struct in6_addr *inaddr6; +#endif + + family = addr->sockaddr->sa_family; + + if (family == AF_INET) { + inaddr = &((struct sockaddr_in *) addr->sockaddr)->sin_addr.s_addr; + } + +#if (NGX_HAVE_INET6) + else if (family == AF_INET6) { + inaddr6 = &((struct sockaddr_in6 *) addr->sockaddr)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + family = AF_INET; + inaddr = (in_addr_t *) &inaddr6->s6_addr[12]; + } + } +#endif + + for (cidr = proxies->elts, i = 0; i < proxies->nelts; i++) { + if (cidr[i].family != family) { + goto next; + } + + switch (family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + for (n = 0; n < 16; n++) { + if ((inaddr6->s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n]) + != cidr[i].u.in6.addr.s6_addr[n]) + { + goto next; + } + } + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + break; +#endif + + default: /* AF_INET */ + if ((*inaddr & cidr[i].u.in.mask) != cidr[i].u.in.addr) { + goto next; + } + break; + } + + for (p = xff + xfflen - 1; p > xff; p--, xfflen--) { + if (*p != ' ' && *p != ',') { + break; + } + } + + for ( /* void */ ; p > xff; p--) { + if (*p == ' ' || *p == ',') { + p++; + break; + } + } + + if (ngx_parse_addr(r->pool, &paddr, p, xfflen - (p - xff)) != NGX_OK) { + return NGX_DECLINED; + } + + *addr = paddr; + + if (recursive && p > xff) { + (void) ngx_http_get_forwarded_addr(r, addr, xff, p - 1 - xff, + proxies, 1); + } + + return NGX_OK; + + next: + continue; + } + + return NGX_DECLINED; +} + + static char * ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) {
--- a/src/http/ngx_http_core_module.h Mon May 14 09:58:07 2012 +0000 +++ b/src/http/ngx_http_core_module.h Mon May 14 12:27:41 2012 +0000 @@ -513,6 +513,9 @@ ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of); +ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, + u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive); + extern ngx_module_t ngx_http_core_module;