# Coredns ###### tags: `c4lab` `server` [toc] ## Target I want to setup a DNS server for alias all the server in the internal networks. It's possible to use ansible to update all `/etc/hosts` in each server. However it is not a elegant way. Thus, I setup the coredns and try to figure out the configuration for supporting all commonly used protocols (plain, https, tls) and test them one by one. Finally, I will set this DNS IP:port in our main router. ## Setup Coredns Github: https://github.com/coredns/coredns Document: https://coredns.io/manual/toc/ How to setup: Option 1. Running in Docker ``` docker pull docker.io/coredns/coredns docker run -it --rm -p 53:53/udp docker.io/coredns/coredns ``` Option 2. Compile and run the binary ``` git clone https://github.com/coredns/coredns docker run -it --rm -v $PWD/coredns:/app -w /app golang:1.18 make ./coredns/coredns ``` ## Setup Testing tools dnslookup https://github.com/ameshkov/dnslookup I think this is the best tool, it cover all protocols and it is easy to use. ``` git clone https://github.com/ameshkov/dnslookup.git docker run -it --rm -v $PWD/dnslookup:/app -w /app golang:1.18 make ``` ### Test it on Cloudflare DNS ``` ./dnslookup/dnslookup google.com https://cloudflare-dns.com/dns-query ./dnslookup/dnslookup google.com tls://one.one.one.one ./dnslookup/dnslookup google.com 1.1.1.1 ``` Example output ``` dnslookup v. dev dnslookup result: ;; opcode: QUERY, status: NOERROR, id: 43550 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;google.com. IN A ;; ANSWER SECTION: google.com. 263 IN A 216.58.200.238 ``` ## Coredns settings: plain DNS `Corefile` ``` .:10053 { log hosts { 192.168.208.206 rna 192.168.208.206 exon fallthrough } rewrite name exact taiwania1 clogin1.twnia.nchc.org.tw forward . tls://1.1.1.1 { tls_servername cloudflare-dns.com } whoami } ``` You can custom your own alias in hosts blocks, it is the same format as `/etc/hosts`. You can also use alias of name i.e. taiwania1 will response the IP of clogin1.twnia.nchc.org.tw. If the query not match in hosts, it will catch the query and redirect to the upstream 1.1.1.1 (with TLS). ### DNS: run and test docker run parameters ``` bash! docker run -it --rm -v $PWD/Corefile:/Corefile -p 10053:10053/tcp -p 10053:10053/udp docker.io/coredns/coredns ``` and test ``` bash! apt install dnsutils dig -p 10053 @c4lab.bime.ntu.edu.tw google.com dig -p 10053 @c4lab.bime.ntu.edu.tw rna nslookup -port=10053 google.com c4lab.bime.ntu.edu.tw ./dnslookup/dnslookup google.com c4lab.bime.ntu.edu.tw:10053 ``` And coredns will logs: `[INFO] 10.0.2.100:45241 - 24292 "A IN google.com. udp 51 false 4096" NOERROR qr,rd,ra 478 0.089646393s` ## Coredns settings: DNS-over-TLS (DoT) Append the `Corefile` with ``` tls://.:10054 { tls /opt/fullchain.pem /opt/privkey.pem forward . 127.0.0.1:10053 } ``` Our `fullchain.pem` and `privkey.pem` are got from Let's Encrypt me. You can set your own certifications and key file. All the query will redirect to the plain DNS internally. ### Run it and test docker run parameters ``` bash! docker run -it --rm -v $PWD/Corefile:/Corefile -p 10054:10054 -v $PWD/fullchain.pem:/opt/fullchain.pem -v $PWD/privkey.pem:/opt/privkey.pem docker.io/coredns/coredns ``` test ``` bash! ./dnslookup/dnslookup google.com tls://c4lab.bime.ntu.edu.tw:10054 # or kdig (see supplement) apt install knot-dnsutils kdig @c4lab.bime.ntu.edu.tw:10054 +tls-ca google.com ``` ## Coredns settings: DNS-over-Http (DoH) Append to `Corefile` with ``` https://.:10055 { tls /opt/fullchain.pem /opt/privkey.pem forward . 127.0.0.1:10053 } ``` The same as DoT, almost. ### Run and test docker parameters ``` bash! docker run -it --rm -v $PWD/Corefile:/Corefile -p 10055:10055 -v $PWD/fullchain.pem:/opt/fullchain.pem -v $PWD/privkey.pem:/opt/privkey.pem docker.io/coredns/coredns ``` test ``` bash! ./dnslookup/dnslookup google.com https://c4lab.bime.ntu.edu.tw:10055/dns-query # curl (see detail in supplement) apt install curl curl "https://c4lab.bime.ntu.edu.tw:10055/dns-query?dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ" -k | xxd ``` ## Overall: Coredns setting `Corefile` ``` .:10053 { whoami hosts { 192.168.208.206 rna fallthrough } forward . tls://1.1.1.1 { tls_servername cloudflare-dns.com } } tls://.:10054 { tls /opt/fullchain.pem /opt/privkey.pem forward . 127.0.0.1:10053 } https://.:10055 { tls /opt/fullchain.pem /opt/privkey.pem forward . 127.0.0.1:10053 } ``` and ``` bash! docker run -it --rm \ -p 10053:10053/tcp \ -p 10053:10053/udp \ -p 10054:10054 \ -p 10055:10055 \ -v $PWD/Corefile:/Corefile:ro \ -v $PWD/coredns/coredns:/coredns:ro \ -v $PWD/fullchain.pem:/opt/fullchain.pem:ro \ -v $PWD/privkey.pem:/opt/privkey.pem:ro \ docker.io/coredns/coredns ``` `log` is removed in production ## Supplements DoT https://datatracker.ietf.org/doc/rfc7858/ DoH https://datatracker.ietf.org/doc/rfc8484/ ### Test DoT by kdig https://www.knot-dns.cz/ ``` bash! apt install knot-dnsutils kdig -d @1.1.1.1 +tls-ca +tls-host=cloudflare-dns.com google.com ``` Example Output ``` ;; TLS session (TLS1.3)-(ECDHE-X25519)-(ECDSA-SECP256R1-SHA256)-(AES-256-GCM) ;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 56882 ;; Flags: qr rd ra; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1 ;; EDNS PSEUDOSECTION: ;; Version: 0; flags: ; UDP size: 1232 B; ext-rcode: NOERROR ;; PADDING: 409 B ;; QUESTION SECTION: ;; google.com. IN A ;; ANSWER SECTION: google.com. 52 IN A 142.250.66.110 ;; Received 468 B ;; Time 2022-09-27 15:51:43 UTC ;; From 1.1.1.1@853(TCP) in 32.9 ms ``` ### Test DoH by curl ``` bash! apt install curl curl "https://cloudflare-dns.com/dns-query?dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ" -k | xxd ``` output ``` 00000000: 0000 8180 0001 0001 0000 0000 0667 6f6f .............goo 00000010: 676c 6503 636f 6d00 0001 0001 c00c 0001 gle.com......... 00000020: 0001 0000 004d 0004 d83a c8ee .....M...:.. ``` The query sequence `dns=...` and the output is base62 encoded sequences (I don't know either). However, Cloudflare provided anthor way to make the [query in json format](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/). But this method doesn't support by coredns. [issue](https://github.com/coredns/coredns/issues/3465) ```! apt install jq curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=google.com&type=A' | jq ``` output ``` json { "Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [ { "name": "google.com", "type": 1 } ], "Answer": [ { "name": "google.com", "type": 1, "TTL": 151, "data": "142.250.66.142" } ] } ``` ### Test DoH by doh https://github.com/curl/doh doh is another tool that can query in json format. Thus, It doesn't support to query to coredns. ``` bash git clone https://github.com/curl/doh docker run -it --rm -v $PWD/doh:/app -w /app golang:1.18 bash apt update apt install libcurl4-openssl-dev make exit ./doh/doh google.com https://cloudflare-dns.com/dns-query ``` output ``` [google.com] TTL: 276 seconds A: 142.250.66.142 AAAA: 2404:6800:4005:080d:0000:0000:0000:200e ```