TuxInvader / nginx-dns

Sample Configuration for DNS over HTTPS (DoH/DoT gateway) and GSLB with NGINX
BSD 2-Clause "Simplified" License
199 stars 48 forks source link

504 - Gateway Time-out #25

Open thepasto opened 1 year ago

thepasto commented 1 year ago

Hello, i'm trying to use your example, nginx-doh-and-dot-to-dns.conf to fit my server configuration. I'm using pihole as dns, so 127.0.0.1:53 is my pihole istance.

Curl test after a while, returns 504 curl --http2 -H 'accept: application/dns-json' 'https://***.***.**/dns-query?name=google.com'

My configuration:

  # DNS logging
  log_format  dns   '$remote_addr [$time_local] $protocol "$dns_qname"';
  access_log /var/log/nginx/dns-access.log dns;

  # Import the NJS module
  js_import /etc/nginx/njs.d/dns/dns.js;

  # The $dns_qname variable can be populated by preread calls, and can be used for DNS routing
  js_set $dns_qname dns.get_qname;

  # DNS upstream pool.
  upstream dns {
    zone dns 64k;
    server 127.0.0.1:53;
  }

  # DNS(TCP) and DNS over TLS (DoT) Server
  # Terminate DoT and DNS TCP, and proxy onto standard DNS
  server {
    #listen 53;
    listen 853 ssl;
    ssl_certificate /etc/letsencrypt/live/***.***.**/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/***.***.**/privkey.pem;
    js_preread dns.preread_dns_request;
    proxy_pass dns;
  }

  # DNS(UDP) Server
  # DNS UDP proxy onto DNS UDP
  #server {
  #  listen 53 udp;
  #  proxy_responses 1;
  #  js_preread dns.preread_dns_request;
  #  proxy_pass dns;
  #}

  # DNS over HTTPS (gateway) Service
  # Upstream can be either DNS(TCP) or DoT. If upstream is DNS, proxy_ssl should be off.
  server {
    listen 127.0.0.1:8053;
    js_filter dns.filter_doh_request;
    proxy_pass dns;
  }
# logging directives
log_format  doh   '$remote_addr - $remote_user [$time_local] "$request" '
                  '[ $msec, $request_time, $upstream_response_time $pipe ] '
                  '$status $body_bytes_sent "$http_x_forwarded_for" '
                  '$upstream_http_x_dns_question $upstream_http_x_dns_type '
                  '$upstream_http_x_dns_result '
                  '$upstream_http_x_dns_ttl $upstream_http_x_dns_answers '
                  '$upstream_cache_status';

access_log  /var/log/nginx/doh-access.log doh;
error_log   /var/log/nginx/doh-error.log;

# This upstream connects to a local Stream service which converts HTTP -> DNS
upstream dohloop {
  zone dohloop 64k;
  server 127.0.0.1:8053;
  keepalive_timeout 60s;
  keepalive_requests 100;
  keepalive 10;
}

# Proxy Cache storage - so we can cache the DoH response from the upstream
proxy_cache_path /var/cache/nginx/doh_cache levels=1:2 keys_zone=doh_cache:10m;

# The DoH server block
server {
  # Listen on standard HTTPS port, and accept HTTP2, with SSL termination
  server_name ***.***.** www.***.***.**;
  listen 443 ssl;
  listen  [::]:443 ssl;
  http2 on;
  ssl_certificate /etc/letsencrypt/live/***.***.**/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/***.***.**/privkey.pem;
  ssl_session_cache shared:ssl_cache:10m;
  ssl_session_timeout 10m;

  # DoH may use GET or POST requests, Cache both
  proxy_cache_methods GET POST;

  # Return 404 to all responses, except for those using our published DoH URI
  location / {
    return 404 "404 Not Found\n";
  }

  # This is our published DoH URI
  location /dns-query {

    # Proxy HTTP/1.1, clear the connection header to enable Keep-Alive
    proxy_http_version 1.1;
    proxy_set_header Connection "";

    # Enable Cache, and set the cache_key to include the request_body
    #proxy_cache doh_cache;
    #proxy_cache_key $scheme$proxy_host$uri$is_args$args$request_body;

    # proxy pass to the dohloop upstream
    proxy_pass http://dohloop;
  }
}

In the dns log file i can see qname is empty:

127.0.0.1 [12/Sep/2023:14:50:44 +0200] TCP ""
127.0.0.1 [12/Sep/2023:14:51:52 +0200] TCP ""
127.0.0.1 [12/Sep/2023:14:53:59 +0200] TCP ""

What am i doing wrong?

If you need more, just ask, thank you

TuxInvader commented 1 year ago

Hi @thepasto,

This code implements the DoH protocol as specified in RFC8484. The dns-query endpoint expects to be receive a GET requests with a dns parameter containing a base64url encoded DNS packet, or a POST with a raw DNS packet. It currently does not support being sent a name parameter with a string.

However, you're not the first to ask about name lookups so it might be something I can add. Can you point me to the reference docs that describe the protocol that you are attempting to use please? Is it this JSON-over-DoH protocol: https://developers.google.com/speed/public-dns/docs/doh/json ?

thepasto commented 1 year ago

Hi @TuxInvader, thanks for your reply, I solved the problem i had using v2 of your repository. Of course using the format you mentioned above, i found an explanation here,

As for my request, the protocol could be described here.

But it looks like the same thing you linked even if from a different source. Thank you for your interest and your work!