Opened 3 years ago
Closed 3 years ago
#2259 closed defect (invalid)
Variables in proxy_pass url lead to unresovable host if host is only defined in /etc/hosts
Reported by: | func0der | Owned by: | |
---|---|---|---|
Priority: | major | Milestone: | nginx-1.21 |
Component: | nginx-module | Version: | |
Keywords: | ngx_http_proxy_module | Cc: | |
uname -a: | Linux nginx-host 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 GNU/Linux | ||
nginx -V: |
nginx version: nginx/1.21.3
built with OpenSSL 1.1.1d 10 Sep 2019 TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-1.21.3=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module |
Description
Setup:
Have a /etc/hosts
files on your nginx machine:
127.0.0.1 nginx-host 127.0.0.1 nginx-proxy-hostname # just as an example, the real mirror would be on another server
Now create an nginx server /etc/nginx/sites-enabled/default
config like the following
server { server_name nginx-host; location / { proxy_pass http://nginx-proxy-hostname/dummy$is_args$args; proxy_read_timeout 90s; proxy_connect_timeout 90s; proxy_send_timeout 90s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Proxy ""; } location /dummy { return 200 OK; } }
No we do a request towards: http://nginx-host/?cmd=dosomething&another=parameter&foo=bar
curl 'http://nginx-host/?cmd=dosomething&another=parameter&foo=bar'
Now there is an error message in the error.log:
2021/10/18 15:45:23 [error] 31052#31052: *1 no resolver defined to resolve nginx-proxy-hostname, client: 127.0.0.1, server: nginx-host, request: "GET /?cmd=dosomething&another=parameter&foo=bar HTTP/1.1", host: "nginx-host"
Nginx is not able to resolve nginx-proxy-hostname
.
If we remove the variables from proxy_pass
in the directive of /
, it works without a problem.
location / { proxy_pass http://nginx-proxy-hostname/dummy; #....
The hostname is resolved, the request reaches the correct server.
This behavior leaves two possible scenarios in the context of mirror requests:
- The resolver is not involved everytime a hostname has to be resolved in
proxy_pass
. It gets involved as soon as we use variables in theproxy_pass
string. This is supported by the fact, that a resolver can be added in the nginx config, the variables are still removed fromproxy_pass
and everything is working fine.
- There is a bug in the resolve process of
proxy_pass
as soon as variables are involved.
Either way, this behavior is inconsistent.
Personally I would rather have nginx consider the entries in /etc/hosts
all the time, so one does not have the hassle to setup a dns resolver.
If that is the solution to this specific problem: Idk
Change History (2)
comment:1 by , 3 years ago
comment:2 by , 3 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
Indeed, this behaviour is as intended and explicitly documented.
Just in case it is not clear, the root cause is as follows. System resolver interface, getaddrinfo()
(or gethostname()
on systems without IPv6 support), is blocking. Since nginx is event-based server, it cannot afford blocking at runtime. So it can only use getaddrinfo()
while parsing the configuration, but not at runtime / while processing requests. On the other hand, variables in the proxy_pass
directive imply that nginx has to somehow resolves names at runtime. To be able to resolve names at runtime nginx implements a simple DNS client, configured with the resolver
directive, which is able to resolve names without blocking. This DNS client is not identical to the system resolver, and does not check non-DNS name resolution interfaces, such as local files.
Seems like this is intended behavior and I did just overread the part in the documentation:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
My bad, sorry. This can probably be closed then.