Skip to content

Latest commit

 

History

History
226 lines (191 loc) · 7.36 KB

README.md

File metadata and controls

226 lines (191 loc) · 7.36 KB

Fast DNS implementation for Go

godoc release goreport

Features

  • 0 Dependency
  • Similar Interface with net/http
  • Fast DoH Server Co-create with fasthttp
  • Fast DNS Client with rich features
  • Compatible metrics with coredns
  • High Performance
    • 0-allocs dns request parser
    • 0-allocs dns records marshaller
    • worker pool + message pool
    • prefork + reuse_port + set_affinity

Getting Started

DNS Server

package main

import (
	"log/slog"
	"net"
	"net/netip"
	"os"

	"github.com/phuslu/fastdns"
)

type DNSHandler struct {
	Debug bool
}

func (h *DNSHandler) ServeDNS(rw fastdns.ResponseWriter, req *fastdns.Message) {
	if h.Debug {
		slog.Info("serve dns request", "domain", req.Domain, "class", req.Question.Class, "type", req.Question.Type)
	}

	switch req.Question.Type {
	case fastdns.TypeA:
		fastdns.HOST1(rw, req, 60, netip.AddrFrom4([4]byte{8, 8, 8, 8}))
	case fastdns.TypeAAAA:
		fastdns.HOST(rw, req, 60, []netip.Addr{netip.MustParseAddr("2001:4860:4860::8888")})
	case fastdns.TypeCNAME:
		fastdns.CNAME(rw, req, 60, []string{"dns.google"}, []netip.Addr{netip.MustParseAddr("8.8.8.8")})
	case fastdns.TypeSRV:
		fastdns.SRV(rw, req, 60, []net.SRV{{"www.google.com", 443, 1000, 1000}})
	case fastdns.TypeNS:
		fastdns.NS(rw, req, 60, []net.NS{{"ns1.google.com"}, {"ns2.google.com"}})
	case fastdns.TypeMX:
		fastdns.MX(rw, req, 60, []net.MX{{"mail.gmail.com", 10}, {"smtp.gmail.com", 10}})
	case fastdns.TypeSOA:
		fastdns.SOA(rw, req, 60, net.NS{"ns1.google"}, net.NS{"ns2.google"}, 60, 90, 90, 180, 60)
	case fastdns.TypePTR:
		fastdns.PTR(rw, req, 0, "ptr.google.com")
	case fastdns.TypeTXT:
		fastdns.TXT(rw, req, 60, "greetingfromgoogle")
	default:
		fastdns.Error(rw, req, fastdns.RcodeNXDomain)
	}
}

func main() {
	addr := ":53"

	server := &fastdns.ForkServer{
		Handler: &DNSHandler{
			Debug: os.Getenv("DEBUG") != "",
		},
		Stats: &fastdns.CoreStats{
			Prefix: "coredns_",
			Family: "1",
			Proto:  "udp",
			Server: "dns://" + addr,
			Zone:   ".",
		},
		ErrorLog: slog.Default(),
	}

	err := server.ListenAndServe(addr)
	if err != nil {
		slog.Error("dnsserver serve failed", "error", err)
	}
}

DoH Client

package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/phuslu/fastdns"
)

func main() {
	endpoint, _ := url.Parse("https://1.1.1.1/dns-query")

	client := &fastdns.Client{
		Addr: endpoint.String(),
		Dialer: &fastdns.HTTPDialer{
			Endpoint:  endpoint,
			Header: http.Header{
				"content-type": {"application/dns-message"},
				"user-agent":   {"fastdns/1.0"},
			},
			Transport: &http.Transport{
				ForceAttemptHTTP2:   true,
				MaxIdleConns:        100,
				IdleConnTimeout:     90 * time.Second,
				TLSHandshakeTimeout: 10 * time.Second,
				TLSClientConfig: &tls.Config{
					NextProtos:         []string{"h2"},
					InsecureSkipVerify: false,
					ServerName:         endpoint.Hostname(),
					ClientSessionCache: tls.NewLRUClientSessionCache(1024),
				},
			},
		},
	}

	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	fmt.Println(client.LookupHTTPS(ctx, "cloud.phus.lu"))
}

DNS Client Tool

$ go install github.com/phuslu/fastdns/cmd/fastdig@master
$ fastdig ip.phus.lu @https://1.1.1.1/dns-query

; <<>> DiG 0.0.1-Fastdns <<>> ip.phus.lu
;; global options: +cmd +noedns
;; Got answer:
;; ->>HEADER<<- opcode: Query, status: Success, id: 2775
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;ip.phus.lu.            IN      A

;; ANSWER SECTION:
ip.phus.lu.     299     IN      CNAME   phus.lu.
phus.lu.        299     IN      A       101.32.116.118

;; Query time: 15 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Mon Apr 12 22:07:16 +08 2021
;; MSG SIZE  rcvd: 58

DoH Server Example

$ go install github.com/phuslu/fastdns/cmd/fastdoh@master
$ fastdoh :8080

High Performance

A Performance result as below, for daily benchmark results see github actions

# go test -v -cpu=1 -run=none -benchmem -bench=.
goos: linux
goarch: amd64
pkg: github.com/phuslu/fastdns
cpu: AMD EPYC 7763 64-Core Processor

BenchmarkHOST1-4               	56613120	        21.09 ns/op	       0 B/op	       0 allocs/op
BenchmarkHOST-4                	57722778	        20.82 ns/op	       0 B/op	       0 allocs/op
BenchmarkCNAME-4               	40001464	        30.00 ns/op	       0 B/op	       0 allocs/op
BenchmarkSRV-4                 	26439794	        44.84 ns/op	       0 B/op	       0 allocs/op
BenchmarkNS-4                  	22967035	        52.28 ns/op	       0 B/op	       0 allocs/op
BenchmarkSOA-4                 	19650216	        61.16 ns/op	       0 B/op	       0 allocs/op
BenchmarkPTR-4                 	50205879	        30.12 ns/op	       0 B/op	       0 allocs/op
BenchmarkMX-4                  	39453458	        29.81 ns/op	       0 B/op	       0 allocs/op
BenchmarkTXT-4                 	62278441	        19.15 ns/op	       0 B/op	       0 allocs/op
BenchmarkParseMessage-4        	83152729	        14.84 ns/op	       0 B/op	       0 allocs/op
BenchmarkSetQuestion-4         	37922407	        31.28 ns/op	       0 B/op	       0 allocs/op
BenchmarkSetResponseHeader-4   	336013587	         3.583 ns/op	       0 B/op	       0 allocs/op
BenchmarkDecodeName-4          	52855680	        22.86 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendHOSTRecord-4    	71025451	        16.81 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendCNAMERecord-4   	52953403	        23.92 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendSRVRecord-4     	30775414	        36.37 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendNSRecord-4      	27102512	        43.92 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendSOARecord-4     	21295884	        56.13 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendPTRRecord-4     	62573373	        24.38 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendMXRecord-4      	43072573	        28.30 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendTXTRecord-4     	100000000	        11.15 ns/op	       0 B/op	       0 allocs/op
BenchmarkUpdateStats-4         	40084848	        29.85 ns/op	       0 B/op	       0 allocs/op
BenchmarkAppendOpenMetrics-4   	  110046	     10824 ns/op	       0 B/op	       0 allocs/op
BenchmarkEncodeDomain-4        	100000000	        11.54 ns/op	       0 B/op	       0 allocs/op

PASS
ok  	github.com/phuslu/fastdns	30.430s

Here is the real-world flamegraph flamegraph when fastdns server reaches 1.4M QPS on a single machine with Xeon 4216 and Intel X710.

Acknowledgment

This dns server is inspired by fasthttp, rawdns and miekg/dns.