TuxInvader / nginx-dns

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

Doh Request Passing Nothing To Upstream Server #12

Open nrnavid opened 2 years ago

nrnavid commented 2 years ago

doh_filter_request function is not working correctly when i pass a dns query over https. it makes the dns_query data to an empty string and passes it to dns upstream server.

TuxInvader commented 2 years ago

Hi @nrnavid - can you share your configuration please?

nrnavid commented 2 years ago

here is my nginx configuration `user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; load_module /etc/nginx/modules/ngx_stream_js_module.so;

events { worker_connections 768;

multi_accept on;

}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

##
# Logging Settings
##

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

##
# Gzip Settings
##

gzip on;

# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

upstream dohloop {
      zone dohloop 64k;
      server 127.0.0.1:8053;

}
##
# Virtual Host Configs
##

server {
      listen *:443 ssl http2;
      #root /var/www/nginx;
      server_name my.dnsserver.com;

      ssl_certificate /etc/nginx/ssl/cert.pem;
      ssl_certificate_key /etc/nginx/ssl/key.pem;
      #ssl_protocols TLSv1.2 TLSv1.3;
      #ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384";
      #ssl_prefer_server_ciphers on;
      #ssl_session_cache shared:ssl_cache:10m;
      #ssl_session_timeout 10m;

      #gzip on;
      #gzip_disable "msie6";
      #gzip_proxied any;
      #gzip_vary on;
      #gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript text/js application/javascript;
      #gzip_static on;

      location / {
            return 404 "Hello this is navid RJ\n";
      }

      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;
      }
   }

#include /etc/nginx/conf.d/*.conf;
#include /etc/nginx/sites-enabled/*;

}

stream {

DNS logging

log_format dns '$remote_addr [$time_local] $protocol "$dns_qname"';

access_log /var/log/nginx/dns-access.log dns;

Include the NJS module

js_include /etc/nginx/njs.d/nginx_stream.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; #My Pi Hole
#}
upstream dns {
    zone dns 64k;
    server 8.8.8.8:53;
}
upstream dot {
    zone dot 64k;
    server 127.0.0.1:853;
}

# DoT server for decryption
server {
    listen 127.0.0.1:8053;
    js_filter doh_filter_request;
    #js_preread dns_preread_doh_request;
    #return 200;
    proxy_ssl on;
    proxy_pass dot;
}
# DNS(TCP) and DNS over TLS (DoT) Server
# Terminates DNS and DoT, then proxies on to standard DNS.
server {
   listen 853 ssl;
   ssl_certificate /etc/nginx/ssl/cert.pem;
   ssl_certificate_key /etc/nginx/ssl/key.pem;
   js_preread dns_preread_dns_request;
   proxy_pass dns;
}

}`

by the way i undrestood that your code is looking for dns= in query string sp it was always returning empty string to dns proxy here was my dns query using curl curl --http2 -H 'accept: application/dns-json' https://my.dnsserver.com/dns-query?name=cloudflare.com so i changed your part of code that was looking for dns= to name= so this time it found the data and it converted this query string to base64 and then your code again decode it to hex but the name field and some parts dont have data they are empty strings so its not converting correctly.

logicReasoner commented 2 years ago

@nrnavid I seem to encounter the same issue as yours, where the upstream DNS server (either 1.1.1.1 or 8.8.8.8) immediately closes the connection (likely due to a corrupt request) and if I point it to a dnsmasq instance running on another computer in the same LAN, I get a timeout which is even weirder. It's really hard to debug the JS libs due to logging not working at all from NJS for some reason. I am on debian bullseye Please let me know if you manage to fix the issue.

TuxInvader commented 2 years ago

Hi @nrnavid

Apologies, but the example you were using was out of date. I must have missed it when I updated the other examples. The function call you are using doesn't exist, the line

js_filter doh_filter_request;

should be

js_filter dns_filter_doh_request;

Fixed in: 58386f205a0feee131ee6bb21fb16fa0e7507add

As a side note, you don't need to pass through the DOH -> 127.0.0.1:DOT -> 8.8.8.8:DNS, you can take out the loopback through DoT section. And just use:

server {
    listen 127.0.0.1:8053;
    js_filter dns_filter_doh_request;
    proxy_pass dns;
}