Total Pageviews

Monday 1 July 2019

DNSoverHTTP (包括服务器端和客户端)

a source code for DNS over HTTP implementation.

Introduction

This is proxy_dns, a way to tunnel DNS inside HTTP. It provides two things:
  1. a FastCGI endpoint that sits between a web server (we use nginx, but Apache would also work) and a DNS server (we use BIND, but Unbound would also work.)
  2. a DNS proxy server that is the target of an /etc/resolv.conf (on UNIX) or DHCP "name server" declaration; it resolves DNS by using upstream HTTP.
The great advantage to this approach is that HTTP usually makes it through even the worst coffee shop or hotel room firewalls, since commerce may be at stake. We also benefit from HTTP's persistent TCP connection pool concept, which DNS on TCP/53 does not have. Lastly, HTTPS will work, giving nominal privacy.
This software is as yet unpackaged, but is portable to FreeBSD 10 and Debian 7 and very probably other BSD-similar and Linux-similar systems. This software is written entirely in C and has been compiled with GCC and Clang with "full warnings" enabled.

Construction

More or less, do this:
(cd proxy_dns_gw; make)
(cd proxy_dns_fcgi; make)
It is possible that the Makefile will need tweaking, since -lresolv is required on Linux but is both not required and will not work on BSD due to differences in their "libc" implementations.

Server Installation

The proxy_dns_fcgi service currently just follows /etc/resolv.conf, so you will need a working name server configuration on your web server. The server should be reachable by UDP and TCP, and you should have a clear ICMP path to it, as well as full MTU (1500 octets or larger) and the ability to receive fragmented UDP (to make EDNS0 usable.)
  1. place the proxy_dns_fcgi executable somewhere that nginx can reach it.
  2. start this executable and look for a /tmp/proxy_dns_fcgi.sock file.
  3. edit nginx.conf to contain something equivilent to the following:
     location /proxy_dns {
             root /;
             fastcgi_pass unix:/tmp/proxy_dns_fcgi.sock;
             include fastcgi_params;
     }
    
    or, edit httpd.conf to contain something equivilent to the following:
     Listen 24.104.150.237:80
     Listen [2001:559:8000::B]:80
    
     LoadModule proxy_module libexec/apache24/mod_proxy.so
     LoadModule proxy_fcgi_module libexec/apache24/mod_proxy_fcgi.so
    
     
       ServerName proxy-dns.tisf.net
       ProxyPass /proxy_dns \
                 unix:/tmp/proxy_dns_fcgi.sock|fcgi://localhost/ \
                 enablereuse=on
     
    
  4. reload the configuration of, or restart, your nginx server.
  5. test the integration by visiting the /proxy_dns page with a browser.

Client Installation

The proxy_dns_gw service must be told what IP address to listen on for DNS (noting, it will open both a UDP and a TCP listener on that address), so if you want it to listen on both ::1 and 127.0.0.1, you will have to start two listeners, by giving proxy_dns_gw two arguments "-l ::1" and "-l 127.0.0.1".
It must also be told where to connect for its DNS proxy service. If your FastCGI service (see previous section) is running on a web server proxy-dns.vix.su, then you will have to specify "-s http://proxy-dns.vix.su" (or "-s https://proxy-dns.vix.su" if you are using TLS to protect your HTTP.)
  1. place the proxy_dns_gw executable somewhere that will survive a reboot.
  2. start this executable at least once with appropriate "-s" and "-l" options.
  3. use "netstat -an" to determine whether it has opened listener sockets.

Testing

Make sure you have a working "dig" command. If you started your client side dns_proxy service on 127.0.0.1, then you should be able to say:
dig @127.0.0.1 www.vix.su aaaa
and get a result back. You can watch this simultaneously on the server side dns_proxy by running a command similar to this:
tail -f /var/log/nginx-access.log

Protocol

The protocol used by the dns_proxy service is alarmingly simple. There's no JSON or XML encoding; the DNS query and response are sent as raw binary via the "libcurl" library on the client side and the "libfcgi" library on the server side. The URI is always "/proxy_dns", which means, it contains no parameters. The result is always marked non-cacheable. The request is always POST. If you send the fcgi server a GET, it will return a human-readable page showing its web server environment. There is one new HTTP header:
Proxy-DNS-Transport: xyz
where xyz is either UDP or TCP, which is the client's indication of how it received the underlying DNS query, and which the server will use when sending the query to the far-end DNS server. This means if a stub DNS client asks for TCP, then that's what the far-end DNS server will see, and likewise for UDP.
The proxy service does not interpret the DNS query or response in any way. It could be DNS, EDNS, or something not yet invented at the time of this writing. The only requirement is that each request message solicits exactly one response message. If anything at all goes wrong with the proxy service, the stub client will hear a DNS SERVFAIL response.

To Do List

This software was written in C in order to be small, self contained, and portable to Windows and Mac/OS some day. The protocol was designed to be very simple in order that higher-performing implementations could be written for high availability production servers. Still, shortcuts were taken, and should be addressed:
  1. threads on the proxy_dns_fcgi side are a problem. should use "libevent".
  2. select() on the proxy_dns_gw side is a problem. should use "libcurl" more.

Authors

This software was conceived and drafted by Paul Vixie during WIDE-2015-03, and is hereby placed into the public domain, and also placed into the care of BII, a Beijing-based non-profit Internet technology company.
Note that there is a follow-up work using Golang to implement DNS over HTTP, Please visit https://github.com/BII-Lab/DNSoverHTTPinGO for more information.

from https://github.com/BII-Lab/DNSoverHTTP
---------

DNS over HTTP proxy written in golang
DNSoverHTTPinGO

Introduction

This proxy implementation is a follow-up works of DNSoverHTTP(https://github.com/BII-Lab/DNSoverHTTP)written in C. Compared with the previous version, this works provides:
  1. A Golang version client proxy and server proxy which is indepentdent of web server(nginx or apache). That is to say the server proxy will listen to 80 and handle the http connect itself based on Golang lib.
  2. This Golang version using the event-based method resoloves the performance problem of threads on the proxy_dns_fcgi side in C version.
  3. The Golang version client/server is implemented without resource name and with different content tpye. For compatible consideration, Go client can connect to FastCGI-version server with -support_version option. If you connect the go version proxy server, do not use -support_version option.
  4. In FastCGI-verion, the client should be told where to connect for its DNS proxy service with the "-s arg". It will cause a kind of loop problem if arg is a url like "http://proxy-dns.vix.su" and GW server happens to use 127.0.0.1 as one of its /etc/resolv.conf nameservers. The Golang version correct it by using a speciall DNS request for the domain in the url firstly.

Construction

To compile the code, make sure your have install golang 1.4 version and already compiled go dns lib written by miekg(https://github.com/miekg/dns).You can find introduction's in miekg's github.To simply get and compile miekg's package in golang, just run:
go get github.com/miekg/dns
go build github.com/miekg/dns
Then you can compile the code in this repository by:
go get github.com/BII-Lab/DNSoverHTTPinGO/
go build github.com/BII-Lab/DNSoverHTTPinGO/ClientProxy
go build github.com/BII-Lab/DNSoverHTTPinGO/ServerProxy

Server Installation

The server proxy will need a working name server configuration on your server. The server should be reachable by UDP and TCP, and you should have a clear ICMP path to it, as well as full MTU (1500 octets or larger) and the ability to receive fragmented UDP (to make EDNS0 usable.)
  1. compile ServerProxy.
    go build github.com/BII-Lab/DNSoverHTTPinGO/ServerProxy
  2. make sure you have a working resolver.
  3. run the ServerProxy as (listion to port 80 by default)
    ./ServerProxy -proxy "[your upper resolver's ip address]"
  4. For more help information, you can use -h option
    ./ServeProxy -h

Client Installation

The ClientProxy will listen on the port assigned(defaut port is 53). And it must also be told where are which type proxy service to connect to. If you want to connect to the FCGI proxy server(https://github.com/BII-Lab/DNSoverHTTP/tree/master/proxy_dns_fcgi) your need add a -support_version option. Both domain name or ip address for server proxy is acceptable. If you use a domain name, you need to set a resolver's IP address as a start point.
  1. compile ClientProxy.
    go build github.com/BII-Lab/DNSoverHTTPinGO/ClientProxy
  2. If you want to redirect all you normal DNS traffic to the proxy, configure your /etc/resolv.conf. Set nameserver to 127.0.0.1.(optional)
  3. run ClientProxy to connect the ServerProxy
    ./ClientProxy -proxy "the domain or address of ServerProxy"
  4. Note that If you want to use domain as the arg for -proxy, the code will use a default resolver 114.114.114.114:53 for the resolution of the ServerProxy domain. You can also specify the resolver with --dns_server with "you prefered dns resolver ip:port"
    ./ClientProxy -proxy "the domain or address of ServerProxy" -dns_server "8.8.8.8:53"
  5. For more help information, you can use -h option
    ./ClientProxy -h

Testing

Make sure you have a working "dig" command. If you started your client side dns_proxy service on 127.0.0.1, then you should be able to say:
dig @127.0.0.1 www.yeti-dns.org aaaa
and get a result back.

No comments:

Post a Comment