Spinning local DNS server sourcing responses over HTTPS to combat Man-in-the-middle attack
Arnav Kumar
What is DNS
- Hierarchical decentralized naming system
- Authoritative name servers
- Resolvers
- Recursive and caching name server
- OS Querying caching DNS servers
dig .
. 6185 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2017110301 1800 900 604800 86400
dig com.
com. 32 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1509848642 1800 900 604800 86400
dig github.com
github.com. 45 IN A 192.30.255.113
dig
- domain information groper
- querying specified servers for specific records
dig atx.sx
; <<>> DiG 9.8.3-P1 <<>> atx.sx
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20540
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;atx.sx. IN A
;; ANSWER SECTION:
atx.sx. 299 IN A 104.27.158.213
atx.sx. 299 IN A 104.27.159.213
;; Query time: 417 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Mon Sep 11 21:44:23 2017
;; MSG SIZE rcvd: 56
dig @127.0.0.1 -p 53 txt txt.ns.atx.sx
Problem at hand
- DNS communication over UDP or TCP is unencrypted. This is vulnerable to eavesdropping and spoofing
- Responses from resolvers to clients are vulnerable to tampering
- DNSSEC provides check of authenticity but NOT availability
Extensions for features that depend on DNSSEC must validate it themselves, as the browser and the OS may not be able to validate DNSSEC
dig thepiratebay.org
;; ANSWER SECTION:
thepiratebay.org. 10 IN A 49.207.46.34
;; Query time: 7 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sun Nov 5 08:10:29 2017
;; MSG SIZE rcvd: 66
ping -c 3 8.8.8.8
64 bytes from 8.8.8.8: icmp_seq=0 ttl=48 time=75.316 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=48 time=75.115 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=48 time=77.209 ms
Mirages
- Changing your DNS servers from the default provided by ISPs to your favourite 8.8.8.8 is NOT guaranteed to solve the problem as the ISP may as-well tamper all communication on Port 53 to respond on behalf of any server, leaving you still with wrong DNS records.
- Tunneling the full traffic via VPN is not a practical solution just to obtain authentic DNS records.
tl;dr We cannot afford the DNS traffic to leave our premises, and we cannot force our systems to fetch DNS over an encrypted channel
Take matters into our
own hands
- We run a DNS Resolver ourselves and tell our Operating System to fetch DNS via the Resolver.
- Our DNS Resolver fetches DNS over HTTPS using APIs provided by Google
Tools of trade
- Twisted
- names
- DNSServerFactory
- Resolver
- names
- requests
twisted.names
- is both a domain name server and a client resolver library
- we use DNSServerFactory, and pass to it a CustomResolver built on top of ResolverBase
CustomResolver
- client.Resolver opens an upstream connection on TCP/UDP port 53, fetches the DNS packets, parses it to Twisted dns.Message, and dispatches it.
- The CustomResolver mimics a client.Resolver for most of its part. It makes an API call over HTTPS, fetches the JSON, translates the JSON to Twisted dns.Message, and dispatches it similarily
Spices to Twisted Async
- Reactor
- Deferred
Reactor
- The reactor is the core of the event loop within Twisted
- The event loop is a programming construct that waits for and dispatches events or messages in a program
- Choice of different reactors
- reactor.callLater
Deferred
- Twisted's way to deal with callbacks
- Deferred is a promise. It's a forecast of things to come.
- deferred.addCallback, deferred.addErrback
- deferred.callback, deferred.errback
DNS Resource Record (RR) Types
- DNS does not only deal with addresses
- RR major types : A, AAAA, CNAME, MX, NS, TXT, SPF
- Utilizing twisted.names.dns classes for RRs
- Implementing decodeJSON for each RR class to work seamlessly like client.Resolver
Caveats
- We must not assume to have a DNS system inplace when our app is being used
- A simple HTTPS request would fail as dns.google.com would fail to resolve
- Changing just the dns.google.com to an IP will not work as HTTPS SSL would fail for an IP (it would be valid for google domain)
- To change the Host Header in the packet, we need to use HostHeaderSSLAdapter from requests-toolbelt
Putting pieces together
github.com/arn7av/gDNS
Using it on system as primary DNS
- Check if everything is running fine with dig
- Running it as root (to allow binding it to port 53)
- Depending on the OS, we follow instructions to make 127.0.0.1 as our DNS server
- GG
To Infinity and Beyond
- Writing custom caching rules
- Writing a separate resolver for our internal network and adding it to DNSServerFactory clients
- Extending the failure mechanism to revert to DNS over TCP/UDP
- Your imagination :-)
gDNS
By arnAV
gDNS
- 1,339