├── debian ├── compat ├── docs ├── install ├── doh.json ├── doh.service ├── rules ├── control ├── changelog └── copyright ├── data ├── routes.list.gz ├── http.json ├── google.json ├── rfc8484.json ├── https.json ├── twin.json ├── cert.pem ├── vendors.csv ├── quick.csv ├── key.pem ├── public.csv ├── sh-unicom.csv ├── sh-telecom.csv ├── jp.csv ├── seattle.csv ├── sh-unicom.md ├── sh-telecom.md ├── jp.md └── seattle.md ├── .gitignore ├── rrtree ├── main.go └── common.go ├── go.mod ├── scripts ├── fmttab.py ├── diagdns ├── test.sh └── test.py ├── go.sum ├── drivers ├── doh.go ├── reties.go ├── hdr.go ├── twin.go ├── godns.go ├── dnspod.go ├── rfc8484.go ├── common.go ├── recursive.go └── google.go ├── Makefile ├── doh-aliases.json ├── doh ├── main.go └── query.go ├── iplist ├── iplist.go └── iplist_test.go ├── README.md └── LICENSE.md /debian/compat: -------------------------------------------------------------------------------- 1 | 11 -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | LICENSE.md 2 | README.md 3 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | debian/doh.json etc/ 2 | -------------------------------------------------------------------------------- /data/routes.list.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shell909090/doh/HEAD/data/routes.list.gz -------------------------------------------------------------------------------- /data/http.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "url": "http://0.0.0.0:8053" 4 | }, 5 | "client": { 6 | "url": "udp://114.114.114.114:53/" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /data/google.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "url": "udp://0.0.0.0:5153" 4 | }, 5 | "client": { 6 | "url": "https://dns.google.com/resolve" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /debian/doh.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "url": "udp://0.0.0.0:5053" 4 | }, 5 | "client": { 6 | "url": "https://dns.google.com/resolve" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /data/rfc8484.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "url": "udp://0.0.0.0:5053" 4 | }, 5 | "client": { 6 | "url": "https://security.cloudflare-dns.com/dns-query" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /data/https.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "url": "https://0.0.0.0:8153", 4 | "certfile": "data/cert.pem", 5 | "keyfile": "data/key.pem" 6 | }, 7 | "client" : { 8 | "url": "udp://114.114.114.114:53/" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.log 3 | *.pyc 4 | *.json 5 | *.html 6 | *.prof 7 | obj* 8 | rt_* 9 | 10 | bin 11 | pkg 12 | key 13 | debuild 14 | 15 | debian/*.debhelper 16 | debian/debhelper-build-stamp 17 | debian/files 18 | debian/*.substvars 19 | debian/doh/ 20 | -------------------------------------------------------------------------------- /debian/doh.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=doh 3 | After=network-online.target 4 | 5 | [Service] 6 | EnvironmentFile=-/etc/default/doh 7 | ExecStart=/usr/bin/doh --config /etc/doh.json 8 | Restart=on-failure 9 | RestartSec=30 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /data/twin.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "url": "udp://0.0.0.0:5253" 4 | }, 5 | "client": { 6 | "driver": "twin", 7 | "direct-routes": "data/routes.list.gz", 8 | "primary": { 9 | "url": "udp://114.114.114.114:53" 10 | }, 11 | "secondary": { 12 | "url": "udp://8.8.4.4:53" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rrtree/main.go: -------------------------------------------------------------------------------- 1 | // package main 2 | 3 | // import ( 4 | // "fmt" 5 | 6 | // "github.com/miekg/dns" 7 | // ) 8 | 9 | // func main() { 10 | // node, partial := DefaultTree.GetNode("c.root-servers.net") 11 | // fmt.Println(partial) 12 | // if rrs, ok := node.Resources[dns.TypeA]; ok { 13 | // fmt.Printf("%+v\n", rrs) 14 | // fmt.Printf("%+v\n", rrs[0]) 15 | // } 16 | 17 | // return 18 | // } 19 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # See debhelper(7) (uncomment to enable) 4 | # output every command that modifies files on the build system. 5 | #export DH_VERBOSE = 1 6 | 7 | # see FEATURE AREAS in dpkg-buildflags(1) 8 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 9 | 10 | export DH_OPTIONS 11 | export DH_GOPKG := github.com/shell909090/doh 12 | 13 | 14 | %: 15 | dh $@ 16 | 17 | override_dh_auto_test: 18 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/shell909090/doh 2 | 3 | go 1.24 4 | 5 | require ( 6 | github.com/miekg/dns v1.1.68 7 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 8 | ) 9 | 10 | require ( 11 | golang.org/x/mod v0.24.0 // indirect 12 | golang.org/x/net v0.40.0 // indirect 13 | golang.org/x/sync v0.14.0 // indirect 14 | golang.org/x/sys v0.33.0 // indirect 15 | golang.org/x/tools v0.33.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: doh 2 | Section: net 3 | Priority: extra 4 | Maintainer: Shell.Xu 5 | Build-Depends: debhelper (>= 11) 6 | Standards-Version: 4.4.0.1 7 | Homepage: https://github.com/shell909090/doh 8 | #Vcs-Browser: https://salsa.debian.org/debian/doh 9 | #Vcs-Git: https://salsa.debian.org/debian/doh.git 10 | 11 | Package: doh 12 | Architecture: any 13 | Depends: ${shlibs:Depends}, ${misc:Depends} 14 | Description: DNS over HTTPS utils written by golang. 15 | doh is a DNS over HTTPS utils written by golang. 16 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | doh (1.1.1) UNRELEASED; urgency=medium 2 | 3 | * fix "can't parse subnet" issue 4 | 5 | -- Shell.Xu Thu, 04 Sep 2025 11:12:36 +0800 6 | 7 | doh (1.1.0) unstable; urgency=medium 8 | 9 | * add result testing scripts. 10 | * migrate to golang 1.24. 11 | * fix edns-client-subnet not working issue. 12 | 13 | -- Shell.Xu Tue, 02 Sep 2025 00:03:32 +0800 14 | 15 | doh (1.0.1) unstable; urgency=medium 16 | 17 | * new config structures. 18 | * introduce twin. 19 | 20 | -- Shell.Xu Thu, 07 May 2020 00:02:45 +0800 21 | 22 | doh (1.0-1) unstable; urgency=medium 23 | 24 | * Initial release. 25 | 26 | -- Shell.Xu Fri, 01 May 2020 11:04:32 +0800 27 | -------------------------------------------------------------------------------- /scripts/fmttab.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | ''' 4 | @date: 2020-05-24 5 | @author: Shell.Xu 6 | @copyright: 2020, Shell.Xu 7 | @license: BSD-3-clause 8 | ''' 9 | import re 10 | import sys 11 | import csv 12 | 13 | accuracy_domains = [ 14 | 'taobao', 'tmall', 'qq', 'baidu', 'sohu', 'jd', 15 | 'amazon', 'bing', 'linkedin', 'weibo', 'meituan'] 16 | 17 | def main(): 18 | re_name = re.compile('[a-z\-]') 19 | s = f'| vendor | protocol | latency | poisoned | edns-client-subnet | accuracy | %s |' % ' | '.join(accuracy_domains) 20 | print(s) 21 | print(re_name.sub('-', s)) 22 | with open(sys.argv[1]) as fi: 23 | reader = csv.reader(fi) 24 | for row in reader: 25 | print('| %s |' % ' | '.join(row)) 26 | 27 | 28 | if __name__ == '__main__': 29 | main() 30 | -------------------------------------------------------------------------------- /data/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICpDCCAYwCCQDys6f3o+I7BTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls 3 | b2NhbGhvc3QwHhcNMjAwNDMwMDQwNTE4WhcNMzAwNDI4MDQwNTE4WjAUMRIwEAYD 4 | VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1 5 | fGK/nLcbeL49v2mDAP4grWjji3OWSCs5Zyl1ZMmlZHBAB+ywxqK8y/JBQgRC7IST 6 | YDjwpGrjQwSjswUHBXaZo2TlSR+0IfNKF5sZuyRhRK3zmKwObJtnnYB2CEMcgu6b 7 | M5sWKFiiz/DPJmSASr9Md6HZwpM1XzzRvsSlnB26dY6MQSw8GUFwQ412uCYTR8cR 8 | AeBK8x4+jD9r3OWGqS3SysgDYYA9EFoRZP8tomLiWfTKl2ARVihgLHt1y7F7p4e2 9 | 65vyVKK7A806RXT16ZxLnHp8Uckf7zJ4qyJCJ0HqRFSkxXyxiiKvdldXd4/A5dKq 10 | NnLDaG8HpcPYpc+XNrYdAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAGIfRUDAko/5 11 | XlvGy2gXNoBRsKM83OXWfsYmKzl9njumi0KnV2C8SrB+oKrpe0pMLQeES8nKCu4x 12 | V3I+UcyjEaszLQDyb3HyvxNOqX7wNSAo5vR6fZRQVOQGeW12FmyuNCtRGDl8/JEa 13 | v64YjktIdZa8HXvQs22m9q4M7sK/+xilf06386OMoLMTxeVQObK6+iU73CaSGYip 14 | wgKYBpL9mzVeRrLtRkuT0bMgJJYlewh7v0xMI6kRAYs1tqbHOlYrEsjXsdl/Tgks 15 | 8I9SSAQEGLxatSN3xFhhVmVxbsgi5ZywFBYlWTCGvpNySjKrrFQKN5+vjZ6wKjX/ 16 | +n5Q5sMvP88= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: doh 3 | Source: https://github.com/shell909090/doh 4 | 5 | Files: * 6 | Copyright: 2020 Shell Xu 7 | License: GPL-2+ 8 | This package is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | . 13 | This package is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | . 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see 20 | . 21 | On Debian systems, the complete text of the GNU General 22 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 23 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 2 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 3 | github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= 4 | github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= 5 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= 6 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 7 | golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= 8 | golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 9 | golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= 10 | golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= 11 | golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= 12 | golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 13 | golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= 14 | golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 15 | golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= 16 | golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= 17 | -------------------------------------------------------------------------------- /drivers/doh.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "net/url" 7 | ) 8 | 9 | type DoHServer struct { 10 | CertFile string 11 | KeyFile string 12 | EdnsClientSubnet string 13 | scheme string 14 | addr string 15 | cli Client 16 | mux *http.ServeMux 17 | } 18 | 19 | func NewDoHServer(cli Client, URL string, body json.RawMessage) (srv *DoHServer) { 20 | u, err := url.Parse(URL) 21 | if err != nil { 22 | panic(err.Error()) 23 | } 24 | 25 | srv = &DoHServer{ 26 | scheme: u.Scheme, 27 | addr: u.Host, 28 | cli: cli, 29 | mux: http.NewServeMux(), 30 | } 31 | 32 | if body != nil { 33 | err = json.Unmarshal(body, &srv) 34 | if err != nil { 35 | panic(err.Error()) 36 | } 37 | } 38 | 39 | srv.mux.Handle("/dns-query", NewRfc8484Handler(cli, srv.EdnsClientSubnet)) 40 | srv.mux.Handle("/resolve", NewGoogleHandler(cli, srv.EdnsClientSubnet)) 41 | srv.mux.Handle("/d", NewDnsPodHandler(cli, srv.EdnsClientSubnet)) 42 | return 43 | } 44 | 45 | func (srv *DoHServer) Serve() (err error) { 46 | server := &http.Server{ 47 | Addr: srv.addr, 48 | Handler: srv.mux, 49 | } 50 | 51 | switch srv.scheme { 52 | case "http": 53 | err = server.ListenAndServe() 54 | case "https", "": 55 | err = server.ListenAndServeTLS(srv.CertFile, srv.KeyFile) 56 | } 57 | return 58 | } 59 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ### Makefile --- 2 | 3 | ## Author: shell@dsk 4 | ## Version: $Id: Makefile,v 0.0 2020/04/29 14:02:48 shell Exp $ 5 | ## Keywords: 6 | ## X-URL: 7 | LEVEL=NOTICE 8 | VERSION=$(shell head -n 1 debian/changelog | sed -E 's/.*\((.*)\).*/\1/g') 9 | GIT_COMMIT=$(shell git rev-list -1 HEAD | head -c 8) 10 | 11 | all: clean build 12 | 13 | clean: 14 | rm -rf bin pkg debuild *.log 15 | 16 | clean-deb: 17 | debian/rules clean 18 | 19 | build: bin/doh 20 | 21 | bin/doh: 22 | mkdir -p bin 23 | go build -o bin/doh -ldflags "-s -X main.Version=$(VERSION)-$(GIT_COMMIT)" github.com/shell909090/doh/doh 24 | 25 | install: bin/doh 26 | install -d $(DESTDIR)/usr/bin/ 27 | install -m 755 -s bin/doh $(DESTDIR)/usr/bin/ 28 | 29 | test: 30 | go test -v github.com/shell909090/doh/iplist 31 | 32 | benchmark: 33 | go test -v github.com/shell909090/doh/iplist -bench . -benchmem 34 | 35 | build-deb: 36 | dpkg-buildpackage --no-sign 37 | mkdir -p debuild 38 | mv -f ../doh_* debuild 39 | 40 | testquery: 41 | scripts/test.sh basic 42 | scripts/test.sh drivers 43 | scripts/test.sh edns 44 | scripts/test.sh rfc8484 45 | scripts/test.sh google 46 | scripts/test.sh http 47 | scripts/test.sh https 48 | 49 | test-public: 50 | scripts/diagdns www.twitter.com www.baidu.com www.google.com www.taobao.com www.jd.com open.163.com github.com en.wikipedia.org www.startpage.com 51 | 52 | ### Makefile ends here 53 | -------------------------------------------------------------------------------- /data/vendors.csv: -------------------------------------------------------------------------------- 1 | 114,https://www.114dns.com/, 2 | alidns,https://www.alidns.com/,tls/rfc8484/edns 3 | dnspod,https://www.dnspod.cn/products/public.dns,edns(httpdns not implemented yet) 4 | baidu,https://dudns.baidu.com/intro/publicdns/, 5 | cnnic,http://public.sdns.cn/, 6 | dnspai,http://www.dnspai.com/public.html, 7 | onedns,https://www.onedns.net/, 8 | cloudflare,https://1.1.1.1/, 9 | google,https://developers.google.com/speed/public-dns/,udp/tcp/tls/rfc8484/google/edns 10 | opendns,https://www.opendns.com/, 11 | quad9,https://www.quad9.net/, 12 | adguard,https://adguard.com/en/adguard-dns/overview.html,tls/rfc8484 13 | nextdns,https://nextdns.io/,tls/rfc8484 14 | freenom,https://www.freenom.world/en/index.html, 15 | containerpi,https://dns.containerpi.com/,tls/rfc8484/google 16 | doh.li,https://doh.li/,tls/rfc8484 17 | he,https://dns.he.net/, 18 | verisign,https://www.verisign.com/en_US/security-services/public-dns/index.xhtml, 19 | comodo,https://www.comodo.com/secure-dns/, 20 | dns-watch,https://dns.watch/, 21 | safedns,https://www.safedns.com/en/, 22 | dyn,https://help.dyn.com/internet-guide-setup/, 23 | freedns,https://freedns.zone/en/, 24 | opennic,https://www.opennic.org/, 25 | dnslify,https://www.dnslify.com/,udp/tcp/rfc8484(according to the website, tls should have worked) 26 | yandex,https://dns.yandex.com/, 27 | neustar,https://www.home.neustar/dns-services, 28 | twnic,https://www.twnic.net.tw/, 29 | -------------------------------------------------------------------------------- /data/quick.csv: -------------------------------------------------------------------------------- 1 | 114,udp,udp://114.114.114.114/ 2 | adguard,rfc8484,https://dns.adguard.com/dns-query 3 | adguard,tls,tcp-tls://dns.adguard.com/ 4 | adguard,udp,udp://176.103.130.130/ 5 | alidns,rfc8484,https://dns.alidns.com/dns-query 6 | alidns,tls,tcp-tls://223.5.5.5/ 7 | alidns,udp,udp://223.5.5.5/ 8 | baidu,udp,udp://180.76.76.76/ 9 | cloudflare,rfc8484,https://security.cloudflare-dns.com/dns-query 10 | cloudflare,tls,tcp-tls://one.one.one.one/ 11 | cloudflare,udp,udp://1.1.1.1/ 12 | cnnic,udp,udp://1.2.4.8/ 13 | containerpi,google,https://dns.containerpi.com/dns-query 14 | containerpi,rfc8484,https://dns.containerpi.com/dns-query 15 | containerpi,tls,tcp-tls://dns.containerpi.com/ 16 | dnspai,udp,udp://101.226.4.6/ 17 | dnspod,udp,udp://119.29.29.29/ 18 | dyn,udp,udp://216.146.35.35/ 19 | google,google,https://dns.google/resolve 20 | google,rfc8484,https://dns.google/dns-query 21 | google,tls,tcp-tls://8.8.8.8/ 22 | google,udp,udp://8.8.8.8/ 23 | he,rfc8484,https://ordns.he.net/dns-query 24 | he,udp,udp://74.82.42.42/ 25 | nextdns,rfc8484,https://dns.nextdns.io/e83b12 26 | nextdns,tls,tcp-tls://76dc6f.dns.nextdns.io/ 27 | nextdns,udp,udp://45.90.28.253/ 28 | onedns,udp,udp://117.50.11.11/ 29 | opendns,rfc8484,https://doh.opendns.com/dns-query 30 | opendns,udp,udp://208.67.222.222/ 31 | quad9,rfc8484,https://dns.quad9.net/dns-query 32 | quad9,tls,tcp-tls://dns.quad9.net/ 33 | quad9,udp,udp://9.9.9.9/ 34 | safedns,udp,udp://195.46.39.39/ 35 | -------------------------------------------------------------------------------- /drivers/reties.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | 8 | "github.com/miekg/dns" 9 | ) 10 | 11 | var ( 12 | ErrEmptyClients = errors.New("empty client list") 13 | ) 14 | 15 | type RetiesClient struct { 16 | Tries int 17 | Clients []json.RawMessage 18 | clis []Client 19 | } 20 | 21 | func NewRetiesClient(URL string, body json.RawMessage) (cli *RetiesClient) { 22 | var err error 23 | cli = &RetiesClient{} 24 | if body != nil { 25 | err = json.Unmarshal(body, &cli) 26 | if err != nil { 27 | panic(err.Error()) 28 | } 29 | } 30 | 31 | var header DriverHeader 32 | for _, cfg := range cli.Clients { 33 | err = json.Unmarshal(cfg, &header) 34 | if err != nil { 35 | panic(err.Error()) 36 | } 37 | cli.clis = append(cli.clis, header.CreateClient(cfg)) 38 | } 39 | 40 | return 41 | } 42 | 43 | func (cli *RetiesClient) AddClient(client Client) { 44 | cli.clis = append(cli.clis, client) 45 | } 46 | 47 | func (cli *RetiesClient) Url() (u string) { 48 | return cli.clis[0].Url() 49 | } 50 | 51 | func (cli *RetiesClient) Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) { 52 | if len(cli.clis) == 0 { 53 | panic(ErrEmptyClients.Error()) 54 | } 55 | 56 | for i := 0; i < cli.Tries; i++ { 57 | cur := cli.clis[i%len(cli.clis)] 58 | ans, err = cur.Exchange(ctx, quiz) 59 | if err == nil { 60 | return 61 | } 62 | logger.Info(err.Error()) 63 | } 64 | return 65 | } 66 | -------------------------------------------------------------------------------- /drivers/hdr.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type DriverHeader struct { 8 | Driver string 9 | URL string 10 | } 11 | 12 | func (header *DriverHeader) CreateClient(body json.RawMessage) (cli Client) { 13 | var err error 14 | if header.Driver == "" { 15 | header.Driver, err = GuessDriver(header.URL) 16 | if err != nil { 17 | panic(err.Error()) 18 | } 19 | } 20 | 21 | switch header.Driver { 22 | case "dns": 23 | cli = NewDnsClient(header.URL, body) 24 | case "google": 25 | cli = NewGoogleClient(header.URL, body) 26 | case "rfc8484": 27 | cli = NewRfc8484Client(header.URL, body) 28 | case "dnspod": 29 | cli = NewDnsPodClient(header.URL, body) 30 | case "twin": 31 | cli = NewTwinClient(header.URL, body) 32 | case "reties": 33 | cli = NewRetiesClient(header.URL, body) 34 | case "recursive": 35 | cli = NewRecursiveClient() 36 | default: 37 | panic("unknown driver") 38 | } 39 | 40 | return 41 | } 42 | 43 | func (header *DriverHeader) CreateService(cli Client, body json.RawMessage) (srv Server) { 44 | var err error 45 | if header.Driver == "" { 46 | header.Driver, err = GuessDriver(header.URL) 47 | if err != nil { 48 | panic(err.Error()) 49 | } 50 | } 51 | 52 | switch header.Driver { 53 | case "dns": 54 | srv = NewDnsServer(cli, header.URL, body) 55 | case "doh", "http", "https": 56 | srv = NewDoHServer(cli, header.URL, body) 57 | default: 58 | err = ErrConfigParse 59 | panic(err.Error()) 60 | } 61 | 62 | return 63 | } 64 | -------------------------------------------------------------------------------- /scripts/diagdns: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function show_ping() { 4 | OUTPUT=$(sudo mtr -i 0.5 -z -j -n "$3") 5 | if [ $(echo "$OUTPUT" | jq -r '.report.hubs[-1]."Loss%"') == "100" ]; then 6 | AVG=$(echo "$OUTPUT" | jq -r '.report.hubs[-2].Avg') 7 | ASN=$(echo "$OUTPUT" | jq -r '.report.hubs[-2].ASN') 8 | else 9 | AVG=$(echo "$OUTPUT" | jq -r '.report.hubs[-1].Avg') 10 | ASN=$(echo "$OUTPUT" | jq -r '.report.hubs[-1].ASN') 11 | fi 12 | echo "$1 $2 $3 $AVG $ASN" 13 | } 14 | 15 | for DN in $@ 16 | do 17 | show_ping "$DN" "direct " $(dig +short "$DN" | tail -n 1) & 18 | show_ping "$DN" "114 " $(dig +short "$DN" @114.114.114.114 | tail -n 1) & 19 | show_ping "$DN" "8888 " $(dig +short "$DN" @8.8.8.8 | tail -n 1) & 20 | show_ping "$DN" "gtls " $(bin/doh -q --short --url "gtls" "$DN" | tail -n 1) & 21 | show_ping "$DN" "google " $(bin/doh -q --short --url "google" "$DN" | tail -n 1) & 22 | show_ping "$DN" "twin " $(bin/doh -q --short --config "data/twin.json" "$DN" | tail -n 1) & 23 | show_ping "$DN" "opendns" $(dig +short "$DN" @208.67.222.222 | tail -n 1) & 24 | show_ping "$DN" "one " $(bin/doh -q --short --url "one" "$DN" | tail -n 1) & 25 | show_ping "$DN" "cf " $(bin/doh -q --short --url "cf" "$DN" | tail -n 1) & 26 | show_ping "$DN" "quad9 " $(bin/doh -q --short --url "9tls" "$DN" | tail -n 1) & 27 | show_ping "$DN" "auguard" $(bin/doh -q --short --url "augtls" "$DN" | tail -n 1) & 28 | show_ping "$DN" "nextdns" $(bin/doh -q --short --url "nexttls" "$DN" | tail -n 1) & 29 | wait 30 | done 31 | -------------------------------------------------------------------------------- /data/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAtXxiv5y3G3i+Pb9pgwD+IK1o44tzlkgrOWcpdWTJpWRwQAfs 3 | sMaivMvyQUIEQuyEk2A48KRq40MEo7MFBwV2maNk5UkftCHzShebGbskYUSt85is 4 | DmybZ52AdghDHILumzObFihYos/wzyZkgEq/THeh2cKTNV880b7EpZwdunWOjEEs 5 | PBlBcEONdrgmE0fHEQHgSvMePow/a9zlhqkt0srIA2GAPRBaEWT/LaJi4ln0ypdg 6 | EVYoYCx7dcuxe6eHtuub8lSiuwPNOkV09emcS5x6fFHJH+8yeKsiQidB6kRUpMV8 7 | sYoir3ZXV3ePwOXSqjZyw2hvB6XD2KXPlza2HQIDAQABAoIBAQCe/0JkLKAe6UGC 8 | R1fg9dWuOz5RW7MATmnP+JlRx+MBi2TsNAUhOmUIkoTCt1uUZjIgC4TXDrS2Ndiy 9 | sfwNkrO9FnEmj1G/Np82oke320ScEtdzOqZCXNQpissonURujicMwcF1QBOnUBXg 10 | 5fnWi6XdEFIzvUvKzo0yFLejf4pr92ed3HVVRHnwYGcdZdJ4zXbphJQeBQK9ebmM 11 | xlEGda4dqPmp/yp6gbAXmfHi61rwgbmBmJ8D213FUIkkT3x8GpFtQ8KjqQdfSO+P 12 | bRbckfqU3rFdbk+aknEm2XFWBQf0Ok2tfow/f8KkVe/jr1rSf+0VBr8XAgxI/rBc 13 | QILOPPrhAoGBAONCQLINlmX9mQgT+TG49S7dSdYWV4mj4nf8ALtrID7alUw2vU+q 14 | GDzZW6hJwUD2yjblan7goD8kcr3IPhlnXxssVmGBneYHUdA4biHRS7u+Nm67wZVP 15 | ANAN5IgAJSKmiPvQdwPU5dcgxsuuCBBIZd2R+oR0XXgMgiYHLZ1XLxDvAoGBAMxw 16 | L4v5Gxkib1j8rGgthaOMqb83dM3p+OX6C1RRpruXMSKKgaRHS60amZ2sI+pUcdd9 17 | uWotRpRNGqluhbUiRQK/ELdtxcawIH9gqmOLKatyEfHx3CfvK3g9trFyBtbr1QVB 18 | r6DI5g9me85SJ9g1SUcl6gPvOr9JkCcY1x31shGzAoGALON8Re87IuAppxfS5Ahl 19 | naEmIXx+Q/i0FgEX3+00DFY+oTQ6xo6RhQtl+GLBImTc4mUEWRVjcbVwWJ5B7eCm 20 | P4bNdSsWFkah2WAcGN/vdqEGvW6muShGv9HOrzJgI20Dp8GwkHgwAgM+YSL6AsVa 21 | IZ7g/eLCR6Eo3/wQ/YAoEs8CgYB9+zwxo6bBTGkVi0+rOzI5YPtR7Ji8M8y/2+CT 22 | a2W2ACu1P2k4lP7bg6LaeTQAuV0WEFHsTk5KIWGmu4cF4kJouNlSUAEquWqtVCJs 23 | CVv6XOcWE5c5vLcq98zXeI8ibl3tSVczW9n574unzxTitaOcho65Mfkf2/NLRJF7 24 | 0uaS5QKBgG3SG8np0p8KYZ8OW+/yE/XvEf/DpdOOWwiqjVu1fGMw0LJ/XPODlEQ2 25 | tfGeFQlptYbwCKwvR7SZhQOSymNM6+FW/y8AAIs+0lDocAhFJ6OmWskDyaubvZGH 26 | 0x7sna3+KNRAenNL34aKfQ2TWf1ekOagUaoiS3LWv+/JImwgnC5/ 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /drivers/twin.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | 8 | "github.com/miekg/dns" 9 | "github.com/shell909090/doh/iplist" 10 | ) 11 | 12 | type TwinClient struct { 13 | Primary json.RawMessage 14 | primary_cli Client 15 | Secondary json.RawMessage 16 | secondary_cli Client 17 | DirectRoutes string `json:"direct-routes"` 18 | dir_routes *iplist.IPList 19 | } 20 | 21 | func NewTwinClient(URL string, body json.RawMessage) (cli *TwinClient) { 22 | var err error 23 | cli = &TwinClient{} 24 | if body != nil { 25 | err = json.Unmarshal(body, &cli) 26 | if err != nil { 27 | panic(err.Error()) 28 | } 29 | } 30 | 31 | var header DriverHeader 32 | err = json.Unmarshal(cli.Primary, &header) 33 | if err != nil { 34 | panic(err.Error()) 35 | } 36 | cli.primary_cli = header.CreateClient(cli.Primary) 37 | logger.Debugf("primary: %+v", cli.primary_cli) 38 | 39 | err = json.Unmarshal(cli.Secondary, &header) 40 | if err != nil { 41 | panic(err.Error()) 42 | } 43 | cli.secondary_cli = header.CreateClient(cli.Secondary) 44 | logger.Debugf("secondary: %+v", cli.secondary_cli) 45 | 46 | cli.dir_routes, err = iplist.ReadIPListFile(cli.DirectRoutes) 47 | if err != nil { 48 | panic(err.Error()) 49 | } 50 | 51 | return 52 | } 53 | 54 | func (cli *TwinClient) Url() (u string) { 55 | return fmt.Sprintf("%s+%s", cli.primary_cli.Url(), cli.secondary_cli.Url()) 56 | } 57 | 58 | func (cli *TwinClient) Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) { 59 | ans, err = cli.primary_cli.Exchange(ctx, quiz) 60 | if err != nil { 61 | return 62 | } 63 | 64 | is_secondary := true 65 | for _, rr := range ans.Answer { 66 | switch v := rr.(type) { 67 | case *dns.A: 68 | if cli.dir_routes.Contain(v.A) { 69 | is_secondary = false 70 | break 71 | } 72 | } 73 | } 74 | 75 | if is_secondary { 76 | logger.Debugf("secondary query") 77 | ans, err = cli.secondary_cli.Exchange(ctx, quiz) 78 | } 79 | 80 | return 81 | } 82 | -------------------------------------------------------------------------------- /data/public.csv: -------------------------------------------------------------------------------- 1 | 114,tcp,tcp://114.114.114.114/ 2 | 114,udp,udp://114.114.114.114/ 3 | adguard,rfc8484,https://dns.adguard.com/dns-query 4 | adguard,tcp,tcp://176.103.130.130/ 5 | adguard,tls,tcp-tls://dns.adguard.com/ 6 | adguard,udp,udp://176.103.130.130/ 7 | alidns,rfc8484,https://dns.alidns.com/dns-query 8 | alidns,tcp,tcp://223.5.5.5/ 9 | alidns,tls,tcp-tls://223.5.5.5/ 10 | alidns,udp,udp://223.5.5.5/ 11 | baidu,udp,udp://180.76.76.76/ 12 | cloudflare,rfc8484,https://security.cloudflare-dns.com/dns-query 13 | cloudflare,tcp,tcp://1.1.1.1/ 14 | cloudflare,tls,tcp-tls://one.one.one.one/ 15 | cloudflare,udp,udp://1.1.1.1/ 16 | cnnic,udp,udp://1.2.4.8/ 17 | comodo,tcp,tcp://8.26.56.26/ 18 | comodo,udp,udp://8.26.56.26/ 19 | containerpi,google,https://dns.containerpi.com/dns-query 20 | containerpi,rfc8484,https://dns.containerpi.com/dns-query 21 | containerpi,tls,tcp-tls://dns.containerpi.com/ 22 | dnslify,rfc8484,https://doh.dnslify.com/dns-query 23 | dnslify,tcp,tcp://185.235.81.1/ 24 | dnslify,udp,udp://185.235.81.1/ 25 | dnspai,udp,udp://101.226.4.6/ 26 | dnspod,tcp,tcp://119.29.29.29/ 27 | dnspod,udp,udp://119.29.29.29/ 28 | dns-watch,tcp,tcp://84.200.69.80/ 29 | dns-watch,udp,udp://84.200.69.80/ 30 | doh.li,rfc8484,https://doh.li/dns-query 31 | doh.li,tls,tcp-tls://doh.li/ 32 | dyn,tcp,tcp://216.146.35.35/ 33 | dyn,udp,udp://216.146.35.35/ 34 | freedns,udp,udp://37.235.1.174/ 35 | freenom,tcp,tcp://80.80.80.80/ 36 | freenom,udp,udp://80.80.80.80/ 37 | google,google,https://dns.google/resolve 38 | google,rfc8484,https://dns.google/dns-query 39 | google,tcp,tcp://8.8.8.8/ 40 | google,tls,tcp-tls://8.8.8.8/ 41 | google,udp,udp://8.8.8.8/ 42 | he,rfc8484,https://ordns.he.net/dns-query 43 | he,tcp,tcp://74.82.42.42/ 44 | he,udp,udp://74.82.42.42/ 45 | neustar,tcp,tcp://156.154.70.1/ 46 | neustar,udp,udp://156.154.70.1/ 47 | nextdns,rfc8484,https://dns.nextdns.io/e83b12 48 | nextdns,tcp,tcp://45.90.28.253/ 49 | nextdns,tls,tcp-tls://76dc6f.dns.nextdns.io/ 50 | nextdns,udp,udp://45.90.28.253/ 51 | onedns,udp,udp://117.50.11.11/ 52 | opendns,rfc8484,https://doh.opendns.com/dns-query 53 | opendns,tcp,tcp://208.67.222.222/ 54 | opendns,udp,udp://208.67.222.222/ 55 | opennic,tcp,tcp://185.121.177.177/ 56 | opennic,udp,udp://185.121.177.177/ 57 | quad9,rfc8484,https://dns.quad9.net/dns-query 58 | quad9,tcp,tcp://9.9.9.9/ 59 | quad9,tls,tcp-tls://dns.quad9.net/ 60 | quad9,udp,udp://9.9.9.9/ 61 | safedns,tcp,tcp://195.46.39.39/ 62 | safedns,udp,udp://195.46.39.39/ 63 | twnic,rfc8484,https://dns.twnic.tw/dns-query 64 | twnic,tcp,tcp://101.101.101.101/ 65 | twnic,tls,tcp-tls://101.101.101.101/ 66 | twnic,udp,udp://101.101.101.101/ 67 | verisign,tcp,tcp://64.6.64.6/ 68 | verisign,udp,udp://64.6.64.6/ 69 | yandex,tcp,tcp://77.88.8.8/ 70 | yandex,udp,udp://77.88.8.8/ 71 | -------------------------------------------------------------------------------- /rrtree/common.go: -------------------------------------------------------------------------------- 1 | package rrtree 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/miekg/dns" 7 | ) 8 | 9 | type ResourceRecord struct { 10 | Name string 11 | Type uint16 12 | // Expire time.Time 13 | RR dns.RR 14 | } 15 | 16 | type Node struct { 17 | Name string 18 | Subs map[string]*Node 19 | Resources map[uint16][]*ResourceRecord 20 | } 21 | 22 | func NewNode(name string) (node *Node) { 23 | node = &Node{ 24 | Name: name, 25 | Subs: make(map[string]*Node, 0), 26 | Resources: make(map[uint16][]*ResourceRecord, 0), 27 | } 28 | return 29 | } 30 | 31 | type RRTree struct { 32 | *Node 33 | } 34 | 35 | func NewRRTree() (tree *RRTree) { 36 | tree = &RRTree{ 37 | Node: NewNode(""), 38 | } 39 | return 40 | } 41 | 42 | func (tree *RRTree) AddRecord(rr dns.RR) { 43 | record := &ResourceRecord{ 44 | Name: rr.Header().Name, 45 | Type: rr.Header().Rrtype, 46 | // Expire: time.Now().Add(time.Duration(rr.Header().Ttl) * time.Second), 47 | RR: rr, 48 | } 49 | 50 | labels := dns.SplitDomainName(record.Name) 51 | fmt.Println(labels) 52 | 53 | node := tree.Node 54 | for i := len(labels) - 1; i >= 0; i-- { 55 | sub, ok := node.Subs[labels[i]] 56 | if !ok { 57 | sub = NewNode(labels[i]) 58 | node.Subs[labels[i]] = sub 59 | } 60 | node = sub 61 | } 62 | 63 | node.Resources[record.Type] = append(node.Resources[record.Type], record) 64 | return 65 | } 66 | 67 | func (tree *RRTree) GetNode(name string) (node *Node, partial bool) { 68 | labels := dns.SplitDomainName(name) 69 | fmt.Println(labels) 70 | 71 | node = tree.Node 72 | for i := len(labels) - 1; i >= 0; i-- { 73 | sub, ok := node.Subs[labels[i]] 74 | if !ok { 75 | partial = true 76 | return 77 | } 78 | node = sub 79 | } 80 | 81 | return 82 | } 83 | 84 | var DefaultTree *RRTree = NewRRTree() 85 | 86 | var ( 87 | ROOTDNS = []string{ 88 | "a.root-servers.net. 300 IN A 198.41.0.4", 89 | "b.root-servers.net. 300 IN A 199.9.14.201", 90 | "c.root-servers.net. 300 IN A 192.33.4.12", 91 | "d.root-servers.net. 300 IN A 199.7.91.13", 92 | "e.root-servers.net. 300 IN A 192.203.230.10", 93 | "f.root-servers.net. 300 IN A 192.5.5.241", 94 | "g.root-servers.net. 300 IN A 192.112.36.4", 95 | "h.root-servers.net. 300 IN A 198.97.190.53", 96 | "i.root-servers.net. 300 IN A 192.36.148.17", 97 | "j.root-servers.net. 300 IN A 192.58.128.30", 98 | "k.root-servers.net. 300 IN A 193.0.14.129", 99 | "l.root-servers.net. 300 IN A 199.7.83.42", 100 | "m.root-servers.net. 300 IN A 202.12.27.33", 101 | } 102 | ) 103 | 104 | func init() { 105 | for _, s := range ROOTDNS { 106 | rr, err := dns.NewRR(s) 107 | if err != nil { 108 | panic(err.Error()) 109 | } 110 | DefaultTree.AddRecord(rr) 111 | } 112 | return 113 | } 114 | -------------------------------------------------------------------------------- /doh-aliases.json: -------------------------------------------------------------------------------- 1 | { 2 | "114": "udp://114.114.114.114", 3 | "114t": "tcp://114.114.114.114", 4 | "adguard": "udp://176.103.130.130/", 5 | "adgt": "tcp://176.103.130.130/", 6 | "adgtls": "tcp-tls://dns.adguard.com/", 7 | "adgdoh": "https://dns.adguard.com/dns-query", 8 | "alidns": "udp://223.5.5.5/", 9 | "alidnst": "tcp://223.5.5.5/", 10 | "alitls": "tcp-tls://223.5.5.5/", 11 | "alidoh": "https://dns.alidns.com/dns-query", 12 | "baidu": "udp://180.76.76.76/", 13 | "cf": "udp://1.1.1.1/", 14 | "1111": "udp://1.1.1.1/", 15 | "cft": "tcp://1.1.1.1/", 16 | "cftls": "tcp-tls://one.one.one.one/", 17 | "cfdoh": "https://security.cloudflare-dns.com/dns-query", 18 | "cnnic": "udp://1.2.4.8/", 19 | "comodo": "udp://8.26.56.26/", 20 | "comodot": "tcp://8.26.56.26/", 21 | "cpitls": "tcp-tls://dns.containerpi.com/", 22 | "cpidoh": "https://dns.containerpi.com/dns-query", 23 | "dnslify": "udp://185.235.81.1/", 24 | "dnslifyt": "tcp://185.235.81.1/", 25 | "dnslifydoh": "https://doh.dnslify.com/dns-query", 26 | "dnspai": "udp://101.226.4.6/", 27 | "dnspod": "udp://119.29.29.29/", 28 | "dnspodt": "tcp://119.29.29.29/", 29 | "dnswatch": "udp://84.200.69.80/", 30 | "dnswatcht": "tcp://84.200.69.80/", 31 | "dohlitls": "tcp-tls://doh.li/", 32 | "dohlidoh": "https://doh.li/dns-query", 33 | "dyn": "udp://216.146.35.35/", 34 | "dynt": "tcp://216.146.35.35/", 35 | "freedns": "udp://37.235.1.174/", 36 | "freenom": "udp://80.80.80.80/", 37 | "freenomt": "tcp://80.80.80.80/", 38 | "gdns": "udp://8.8.8.8/", 39 | "8888": "udp://8.8.8.8/", 40 | "gdnst": "tcp://8.8.8.8/", 41 | "gdnstls": "tcp-tls://8.8.8.8/", 42 | "gdoh": "https://dns.google/dns-query", 43 | "google": "https://dns.google/resolve", 44 | "he": "udp://74.82.42.42/", 45 | "het": "tcp://74.82.42.42/", 46 | "hedoh": "https://ordns.he.net/dns-query", 47 | "neustar": "udp://156.154.70.1/", 48 | "neustart": "tcp://156.154.70.1/", 49 | "nextdns": "udp://45.90.28.253/", 50 | "nextdnst": "tcp://45.90.28.253/", 51 | "nexttls": "tcp-tls://76dc6f.dns.nextdns.io/", 52 | "nextdoh": "https://dns.nextdns.io/e83b12", 53 | "onedns": "udp://117.50.11.11/", 54 | "opendns": "udp://208.67.222.222/", 55 | "opendnst": "tcp://208.67.222.222/", 56 | "opendoh": "https://doh.opendns.com/dns-query", 57 | "opennic": "udp://185.121.177.177/", 58 | "opennict": "tcp://185.121.177.177/", 59 | "quad9": "udp://9.9.9.9/", 60 | "9999": "udp://9.9.9.9/", 61 | "quad9t": "tcp://9.9.9.9/", 62 | "quad9tls": "tcp-tls://dns.quad9.net/", 63 | "quad9doh": "https://dns.quad9.net/dns-query", 64 | "safedns": "udp://195.46.39.39/", 65 | "safednst": "tcp://195.46.39.39/", 66 | "twnic": "udp://101.101.101.101/", 67 | "twnict": "tcp://101.101.101.101/", 68 | "twnictls": "tcp-tls://101.101.101.101/", 69 | "twnicdoh": "https://dns.twnic.tw/dns-query", 70 | "verisign": "udp://64.6.64.6/", 71 | "verisignt": "tcp://64.6.64.6/", 72 | "yandex": "udp://77.88.8.8/", 73 | "yandext": "tcp://77.88.8.8/" 74 | } 75 | -------------------------------------------------------------------------------- /doh/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "net/http" 9 | 10 | logging "github.com/op/go-logging" 11 | "github.com/shell909090/doh/drivers" 12 | ) 13 | 14 | const ( 15 | DEFAULT_ALIASES = "doh-aliases.json;~/.doh-aliases.json" 16 | ) 17 | 18 | var ( 19 | ErrConfigParse = errors.New("config parse error") 20 | ErrParameter = errors.New("parameter error") 21 | logger = logging.MustGetLogger("") 22 | Version string = "unknown" 23 | ) 24 | 25 | type Config struct { 26 | Logfile string 27 | Loglevel string 28 | Service json.RawMessage 29 | Client json.RawMessage 30 | } 31 | 32 | func (cfg *Config) CreateClient() (cli drivers.Client) { 33 | var header drivers.DriverHeader 34 | err := json.Unmarshal(cfg.Client, &header) 35 | if err != nil { 36 | panic(err.Error()) 37 | } 38 | cli = header.CreateClient(cfg.Client) 39 | return 40 | } 41 | 42 | func (cfg *Config) CreateService(cli drivers.Client) (srv drivers.Server) { 43 | var header drivers.DriverHeader 44 | err := json.Unmarshal(cfg.Service, &header) 45 | if err != nil { 46 | panic(err.Error()) 47 | } 48 | srv = header.CreateService(cli, cfg.Service) 49 | return 50 | } 51 | 52 | // -i reverse 53 | // trace 54 | 55 | func main() { 56 | var err error 57 | var q Query 58 | var Loglevel string 59 | var ShowVersion bool 60 | var ConfigFile string 61 | var Profile string 62 | var Query bool 63 | flag.BoolVar(&ShowVersion, "version", false, "show version") 64 | flag.StringVar(&Loglevel, "loglevel", "", "log level") 65 | flag.StringVar(&ConfigFile, "config", "", "config file") 66 | flag.StringVar(&Profile, "profile", "", "run profile") 67 | flag.BoolVar(&Query, "q", false, "force do query") 68 | flag.BoolVar(&drivers.Insecure, "insecure", false, "don't check cert in https") 69 | flag.IntVar(&drivers.Timeout, "timeout", 0, "query timeout, in ms.") 70 | q.Parse() 71 | flag.Parse() 72 | 73 | if ShowVersion { 74 | fmt.Printf("version: %s\n", Version) 75 | return 76 | } 77 | 78 | cfg := &Config{} 79 | if ConfigFile != "" { 80 | drivers.LoadJson(ConfigFile, cfg, false) 81 | } 82 | 83 | switch { 84 | case Loglevel != "": 85 | cfg.Loglevel = Loglevel 86 | case cfg.Loglevel != "": 87 | case q.Trace: 88 | cfg.Loglevel = "INFO" 89 | } 90 | drivers.SetLogging(cfg.Logfile, cfg.Loglevel) 91 | 92 | var cli drivers.Client 93 | q.Prepare() 94 | if cfg.Client != nil { 95 | cli = cfg.CreateClient() 96 | } else { 97 | cli = q.CreateClient() 98 | } 99 | if cli == nil { 100 | panic("can't create client") 101 | } 102 | logger.Debugf("%+v", cli) 103 | 104 | switch { 105 | case cfg.Service != nil && !Query: 106 | if Profile != "" { 107 | go func() { 108 | logger.Infof("golang profile %s", Profile) 109 | logger.Infof("golang profile result: %s", 110 | http.ListenAndServe(Profile, nil)) 111 | }() 112 | } 113 | 114 | var srv drivers.Server 115 | srv = cfg.CreateService(cli) 116 | err = srv.Serve() 117 | if err != nil { 118 | logger.Error(err.Error()) 119 | return 120 | } 121 | 122 | default: 123 | q.QueryAll(cli) 124 | } 125 | 126 | return 127 | } 128 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function basic() { 4 | echo "version" 5 | bin/doh -version 6 | echo "resolv.conf" 7 | bin/doh www.baidu.com 8 | echo "short" 9 | bin/doh -short www.baidu.com 10 | echo "json" 11 | bin/doh -json www.baidu.com | jq -r '.Answer[].data' 12 | echo "url" 13 | bin/doh -short -s udp://114.114.114.114 www.baidu.com 14 | echo "tcp" 15 | bin/doh -short -tcp -s 114.114.114.114 www.baidu.com 16 | echo "alias" 17 | bin/doh -short -s 114 www.baidu.com 18 | echo "at server" 19 | bin/doh -short @114 www.baidu.com 20 | echo "retries" 21 | bin/doh -short -tries 3 @114 @114t www.baidu.com 22 | echo "QType" 23 | bin/doh -short -t NS @114 baidu.com 24 | bin/doh -short @114 NS baidu.com 25 | echo "QClass" 26 | bin/doh -short -c IN @114 www.baidu.com 27 | bin/doh -short @114 IN www.baidu.com 28 | echo "timeout" 29 | bin/doh -s 114 -timeout 1 www.baidu.com 30 | echo "query with config" 31 | bin/doh -short -q -config data/twin.json www.baidu.com 32 | } 33 | 34 | function drivers() { 35 | echo "drivers, except google" 36 | bin/doh -short -s 114 www.baidu.com 37 | bin/doh -short -s 114t www.baidu.com 38 | bin/doh -short -s cftls www.baidu.com 39 | bin/doh -short -s cfdoh www.baidu.com 40 | bin/doh -short -s gdnstls www.baidu.com 41 | bin/doh -short -s http://119.29.29.29/d www.baidu.com 42 | } 43 | 44 | function edns() { 45 | bin/doh -short -s alidns www.taobao.com 46 | bin/doh -short -s alidns -subnet 101.80.0.0 www.taobao.com 47 | bin/doh -short -s alidns -subnet 104.244.42.1 www.taobao.com 48 | bin/doh -short -s dnspod www.taobao.com 49 | bin/doh -short -s dnspod -subnet 101.80.0.0 www.taobao.com 50 | bin/doh -short -s dnspod -subnet 104.244.42.1 www.taobao.com 51 | } 52 | 53 | function rfc8484() { 54 | bin/doh -config data/rfc8484.json & 55 | sleep 1 56 | bin/doh -short -s udp://127.0.0.1:5053 www.taobao.com 57 | killall doh 58 | } 59 | 60 | function google() { 61 | bin/doh -config data/google.json & 62 | sleep 1 63 | bin/doh -short -s udp://127.0.0.1:5153 www.taobao.com 64 | killall doh 65 | } 66 | 67 | function dnspod() { 68 | bin/doh -config data/dnspod.json & 69 | sleep 1 70 | bin/doh -short -s udp://127.0.0.1:5253 www.taobao.com 71 | killall doh 72 | } 73 | 74 | function http() { 75 | bin/doh -config data/http.json & 76 | sleep 1 77 | bin/doh -short -s http://localhost:8053/dns-query www.baidu.com 78 | bin/doh -short -s http://localhost:8053/resolve www.baidu.com 79 | bin/doh -short -s http://localhost:8053/d www.baidu.com 80 | curl -s "http://localhost:8053/resolve?name=www.baidu.com" | jq -r '.Answer[].data' 81 | curl -s "http://localhost:8053/d?dn=www.baidu.com&ttl=1" 82 | echo "" 83 | killall doh 84 | } 85 | 86 | function https() { 87 | bin/doh -config data/https.json & 88 | sleep 1 89 | bin/doh -short -s https://localhost:8153/dns-query -insecure www.baidu.com 90 | bin/doh -short -s https://localhost:8153/resolve -insecure www.baidu.com 91 | curl -s -k "https://localhost:8153/resolve?name=www.baidu.com" | jq -r '.Answer[].data' 92 | curl -s -k "https://localhost:8153/d?dn=www.baidu.com&ttl=1" 93 | echo "" 94 | killall doh 95 | } 96 | 97 | $@ 98 | -------------------------------------------------------------------------------- /iplist/iplist.go: -------------------------------------------------------------------------------- 1 | package iplist 2 | 3 | import ( 4 | "bufio" 5 | "compress/gzip" 6 | "encoding/binary" 7 | "io" 8 | "net" 9 | "os" 10 | "strings" 11 | 12 | logging "github.com/op/go-logging" 13 | ) 14 | 15 | var ( 16 | logger = logging.MustGetLogger("iplist") 17 | ) 18 | 19 | type IPList struct { 20 | rest []*net.IPNet 21 | idx1 map[byte][]*net.IPNet 22 | idx2 map[uint16][]*net.IPNet 23 | } 24 | 25 | func ListConatins(iplist []*net.IPNet, ip net.IP) bool { 26 | for _, ipnet := range iplist { 27 | if ipnet.Contains(ip) { 28 | logger.Debugf("%s matched %s.", ip.String(), ipnet.String()) 29 | return true 30 | } 31 | } 32 | return false 33 | } 34 | 35 | func (f *IPList) Contain(ip net.IP) bool { 36 | if x := ip.To4(); x != nil { 37 | ip = x 38 | } 39 | 40 | prefix2 := binary.BigEndian.Uint16(ip[:2]) 41 | if iplist, ok := f.idx2[prefix2]; ok { 42 | if ListConatins(iplist, ip) { 43 | return true 44 | } 45 | } 46 | 47 | prefix1 := ip[0] 48 | if iplist, ok := f.idx1[prefix1]; ok { 49 | if ListConatins(iplist, ip) { 50 | return true 51 | } 52 | } 53 | 54 | if ListConatins(f.rest, ip) { 55 | return true 56 | } 57 | 58 | logger.Debugf("%s not match anything.", ip.String()) 59 | return false 60 | } 61 | 62 | func ParseLine(line string) (ipnet *net.IPNet, err error) { 63 | _, ipnet, err = net.ParseCIDR(line) 64 | if err == nil { 65 | return 66 | } 67 | err = nil 68 | 69 | addrs := strings.Split(line, " ") 70 | 71 | ip := net.ParseIP(addrs[0]) 72 | if x := ip.To4(); x != nil { 73 | ip = x 74 | } 75 | 76 | mask := net.ParseIP(addrs[1]) 77 | if x := mask.To4(); x != nil { 78 | mask = x 79 | } 80 | 81 | ipnet = &net.IPNet{IP: ip, Mask: net.IPMask(mask)} 82 | return 83 | } 84 | 85 | func ReadIPList(f io.Reader) (filter *IPList, err error) { 86 | reader := bufio.NewReader(f) 87 | filter = &IPList{ 88 | idx1: make(map[byte][]*net.IPNet), 89 | idx2: make(map[uint16][]*net.IPNet), 90 | } 91 | counter := 0 92 | 93 | var ipnet *net.IPNet 94 | QUIT: 95 | for { 96 | line, err := reader.ReadString('\n') 97 | switch err { 98 | case io.EOF: 99 | if len(line) == 0 { 100 | break QUIT 101 | } 102 | case nil: 103 | default: 104 | logger.Error(err.Error()) 105 | return nil, err 106 | } 107 | line = strings.Trim(line, "\r\n ") 108 | 109 | ipnet, err = ParseLine(line) 110 | if err != nil { 111 | logger.Error(err.Error()) 112 | return nil, err 113 | } 114 | 115 | ones, _ := ipnet.Mask.Size() 116 | switch { 117 | case ones < 8: 118 | filter.rest = append(filter.rest, ipnet) 119 | case ones >= 8 && ones < 16: 120 | prefix := ipnet.IP[0] 121 | filter.idx1[prefix] = append(filter.idx1[prefix], ipnet) 122 | default: 123 | prefix := binary.BigEndian.Uint16(ipnet.IP[:2]) 124 | filter.idx2[prefix] = append(filter.idx2[prefix], ipnet) 125 | } 126 | counter++ 127 | } 128 | 129 | logger.Infof( 130 | "blacklist loaded %d record(s), %d index1, %d index2 and %d no indexed.", 131 | counter, len(filter.idx1), len(filter.idx2), len(filter.rest)) 132 | return 133 | } 134 | 135 | func ReadIPListFile(filename string) (filter *IPList, err error) { 136 | logger.Infof("load iplist from file %s.", filename) 137 | 138 | var f io.ReadCloser 139 | f, err = os.Open(filename) 140 | if err != nil { 141 | logger.Error(err.Error()) 142 | return 143 | } 144 | defer f.Close() 145 | 146 | if strings.HasSuffix(filename, ".gz") { 147 | f, err = gzip.NewReader(f) 148 | if err != nil { 149 | logger.Error(err.Error()) 150 | return 151 | } 152 | } 153 | 154 | return ReadIPList(f) 155 | } 156 | -------------------------------------------------------------------------------- /drivers/godns.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "encoding/json" 7 | "fmt" 8 | "net" 9 | "net/url" 10 | "time" 11 | 12 | "github.com/miekg/dns" 13 | ) 14 | 15 | type DnsClient struct { 16 | URL string 17 | Timeout int 18 | host string 19 | cli *dns.Client 20 | } 21 | 22 | func NewDnsClient(URL string, body json.RawMessage) (cli *DnsClient) { 23 | cli = &DnsClient{} 24 | if body != nil { 25 | err := json.Unmarshal(body, &cli) 26 | if err != nil { 27 | panic(err.Error()) 28 | } 29 | } 30 | cli.URL = URL 31 | 32 | if Timeout != 0 { 33 | cli.Timeout = Timeout 34 | } 35 | 36 | u, err := url.Parse(URL) 37 | if err != nil { 38 | panic(err.Error()) 39 | } 40 | GuessPort(u) 41 | 42 | cli.host = u.Host 43 | cli.cli = &dns.Client{ 44 | Net: u.Scheme, 45 | } 46 | 47 | if cli.Timeout != 0 { 48 | cli.cli.Timeout = time.Duration(cli.Timeout) * time.Millisecond 49 | } 50 | 51 | return 52 | } 53 | 54 | func (cli *DnsClient) Url() (u string) { 55 | return cli.URL 56 | } 57 | 58 | func (cli *DnsClient) Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) { 59 | ans, _, err = cli.cli.ExchangeContext(ctx, quiz, cli.host) 60 | return 61 | } 62 | 63 | type DnsServer struct { 64 | EdnsClientSubnet string `json:"edns-client-subnet"` 65 | CertFile string 66 | CertKeyFile string 67 | net string 68 | addr string 69 | cert *tls.Certificate 70 | cli Client 71 | } 72 | 73 | func NewDnsServer(cli Client, URL string, body json.RawMessage) (srv *DnsServer) { 74 | u, err := url.Parse(URL) 75 | if err != nil { 76 | panic(err.Error()) 77 | } 78 | 79 | GuessPort(u) 80 | 81 | srv = &DnsServer{ 82 | net: u.Scheme, 83 | addr: u.Host, 84 | cli: cli, 85 | } 86 | 87 | if body != nil { 88 | err = json.Unmarshal(body, &srv) 89 | if err != nil { 90 | logger.Error(err.Error()) 91 | return 92 | } 93 | } 94 | 95 | if srv.CertFile != "" && srv.CertKeyFile != "" { 96 | var cert tls.Certificate 97 | cert, err = tls.LoadX509KeyPair(srv.CertFile, srv.CertKeyFile) 98 | if err != nil { 99 | panic(err.Error) 100 | } 101 | srv.cert = &cert 102 | } 103 | 104 | return 105 | } 106 | 107 | func (srv *DnsServer) ServeDNS(w dns.ResponseWriter, quiz *dns.Msg) { 108 | logger.Infof("dns server query: %s", quiz.Question[0].Name) 109 | 110 | var addr net.IP 111 | var mask uint8 112 | var err error 113 | switch srv.EdnsClientSubnet { 114 | case "": 115 | case "client": 116 | raddr := w.RemoteAddr() 117 | switch taddr := raddr.(type) { 118 | case *net.TCPAddr: 119 | addr = taddr.IP 120 | case *net.UDPAddr: 121 | addr = taddr.IP 122 | default: 123 | panic(fmt.Sprintf("unknown addr %s", raddr.Network())) 124 | } 125 | mask = 32 126 | AppendEdns0Subnet(quiz, addr, mask) 127 | 128 | default: 129 | addr, mask, err = ParseSubnet(srv.EdnsClientSubnet) 130 | if err != nil { 131 | panic(err.Error()) 132 | } 133 | AppendEdns0Subnet(quiz, addr, mask) 134 | } 135 | 136 | ctx := context.Background() 137 | ans, err := srv.cli.Exchange(ctx, quiz) 138 | if err != nil { 139 | // FIXME: google dns not 2xx or 3xx 140 | logger.Error(err.Error()) 141 | return 142 | } 143 | if ans == nil { 144 | logger.Error("response is nil.") 145 | return 146 | } 147 | 148 | err = w.WriteMsg(ans) 149 | if err != nil { 150 | logger.Error(err.Error()) 151 | return 152 | } 153 | 154 | return 155 | } 156 | 157 | func (srv *DnsServer) Serve() (err error) { 158 | server := &dns.Server{ 159 | Net: srv.net, 160 | Addr: srv.addr, 161 | Handler: srv, 162 | } 163 | if srv.cert != nil { 164 | server.TLSConfig = &tls.Config{ 165 | Certificates: []tls.Certificate{*srv.cert}, 166 | } 167 | } 168 | 169 | logger.Infof("dns server start. listen in %s://%s", srv.net, srv.addr) 170 | err = server.ListenAndServe() 171 | return 172 | } 173 | -------------------------------------------------------------------------------- /drivers/dnspod.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "net" 10 | "net/http" 11 | "strconv" 12 | "strings" 13 | 14 | "github.com/miekg/dns" 15 | ) 16 | 17 | type DnsPodClient struct { 18 | URL string 19 | transport *http.Transport 20 | } 21 | 22 | func NewDnsPodClient(URL string, body json.RawMessage) (cli *DnsPodClient) { 23 | cli = &DnsPodClient{} 24 | if body != nil { 25 | err := json.Unmarshal(body, &cli) 26 | if err != nil { 27 | panic(err.Error()) 28 | } 29 | } 30 | 31 | cli.URL = URL 32 | cli.transport = &http.Transport{ 33 | Proxy: http.ProxyFromEnvironment, 34 | } 35 | return 36 | } 37 | 38 | func (cli *DnsPodClient) Url() (u string) { 39 | return cli.URL 40 | } 41 | 42 | func (cli *DnsPodClient) Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) { 43 | if quiz.Question[0].Qtype != dns.TypeA { 44 | return nil, ErrBadQtype 45 | } 46 | 47 | req, err := http.NewRequestWithContext(ctx, "GET", cli.URL, nil) 48 | if err != nil { 49 | logger.Error(err.Error()) 50 | return 51 | } 52 | 53 | query := req.URL.Query() 54 | query.Add("dn", quiz.Question[0].Name) 55 | query.Add("ttl", "1") 56 | 57 | opt := quiz.IsEdns0() 58 | if opt != nil { 59 | for _, o := range opt.Option { 60 | if e, ok := o.(*dns.EDNS0_SUBNET); ok { 61 | query.Add("ip", e.Address.String()) 62 | break 63 | } 64 | } 65 | } 66 | 67 | req.URL.RawQuery = query.Encode() 68 | 69 | resp, err := cli.transport.RoundTrip(req) 70 | if err != nil { 71 | logger.Error(err.Error()) 72 | return 73 | } 74 | defer resp.Body.Close() 75 | 76 | if resp.StatusCode < 200 || resp.StatusCode >= 300 { 77 | err = ErrRequest 78 | return 79 | } 80 | 81 | bresp, err := ioutil.ReadAll(resp.Body) 82 | if err != nil { 83 | logger.Error(err.Error()) 84 | return 85 | } 86 | sresp := string(bresp) 87 | 88 | ans = &dns.Msg{ 89 | MsgHdr: dns.MsgHdr{ 90 | Id: quiz.Id, 91 | Response: true, 92 | Opcode: dns.OpcodeQuery, 93 | Rcode: dns.RcodeSuccess, 94 | }, 95 | Compress: quiz.Compress, 96 | Question: quiz.Question, 97 | } 98 | 99 | for _, rec := range strings.Split(sresp, ";") { 100 | var n int = 0 101 | if strings.Contains(rec, ",") { 102 | r := strings.SplitN(rec, ",", 2) 103 | n, err = strconv.Atoi(r[1]) 104 | if err != nil { 105 | logger.Error(err.Error()) 106 | return 107 | } 108 | rec = r[0] 109 | } 110 | rr := &dns.A{ 111 | Hdr: dns.RR_Header{ 112 | Name: quiz.Question[0].Name, 113 | Rrtype: dns.TypeA, 114 | Class: quiz.Question[0].Qclass, 115 | Ttl: uint32(n), 116 | }, 117 | A: net.ParseIP(rec), 118 | } 119 | ans.Answer = append(ans.Answer, rr) 120 | } 121 | 122 | if opt != nil { 123 | ans.Extra = append(ans.Extra, opt) 124 | } 125 | 126 | return 127 | } 128 | 129 | type DnsPodHandler struct { 130 | EdnsClientSubnet string 131 | cli Client 132 | } 133 | 134 | func NewDnsPodHandler(cli Client, EdnsClientSubnet string) (handler *DnsPodHandler) { 135 | handler = &DnsPodHandler{ 136 | EdnsClientSubnet: EdnsClientSubnet, 137 | cli: cli, 138 | } 139 | return 140 | } 141 | 142 | func (handler *DnsPodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 143 | defer req.Body.Close() 144 | 145 | err := req.ParseForm() 146 | if err != nil { 147 | logger.Error(err.Error()) 148 | w.WriteHeader(http.StatusBadRequest) 149 | return 150 | } 151 | 152 | quiz := &dns.Msg{} 153 | name := req.Form.Get("dn") 154 | quiz.SetQuestion(dns.Fqdn(name), dns.TypeA) 155 | quiz.SetEdns0(4096, true) 156 | 157 | ecs := req.Form.Get("ip") 158 | err = HttpSetEdns0Subnet(w, req, ecs, handler.EdnsClientSubnet, quiz) 159 | if err != nil { 160 | return 161 | } 162 | 163 | logger.Infof("dnspod server query: %s", quiz.Question[0].Name) 164 | 165 | ctx := context.Background() 166 | ans, err := handler.cli.Exchange(ctx, quiz) 167 | if err != nil { 168 | logger.Error(err.Error()) 169 | w.WriteHeader(http.StatusBadGateway) 170 | return 171 | } 172 | 173 | isttl := req.Form.Get("ttl") 174 | var secs []string 175 | for _, rr := range ans.Answer { 176 | switch v := rr.(type) { 177 | case *dns.A: 178 | if isttl == "" { 179 | secs = append(secs, v.A.String()) 180 | } else { 181 | secs = append(secs, fmt.Sprintf("%s,%d", v.A.String(), v.Hdr.Ttl)) 182 | } 183 | } 184 | } 185 | 186 | w.WriteHeader(http.StatusOK) 187 | io.WriteString(w, strings.Join(secs, ";")) 188 | return 189 | } 190 | -------------------------------------------------------------------------------- /iplist/iplist_test.go: -------------------------------------------------------------------------------- 1 | package iplist 2 | 3 | import ( 4 | "bytes" 5 | crand "crypto/rand" 6 | "fmt" 7 | "io" 8 | "math/rand" 9 | "net" 10 | "os" 11 | "testing" 12 | 13 | logging "github.com/op/go-logging" 14 | ) 15 | 16 | const ( 17 | IPLIST = "10.0.0.0 255.0.0.0\n172.16.0.0 255.240.0.0\n192.168.0.0 255.255.0.0" 18 | ) 19 | 20 | func SetLogging(logfile, loglevel string) (err error) { 21 | var file *os.File 22 | file = os.Stdout 23 | 24 | if loglevel == "" { 25 | loglevel = "WARNING" 26 | } 27 | if logfile != "" { 28 | file, err = os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) 29 | if err != nil { 30 | panic(err.Error()) 31 | } 32 | } 33 | logging.SetBackend(logging.NewLogBackend(file, "", 0)) 34 | logging.SetFormatter(logging.MustStringFormatter( 35 | "%{time:01-02 15:04:05.000}[%{level}] %{shortpkg}/%{shortfile}: %{message}")) 36 | lv, err := logging.LogLevel(loglevel) 37 | if err != nil { 38 | panic(err.Error()) 39 | } 40 | logging.SetLevel(lv, "") 41 | return 42 | } 43 | 44 | func init() { 45 | SetLogging("", "ERROR") 46 | } 47 | 48 | func genIP() (ip net.IP) { 49 | buf := make([]byte, 4) 50 | _, err := io.ReadFull(crand.Reader, buf) 51 | if err != nil { 52 | panic("no rand.") 53 | } 54 | return net.IP(buf) 55 | } 56 | 57 | func genMask() (mask net.IPMask, n int) { 58 | n = 1 + rand.Intn(31) 59 | mask = net.CIDRMask(n, 32) 60 | return 61 | } 62 | 63 | func TestReadIPList(t *testing.T) { 64 | var buf bytes.Buffer 65 | 66 | for i := 0; i < 100; i++ { 67 | mask, _ := genMask() 68 | fmt.Fprintf(&buf, "%s %s\n", genIP().String(), net.IP(mask).String()) 69 | } 70 | 71 | _, err := ReadIPList(&buf) 72 | if err != nil { 73 | t.Error(err) 74 | return 75 | } 76 | return 77 | } 78 | 79 | func BenchmarkReadIPList(b *testing.B) { 80 | var buf bytes.Buffer 81 | 82 | for i := 0; i < b.N; i++ { 83 | mask, _ := genMask() 84 | fmt.Fprintf(&buf, "%s %s\n", genIP().String(), net.IP(mask).String()) 85 | } 86 | b.ResetTimer() 87 | 88 | _, err := ReadIPList(&buf) 89 | if err != nil { 90 | b.Error(err) 91 | return 92 | } 93 | return 94 | } 95 | 96 | func TestReadIPListCIDR(t *testing.T) { 97 | var buf bytes.Buffer 98 | 99 | for i := 0; i < 100; i++ { 100 | _, n := genMask() 101 | fmt.Fprintf(&buf, "%s/%d\n", genIP().String(), n) 102 | } 103 | 104 | _, err := ReadIPList(&buf) 105 | if err != nil { 106 | t.Error(err) 107 | return 108 | } 109 | return 110 | } 111 | 112 | func BenchmarkReadIPListCIDR(b *testing.B) { 113 | var buf bytes.Buffer 114 | 115 | for i := 0; i < b.N; i++ { 116 | _, n := genMask() 117 | fmt.Fprintf(&buf, "%s/%d\n", genIP().String(), n) 118 | } 119 | b.ResetTimer() 120 | 121 | _, err := ReadIPList(&buf) 122 | if err != nil { 123 | b.Error(err) 124 | return 125 | } 126 | return 127 | } 128 | 129 | func TestIPList(t *testing.T) { 130 | buf := bytes.NewBufferString(IPLIST) 131 | filter, err := ReadIPList(buf) 132 | if err != nil { 133 | t.Fatalf("ReadIPList failed: %s", err) 134 | } 135 | 136 | if !filter.Contain(net.ParseIP("192.168.1.1")) { 137 | t.Fatalf("Contain wrong1.") 138 | } 139 | 140 | if !filter.Contain(net.ParseIP("10.8.0.1")) { 141 | t.Fatalf("Contain wrong2.") 142 | } 143 | 144 | if filter.Contain(net.ParseIP("211.80.90.25")) { 145 | t.Fatalf("Contain wrong3.") 146 | } 147 | } 148 | 149 | func BenchmarkIPList(b *testing.B) { 150 | var buf bytes.Buffer 151 | 152 | for i := 0; i < b.N/1000; i++ { 153 | _, n := genMask() 154 | fmt.Fprintf(&buf, "%s/%d\n", genIP().String(), n) 155 | } 156 | 157 | filter, err := ReadIPList(&buf) 158 | if err != nil { 159 | b.Error(err) 160 | return 161 | } 162 | ip := genIP() 163 | b.ResetTimer() 164 | 165 | for i := 0; i < b.N; i++ { 166 | filter.Contain(ip) 167 | } 168 | return 169 | } 170 | 171 | func BenchmarkIPListBig(b *testing.B) { 172 | var buf bytes.Buffer 173 | 174 | for i := 0; i < b.N; i++ { 175 | _, n := genMask() 176 | fmt.Fprintf(&buf, "%s/%d\n", genIP().String(), n) 177 | } 178 | 179 | filter, err := ReadIPList(&buf) 180 | if err != nil { 181 | b.Error(err) 182 | return 183 | } 184 | ip := genIP() 185 | b.ResetTimer() 186 | 187 | for i := 0; i < b.N; i++ { 188 | filter.Contain(ip) 189 | } 190 | return 191 | } 192 | 193 | func BenchmarkIPListRand(b *testing.B) { 194 | var buf bytes.Buffer 195 | 196 | for i := 0; i < b.N/1000; i++ { 197 | _, n := genMask() 198 | fmt.Fprintf(&buf, "%s/%d\n", genIP().String(), n) 199 | } 200 | 201 | filter, err := ReadIPList(&buf) 202 | if err != nil { 203 | b.Error(err) 204 | return 205 | } 206 | b.ResetTimer() 207 | 208 | for i := 0; i < b.N; i++ { 209 | filter.Contain(genIP()) 210 | } 211 | return 212 | } 213 | -------------------------------------------------------------------------------- /drivers/rfc8484.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/tls" 7 | "encoding/base64" 8 | "encoding/json" 9 | "io" 10 | "io/ioutil" 11 | "net/http" 12 | "time" 13 | 14 | "github.com/miekg/dns" 15 | ) 16 | 17 | func WriteFull(w io.Writer, b []byte) (err error) { 18 | n, err := w.Write(b) 19 | if err != nil { 20 | return 21 | } 22 | if n != len(b) { 23 | return io.ErrShortWrite 24 | } 25 | return 26 | } 27 | 28 | type Rfc8484Client struct { 29 | URL string 30 | Insecure bool 31 | Timeout int 32 | transport *http.Transport 33 | } 34 | 35 | func NewRfc8484Client(URL string, body json.RawMessage) (cli *Rfc8484Client) { 36 | cli = &Rfc8484Client{} 37 | if body != nil { 38 | err := json.Unmarshal(body, &cli) 39 | if err != nil { 40 | panic(err.Error()) 41 | } 42 | } 43 | cli.URL = URL 44 | 45 | if Insecure { 46 | cli.Insecure = Insecure 47 | } 48 | if Timeout != 0 { 49 | cli.Timeout = Timeout 50 | } 51 | 52 | cli.transport = &http.Transport{ 53 | Proxy: http.ProxyFromEnvironment, 54 | } 55 | if cli.Insecure { 56 | cli.transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} 57 | } 58 | 59 | return 60 | } 61 | 62 | func (cli *Rfc8484Client) Url() (u string) { 63 | return cli.URL 64 | } 65 | func (cli *Rfc8484Client) Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) { 66 | bquiz, err := quiz.Pack() 67 | if err != nil { 68 | logger.Error(err.Error()) 69 | return 70 | } 71 | 72 | if cli.Timeout != 0 { 73 | ctx, _ = context.WithTimeout(ctx, time.Duration(cli.Timeout)*time.Millisecond) 74 | } 75 | 76 | req, err := http.NewRequestWithContext(ctx, "POST", cli.URL, bytes.NewBuffer(bquiz)) 77 | if err != nil { 78 | logger.Error(err.Error()) 79 | return 80 | } 81 | req.Header.Add("Accept", "application/dns-message") 82 | req.Header.Add("Content-Type", "application/dns-message") 83 | 84 | resp, err := cli.transport.RoundTrip(req) 85 | if err != nil { 86 | logger.Error(err.Error()) 87 | return 88 | } 89 | defer resp.Body.Close() 90 | 91 | if resp.StatusCode < 200 || resp.StatusCode >= 300 { 92 | err = ErrRequest 93 | return 94 | } 95 | 96 | bbody, err := ioutil.ReadAll(resp.Body) 97 | if err != nil { 98 | logger.Error(err.Error()) 99 | return 100 | } 101 | 102 | ans = &dns.Msg{} 103 | err = ans.Unpack(bbody) 104 | if err != nil { 105 | logger.Error(err.Error()) 106 | return 107 | } 108 | 109 | return 110 | } 111 | 112 | type Rfc8484Handler struct { 113 | EdnsClientSubnet string 114 | cli Client 115 | } 116 | 117 | func NewRfc8484Handler(cli Client, EdnsClientSubnet string) (handler *Rfc8484Handler) { 118 | handler = &Rfc8484Handler{ 119 | EdnsClientSubnet: EdnsClientSubnet, 120 | cli: cli, 121 | } 122 | return 123 | } 124 | 125 | func (handler *Rfc8484Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 126 | var err error 127 | defer req.Body.Close() 128 | 129 | var bdns []byte 130 | switch req.Method { 131 | case "GET": 132 | err = req.ParseForm() 133 | if err != nil { 134 | logger.Error(err.Error()) 135 | w.WriteHeader(http.StatusBadRequest) 136 | return 137 | } 138 | 139 | b64dns := req.Form.Get("dns") 140 | bdns, err = base64.StdEncoding.DecodeString(b64dns) 141 | if err != nil { 142 | logger.Error(err.Error()) 143 | w.WriteHeader(http.StatusBadRequest) 144 | return 145 | } 146 | 147 | case "POST": 148 | bdns, err = ioutil.ReadAll(req.Body) 149 | if err != nil { 150 | logger.Error(err.Error()) 151 | w.WriteHeader(http.StatusBadRequest) 152 | return 153 | } 154 | 155 | default: 156 | w.WriteHeader(http.StatusBadRequest) 157 | return 158 | } 159 | 160 | quiz := &dns.Msg{} 161 | err = quiz.Unpack(bdns) 162 | if err != nil { 163 | logger.Error(err.Error()) 164 | w.WriteHeader(http.StatusBadRequest) 165 | return 166 | } 167 | 168 | err = HttpSetEdns0Subnet(w, req, "", handler.EdnsClientSubnet, quiz) 169 | if err != nil { 170 | return 171 | } 172 | 173 | logger.Infof("rfc8484 server query: %s", quiz.Question[0].Name) 174 | 175 | ctx := context.Background() 176 | ans, err := handler.cli.Exchange(ctx, quiz) 177 | if err != nil { 178 | logger.Error(err.Error()) 179 | w.WriteHeader(http.StatusBadGateway) 180 | return 181 | } 182 | 183 | bdns, err = ans.Pack() 184 | if err != nil { 185 | logger.Error(err.Error()) 186 | w.WriteHeader(http.StatusBadGateway) 187 | return 188 | } 189 | 190 | w.Header().Add("Content-Type", "application/dns-message") 191 | w.Header().Add("Cache-Control", "no-cache, max-age=0") 192 | w.WriteHeader(http.StatusOK) 193 | 194 | err = WriteFull(w, bdns) 195 | if err != nil { 196 | logger.Error(err.Error()) 197 | w.WriteHeader(http.StatusBadGateway) 198 | return 199 | } 200 | 201 | return 202 | } 203 | -------------------------------------------------------------------------------- /drivers/common.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "math/rand" 8 | "net" 9 | "net/http" 10 | "net/url" 11 | "os" 12 | "os/user" 13 | "path/filepath" 14 | "strings" 15 | "time" 16 | 17 | "github.com/miekg/dns" 18 | logging "github.com/op/go-logging" 19 | ) 20 | 21 | var ( 22 | ErrConfigParse = errors.New("config parse error") 23 | ErrParseSubnet = errors.New("failed to parse subnet") 24 | ErrRequest = errors.New("failed to get response") 25 | ErrBadQtype = errors.New("wrong or unsupported qtype") 26 | logger = logging.MustGetLogger("drivers") 27 | Insecure bool 28 | Timeout int 29 | ) 30 | 31 | type Client interface { 32 | Url() (u string) 33 | Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) 34 | } 35 | 36 | type Server interface { 37 | Serve() (err error) 38 | } 39 | 40 | func init() { 41 | rand.Seed(time.Now().UnixNano()) 42 | } 43 | 44 | func LoadJson(configfiles string, cfg interface{}, ignore_notexist bool) { 45 | for _, conf := range strings.Split(configfiles, ";") { 46 | if strings.HasPrefix(conf, "~/") { 47 | usr, _ := user.Current() 48 | conf = filepath.Join(usr.HomeDir, conf[2:]) 49 | } 50 | 51 | file, err := os.Open(conf) 52 | if err != nil { 53 | if ignore_notexist { 54 | continue 55 | } 56 | panic(err.Error()) 57 | } 58 | defer file.Close() 59 | 60 | dec := json.NewDecoder(file) 61 | err = dec.Decode(&cfg) 62 | if err != nil { 63 | panic(err.Error()) 64 | } 65 | } 66 | 67 | return 68 | } 69 | 70 | func SetLogging(logfile, loglevel string) (err error) { 71 | var file *os.File 72 | file = os.Stdout 73 | 74 | if loglevel == "" { 75 | loglevel = "WARNING" 76 | } 77 | if logfile != "" { 78 | file, err = os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) 79 | if err != nil { 80 | panic(err.Error()) 81 | } 82 | } 83 | logging.SetBackend(logging.NewLogBackend(file, "", 0)) 84 | logging.SetFormatter(logging.MustStringFormatter( 85 | "%{time:01-02 15:04:05.000}[%{level}] %{shortpkg}/%{shortfile}: %{message}")) 86 | lv, err := logging.LogLevel(loglevel) 87 | if err != nil { 88 | panic(err.Error()) 89 | } 90 | logging.SetLevel(lv, "") 91 | return 92 | } 93 | 94 | func GuessDriver(URL string) (driver string, err error) { 95 | var u *url.URL 96 | u, err = url.Parse(URL) 97 | if err != nil { 98 | logger.Error(err.Error()) 99 | return 100 | } 101 | 102 | switch u.Scheme { 103 | case "udp", "tcp", "tcp-tls": 104 | driver = "dns" 105 | 106 | case "http", "https": 107 | switch u.Path { 108 | case "/resolve": 109 | driver = "google" 110 | case "/dns-query": 111 | driver = "rfc8484" 112 | case "/d": 113 | driver = "dnspod" 114 | default: 115 | driver = "doh" 116 | } 117 | 118 | default: 119 | err = ErrConfigParse 120 | } 121 | 122 | return 123 | } 124 | 125 | func GuessPort(u *url.URL) { 126 | if strings.Contains(u.Host, ":") { 127 | return 128 | } 129 | 130 | switch u.Scheme { 131 | case "udp", "tcp": 132 | u.Host = net.JoinHostPort(u.Host, "53") 133 | case "tcp-tls": 134 | u.Host = net.JoinHostPort(u.Host, "853") 135 | default: 136 | } 137 | return 138 | } 139 | 140 | func AppendEdns0Subnet(m *dns.Msg, addr net.IP, mask uint8) { 141 | opt := m.IsEdns0() 142 | if opt == nil { 143 | opt = &dns.OPT{} 144 | opt.Hdr.Name = "." 145 | opt.Hdr.Rrtype = dns.TypeOPT 146 | m.Extra = append(m.Extra, opt) 147 | } 148 | 149 | e := &dns.EDNS0_SUBNET{ 150 | Code: dns.EDNS0SUBNET, 151 | SourceNetmask: mask, 152 | SourceScope: 0, 153 | Address: addr, 154 | } 155 | if addr.To4() == nil { 156 | e.Family = 2 // IP6 157 | } else { 158 | e.Family = 1 // IP4 159 | } 160 | 161 | opt.Option = append(opt.Option, e) 162 | } 163 | 164 | func ParseSubnet(subnet string) (ip net.IP, mask uint8, err error) { 165 | ip, ipnet, err := net.ParseCIDR(subnet) 166 | if err != nil { 167 | err = nil 168 | ipstring := strings.SplitN(subnet, "/", 2)[0] 169 | ip = net.ParseIP(ipstring) 170 | switch { 171 | case ip == nil: 172 | err = ErrParseSubnet 173 | return 174 | case ip.To4() == nil: 175 | mask = net.IPv6len * 8 176 | default: 177 | mask = net.IPv4len * 8 178 | } 179 | return 180 | } 181 | one, _ := ipnet.Mask.Size() 182 | mask = uint8(one) 183 | return 184 | } 185 | 186 | func HttpSetEdns0Subnet(w http.ResponseWriter, req *http.Request, ecs1, ecs2 string, quiz *dns.Msg) (err error) { 187 | var addr net.IP 188 | var mask uint8 189 | switch { 190 | case ecs1 != "": 191 | addr, mask, err = ParseSubnet(ecs1) 192 | if err != nil { 193 | logger.Error(err.Error()) 194 | w.WriteHeader(http.StatusBadRequest) 195 | return 196 | } 197 | AppendEdns0Subnet(quiz, addr, mask) 198 | 199 | case ecs2 == "client": 200 | addr, mask, err = ParseSubnet(req.RemoteAddr) 201 | if err != nil { 202 | logger.Error(err.Error()) 203 | w.WriteHeader(http.StatusBadRequest) 204 | return 205 | } 206 | AppendEdns0Subnet(quiz, addr, mask) 207 | 208 | case ecs2 != "": 209 | addr, mask, err = ParseSubnet(ecs2) 210 | if err != nil { 211 | panic(err.Error()) 212 | } 213 | AppendEdns0Subnet(quiz, addr, mask) 214 | } 215 | return 216 | } 217 | -------------------------------------------------------------------------------- /scripts/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | ''' 4 | @date: 2020-05-24 5 | @author: Shell.Xu 6 | @copyright: 2020, Shell.Xu 7 | @license: BSD-3-clause 8 | ''' 9 | import sys 10 | import csv 11 | import random 12 | import ipaddress 13 | import subprocess 14 | 15 | import pprint 16 | 17 | from multiprocessing.pool import ThreadPool 18 | 19 | # 101.80.0.0/12 // sh telecom 20 | # 52.88.0.0/13 // aws canada 21 | # 104.244.40.0/21 // twitter 22 | 23 | accuracy_domains = [ 24 | 'www.taobao.com', 'www.tmall.com', 'www.qq.com', 'www.baidu.com', 'www.sohu.com', 'www.jd.com', 25 | 'www.amazon.com', 'www.bing.com', 'www.linkedin.com', 'www.weibo.com', 'www.meituan.com'] 26 | 27 | 28 | def result_parse(p): 29 | for rec in p.stdout.decode('utf-8').splitlines(): 30 | try: 31 | rec = rec.strip() 32 | yield ipaddress.ip_address(rec) 33 | except ValueError: 34 | if 'ERROR' in rec or 'WARNING' in rec: 35 | print(rec, file=sys.stderr) 36 | 37 | 38 | def repeat_ips(num, cmd): 39 | ips = set() 40 | for _ in range(num): 41 | p = subprocess.run(cmd, capture_output=True) 42 | ips |= set(result_parse(p)) 43 | return ips 44 | 45 | 46 | ping_cache = {} 47 | def ping(ip): 48 | if ip in ping_cache: 49 | return ping_cache[ip] 50 | p = subprocess.run( 51 | ['ping', '-qc', '5', '-i', '0.2', str(ip)], 52 | capture_output=True) 53 | for line in p.stdout.decode('utf-8').splitlines(): 54 | line = line.strip() 55 | if not line.startswith('rtt') and not line.startswith('round-trip'): 56 | continue 57 | rtt = line.split('=')[1].split('/') 58 | ping_cache[ip] = float(rtt[0]) # take the min 59 | break 60 | if ip not in ping_cache: 61 | print(f'ping ip {ip} has no response', file=sys.stderr) 62 | ping_cache[ip] = 10000 63 | return ping_cache[ip] 64 | 65 | 66 | def test_available(row): 67 | name, prot, url = row 68 | driver = prot 69 | if prot in ('udp', 'tcp', 'tls'): 70 | driver = 'dns' 71 | ips = repeat_ips(2, ['bin/doh', '-short', '-driver', driver, '-s', url, 'www.amazon.com']) 72 | if not ips: 73 | writer.writerow((name, prot, 'not available', '', '', '', '', '', '', '', '', '', '', '', '', '', '')) 74 | else: 75 | return (name, prot, driver, url) 76 | 77 | 78 | accuracies = {} 79 | def test_accuracy(domain): 80 | global accuracies 81 | rslt = {} 82 | avgs, mins = [], [] 83 | for row in servers: 84 | name, prot, driver, url = row 85 | ips = repeat_ips(2, ['bin/doh', '-short', '-insecure', '-driver', driver, '-s', url, domain]) 86 | if not ips: 87 | print(name, prot, domain, 'fuck off', file=sys.stderr) 88 | mins.append(10000) 89 | avgs.append(10000) 90 | continue 91 | # print(f'accuracy {domain} by {url} ips: {ips}', file=sys.stderr) 92 | latency = [ping(ip) for ip in ips] 93 | mins.append(min(latency)) 94 | avgs.append(sum(latency) / len(latency)) 95 | min_latency = min(mins) 96 | for row, latency in zip(servers, avgs): 97 | rslt[row] = latency/min_latency 98 | accuracies[domain] = rslt 99 | 100 | 101 | def test_latency(driver, url): 102 | latency = [] 103 | for _ in range(5): 104 | p = subprocess.run( 105 | ['bin/doh', '-driver', driver, '-s', url, 'www.amazon.com'], 106 | capture_output=True) 107 | for rec in p.stdout.decode('utf-8').splitlines(): 108 | if not rec.startswith(";; Query time:"): 109 | continue 110 | latency.append(int(rec.strip().split(':', 1)[1].split()[0])) 111 | if len(latency) != 0: 112 | return sum(latency)/len(latency) 113 | else: 114 | print(f"{driver} {url} has no query time: {p.stdout}", file=sys.stdout) 115 | 116 | 117 | def check_poisoned(driver, url): 118 | cidr = ipaddress.ip_network('104.244.40.0/21') 119 | p = subprocess.run( 120 | ['bin/doh', '-short', '-insecure', '-driver', driver, '-s', url, 'www.twitter.com'], 121 | capture_output=True) 122 | return not all([(ip in cidr) for ip in result_parse(p)]) 123 | 124 | 125 | def test_edns_subnet(driver, url): 126 | ips1 = repeat_ips(3, ['bin/doh', '-short', '-insecure', '-driver', driver, '-s', url, 127 | '-subnet', '101.80.0.0', 'www.taobao.com']) 128 | ips2 = repeat_ips(3, ['bin/doh', '-short', '-insecure', '-driver', driver, '-s', url, 129 | '-subnet', '52.88.0.0', 'www.taobao.com']) 130 | # print(f'edns {url} {ips1} {ips2}', file=sys.stderr) 131 | return bool(ips1) and bool(ips2) and not bool(ips1 & ips2) 132 | 133 | 134 | def test_all(row): 135 | name, prot, driver, url = row 136 | latency = test_latency(driver, url) 137 | if latency is None: 138 | writer.writerow((name, prot, 'not available', '', '', '', '', '', '', '', '', '', '', '', '', '', '')) 139 | return 140 | poisoned = 'Yes' if check_poisoned(driver, url) else 'No' 141 | edns_subnet = 'Yes' if test_edns_subnet(driver, url) else 'No' 142 | accuracy = [accuracies[domain][row] for domain in accuracy_domains] 143 | rslt = [name, prot, latency, poisoned, edns_subnet, '%0.3f' % sum(accuracy)] 144 | writer.writerow(rslt + ['%0.2f' % score for score in accuracy]) 145 | 146 | 147 | def main(): 148 | global writer 149 | writer = csv.writer(sys.stdout) 150 | 151 | global servers 152 | with open(sys.argv[1]) as fi: 153 | servers = list(csv.reader(fi)) 154 | random.shuffle(servers) 155 | 156 | pool = ThreadPool(10) 157 | servers = [row for row in pool.map(test_available, servers) if row] 158 | pool.map(test_accuracy, accuracy_domains) 159 | pool.map(test_all, servers) 160 | 161 | 162 | if __name__ == '__main__': 163 | main() 164 | -------------------------------------------------------------------------------- /data/sh-unicom.csv: -------------------------------------------------------------------------------- 1 | 114,tcp,37.4,Yes,No,19.500,2.03,3.52,1.03,1.75,1.09,2.70,3.29,1.04,1.00,1.00,1.04 2 | 114,udp,274.2,Yes,No,20.378,2.03,3.52,1.03,1.75,1.09,2.70,4.17,1.04,1.00,1.00,1.04 3 | adguard,rfc8484,2287.8,No,No,88.546,13.80,13.85,14.31,5.76,5.38,12.93,1.00,1.80,17.31,1.34,1.08 4 | adguard,tcp,124.4,No,No,88.546,13.80,13.85,14.31,5.76,5.38,12.93,1.00,1.80,17.31,1.34,1.08 5 | adguard,tls,1660.5,No,No,88.546,13.80,13.85,14.31,5.76,5.38,12.93,1.00,1.80,17.31,1.34,1.08 6 | adguard,udp,253.0,Yes,No,88.572,13.80,13.88,14.31,5.76,5.38,12.93,1.00,1.80,17.31,1.34,1.08 7 | alidns,rfc8484,2049.2,Yes,Yes,18.489,2.03,3.52,1.03,1.75,1.09,2.70,2.28,1.04,1.00,1.00,1.04 8 | alidns,tcp,13.8,Yes,Yes,17.597,2.15,3.52,1.03,1.75,1.09,2.70,1.27,1.04,1.00,1.00,1.04 9 | alidns,tls,750.0,Yes,Yes,17.699,2.25,3.52,1.03,1.75,1.09,2.70,1.27,1.04,1.00,1.00,1.04 10 | alidns,udp,259.2,Yes,Yes,18.003,2.15,3.52,1.03,1.75,1.09,2.70,1.68,1.04,1.00,1.00,1.04 11 | baidu,udp,287.8,Yes,No,19.368,2.03,3.39,1.03,1.75,1.09,2.70,3.29,1.04,1.00,1.00,1.04 12 | cloudflare,rfc8484,2395.8,No,No,175.822,26.65,27.35,20.08,17.25,25.82,27.36,5.98,1.80,17.31,5.15,1.08 13 | cloudflare,tcp,335.6,No,No,175.822,26.65,27.35,20.08,17.25,25.82,27.36,5.98,1.80,17.31,5.15,1.08 14 | cloudflare,tls,2279.0,No,No,175.822,26.65,27.35,20.08,17.25,25.82,27.36,5.98,1.80,17.31,5.15,1.08 15 | cloudflare,udp,277.2,Yes,No,175.822,26.65,27.35,20.08,17.25,25.82,27.36,5.98,1.80,17.31,5.15,1.08 16 | cnnic,udp,277.0,Yes,No,33.676,5.00,5.12,4.11,2.98,4.73,5.57,2.08,1.04,1.00,1.00,1.04 17 | comodo,tcp,256.8,No,No,177.104,26.65,26.75,21.20,17.25,25.82,27.36,6.38,1.80,17.31,5.52,1.08 18 | comodo,udp,256.0,Yes,No,178.442,26.65,26.75,21.20,17.25,25.82,27.36,7.72,1.80,17.31,5.52,1.08 19 | containerpi,google,2174.4,No,No,74.199,7.76,24.53,11.25,5.76,5.38,7.04,3.50,1.42,4.41,2.10,1.05 20 | containerpi,rfc8484,2125.2,No,Yes,81.944,7.63,24.53,11.25,5.76,5.38,7.04,3.57,1.04,12.57,2.10,1.08 21 | containerpi,tls,1916.4,No,No,119.151,16.04,24.53,31.70,5.76,5.38,11.38,2.08,1.80,17.31,2.10,1.08 22 | dns-watch,tcp,496.3333333333333,No,No,3530.155,44.72,44.89,1597.19,1048.11,5.38,37.73,9.84,362.98,17.31,9.94,352.08 23 | dns-watch,udp,305.2,Yes,No,207.436,44.72,44.89,34.61,3.52,5.38,37.73,7.73,1.80,17.31,8.66,1.08 24 | dnslify,rfc8484,2723.2,No,No,2089.459,1013.90,1017.78,8.88,7.20,5.38,13.70,1.18,1.80,17.31,1.25,1.08 25 | dnslify,tcp,716.4,No,No,2089.459,1013.90,1017.78,8.88,7.20,5.38,13.70,1.18,1.80,17.31,1.25,1.08 26 | dnslify,udp,382.0,Yes,No,2089.459,1013.90,1017.78,8.88,7.20,5.38,13.70,1.18,1.80,17.31,1.25,1.08 27 | dnspai,udp,265.8,Yes,No,19.279,2.03,3.30,1.03,1.75,1.09,2.70,3.29,1.04,1.00,1.00,1.04 28 | dnspod,tcp,116.6,Yes,No,49.550,6.20,6.04,5.43,3.26,5.00,5.83,6.84,1.04,7.82,1.05,1.04 29 | dnspod,udp,274.6,Yes,Yes,18.289,2.03,3.52,1.03,1.75,1.09,2.70,2.08,1.04,1.00,1.00,1.04 30 | doh.li,rfc8484,2601.6,No,No,22.268,2.25,3.30,1.03,1.75,1.09,2.70,6.06,1.04,1.00,1.00,1.04 31 | doh.li,tls,1548.8,No,No,2006.833,52.21,52.41,37.05,1.02,5.28,1845.36,9.39,1.04,1.00,1.05,1.04 32 | dyn,tcp,not available,,,,,,,,,,,,,, 33 | dyn,udp,256.4,Yes,No,80.626,2.15,3.45,43.44,1.75,1.09,2.70,4.88,1.80,17.31,1.00,1.04 34 | freedns,udp,337.4,Yes,No,238.563,44.72,54.04,38.96,17.25,5.38,39.66,8.18,1.80,17.31,10.19,1.08 35 | freenom,tcp,72.33333333333333,No,No,2330.732,16.04,24.53,9.47,5.76,5.38,11.38,2.29,1.80,2247.19,5.81,1.08 36 | freenom,udp,271.4,Yes,No,100.852,16.04,24.53,9.47,5.76,5.38,11.38,2.29,1.80,17.31,5.81,1.08 37 | google,google,not available,,,,,,,,,,,,,, 38 | google,rfc8484,not available,,,,,,,,,,,,,, 39 | google,tcp,105.2,No,Yes,33.717,2.03,3.45,1.03,17.25,1.09,2.70,2.08,1.04,1.00,1.00,1.04 40 | google,tls,856.0,No,Yes,35.707,2.03,3.45,1.03,17.25,1.09,2.70,4.07,1.04,1.00,1.00,1.04 41 | google,udp,265.2,Yes,Yes,23.586,2.15,3.52,1.03,3.52,1.09,2.70,2.08,1.04,4.41,1.00,1.04 42 | he,rfc8484,not available,,,,,,,,,,,,,, 43 | he,tcp,333.8,No,No,527.197,26.65,27.35,21.20,17.25,25.82,27.36,4.87,1.80,17.31,5.52,352.08 44 | he,udp,275.8,Yes,No,176.602,26.65,27.35,21.20,17.25,25.82,27.36,5.27,1.80,17.31,5.52,1.08 45 | neustar,tcp,41.2,No,No,55.175,1.07,1.03,20.36,17.25,1.00,1.04,5.91,1.04,4.41,1.05,1.04 46 | neustar,udp,275.4,No,No,51.765,1.07,1.03,20.36,17.25,1.00,1.04,5.91,1.04,1.00,1.05,1.04 47 | nextdns,rfc8484,1475.0,No,No,160.866,24.96,26.18,38.69,7.20,5.38,25.90,7.13,1.80,17.31,5.24,1.08 48 | nextdns,tcp,277.6,No,No,164.595,26.08,26.18,38.69,7.20,5.38,25.90,9.74,1.80,17.31,5.24,1.08 49 | nextdns,tls,2328.4,No,No,161.983,26.08,26.18,38.69,7.20,5.38,25.90,7.13,1.80,17.31,5.24,1.08 50 | nextdns,udp,264.0,Yes,No,163.289,26.08,26.18,38.69,7.20,5.38,25.90,8.43,1.80,17.31,5.24,1.08 51 | onedns,udp,257.0,Yes,No,18.092,2.03,3.32,1.03,1.75,1.09,2.70,2.08,1.04,1.00,1.00,1.04 52 | opendns,rfc8484,not available,,,,,,,,,,,,,, 53 | opendns,tcp,113.8,No,No,43.280,2.15,3.45,1.03,1.75,5.38,7.20,5.56,1.04,7.82,6.87,1.04 54 | opendns,udp,253.8,Yes,No,36.407,2.15,3.45,1.03,1.75,5.38,7.20,4.07,1.04,4.41,4.89,1.04 55 | opennic,tcp,632.0,No,No,239.597,52.21,52.41,38.57,17.25,5.38,35.23,8.36,1.80,17.31,10.01,1.08 56 | opennic,udp,356.0,Yes,No,229.195,52.21,52.41,32.14,17.25,5.38,35.23,7.09,1.80,17.31,7.31,1.08 57 | quad9,rfc8484,2578.2,No,No,115.379,26.65,26.75,8.88,7.20,5.38,13.70,2.75,1.80,17.31,3.88,1.08 58 | quad9,tcp,691.0,No,No,112.908,26.65,26.75,8.88,7.20,5.38,13.70,2.91,1.80,17.31,1.25,1.08 59 | quad9,tls,2576.6,No,No,120.808,26.65,26.75,14.31,7.20,5.38,13.70,2.75,1.80,17.31,3.88,1.08 60 | quad9,udp,325.8,Yes,No,115.285,26.65,26.82,8.88,7.20,5.38,13.70,2.59,1.80,17.31,3.88,1.08 61 | safedns,tcp,182.6,No,No,100.351,16.04,24.53,9.47,5.76,5.38,11.38,3.63,1.80,17.31,3.98,1.08 62 | safedns,udp,267.2,Yes,No,102.786,16.04,24.53,9.47,5.76,5.38,11.38,6.06,1.80,17.31,3.98,1.08 63 | twnic,rfc8484,2156.8,No,No,88.818,16.68,16.68,9.40,3.52,5.38,10.98,2.61,1.80,17.31,3.39,1.08 64 | twnic,tcp,815.2,No,No,88.306,16.62,16.68,9.40,3.52,5.38,10.98,2.16,1.80,17.31,3.39,1.08 65 | twnic,tls,1016.4,No,Yes,88.763,16.62,16.68,9.40,3.52,5.38,10.98,2.62,1.80,17.31,3.39,1.08 66 | twnic,udp,264.2,Yes,No,88.306,16.62,16.68,9.40,3.52,5.38,10.98,2.16,1.80,17.31,3.39,1.08 67 | verisign,tcp,105.4,No,No,110.490,16.04,24.53,9.47,17.25,5.38,11.38,2.29,1.80,17.31,3.97,1.08 68 | verisign,udp,279.6,Yes,No,110.490,16.04,24.53,9.47,17.25,5.38,11.38,2.29,1.80,17.31,3.97,1.08 69 | yandex,tcp,763.2,No,No,227.232,48.93,48.03,38.51,3.52,5.38,42.71,9.15,1.80,17.31,10.82,1.08 70 | yandex,udp,391.2,Yes,No,237.811,48.93,48.03,38.51,3.52,5.38,42.71,7.43,1.80,29.61,10.82,1.08 71 | -------------------------------------------------------------------------------- /data/sh-telecom.csv: -------------------------------------------------------------------------------- 1 | 114,tcp,21.8,Yes,No,12.145,1.02,1.04,1.10,1.03,1.00,1.01,1.72,1.04,1.00,1.12,1.06 2 | 114,udp,17.2,Yes,No,12.238,1.02,1.04,1.10,1.03,1.00,1.01,1.81,1.04,1.00,1.12,1.06 3 | adguard,rfc8484,362.8,No,No,1724.679,839.44,828.27,10.32,8.84,4.78,11.53,2.46,1.96,12.70,3.29,1.09 4 | adguard,tcp,144.0,No,No,1729.756,839.44,828.27,10.32,8.84,4.78,11.53,2.46,1.96,12.70,8.36,1.09 5 | adguard,tls,289.6,No,No,1729.194,839.44,828.27,10.32,8.84,4.78,11.53,4.91,1.96,12.70,5.35,1.09 6 | adguard,udp,72.6,Yes,No,1753.247,839.44,828.27,38.88,8.84,4.78,11.53,2.46,1.96,12.70,3.29,1.09 7 | alidns,rfc8484,82.6,Yes,Yes,19.767,1.02,1.04,1.10,1.03,1.00,1.01,3.87,1.04,6.48,1.12,1.06 8 | alidns,tcp,17.2,Yes,Yes,14.235,1.02,1.04,1.10,1.03,1.00,1.01,1.07,1.04,3.74,1.12,1.06 9 | alidns,tls,84.8,Yes,Yes,19.767,1.02,1.04,1.10,1.03,1.00,1.01,3.87,1.04,6.48,1.12,1.06 10 | alidns,udp,9.2,Yes,Yes,19.760,1.02,1.04,1.10,1.03,1.00,1.00,3.87,1.04,6.48,1.12,1.06 11 | baidu,udp,41.2,Yes,No,17.809,1.02,1.04,1.10,1.03,1.00,1.01,1.91,1.04,6.48,1.12,1.06 12 | cloudflare,rfc8484,220.2,No,No,63.238,5.72,5.64,19.78,3.10,4.78,4.96,1.02,1.96,12.70,2.49,1.09 13 | cloudflare,tcp,68.0,No,No,63.238,5.72,5.64,19.78,3.10,4.78,4.96,1.02,1.96,12.70,2.49,1.09 14 | cloudflare,tls,194.6,No,No,63.238,5.72,5.64,19.78,3.10,4.78,4.96,1.02,1.96,12.70,2.49,1.09 15 | cloudflare,udp,33.8,Yes,No,63.217,5.69,5.64,19.78,3.10,4.78,4.96,1.02,1.96,12.70,2.49,1.09 16 | cnnic,udp,12.2,No,No,28.305,2.29,2.47,5.86,1.03,4.34,2.32,3.04,1.04,3.74,1.12,1.06 17 | comodo,tcp,185.0,No,No,1723.151,839.44,828.27,10.32,8.84,4.78,11.53,1.88,1.96,12.70,2.33,1.09 18 | comodo,udp,95.8,Yes,No,1723.151,839.44,828.27,10.32,8.84,4.78,11.53,1.88,1.96,12.70,2.33,1.09 19 | containerpi,google,385.2,No,No,37.216,1.02,1.04,8.45,5.59,4.78,1.01,1.07,1.96,9.59,1.64,1.06 20 | containerpi,rfc8484,351.4,No,No,62.003,13.61,13.42,1.10,10.15,2.89,4.89,2.86,1.96,6.85,3.18,1.09 21 | containerpi,tls,257.0,No,No,81.218,13.60,13.42,9.84,10.15,4.78,8.77,1.72,1.96,12.70,3.18,1.09 22 | dnslify,rfc8484,279.4,No,No,1723.340,839.44,828.27,10.32,8.84,4.78,11.53,2.07,1.96,12.70,2.33,1.09 23 | dnslify,tcp,150.6,No,No,1723.340,839.44,828.27,10.32,8.84,4.78,11.53,2.07,1.96,12.70,2.33,1.09 24 | dnslify,udp,73.4,Yes,No,1723.340,839.44,828.27,10.32,8.84,4.78,11.53,2.07,1.96,12.70,2.33,1.09 25 | dnspai,udp,6.8,Yes,No,17.795,1.02,1.04,1.10,1.03,1.00,1.00,1.91,1.04,6.48,1.12,1.06 26 | dnspod,tcp,83.4,Yes,No,39.097,5.42,5.25,5.86,2.83,4.83,4.74,5.95,1.04,1.00,1.12,1.06 27 | dnspod,udp,8.2,Yes,Yes,14.360,1.02,1.04,1.10,1.03,1.00,1.00,3.95,1.04,1.00,1.12,1.06 28 | dns-watch,tcp,523.0,No,No,1964.058,33.50,33.05,37.14,3.10,4.78,34.39,6.08,1.96,1798.24,10.73,1.09 29 | dns-watch,udp,231.2,Yes,No,187.675,33.50,33.05,43.56,3.10,4.78,34.39,8.81,1.96,12.70,10.73,1.09 30 | doh.li,rfc8484,853.0,No,No,11.497,1.02,1.04,1.10,1.03,1.00,1.01,1.07,1.04,1.00,1.12,1.06 31 | doh.li,tls,690.2,No,No,1631.628,6.51,33.07,38.31,1.03,4.34,1525.09,6.44,1.96,12.70,1.12,1.06 32 | dyn,tcp,78.2,No,No,42.726,1.02,1.04,19.78,1.03,1.00,1.01,1.00,1.96,12.70,1.12,1.06 33 | dyn,udp,36.2,Yes,No,42.712,1.02,1.04,19.78,1.03,1.00,1.00,1.00,1.96,12.70,1.12,1.06 34 | freedns,udp,287.0,Yes,No,195.614,33.50,42.85,40.50,14.03,4.78,29.37,6.59,1.96,12.70,8.23,1.09 35 | freenom,tcp,243.6,No,No,1736.478,839.44,828.27,19.78,8.84,4.78,11.53,5.45,1.96,12.70,2.63,1.09 36 | freenom,udp,144.4,Yes,No,1739.353,839.44,828.27,22.65,8.84,4.78,11.53,5.45,1.96,12.70,2.63,1.09 37 | google,google,12865.8,No,Yes,83.330,13.60,13.42,10.32,10.15,4.78,8.77,2.86,1.96,12.70,3.68,1.09 38 | google,rfc8484,12841.0,No,Yes,83.349,13.60,13.42,10.32,10.15,4.78,8.77,2.88,1.96,12.70,3.68,1.09 39 | google,tcp,142.0,No,Yes,30.292,1.02,1.04,4.04,10.39,1.00,1.01,1.72,1.04,6.85,1.12,1.06 40 | google,tls,232.4,No,Yes,30.487,1.02,1.04,4.04,14.03,1.00,1.00,1.40,1.04,3.74,1.12,1.06 41 | google,udp,52.4,Yes,Yes,19.354,1.02,1.04,1.10,3.10,1.00,1.00,1.40,1.04,6.48,1.12,1.06 42 | he,rfc8484,not available,,,,,,,,,,,,,, 43 | he,tcp,444.6,No,No,149.887,23.25,20.63,24.84,14.03,22.04,20.56,3.91,1.96,12.70,4.85,1.09 44 | he,udp,238.4,Yes,No,150.435,23.25,20.63,24.84,14.03,22.04,20.56,4.46,1.96,12.70,4.85,1.09 45 | neustar,tcp,17.6,No,No,45.740,1.02,1.04,19.78,14.03,1.00,1.01,3.63,1.04,1.00,1.12,1.06 46 | neustar,udp,8.6,No,No,50.354,1.02,1.04,19.78,14.03,1.00,1.01,2.77,1.04,6.48,1.12,1.06 47 | nextdns,rfc8484,225.8,No,No,70.747,11.64,11.48,4.65,8.84,4.78,10.47,2.14,1.96,12.70,1.00,1.09 48 | nextdns,tcp,101.4,No,No,70.747,11.64,11.48,4.65,8.84,4.78,10.47,2.14,1.96,12.70,1.00,1.09 49 | nextdns,tls,261.4,No,No,70.747,11.64,11.48,4.65,8.84,4.78,10.47,2.14,1.96,12.70,1.00,1.09 50 | nextdns,udp,52.4,Yes,No,70.720,11.64,11.45,4.65,8.84,4.78,10.47,2.14,1.96,12.70,1.00,1.09 51 | onedns,udp,39.4,Yes,No,13.284,1.02,1.04,1.10,1.03,1.00,1.01,2.86,1.04,1.00,1.12,1.06 52 | opendns,rfc8484,234.4,No,No,48.697,5.72,5.64,12.68,3.10,4.78,4.96,1.01,1.96,6.48,1.29,1.09 53 | opendns,tcp,138.2,No,No,16.625,1.02,1.04,1.10,1.03,4.78,1.01,1.40,1.04,1.00,2.14,1.06 54 | opendns,udp,59.2,Yes,No,15.881,1.02,1.04,1.10,1.03,4.78,1.01,1.07,1.04,1.00,1.73,1.06 55 | opennic,tcp,268.8,No,No,1723.151,839.44,828.27,10.32,8.84,4.78,11.53,1.88,1.96,12.70,2.33,1.09 56 | opennic,udp,72.2,Yes,No,1723.151,839.44,828.27,10.32,8.84,4.78,11.53,1.88,1.96,12.70,2.33,1.09 57 | quad9,rfc8484,394.8,No,No,108.257,23.25,22.94,17.76,8.84,4.78,11.53,2.09,1.96,12.70,1.31,1.09 58 | quad9,tcp,178.8,No,No,109.874,23.25,22.94,17.76,8.84,4.78,11.53,3.70,1.96,12.70,1.31,1.09 59 | quad9,tls,324.0,No,No,109.058,23.25,22.94,17.76,8.84,4.78,11.53,2.89,1.96,12.70,1.31,1.09 60 | quad9,udp,95.0,Yes,No,108.245,23.25,22.94,17.76,8.84,4.78,11.53,2.07,1.96,12.70,1.31,1.09 61 | safedns,tcp,626.6,No,No,202.060,44.56,43.96,38.32,14.03,4.78,29.94,1.07,1.96,12.70,9.64,1.09 62 | safedns,udp,199.8,Yes,No,202.061,44.56,43.96,38.32,14.03,4.78,29.94,1.07,1.96,12.70,9.64,1.09 63 | twnic,rfc8484,not available,,,,,,,,,,,,,, 64 | twnic,tcp,953.0,No,No,77.977,14.53,14.33,10.17,3.10,4.78,9.94,1.88,1.96,12.70,3.49,1.09 65 | twnic,tls,not available,,,,,,,,,,,,,, 66 | twnic,udp,193.0,Yes,No,78.965,14.53,14.33,10.17,3.10,4.78,9.94,2.86,1.96,12.70,3.49,1.09 67 | verisign,tcp,67.8,No,No,72.744,5.72,5.42,19.78,14.03,4.78,4.96,1.00,1.96,12.70,1.31,1.09 68 | verisign,udp,36.0,Yes,No,73.826,5.72,5.42,19.78,14.03,4.78,4.96,2.08,1.96,12.70,1.31,1.09 69 | yandex,tcp,588.0,No,No,211.649,41.16,40.06,40.29,3.10,4.78,36.86,6.76,1.96,24.69,10.90,1.09 70 | yandex,udp,305.0,Yes,No,560.894,41.16,40.06,40.29,3.10,4.78,36.86,6.26,1.96,36.67,10.90,338.85 71 | -------------------------------------------------------------------------------- /data/jp.csv: -------------------------------------------------------------------------------- 1 | 114,tcp,292.0,No,No,1321.684,116.20,116.20,132.18,71.09,2.12,115.57,187.41,1.06,1.00,577.87,1.00 2 | 114,udp,146.0,No,No,1321.684,116.20,116.20,132.18,71.09,2.12,115.57,187.41,1.06,1.00,577.87,1.00 3 | adguard,rfc8484,67.4,No,No,14.881,1.01,1.01,1.00,1.13,1.00,1.00,1.89,1.06,1.00,3.79,1.00 4 | adguard,tcp,0.4,No,No,15.874,1.01,1.01,1.00,1.13,1.00,1.00,1.89,1.06,1.00,4.78,1.00 5 | adguard,tls,84.6,No,No,15.428,1.01,1.01,1.00,1.13,1.00,1.00,1.45,1.06,1.00,4.78,1.00 6 | adguard,udp,0.0,No,No,13.887,1.01,1.01,1.00,1.13,1.00,1.00,1.89,1.06,1.00,2.80,1.00 7 | alidns,rfc8484,981.8,No,Yes,1514.231,94.60,92.83,118.41,71.09,3.40,77.84,263.78,1.06,1.00,789.23,1.00 8 | alidns,tcp,237.8,No,Yes,1493.444,94.60,69.46,146.07,71.09,3.40,73.82,242.72,1.06,1.00,789.23,1.00 9 | alidns,tls,7109.8,No,Yes,43240.094,94.60,92.83,118.41,71.09,3.40,81.86,221.66,1.06,1.00,42553.19,1.00 10 | alidns,udp,128.25,Yes,Yes,1574.122,116.20,92.83,173.74,71.09,3.40,81.86,242.72,1.06,1.00,789.23,1.00 11 | baidu,udp,65.6,No,No,1083.755,28.57,28.56,107.71,31.99,1.00,27.58,112.62,172.83,193.83,378.07,1.00 12 | cloudflare,rfc8484,99.6,No,No,16.228,1.01,1.01,1.50,1.13,1.00,1.00,1.74,1.06,1.00,4.78,1.00 13 | cloudflare,tcp,1.6,No,No,16.378,1.01,1.01,1.50,1.13,1.00,1.00,1.89,1.06,1.00,4.78,1.00 14 | cloudflare,tls,165.4,No,No,16.142,1.01,1.01,1.27,1.13,1.00,1.00,1.89,1.06,1.00,4.78,1.00 15 | cloudflare,udp,1.6,No,No,16.154,1.02,1.01,1.27,1.13,1.00,1.00,1.89,1.06,1.00,4.78,1.00 16 | cnnic,udp,134.33333333333334,Yes,No,1488.834,59.15,59.33,107.71,105.03,1.80,98.37,1.86,172.83,193.83,649.45,39.48 17 | comodo,tcp,2.6,No,No,82.953,1.01,1.01,1.00,71.09,1.00,1.00,1.00,1.06,1.00,2.80,1.00 18 | comodo,udp,39.2,No,No,82.953,1.01,1.01,1.00,71.09,1.00,1.00,1.00,1.06,1.00,2.80,1.00 19 | containerpi,google,84.8,No,No,716.897,1.01,2.94,1.00,1.13,1.00,55.87,1.45,1.06,1.00,649.45,1.00 20 | containerpi,rfc8484,115.0,No,Yes,733.503,1.01,2.94,1.25,1.13,1.00,110.73,124.10,1.06,1.00,488.28,1.00 21 | containerpi,tls,71.8,No,No,16.378,1.01,1.01,1.50,1.13,1.00,1.00,1.89,1.06,1.00,4.78,1.00 22 | dnslify,rfc8484,962.2,No,No,382.521,119.07,119.07,1.00,69.59,1.00,63.26,1.61,1.06,1.00,4.86,1.00 23 | dnslify,tcp,609.4,No,No,497.008,119.07,119.07,1.00,69.59,1.00,63.26,1.61,1.06,1.00,4.86,115.49 24 | dnslify,udp,298.2,No,No,382.521,119.07,119.07,1.00,69.59,1.00,63.26,1.61,1.06,1.00,4.86,1.00 25 | dnspai,udp,206.0,No,No,2064.772,123.86,136.83,197.57,138.67,4.34,130.94,276.97,172.83,193.83,649.45,39.48 26 | dnspod,tcp,240.6,Yes,No,1441.552,74.48,51.29,107.71,41.78,2.50,35.31,72.89,172.83,193.83,649.45,39.48 27 | dnspod,udp,128.4,Yes,Yes,251.782,1.01,1.01,240.73,1.13,1.00,1.00,1.86,1.06,1.00,1.00,1.00 28 | dns-watch,tcp,590.0,No,No,2325.898,168.83,168.83,253.06,31.99,1.00,184.59,410.89,1.06,1.00,1103.66,1.00 29 | dns-watch,udp,272.0,No,No,2325.898,168.83,168.83,253.06,31.99,1.00,184.59,410.89,1.06,1.00,1103.66,1.00 30 | doh.li,rfc8484,1059.2,No,No,1490.153,1.01,1.01,213.17,1.13,1.00,1.00,333.12,1.06,1.00,935.66,1.00 31 | doh.li,tls,722.6,No,No,8095.619,185.60,79.23,213.17,138.67,3.40,6165.23,333.12,1.06,1.00,935.66,39.48 32 | dyn,tcp,not available,,,,,,,,,,,,,, 33 | dyn,udp,11.8,No,No,218.203,1.01,1.01,1.00,1.13,1.00,1.00,34.44,172.83,1.00,2.80,1.00 34 | freedns,udp,274.6,No,No,2258.441,168.83,164.50,217.36,71.09,1.00,162.94,285.78,1.06,1.00,1183.90,1.00 35 | freenom,tcp,737.8,No,No,1017.869,119.07,119.07,1.50,69.59,1.00,63.26,160.03,1.06,1.00,481.29,1.00 36 | freenom,udp,67.0,No,No,1017.919,119.12,119.07,1.50,69.59,1.00,63.26,160.03,1.06,1.00,481.29,1.00 37 | google,google,106.2,No,Yes,903.830,1.01,12.80,1.00,1.13,1.00,110.73,123.65,1.06,1.00,649.45,1.00 38 | google,rfc8484,109.2,No,Yes,1027.259,1.01,13.58,1.00,1.13,1.00,110.73,246.31,1.06,1.00,649.45,1.00 39 | google,tcp,4.0,No,Yes,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 40 | google,tls,98.8,No,Yes,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 41 | google,udp,4.4,No,Yes,13.441,1.01,1.01,1.00,1.13,1.00,1.00,1.45,1.06,1.00,2.80,1.00 42 | he,rfc8484,81.8,No,No,18.283,1.01,1.01,1.50,1.13,1.00,1.00,1.74,1.06,1.00,6.84,1.00 43 | he,tcp,22.4,No,No,6182.512,1.01,1.01,1.50,1.13,1.00,6165.23,1.74,1.06,1.00,6.84,1.00 44 | he,udp,0.2,No,No,18.283,1.01,1.01,1.50,1.13,1.00,1.00,1.74,1.06,1.00,6.84,1.00 45 | neustar,tcp,63.4,No,No,322.388,20.86,20.86,49.79,71.09,1.00,19.71,1.86,1.06,1.00,134.16,1.00 46 | neustar,udp,31.6,No,No,322.388,20.86,20.86,49.79,71.09,1.00,19.71,1.86,1.06,1.00,134.16,1.00 47 | nextdns,rfc8484,140.2,No,No,191.669,1.01,4.88,1.00,1.13,1.00,1.00,175.80,1.06,1.00,2.80,1.00 48 | nextdns,tcp,1.0,No,No,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 49 | nextdns,tls,70.8,No,No,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 50 | nextdns,udp,0.4,No,No,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 51 | onedns,udp,173.0,No,No,17224.710,6435.01,154.47,124.63,135.40,4.72,126.00,1.86,172.83,9380.86,649.45,39.48 52 | opendns,rfc8484,76.0,No,No,45.518,1.01,1.01,1.27,31.99,1.00,1.00,2.33,1.06,1.00,2.86,1.00 53 | opendns,tcp,15.4,No,No,13.441,1.01,1.01,1.00,1.13,1.00,1.00,1.45,1.06,1.00,2.80,1.00 54 | opendns,udp,3.4,No,No,13.441,1.01,1.01,1.00,1.13,1.00,1.00,1.45,1.06,1.00,2.80,1.00 55 | opennic,tcp,63.2,No,No,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 56 | opennic,udp,141.4,No,No,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 57 | quad9,rfc8484,98.4,No,No,84.835,1.01,1.01,1.50,69.59,1.00,1.00,1.89,1.06,1.00,4.78,1.00 58 | quad9,tcp,240.2,No,No,1454.735,73.00,73.00,1.00,69.59,1.00,63.26,160.43,1.06,1.00,1010.39,1.00 59 | quad9,tls,114.4,No,No,84.760,1.01,1.01,1.50,69.59,1.00,1.00,1.82,1.06,1.00,4.78,1.00 60 | quad9,udp,110.0,No,No,1194.354,73.00,73.00,1.33,69.59,1.00,63.26,168.40,1.06,1.00,741.71,1.00 61 | safedns,tcp,1.8,No,No,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 62 | safedns,udp,72.6,No,No,12.995,1.01,1.01,1.00,1.13,1.00,1.00,1.00,1.06,1.00,2.80,1.00 63 | twnic,rfc8484,2329.0,No,No,323.071,20.86,20.86,30.24,31.99,1.00,19.71,47.61,1.06,1.00,147.74,1.00 64 | twnic,tcp,670.0,No,No,323.071,20.86,20.86,30.24,31.99,1.00,19.71,47.61,1.06,1.00,147.74,1.00 65 | twnic,tls,321.2,No,Yes,373.363,20.86,20.86,30.24,31.99,1.00,19.71,97.90,1.06,1.00,147.74,1.00 66 | twnic,udp,32.2,No,No,373.363,20.86,20.86,30.24,31.99,1.00,19.71,97.90,1.06,1.00,147.74,1.00 67 | verisign,tcp,16.8,No,No,84.418,1.01,1.01,1.50,71.09,1.00,1.00,1.89,1.06,1.00,2.86,1.00 68 | verisign,udp,2.2,No,No,84.413,1.01,1.01,1.50,71.09,1.00,1.00,1.89,1.06,1.00,2.86,1.00 69 | yandex,tcp,669.2,No,No,2431.797,175.66,176.74,251.43,31.99,1.00,168.96,428.65,1.06,1.00,1194.30,1.00 70 | yandex,udp,287.8,No,No,2503.845,175.66,176.74,264.27,31.99,1.00,168.96,385.79,1.06,103.07,1194.30,1.00 71 | -------------------------------------------------------------------------------- /data/seattle.csv: -------------------------------------------------------------------------------- 1 | 114,tcp,106.0,No,No,502.171,2.96,202.35,107.64,1.00,1.00,60.36,1.00,1.04,1.00,122.82,1.00 2 | 114,udp,53.6,No,No,502.171,2.96,202.35,107.64,1.00,1.00,60.36,1.00,1.04,1.00,122.82,1.00 3 | adguard,rfc8484,91.0,No,No,214.401,2.96,202.35,1.00,1.00,1.00,1.00,1.00,1.04,1.00,1.05,1.00 4 | adguard,tcp,0.8,No,No,214.401,2.96,202.35,1.00,1.00,1.00,1.00,1.00,1.04,1.00,1.05,1.00 5 | adguard,tls,133.6,No,No,214.613,2.96,202.35,1.00,1.00,1.00,1.00,1.21,1.04,1.00,1.05,1.00 6 | adguard,udp,0.0,No,No,214.401,2.96,202.35,1.00,1.00,1.00,1.00,1.00,1.04,1.00,1.05,1.00 7 | alidns,rfc8484,1751.2,Yes,Yes,446.354,1.06,129.28,38.48,1.00,10.35,50.91,88.66,1.04,1.00,123.56,1.00 8 | alidns,tcp,1292.6,No,Yes,1024.992,2.01,202.35,148.09,1.00,10.35,50.91,113.07,1.04,371.61,123.56,1.00 9 | alidns,tls,3940.4,No,Yes,1061.799,2.01,202.35,93.29,1.00,10.35,38.20,140.36,1.04,371.61,200.59,1.00 10 | alidns,udp,182.8,Yes,Yes,834.843,2.96,202.35,148.09,1.00,10.35,38.20,119.98,1.04,186.30,123.56,1.00 11 | baidu,udp,152.0,No,No,2148.733,6.18,423.33,405.49,8.22,8.74,213.03,296.21,381.61,1.00,403.91,1.00 12 | cloudflare,rfc8484,163.2,No,No,215.643,2.96,202.35,1.61,1.00,1.00,1.00,1.14,1.04,1.00,1.53,1.00 13 | cloudflare,tcp,1.4,No,No,215.643,2.96,202.35,1.61,1.00,1.00,1.00,1.14,1.04,1.00,1.53,1.00 14 | cloudflare,tls,92.6,No,No,215.643,2.96,202.35,1.61,1.00,1.00,1.00,1.14,1.04,1.00,1.53,1.00 15 | cloudflare,udp,0.8,No,No,215.643,2.96,202.35,1.61,1.00,1.00,1.00,1.14,1.04,1.00,1.53,1.00 16 | cnnic,udp,201.5,Yes,No,2908.146,7.49,533.90,405.49,11.01,11.86,285.68,412.85,381.61,371.61,465.87,20.79 17 | comodo,tcp,7.0,No,No,511.675,1.06,202.35,1.00,1.00,1.00,1.00,300.05,1.04,1.00,1.17,1.00 18 | comodo,udp,1.6,No,No,511.675,1.06,202.35,1.00,1.00,1.00,1.00,300.05,1.04,1.00,1.17,1.00 19 | containerpi,google,601.0,No,No,1297.206,4.44,253.33,128.30,6.91,1.00,167.95,300.05,1.04,1.00,432.18,1.00 20 | containerpi,rfc8484,480.2,No,No,1514.383,2.96,304.30,255.60,6.91,8.74,200.60,300.05,1.04,1.00,432.18,1.00 21 | containerpi,tls,367.4,No,No,1454.738,4.44,304.41,328.07,6.91,8.74,167.95,300.05,1.04,1.00,331.12,1.00 22 | dnslify,rfc8484,159.2,No,No,40880.245,1.06,72.54,39.27,530.11,574.42,13908.21,44.66,1.04,1.00,25706.94,1.00 23 | dnslify,tcp,43.6,No,No,89855.117,400.14,27397.26,21231.42,530.11,574.42,13908.21,44.66,1.04,1.00,25706.94,59.91 24 | dnslify,udp,19.4,No,No,40939.156,1.06,72.54,39.27,530.11,574.42,13908.21,44.66,1.04,1.00,25706.94,59.91 25 | dnspai,udp,172.8,Yes,No,2374.501,7.65,450.03,380.79,9.47,12.10,233.25,46.82,381.61,366.13,465.87,20.79 26 | dnspod,tcp,not available,,,,,,,,,,,,,, 27 | dnspod,udp,217.0,Yes,Yes,523.060,1.06,202.35,56.63,1.00,8.74,190.32,11.90,1.04,1.00,48.00,1.00 28 | dns-watch,tcp,305.6666666666667,No,No,1631.270,6.02,412.45,291.39,8.22,8.74,197.44,346.04,1.04,1.00,357.91,1.00 29 | dns-watch,udp,142.8,No,No,1631.270,6.02,412.45,291.39,8.22,8.74,197.44,346.04,1.04,1.00,357.91,1.00 30 | doh.li,rfc8484,616.6,No,No,1131.461,2.96,202.35,283.38,1.00,1.00,1.00,311.56,1.04,1.00,325.16,1.00 31 | doh.li,tls,453.4,No,No,42706.468,6.17,27397.26,283.38,9.47,10.35,13908.21,602.92,1.04,1.00,465.87,20.79 32 | dyn,tcp,92.4,No,No,219.219,2.01,202.35,1.00,1.00,1.00,1.00,6.56,1.04,1.00,1.26,1.00 33 | dyn,udp,0.2,No,No,219.219,2.01,202.35,1.00,1.00,1.00,1.00,6.56,1.04,1.00,1.26,1.00 34 | freedns,udp,156.8,No,No,1517.475,6.02,420.35,312.35,1.00,8.74,191.17,188.66,1.04,1.00,386.13,1.00 35 | freenom,tcp,368.75,No,No,1733.547,8.11,555.45,56.65,8.87,8.74,256.03,405.87,1.04,1.00,430.78,1.00 36 | freenom,udp,184.2,No,No,1947.400,8.11,555.45,270.51,8.87,8.74,256.03,405.87,1.04,1.00,430.78,1.00 37 | google,google,100.6,No,Yes,920.366,2.01,202.35,1.00,1.00,1.00,233.25,10.84,1.04,1.00,465.87,1.00 38 | google,rfc8484,112.4,No,No,911.684,2.96,202.35,1.00,1.00,1.00,233.25,1.21,1.04,1.00,465.87,1.00 39 | google,tcp,13.8,No,No,223.615,1.06,202.35,1.00,1.00,1.00,1.00,11.90,1.04,1.00,1.26,1.00 40 | google,tls,121.8,No,Yes,212.928,1.06,202.35,1.00,1.00,1.00,1.00,1.21,1.04,1.00,1.26,1.00 41 | google,udp,41.4,No,No,225.511,2.96,202.35,1.00,1.00,1.00,1.00,11.90,1.04,1.00,1.26,1.00 42 | he,rfc8484,not available,,,,,,,,,,,,,, 43 | he,tcp,7.6,No,No,13.668,2.96,1.20,1.00,1.00,1.00,1.00,1.21,1.04,1.00,1.26,1.00 44 | he,udp,4.4,No,No,11.703,1.06,1.20,1.00,1.00,1.00,1.00,1.14,1.04,1.00,1.26,1.00 45 | neustar,tcp,1.4,No,No,213.390,1.06,202.35,1.10,1.00,1.00,1.00,1.32,1.04,1.00,1.51,1.00 46 | neustar,udp,0.6,No,No,213.390,1.06,202.35,1.10,1.00,1.00,1.00,1.32,1.04,1.00,1.51,1.00 47 | nextdns,rfc8484,115.0,No,No,322.157,1.06,137.45,52.61,1.00,1.00,20.93,36.70,1.04,1.00,68.37,1.00 48 | nextdns,tcp,1.0,No,No,40399.233,1.06,202.35,1.00,1.00,574.42,13908.21,1.21,1.04,1.00,25706.94,1.00 49 | nextdns,tls,86.6,No,No,40468.831,1.06,202.35,1.00,1.00,574.42,13908.21,11.90,1.04,1.00,25706.94,59.91 50 | nextdns,udp,0.6,No,No,14864.233,2.96,202.35,1.00,1.00,574.42,13908.21,169.72,1.04,1.00,1.53,1.00 51 | onedns,udp,183.2,Yes,No,3124.801,400.14,524.22,368.21,9.88,9.83,266.58,317.02,381.61,360.66,465.87,20.79 52 | opendns,rfc8484,112.2,No,No,14128.196,2.01,202.35,1.00,8.22,1.00,13908.21,1.11,1.04,1.00,1.26,1.00 53 | opendns,tcp,12.8,No,No,220.481,2.96,202.35,1.00,1.00,1.00,1.00,6.56,1.04,1.00,1.57,1.00 54 | opendns,udp,36.8,No,No,219.376,2.01,202.35,1.00,1.00,1.00,1.00,6.56,1.04,1.00,1.41,1.00 55 | opennic,tcp,41.2,No,No,275.519,1.06,72.54,38.48,1.00,1.00,38.20,73.66,1.04,1.00,46.53,1.00 56 | opennic,udp,19.4,No,No,275.519,1.06,72.54,38.48,1.00,1.00,38.20,73.66,1.04,1.00,46.53,1.00 57 | quad9,rfc8484,128.4,No,No,214.864,2.96,202.35,1.00,1.00,1.00,1.00,1.00,1.04,1.00,1.51,1.00 58 | quad9,tcp,1.2,No,No,215.007,2.96,202.35,1.00,1.00,1.00,1.00,1.14,1.04,1.00,1.51,1.00 59 | quad9,tls,101.6,No,Yes,215.076,2.96,202.35,1.00,1.00,1.00,1.00,1.21,1.04,1.00,1.51,1.00 60 | quad9,udp,0.6,No,No,214.970,2.96,202.35,1.00,1.00,1.00,1.00,1.11,1.04,1.00,1.51,1.00 61 | safedns,tcp,1.0,No,No,213.112,1.06,202.35,1.61,1.00,1.00,1.00,1.04,1.04,1.00,1.00,1.00 62 | safedns,udp,0.8,No,No,213.282,1.06,202.35,1.61,1.00,1.00,1.00,1.04,1.04,1.00,1.17,1.00 63 | twnic,rfc8484,680.4,No,No,1732.219,6.09,417.07,303.48,8.22,8.74,196.71,413.96,1.04,1.00,374.89,1.00 64 | twnic,tcp,1098.2,No,No,1732.219,6.09,417.07,303.48,8.22,8.74,196.71,413.96,1.04,1.00,374.89,1.00 65 | twnic,tls,698.6,No,Yes,1701.584,6.09,417.07,303.48,8.22,8.74,196.71,383.33,1.04,1.00,374.89,1.00 66 | twnic,udp,145.4,No,No,1732.219,6.09,417.07,303.48,8.22,8.74,196.71,413.96,1.04,1.00,374.89,1.00 67 | verisign,tcp,254.2,No,No,303.978,1.06,72.54,57.60,1.00,1.00,38.20,55.06,1.04,1.00,74.47,1.00 68 | verisign,udp,25.6,No,No,366.459,1.06,72.54,57.60,1.00,1.00,38.20,117.54,1.04,1.00,74.47,1.00 69 | yandex,tcp,406.4,No,No,29079.533,7.05,27397.26,285.73,8.22,8.74,248.11,377.64,1.04,260.68,484.05,1.00 70 | yandex,udp,201.4,No,No,1898.528,7.05,475.94,285.73,8.22,8.74,248.11,377.64,1.04,1.00,484.05,1.00 71 | -------------------------------------------------------------------------------- /doh/query.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "flag" 7 | "fmt" 8 | "strings" 9 | "time" 10 | 11 | "github.com/miekg/dns" 12 | "github.com/shell909090/doh/drivers" 13 | ) 14 | 15 | type Query struct { 16 | AliasesFile string 17 | Aliases map[string]string 18 | ResolvFile string 19 | Driver string 20 | URL string 21 | URLs []string 22 | TCP bool 23 | Tries int 24 | Subnet string 25 | QType string 26 | QClass string 27 | NoRecurse bool 28 | CheckingDisabled bool 29 | FmtQuestion bool 30 | FmtShort bool 31 | FmtJson bool 32 | Microseconds bool 33 | Trace bool 34 | DNlist []string 35 | } 36 | 37 | func (q *Query) Parse() { 38 | flag.StringVar(&q.AliasesFile, "alias", "", "aliases file") 39 | flag.StringVar(&q.ResolvFile, "resolv", "/etc/resolv.conf", "file path of resolv.conf") 40 | flag.StringVar(&q.Driver, "driver", "", "client driver") 41 | flag.StringVar(&q.URL, "s", "", "server url to query") 42 | flag.BoolVar(&q.TCP, "tcp", false, "use tcp as default protocol") 43 | flag.IntVar(&q.Tries, "tries", 0, "retries") 44 | flag.StringVar(&q.Subnet, "subnet", "", "edns client subnet") 45 | flag.StringVar(&q.QType, "t", "A", "resource record type to query") 46 | flag.StringVar(&q.QClass, "c", "IN", "resource record class to query") 47 | flag.BoolVar(&q.NoRecurse, "norecurse", false, "not desire recurse") 48 | flag.BoolVar(&q.CheckingDisabled, "cd", false, "checking disabled, don't check ENSSEC validation") 49 | flag.BoolVar(&q.FmtQuestion, "question", false, "print question") 50 | flag.BoolVar(&q.FmtShort, "short", false, "show short answer") 51 | flag.BoolVar(&q.FmtJson, "json", false, "show json answer") 52 | flag.BoolVar(&q.Microseconds, "u", false, "print query times in microseconds instead of milliseconds") 53 | flag.BoolVar(&q.Trace, "trace", false, "trace the query") 54 | } 55 | 56 | func (q *Query) Prepare() { 57 | drivers.LoadJson(DEFAULT_ALIASES, &q.Aliases, true) 58 | if q.AliasesFile != "" { 59 | drivers.LoadJson(q.AliasesFile, &q.Aliases, false) 60 | } 61 | 62 | if q.URL != "" { 63 | q.URLs = append(q.URLs, q.FillURL(q.URL)) 64 | } 65 | 66 | for _, p := range flag.Args() { 67 | _, typeok := dns.StringToType[p] 68 | _, classok := dns.StringToClass[p] 69 | switch { 70 | case strings.HasPrefix(p, "@"): 71 | q.URLs = append(q.URLs, q.FillURL(p[1:])) 72 | case typeok: 73 | q.QType = p 74 | case classok: 75 | q.QClass = p 76 | default: 77 | q.DNlist = append(q.DNlist, p) 78 | } 79 | } 80 | 81 | if q.ResolvFile != "" { 82 | cfg, err := dns.ClientConfigFromFile(q.ResolvFile) 83 | if err != nil { 84 | panic("no server and can't read resolv.conf") 85 | } 86 | // don't append, user can't overwrite resolv if it's append. 87 | if len(q.URLs) == 0 { 88 | for _, srv := range cfg.Servers { 89 | q.URLs = append(q.URLs, q.FillURL(srv)) 90 | } 91 | } 92 | if drivers.Timeout == 0 { 93 | drivers.Timeout = cfg.Timeout * 1000 94 | } 95 | if q.Tries == 0 { 96 | q.Tries = cfg.Attempts 97 | } 98 | } 99 | 100 | logger.Debugf("%+v", q) 101 | return 102 | } 103 | 104 | func (q *Query) FillURL(u string) (URL string) { 105 | URL = u 106 | if AliasURL, ok := q.Aliases[URL]; ok { 107 | URL = AliasURL 108 | } 109 | if !strings.Contains(URL, "://") { 110 | if q.TCP { 111 | URL = "tcp://" + URL 112 | } else { 113 | URL = "udp://" + URL 114 | } 115 | } 116 | return 117 | } 118 | 119 | func (q *Query) CreateClient() (cli drivers.Client) { 120 | var header *drivers.DriverHeader 121 | 122 | if len(q.URLs) == 0 { 123 | return 124 | } 125 | 126 | switch { 127 | case q.Trace: 128 | cli = drivers.NewRecursiveClient() 129 | 130 | case q.Tries <= 1: 131 | header = &drivers.DriverHeader{ 132 | Driver: q.Driver, 133 | URL: q.URLs[0], 134 | } 135 | cli = header.CreateClient(nil) 136 | 137 | default: 138 | reties := &drivers.RetiesClient{Tries: q.Tries} 139 | for _, URL := range q.URLs { 140 | header = &drivers.DriverHeader{ 141 | Driver: q.Driver, 142 | URL: URL, 143 | } 144 | reties.AddClient(header.CreateClient(nil)) 145 | } 146 | cli = reties 147 | } 148 | 149 | return 150 | } 151 | 152 | func (q *Query) NewQuiz(dn string) (quiz *dns.Msg) { 153 | qtype, ok := dns.StringToType[q.QType] 154 | if !ok { 155 | panic(ErrParameter.Error()) 156 | } 157 | 158 | quiz = &dns.Msg{} 159 | quiz.SetQuestion(dns.Fqdn(dn), qtype) 160 | quiz.SetEdns0(4096, true) 161 | if q.NoRecurse { 162 | quiz.MsgHdr.RecursionDesired = false 163 | } 164 | if q.CheckingDisabled { 165 | quiz.MsgHdr.CheckingDisabled = true 166 | } 167 | 168 | if q.QClass != "" { 169 | qclass, ok := dns.StringToClass[q.QClass] 170 | if !ok { 171 | panic(ErrParameter.Error()) 172 | } 173 | quiz.Question[0].Qclass = qclass 174 | } 175 | 176 | if q.Subnet != "" { 177 | addr, mask, err := drivers.ParseSubnet(q.Subnet) 178 | if err != nil { 179 | panic(err.Error()) 180 | } 181 | drivers.AppendEdns0Subnet(quiz, addr, mask) 182 | } 183 | return 184 | } 185 | 186 | func (q *Query) QueryDN(cli drivers.Client, quiz *dns.Msg) (err error) { 187 | ctx := context.Background() 188 | start := time.Now() 189 | 190 | ans, err := cli.Exchange(ctx, quiz) 191 | if err != nil { 192 | return 193 | } 194 | 195 | elapsed := time.Since(start) 196 | 197 | switch { 198 | case q.FmtShort: 199 | q.PrintShort(ans) 200 | 201 | case q.FmtJson: 202 | q.PrintJson(quiz, ans) 203 | 204 | default: 205 | if q.FmtQuestion { 206 | fmt.Println(quiz.String()) 207 | } 208 | fmt.Println(ans.String()) 209 | if q.Microseconds { 210 | fmt.Printf(";; Query time: %d usec\n", elapsed.Microseconds()) 211 | } else { 212 | fmt.Printf(";; Query time: %d msec\n", elapsed.Milliseconds()) 213 | } 214 | fmt.Printf(";; SERVER: %s\n", cli.Url()) 215 | fmt.Printf(";; WHEN: %s\n\n", start.Format(time.UnixDate)) 216 | } 217 | 218 | return 219 | } 220 | 221 | func (q *Query) PrintShort(ans *dns.Msg) { 222 | for _, rr := range ans.Answer { 223 | switch v := rr.(type) { 224 | case *dns.A: 225 | fmt.Println(v.A.String()) 226 | case *dns.AAAA: 227 | fmt.Println(v.AAAA.String()) 228 | case *dns.CNAME: 229 | fmt.Println(v.Target) 230 | } 231 | } 232 | return 233 | } 234 | 235 | func (q *Query) PrintJson(quiz, ans *dns.Msg) { 236 | jsonresp := &drivers.DNSMsg{} 237 | err := jsonresp.FromAnswer(quiz, ans) 238 | if err != nil { 239 | panic(err.Error()) 240 | } 241 | 242 | var bresp []byte 243 | bresp, err = json.Marshal(jsonresp) 244 | if err != nil { 245 | panic(err.Error()) 246 | } 247 | 248 | fmt.Printf("%s", string(bresp)) 249 | return 250 | } 251 | 252 | func (q *Query) QueryAll(cli drivers.Client) { 253 | for _, dn := range q.DNlist { 254 | quiz := q.NewQuiz(dn) 255 | err := q.QueryDN(cli, quiz) 256 | if err != nil { 257 | logger.Error(err.Error()) 258 | } 259 | } 260 | return 261 | } 262 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Table of content 2 | 3 | * [Abstract](#abstract) 4 | * [Compile and Install](#compile-and-install) 5 | * [Command line options and args](#command-line-options-and-args) 6 | * [Config](#config) 7 | * [Client Config](#client-config) 8 | * [Drivers and Protocols](#drivers-and-protocols) 9 | * [dns](#dns) 10 | * [rfc8484](#rfc8484) 11 | * [google](#google) 12 | * [doh/http/https](#doh/http/https) 13 | * [twin](twin) 14 | * [Public recursive server](#public-recursive-server) 15 | * [Summary in China](#summary-in-china) 16 | * [Summary outside China](#summary-outside-china) 17 | * [Suggestions](#suggestions) 18 | * [TODO](#todo) 19 | 20 | # Abstract 21 | 22 | [DNS over HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) utils written by golang. 23 | 24 | # Compile and Install 25 | 26 | make 27 | 28 | The executable file is placed under `bin/`. Copy it to wherever you like. Enjoy. 29 | 30 | # Command line options and args 31 | 32 | See `doh --help`. 33 | 34 | # Config 35 | 36 | Defaultly doh will try to read configs from `doh.json;~/.doh.json;/etc/doh.json`. 37 | 38 | * logfile: optional. indicate which file log should be written to. empty means stdout. empty by default. 39 | * loglevel: optional. log level. warning by default. 40 | * service: service config 41 | * driver: driver to use. 42 | * url: url to driver. 43 | * ... the rest of the config depends on the driver. 44 | * client: client config 45 | * driver: driver to use. 46 | * url: url to driver. 47 | * ... the rest of the config depends on the driver. 48 | 49 | ## aliases 50 | 51 | Defaultly doh will try to read aliases from `doh-aliases.json;~/.doh-aliases.json`. 52 | 53 | If the server from the command line matches the key, the value will be used. 54 | 55 | ## Client Config 56 | 57 | * driver: optional. determine which system will be used as a client. see "drivers and protocols". if empty, the program will auto guess. 58 | * url: required. see "drivers and protocols". 59 | * insecure: optional. don't verify the certificate from the server. 60 | 61 | # Drivers and Protocols 62 | 63 | ## dns 64 | 65 | There are three different protocols in driver `dns`: 66 | 67 | * udp: default port 53 68 | * tcp: default port 53 69 | * tcp-tls: default port 853 70 | 71 | This driver can be used in both client and server settings. 72 | 73 | Client Config: 74 | 75 | * timeout: as its name. 76 | 77 | Server Config: 78 | 79 | * ednsclientsubnet: as its name. 80 | * certfile: file path of certificates. 81 | * certkeyfile: file path of key. 82 | 83 | ## rfc8484 84 | 85 | There is one protocol in driver `rfc8484`. 86 | 87 | * https: default port 443, default path is `/dns-query`. 88 | 89 | This driver can only be used in client setting. 90 | 91 | Client Config: 92 | 93 | * insecure: don't check the certificates. 94 | * timeout: as its name. 95 | 96 | ## google 97 | 98 | There is one protocol in driver `rfc8484`. 99 | 100 | * https: default port 443, default path is `/resolve`. 101 | 102 | This driver can only be used in client setting. 103 | 104 | Client Config: 105 | 106 | * insecure: don't check the certificates. 107 | * timeout: as its name. 108 | 109 | ## doh/http/https 110 | 111 | This driver can only be used in server setting. It supports both `rfc8484` and `google`. 112 | 113 | Server Config: 114 | 115 | * ednsclientsubnet: as its name. if it's `client`, then the actual client IP address will be put into the field. 116 | * certfile: file path of the certificates. 117 | * keyfile: file path of the key. 118 | 119 | ## twin 120 | 121 | This driver can only be used in client setting. 122 | 123 | Client Config: 124 | 125 | * primary: another client config. 126 | * secondary: another client config. 127 | * direct-routes: a route file. 128 | 129 | The quiz will be sent to the primary. If none of the answers match any routes in `direct-routes`, the quiz will be sent to the secondary and we return the answers from the secondary. Otherwise the answers from the primary will be used. 130 | 131 | # Public recursive server 132 | 133 | * [Public Recursive Servers](data/public.csv) 134 | * [Shanghai Telecom](data/sh-telecom.md), [csv](data/sh-telecom.csv) 135 | * [Shanghai Unicom](data/sh-unicom.md), [csv](data/sh-unicom.csv) 136 | * [Japan IDC](data/jp.md), [csv](data/jp.csv) 137 | * [Seattle IDC](data/seattle.md), [csv](data/seattle.csv) 138 | 139 | source: 140 | 141 | * https://blog.skk.moe/post/which-public-dns-to-use/ 142 | * https://github.com/curl/curl/wiki/DNS-over-HTTPS 143 | * https://www.publicdns.xyz/ 144 | 145 | ## Summary in China 146 | 147 | | name | sh tc latency | sh tc accuracy | sh uc latency | sh uc accuracy | 148 | | ---- | ------------- | -------------- | ------------- | -------------- | 149 | | 114 | 17.2 | 12.2 | 274.2 | 20.3 | 150 | | alidns | 9.2 | 19.7 | 259.2 | 18.0 | 151 | | baidu | 41.2 | 17.8 | 287.8 | 19.3 | 152 | | cnnic | 12.2 | 28.3 | 277.0 | 33.6 | 153 | | dnspai | 6.8 | 17.7 | 265.8 | 19.2 | 154 | | dnspod | 8.2 | 14.3 | 274.6 | 18.2 | 155 | | dyn | 36.2 | 42.7 | 256.4 | 80.6 | 156 | | google | 52.4 | 19.3 | 265.2 | 23.5 | 157 | | onedns | 39.4 | 13.2 | 257.0 | 18.0 | 158 | | opendns | 59.2 | 15.8 | 253.8 | 36.4 | 159 | 160 | * Ignore those that have an accuracy more than 30. 161 | * Ignore those that have a latency more than 30. 162 | * alidns, dnspod, and google support edns client subnet, at least in some way. 163 | * cnnic hasn't been poisoned, at least not to twitter. 164 | * alidns has the most wide protocol supportive in China. 165 | * In China Unicom, sometime the latency of TCP are less than the latency of UDP. Have no idea why it been like that. 166 | 167 | ## Summary outside China 168 | 169 | | name | jp latency | jp accuracy | seattle latency | seattle accuracy | 170 | | ---- | ---------- | ----------- | --------------- | ---------------- | 171 | | adguard | 0.0 | 13.8 | 0.0 | 214.4 | 172 | | cloudflare | 1.6 | 16.1 | 0.8 | 215.6 | 173 | | containerpi | 71.8 | 16.3 | 367.4 | 1454.7 | 174 | | google | 4.4 | 13.4 | 41.4 | 225.511 | 175 | | he | 0.2 | 18.2 | 4.4 | 11.7 | 176 | | nextdns | 0.4 | 12.9 | 0.6 | 14864.2 | 177 | | opendns | 3.4 | 13.4 | 36.8 | 219.376 | 178 | | quad9 | 110.0 | 1194.3 | 0.6 | 214.9 | 179 | | safedns | 72.6 | 12.9 | 0.8 | 213.2 | 180 | 181 | * Ignore those that have an accuracy more than 30. 182 | * Ignore those that have a latency more than 30. 183 | * google support edns client subnet. 184 | * Most of the dns get a dramatically high score in seattle accuracy test, because they get the same result for tmall. `47.246.24.233`. `he` get a very close result, which is `47.246.18.236`. The latency of `47.246.24.233` is 66.7, and the latency of `47.246.18.236` is 0.6. 185 | 186 | # Suggestions 187 | 188 | 4. adguard, cloudflare, comodo, google, he, nextdns, opennic, safedns are acceptable in Japan. dnspod are almost 50. opendns are more than 40. 189 | 5. adguard, google support edns client subnet, and they have the most wide protocol supportive in China. cloudflare, nextdns also support 4 protocols, except they don't support edns client subnet. 190 | 6. Seattle has almost the same situation as Japan. Except dyn becomes acceptable, and opennic becomes unacceptable. 191 | 7. If you are in China. alidns is the best choice you have. And if you are not in China, adguard and google are the best. 192 | 193 | # TODO 194 | 195 | * cache 196 | -------------------------------------------------------------------------------- /drivers/recursive.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "math/rand" 7 | "reflect" 8 | "strings" 9 | 10 | "github.com/miekg/dns" 11 | ) 12 | 13 | var ( 14 | ErrUndeterminedNext = errors.New("can't determine next hop") 15 | ) 16 | 17 | type RecursiveClient struct { 18 | client *dns.Client 19 | Cache map[string][]string 20 | NameServers map[string][]string 21 | } 22 | 23 | func NewRecursiveClient() (cli *RecursiveClient) { 24 | cli = &RecursiveClient{ 25 | client: &dns.Client{Net: "udp"}, 26 | Cache: map[string][]string{ 27 | "a.root-servers.net": []string{"198.41.0.4"}, 28 | "b.root-servers.net": []string{"199.9.14.201"}, 29 | "c.root-servers.net": []string{"192.33.4.12"}, 30 | "d.root-servers.net": []string{"199.7.91.13"}, 31 | "e.root-servers.net": []string{"192.203.230.10"}, 32 | "f.root-servers.net": []string{"192.5.5.241"}, 33 | "g.root-servers.net": []string{"192.112.36.4"}, 34 | "h.root-servers.net": []string{"198.97.190.53"}, 35 | "i.root-servers.net": []string{"192.36.148.17"}, 36 | "j.root-servers.net": []string{"192.58.128.30"}, 37 | "k.root-servers.net": []string{"193.0.14.129"}, 38 | "l.root-servers.net": []string{"199.7.83.42"}, 39 | "m.root-servers.net": []string{"202.12.27.33"}, 40 | }, 41 | NameServers: map[string][]string{ 42 | ".": []string{ 43 | "a.root-servers.net", "b.root-servers.net", "c.root-servers.net", "d.root-servers.net", 44 | "e.root-servers.net", "f.root-servers.net", "g.root-servers.net", "h.root-servers.net", 45 | "i.root-servers.net", "j.root-servers.net", "k.root-servers.net", "l.root-servers.net", 46 | "m.root-servers.net", 47 | }, 48 | }, 49 | } 50 | 51 | return 52 | } 53 | 54 | func (client *RecursiveClient) ReadSection(section []dns.RR) (err error) { 55 | for _, rr := range section { 56 | if v, ok := rr.(*dns.A); ok { 57 | client.Cache[v.Hdr.Name] = append(client.Cache[v.Hdr.Name], v.A.String()) 58 | } 59 | } 60 | return 61 | } 62 | 63 | func (client *RecursiveClient) AddNameServer(name, server string) { 64 | client.NameServers[name] = append(client.NameServers[name], server) 65 | return 66 | } 67 | 68 | func (client *RecursiveClient) SetNameServer(name, server string) { 69 | client.NameServers[name] = nil 70 | client.NameServers[name] = append(client.NameServers[name], server) 71 | return 72 | } 73 | 74 | func (client *RecursiveClient) MatchNameServers(domain string) (suffix string, servers []string) { 75 | length := 0 76 | for name, srv := range client.NameServers { 77 | if !strings.HasSuffix(domain, name) { 78 | continue 79 | } 80 | if len(name) > length { 81 | suffix = name 82 | servers = srv 83 | length = len(name) 84 | } 85 | } 86 | return 87 | } 88 | 89 | func (cli *RecursiveClient) Url() (u string) { 90 | return "(trace)" 91 | } 92 | 93 | func (cli *RecursiveClient) Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) { 94 | query := NewRecursiveQuery(ctx, cli, quiz) 95 | err = query.Procedure() 96 | if err != nil { 97 | return 98 | } 99 | ans = query.ans 100 | return 101 | } 102 | 103 | type RecursiveQuery struct { 104 | client *RecursiveClient 105 | ctx context.Context 106 | deep int 107 | quiz *dns.Msg 108 | ans *dns.Msg 109 | current string 110 | } 111 | 112 | func NewRecursiveQuery(ctx context.Context, client *RecursiveClient, quiz *dns.Msg) (query *RecursiveQuery) { 113 | query = &RecursiveQuery{ 114 | client: client, 115 | ctx: ctx, 116 | quiz: quiz.Copy(), 117 | ans: &dns.Msg{}, 118 | } 119 | query.quiz.MsgHdr.RecursionDesired = false 120 | query.quiz.SetEdns0(4096, true) 121 | query.ans.SetReply(query.quiz) 122 | return 123 | } 124 | 125 | func (query *RecursiveQuery) SelectServer() (host, addr string, err error) { 126 | question := query.quiz.Question[0] 127 | suffix, servers := query.client.MatchNameServers(question.Name) 128 | logger.Infof("%d %s match %s in ns cache.", query.deep, question.Name, suffix) 129 | 130 | host = servers[rand.Intn(len(servers))] 131 | 132 | addrs, ok := query.client.Cache[host] 133 | if ok { 134 | addr = addrs[rand.Intn(len(addrs))] 135 | return 136 | } 137 | 138 | logger.Infof("%d query A record for host %s", query.deep, host) 139 | 140 | quiz := &dns.Msg{} 141 | quiz.SetQuestion(host, dns.TypeA) 142 | quiz.SetEdns0(4096, true) 143 | 144 | rquery := NewRecursiveQuery(query.ctx, query.client, quiz) 145 | rquery.deep = query.deep + 1 146 | err = rquery.Procedure() 147 | if err != nil { 148 | return 149 | } 150 | 151 | query.client.ReadSection(rquery.ans.Answer) 152 | addrs, ok = query.client.Cache[host] 153 | if ok { 154 | addr = addrs[rand.Intn(len(addrs))] 155 | logger.Infof("%d %s: %s", query.deep, host, addr) 156 | return 157 | } 158 | 159 | err = ErrUndeterminedNext 160 | return 161 | } 162 | 163 | func (query *RecursiveQuery) Query() (interm *dns.Msg, err error) { 164 | var addr string 165 | for i := 0; i < 3; i++ { 166 | query.current, addr, err = query.SelectServer() 167 | if err != nil { 168 | return 169 | } 170 | 171 | question := query.quiz.Question[0] 172 | logger.Infof("%d doh -[%s %s]-> %s|%s", 173 | query.deep, question.Name, dns.TypeToString[question.Qtype], query.current, addr) 174 | 175 | interm, _, err = query.client.client.ExchangeContext(query.ctx, query.quiz, addr+":53") 176 | if err == nil { 177 | break 178 | } 179 | logger.Infof(err.Error()) 180 | } 181 | 182 | switch { 183 | case err == nil: 184 | case interm != nil: 185 | query.ans.MsgHdr.Rcode = interm.MsgHdr.Rcode 186 | return 187 | default: 188 | query.ans.MsgHdr.Rcode = dns.RcodeServerFailure 189 | return 190 | } 191 | 192 | logger.Debug(interm.String()) 193 | return 194 | } 195 | 196 | func (query *RecursiveQuery) ParseAnswer(section []dns.RR) (finished bool) { 197 | for _, rr := range section { 198 | switch rr.Header().Rrtype { 199 | case dns.TypeCNAME: 200 | v := rr.(*dns.CNAME) 201 | query.quiz.Question[0].Name = v.Target 202 | query.ans.Answer = append(query.ans.Answer, v) 203 | logger.Infof("%d doh <-[%s CNAME]- %s", query.deep, v.Target, query.current) 204 | query.deep++ 205 | 206 | case query.quiz.Question[0].Qtype: 207 | query.ans.Answer = append(query.ans.Answer, rr) 208 | finished = true 209 | } 210 | } 211 | return 212 | } 213 | 214 | func (query *RecursiveQuery) ParseAuthority(section []dns.RR) { 215 | domain := query.quiz.Question[0].Name 216 | name := "" 217 | qtype := "" 218 | count := 0 219 | for _, rr := range section { 220 | switch v := rr.(type) { 221 | case *dns.NS: 222 | qtype = "NS" 223 | name = v.Hdr.Name 224 | query.client.AddNameServer(name, v.Ns) 225 | 226 | if !strings.HasSuffix(domain, name) { 227 | count++ 228 | } 229 | 230 | case *dns.SOA: 231 | qtype = "SOA" 232 | name = v.Hdr.Name 233 | query.client.SetNameServer(name, v.Ns) 234 | 235 | if strings.HasSuffix(domain, name) { 236 | count++ 237 | } 238 | break 239 | } 240 | } 241 | 242 | if count != 0 { 243 | logger.Infof("%d doh <-[%s %s %d]- %s", 244 | query.deep, name, qtype, count, query.current) 245 | logger.Infof("%d ns: %v", 246 | query.deep, reflect.ValueOf(query.client.NameServers).MapKeys()) 247 | } 248 | 249 | return 250 | } 251 | 252 | func (query *RecursiveQuery) Procedure() (err error) { 253 | var interm *dns.Msg 254 | for i := 0; i < 10; i++ { 255 | interm, err = query.Query() 256 | if err != nil { 257 | return 258 | } 259 | if query.ParseAnswer(interm.Answer) { 260 | logger.Infof("%d doh <-[final]- %s", query.deep, query.current) 261 | break 262 | } 263 | query.ParseAuthority(interm.Ns) 264 | query.client.ReadSection(interm.Extra) 265 | } 266 | return 267 | } 268 | -------------------------------------------------------------------------------- /data/sh-unicom.md: -------------------------------------------------------------------------------- 1 | | vendor | protocol | latency | poisoned | edns-client-subnet | accuracy | taobao | tmall | qq | baidu | sohu | jd | amazon | bing | linkedin | weibo | meituan | 2 | | ------ | -------- | ------- | -------- | ------------------ | -------- | ------ | ----- | -- | ----- | ---- | -- | ------ | ---- | -------- | ----- | ------- | 3 | | 114 | tcp | 37.4 | Yes | No | 19.500 | 2.03 | 3.52 | 1.03 | 1.75 | 1.09 | 2.70 | 3.29 | 1.04 | 1.00 | 1.00 | 1.04 | 4 | | 114 | udp | 274.2 | Yes | No | 20.378 | 2.03 | 3.52 | 1.03 | 1.75 | 1.09 | 2.70 | 4.17 | 1.04 | 1.00 | 1.00 | 1.04 | 5 | | adguard | rfc8484 | 2287.8 | No | No | 88.546 | 13.80 | 13.85 | 14.31 | 5.76 | 5.38 | 12.93 | 1.00 | 1.80 | 17.31 | 1.34 | 1.08 | 6 | | adguard | tcp | 124.4 | No | No | 88.546 | 13.80 | 13.85 | 14.31 | 5.76 | 5.38 | 12.93 | 1.00 | 1.80 | 17.31 | 1.34 | 1.08 | 7 | | adguard | tls | 1660.5 | No | No | 88.546 | 13.80 | 13.85 | 14.31 | 5.76 | 5.38 | 12.93 | 1.00 | 1.80 | 17.31 | 1.34 | 1.08 | 8 | | adguard | udp | 253.0 | Yes | No | 88.572 | 13.80 | 13.88 | 14.31 | 5.76 | 5.38 | 12.93 | 1.00 | 1.80 | 17.31 | 1.34 | 1.08 | 9 | | alidns | rfc8484 | 2049.2 | Yes | Yes | 18.489 | 2.03 | 3.52 | 1.03 | 1.75 | 1.09 | 2.70 | 2.28 | 1.04 | 1.00 | 1.00 | 1.04 | 10 | | alidns | tcp | 13.8 | Yes | Yes | 17.597 | 2.15 | 3.52 | 1.03 | 1.75 | 1.09 | 2.70 | 1.27 | 1.04 | 1.00 | 1.00 | 1.04 | 11 | | alidns | tls | 750.0 | Yes | Yes | 17.699 | 2.25 | 3.52 | 1.03 | 1.75 | 1.09 | 2.70 | 1.27 | 1.04 | 1.00 | 1.00 | 1.04 | 12 | | alidns | udp | 259.2 | Yes | Yes | 18.003 | 2.15 | 3.52 | 1.03 | 1.75 | 1.09 | 2.70 | 1.68 | 1.04 | 1.00 | 1.00 | 1.04 | 13 | | baidu | udp | 287.8 | Yes | No | 19.368 | 2.03 | 3.39 | 1.03 | 1.75 | 1.09 | 2.70 | 3.29 | 1.04 | 1.00 | 1.00 | 1.04 | 14 | | cloudflare | rfc8484 | 2395.8 | No | No | 175.822 | 26.65 | 27.35 | 20.08 | 17.25 | 25.82 | 27.36 | 5.98 | 1.80 | 17.31 | 5.15 | 1.08 | 15 | | cloudflare | tcp | 335.6 | No | No | 175.822 | 26.65 | 27.35 | 20.08 | 17.25 | 25.82 | 27.36 | 5.98 | 1.80 | 17.31 | 5.15 | 1.08 | 16 | | cloudflare | tls | 2279.0 | No | No | 175.822 | 26.65 | 27.35 | 20.08 | 17.25 | 25.82 | 27.36 | 5.98 | 1.80 | 17.31 | 5.15 | 1.08 | 17 | | cloudflare | udp | 277.2 | Yes | No | 175.822 | 26.65 | 27.35 | 20.08 | 17.25 | 25.82 | 27.36 | 5.98 | 1.80 | 17.31 | 5.15 | 1.08 | 18 | | cnnic | udp | 277.0 | Yes | No | 33.676 | 5.00 | 5.12 | 4.11 | 2.98 | 4.73 | 5.57 | 2.08 | 1.04 | 1.00 | 1.00 | 1.04 | 19 | | comodo | tcp | 256.8 | No | No | 177.104 | 26.65 | 26.75 | 21.20 | 17.25 | 25.82 | 27.36 | 6.38 | 1.80 | 17.31 | 5.52 | 1.08 | 20 | | comodo | udp | 256.0 | Yes | No | 178.442 | 26.65 | 26.75 | 21.20 | 17.25 | 25.82 | 27.36 | 7.72 | 1.80 | 17.31 | 5.52 | 1.08 | 21 | | containerpi | google | 2174.4 | No | No | 74.199 | 7.76 | 24.53 | 11.25 | 5.76 | 5.38 | 7.04 | 3.50 | 1.42 | 4.41 | 2.10 | 1.05 | 22 | | containerpi | rfc8484 | 2125.2 | No | Yes | 81.944 | 7.63 | 24.53 | 11.25 | 5.76 | 5.38 | 7.04 | 3.57 | 1.04 | 12.57 | 2.10 | 1.08 | 23 | | containerpi | tls | 1916.4 | No | No | 119.151 | 16.04 | 24.53 | 31.70 | 5.76 | 5.38 | 11.38 | 2.08 | 1.80 | 17.31 | 2.10 | 1.08 | 24 | | dns-watch | tcp | 496.3333333333333 | No | No | 3530.155 | 44.72 | 44.89 | 1597.19 | 1048.11 | 5.38 | 37.73 | 9.84 | 362.98 | 17.31 | 9.94 | 352.08 | 25 | | dns-watch | udp | 305.2 | Yes | No | 207.436 | 44.72 | 44.89 | 34.61 | 3.52 | 5.38 | 37.73 | 7.73 | 1.80 | 17.31 | 8.66 | 1.08 | 26 | | dnslify | rfc8484 | 2723.2 | No | No | 2089.459 | 1013.90 | 1017.78 | 8.88 | 7.20 | 5.38 | 13.70 | 1.18 | 1.80 | 17.31 | 1.25 | 1.08 | 27 | | dnslify | tcp | 716.4 | No | No | 2089.459 | 1013.90 | 1017.78 | 8.88 | 7.20 | 5.38 | 13.70 | 1.18 | 1.80 | 17.31 | 1.25 | 1.08 | 28 | | dnslify | udp | 382.0 | Yes | No | 2089.459 | 1013.90 | 1017.78 | 8.88 | 7.20 | 5.38 | 13.70 | 1.18 | 1.80 | 17.31 | 1.25 | 1.08 | 29 | | dnspai | udp | 265.8 | Yes | No | 19.279 | 2.03 | 3.30 | 1.03 | 1.75 | 1.09 | 2.70 | 3.29 | 1.04 | 1.00 | 1.00 | 1.04 | 30 | | dnspod | tcp | 116.6 | Yes | No | 49.550 | 6.20 | 6.04 | 5.43 | 3.26 | 5.00 | 5.83 | 6.84 | 1.04 | 7.82 | 1.05 | 1.04 | 31 | | dnspod | udp | 274.6 | Yes | Yes | 18.289 | 2.03 | 3.52 | 1.03 | 1.75 | 1.09 | 2.70 | 2.08 | 1.04 | 1.00 | 1.00 | 1.04 | 32 | | doh.li | rfc8484 | 2601.6 | No | No | 22.268 | 2.25 | 3.30 | 1.03 | 1.75 | 1.09 | 2.70 | 6.06 | 1.04 | 1.00 | 1.00 | 1.04 | 33 | | doh.li | tls | 1548.8 | No | No | 2006.833 | 52.21 | 52.41 | 37.05 | 1.02 | 5.28 | 1845.36 | 9.39 | 1.04 | 1.00 | 1.05 | 1.04 | 34 | | dyn | tcp | not available | | | | | | | | | | | | | | | 35 | | dyn | udp | 256.4 | Yes | No | 80.626 | 2.15 | 3.45 | 43.44 | 1.75 | 1.09 | 2.70 | 4.88 | 1.80 | 17.31 | 1.00 | 1.04 | 36 | | freedns | udp | 337.4 | Yes | No | 238.563 | 44.72 | 54.04 | 38.96 | 17.25 | 5.38 | 39.66 | 8.18 | 1.80 | 17.31 | 10.19 | 1.08 | 37 | | freenom | tcp | 72.33333333333333 | No | No | 2330.732 | 16.04 | 24.53 | 9.47 | 5.76 | 5.38 | 11.38 | 2.29 | 1.80 | 2247.19 | 5.81 | 1.08 | 38 | | freenom | udp | 271.4 | Yes | No | 100.852 | 16.04 | 24.53 | 9.47 | 5.76 | 5.38 | 11.38 | 2.29 | 1.80 | 17.31 | 5.81 | 1.08 | 39 | | google | google | not available | | | | | | | | | | | | | | | 40 | | google | rfc8484 | not available | | | | | | | | | | | | | | | 41 | | google | tcp | 105.2 | No | Yes | 33.717 | 2.03 | 3.45 | 1.03 | 17.25 | 1.09 | 2.70 | 2.08 | 1.04 | 1.00 | 1.00 | 1.04 | 42 | | google | tls | 856.0 | No | Yes | 35.707 | 2.03 | 3.45 | 1.03 | 17.25 | 1.09 | 2.70 | 4.07 | 1.04 | 1.00 | 1.00 | 1.04 | 43 | | google | udp | 265.2 | Yes | Yes | 23.586 | 2.15 | 3.52 | 1.03 | 3.52 | 1.09 | 2.70 | 2.08 | 1.04 | 4.41 | 1.00 | 1.04 | 44 | | he | rfc8484 | not available | | | | | | | | | | | | | | | 45 | | he | tcp | 333.8 | No | No | 527.197 | 26.65 | 27.35 | 21.20 | 17.25 | 25.82 | 27.36 | 4.87 | 1.80 | 17.31 | 5.52 | 352.08 | 46 | | he | udp | 275.8 | Yes | No | 176.602 | 26.65 | 27.35 | 21.20 | 17.25 | 25.82 | 27.36 | 5.27 | 1.80 | 17.31 | 5.52 | 1.08 | 47 | | neustar | tcp | 41.2 | No | No | 55.175 | 1.07 | 1.03 | 20.36 | 17.25 | 1.00 | 1.04 | 5.91 | 1.04 | 4.41 | 1.05 | 1.04 | 48 | | neustar | udp | 275.4 | No | No | 51.765 | 1.07 | 1.03 | 20.36 | 17.25 | 1.00 | 1.04 | 5.91 | 1.04 | 1.00 | 1.05 | 1.04 | 49 | | nextdns | rfc8484 | 1475.0 | No | No | 160.866 | 24.96 | 26.18 | 38.69 | 7.20 | 5.38 | 25.90 | 7.13 | 1.80 | 17.31 | 5.24 | 1.08 | 50 | | nextdns | tcp | 277.6 | No | No | 164.595 | 26.08 | 26.18 | 38.69 | 7.20 | 5.38 | 25.90 | 9.74 | 1.80 | 17.31 | 5.24 | 1.08 | 51 | | nextdns | tls | 2328.4 | No | No | 161.983 | 26.08 | 26.18 | 38.69 | 7.20 | 5.38 | 25.90 | 7.13 | 1.80 | 17.31 | 5.24 | 1.08 | 52 | | nextdns | udp | 264.0 | Yes | No | 163.289 | 26.08 | 26.18 | 38.69 | 7.20 | 5.38 | 25.90 | 8.43 | 1.80 | 17.31 | 5.24 | 1.08 | 53 | | onedns | udp | 257.0 | Yes | No | 18.092 | 2.03 | 3.32 | 1.03 | 1.75 | 1.09 | 2.70 | 2.08 | 1.04 | 1.00 | 1.00 | 1.04 | 54 | | opendns | rfc8484 | not available | | | | | | | | | | | | | | | 55 | | opendns | tcp | 113.8 | No | No | 43.280 | 2.15 | 3.45 | 1.03 | 1.75 | 5.38 | 7.20 | 5.56 | 1.04 | 7.82 | 6.87 | 1.04 | 56 | | opendns | udp | 253.8 | Yes | No | 36.407 | 2.15 | 3.45 | 1.03 | 1.75 | 5.38 | 7.20 | 4.07 | 1.04 | 4.41 | 4.89 | 1.04 | 57 | | opennic | tcp | 632.0 | No | No | 239.597 | 52.21 | 52.41 | 38.57 | 17.25 | 5.38 | 35.23 | 8.36 | 1.80 | 17.31 | 10.01 | 1.08 | 58 | | opennic | udp | 356.0 | Yes | No | 229.195 | 52.21 | 52.41 | 32.14 | 17.25 | 5.38 | 35.23 | 7.09 | 1.80 | 17.31 | 7.31 | 1.08 | 59 | | quad9 | rfc8484 | 2578.2 | No | No | 115.379 | 26.65 | 26.75 | 8.88 | 7.20 | 5.38 | 13.70 | 2.75 | 1.80 | 17.31 | 3.88 | 1.08 | 60 | | quad9 | tcp | 691.0 | No | No | 112.908 | 26.65 | 26.75 | 8.88 | 7.20 | 5.38 | 13.70 | 2.91 | 1.80 | 17.31 | 1.25 | 1.08 | 61 | | quad9 | tls | 2576.6 | No | No | 120.808 | 26.65 | 26.75 | 14.31 | 7.20 | 5.38 | 13.70 | 2.75 | 1.80 | 17.31 | 3.88 | 1.08 | 62 | | quad9 | udp | 325.8 | Yes | No | 115.285 | 26.65 | 26.82 | 8.88 | 7.20 | 5.38 | 13.70 | 2.59 | 1.80 | 17.31 | 3.88 | 1.08 | 63 | | safedns | tcp | 182.6 | No | No | 100.351 | 16.04 | 24.53 | 9.47 | 5.76 | 5.38 | 11.38 | 3.63 | 1.80 | 17.31 | 3.98 | 1.08 | 64 | | safedns | udp | 267.2 | Yes | No | 102.786 | 16.04 | 24.53 | 9.47 | 5.76 | 5.38 | 11.38 | 6.06 | 1.80 | 17.31 | 3.98 | 1.08 | 65 | | twnic | rfc8484 | 2156.8 | No | No | 88.818 | 16.68 | 16.68 | 9.40 | 3.52 | 5.38 | 10.98 | 2.61 | 1.80 | 17.31 | 3.39 | 1.08 | 66 | | twnic | tcp | 815.2 | No | No | 88.306 | 16.62 | 16.68 | 9.40 | 3.52 | 5.38 | 10.98 | 2.16 | 1.80 | 17.31 | 3.39 | 1.08 | 67 | | twnic | tls | 1016.4 | No | Yes | 88.763 | 16.62 | 16.68 | 9.40 | 3.52 | 5.38 | 10.98 | 2.62 | 1.80 | 17.31 | 3.39 | 1.08 | 68 | | twnic | udp | 264.2 | Yes | No | 88.306 | 16.62 | 16.68 | 9.40 | 3.52 | 5.38 | 10.98 | 2.16 | 1.80 | 17.31 | 3.39 | 1.08 | 69 | | verisign | tcp | 105.4 | No | No | 110.490 | 16.04 | 24.53 | 9.47 | 17.25 | 5.38 | 11.38 | 2.29 | 1.80 | 17.31 | 3.97 | 1.08 | 70 | | verisign | udp | 279.6 | Yes | No | 110.490 | 16.04 | 24.53 | 9.47 | 17.25 | 5.38 | 11.38 | 2.29 | 1.80 | 17.31 | 3.97 | 1.08 | 71 | | yandex | tcp | 763.2 | No | No | 227.232 | 48.93 | 48.03 | 38.51 | 3.52 | 5.38 | 42.71 | 9.15 | 1.80 | 17.31 | 10.82 | 1.08 | 72 | | yandex | udp | 391.2 | Yes | No | 237.811 | 48.93 | 48.03 | 38.51 | 3.52 | 5.38 | 42.71 | 7.43 | 1.80 | 29.61 | 10.82 | 1.08 | 73 | -------------------------------------------------------------------------------- /data/sh-telecom.md: -------------------------------------------------------------------------------- 1 | | vendor | protocol | latency | poisoned | edns-client-subnet | accuracy | taobao | tmall | qq | baidu | sohu | jd | amazon | bing | linkedin | weibo | meituan | 2 | | ------ | -------- | ------- | -------- | ------------------ | -------- | ------ | ----- | -- | ----- | ---- | -- | ------ | ---- | -------- | ----- | ------- | 3 | | 114 | tcp | 21.8 | Yes | No | 12.145 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 1.72 | 1.04 | 1.00 | 1.12 | 1.06 | 4 | | 114 | udp | 17.2 | Yes | No | 12.238 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 1.81 | 1.04 | 1.00 | 1.12 | 1.06 | 5 | | adguard | rfc8484 | 362.8 | No | No | 1724.679 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 2.46 | 1.96 | 12.70 | 3.29 | 1.09 | 6 | | adguard | tcp | 144.0 | No | No | 1729.756 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 2.46 | 1.96 | 12.70 | 8.36 | 1.09 | 7 | | adguard | tls | 289.6 | No | No | 1729.194 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 4.91 | 1.96 | 12.70 | 5.35 | 1.09 | 8 | | adguard | udp | 72.6 | Yes | No | 1753.247 | 839.44 | 828.27 | 38.88 | 8.84 | 4.78 | 11.53 | 2.46 | 1.96 | 12.70 | 3.29 | 1.09 | 9 | | alidns | rfc8484 | 82.6 | Yes | Yes | 19.767 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 3.87 | 1.04 | 6.48 | 1.12 | 1.06 | 10 | | alidns | tcp | 17.2 | Yes | Yes | 14.235 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 1.07 | 1.04 | 3.74 | 1.12 | 1.06 | 11 | | alidns | tls | 84.8 | Yes | Yes | 19.767 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 3.87 | 1.04 | 6.48 | 1.12 | 1.06 | 12 | | alidns | udp | 9.2 | Yes | Yes | 19.760 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.00 | 3.87 | 1.04 | 6.48 | 1.12 | 1.06 | 13 | | baidu | udp | 41.2 | Yes | No | 17.809 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 1.91 | 1.04 | 6.48 | 1.12 | 1.06 | 14 | | cloudflare | rfc8484 | 220.2 | No | No | 63.238 | 5.72 | 5.64 | 19.78 | 3.10 | 4.78 | 4.96 | 1.02 | 1.96 | 12.70 | 2.49 | 1.09 | 15 | | cloudflare | tcp | 68.0 | No | No | 63.238 | 5.72 | 5.64 | 19.78 | 3.10 | 4.78 | 4.96 | 1.02 | 1.96 | 12.70 | 2.49 | 1.09 | 16 | | cloudflare | tls | 194.6 | No | No | 63.238 | 5.72 | 5.64 | 19.78 | 3.10 | 4.78 | 4.96 | 1.02 | 1.96 | 12.70 | 2.49 | 1.09 | 17 | | cloudflare | udp | 33.8 | Yes | No | 63.217 | 5.69 | 5.64 | 19.78 | 3.10 | 4.78 | 4.96 | 1.02 | 1.96 | 12.70 | 2.49 | 1.09 | 18 | | cnnic | udp | 12.2 | No | No | 28.305 | 2.29 | 2.47 | 5.86 | 1.03 | 4.34 | 2.32 | 3.04 | 1.04 | 3.74 | 1.12 | 1.06 | 19 | | comodo | tcp | 185.0 | No | No | 1723.151 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 1.88 | 1.96 | 12.70 | 2.33 | 1.09 | 20 | | comodo | udp | 95.8 | Yes | No | 1723.151 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 1.88 | 1.96 | 12.70 | 2.33 | 1.09 | 21 | | containerpi | google | 385.2 | No | No | 37.216 | 1.02 | 1.04 | 8.45 | 5.59 | 4.78 | 1.01 | 1.07 | 1.96 | 9.59 | 1.64 | 1.06 | 22 | | containerpi | rfc8484 | 351.4 | No | No | 62.003 | 13.61 | 13.42 | 1.10 | 10.15 | 2.89 | 4.89 | 2.86 | 1.96 | 6.85 | 3.18 | 1.09 | 23 | | containerpi | tls | 257.0 | No | No | 81.218 | 13.60 | 13.42 | 9.84 | 10.15 | 4.78 | 8.77 | 1.72 | 1.96 | 12.70 | 3.18 | 1.09 | 24 | | dnslify | rfc8484 | 279.4 | No | No | 1723.340 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 2.07 | 1.96 | 12.70 | 2.33 | 1.09 | 25 | | dnslify | tcp | 150.6 | No | No | 1723.340 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 2.07 | 1.96 | 12.70 | 2.33 | 1.09 | 26 | | dnslify | udp | 73.4 | Yes | No | 1723.340 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 2.07 | 1.96 | 12.70 | 2.33 | 1.09 | 27 | | dnspai | udp | 6.8 | Yes | No | 17.795 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.00 | 1.91 | 1.04 | 6.48 | 1.12 | 1.06 | 28 | | dnspod | tcp | 83.4 | Yes | No | 39.097 | 5.42 | 5.25 | 5.86 | 2.83 | 4.83 | 4.74 | 5.95 | 1.04 | 1.00 | 1.12 | 1.06 | 29 | | dnspod | udp | 8.2 | Yes | Yes | 14.360 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.00 | 3.95 | 1.04 | 1.00 | 1.12 | 1.06 | 30 | | dns-watch | tcp | 523.0 | No | No | 1964.058 | 33.50 | 33.05 | 37.14 | 3.10 | 4.78 | 34.39 | 6.08 | 1.96 | 1798.24 | 10.73 | 1.09 | 31 | | dns-watch | udp | 231.2 | Yes | No | 187.675 | 33.50 | 33.05 | 43.56 | 3.10 | 4.78 | 34.39 | 8.81 | 1.96 | 12.70 | 10.73 | 1.09 | 32 | | doh.li | rfc8484 | 853.0 | No | No | 11.497 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 1.07 | 1.04 | 1.00 | 1.12 | 1.06 | 33 | | doh.li | tls | 690.2 | No | No | 1631.628 | 6.51 | 33.07 | 38.31 | 1.03 | 4.34 | 1525.09 | 6.44 | 1.96 | 12.70 | 1.12 | 1.06 | 34 | | dyn | tcp | 78.2 | No | No | 42.726 | 1.02 | 1.04 | 19.78 | 1.03 | 1.00 | 1.01 | 1.00 | 1.96 | 12.70 | 1.12 | 1.06 | 35 | | dyn | udp | 36.2 | Yes | No | 42.712 | 1.02 | 1.04 | 19.78 | 1.03 | 1.00 | 1.00 | 1.00 | 1.96 | 12.70 | 1.12 | 1.06 | 36 | | freedns | udp | 287.0 | Yes | No | 195.614 | 33.50 | 42.85 | 40.50 | 14.03 | 4.78 | 29.37 | 6.59 | 1.96 | 12.70 | 8.23 | 1.09 | 37 | | freenom | tcp | 243.6 | No | No | 1736.478 | 839.44 | 828.27 | 19.78 | 8.84 | 4.78 | 11.53 | 5.45 | 1.96 | 12.70 | 2.63 | 1.09 | 38 | | freenom | udp | 144.4 | Yes | No | 1739.353 | 839.44 | 828.27 | 22.65 | 8.84 | 4.78 | 11.53 | 5.45 | 1.96 | 12.70 | 2.63 | 1.09 | 39 | | google | google | 12865.8 | No | Yes | 83.330 | 13.60 | 13.42 | 10.32 | 10.15 | 4.78 | 8.77 | 2.86 | 1.96 | 12.70 | 3.68 | 1.09 | 40 | | google | rfc8484 | 12841.0 | No | Yes | 83.349 | 13.60 | 13.42 | 10.32 | 10.15 | 4.78 | 8.77 | 2.88 | 1.96 | 12.70 | 3.68 | 1.09 | 41 | | google | tcp | 142.0 | No | Yes | 30.292 | 1.02 | 1.04 | 4.04 | 10.39 | 1.00 | 1.01 | 1.72 | 1.04 | 6.85 | 1.12 | 1.06 | 42 | | google | tls | 232.4 | No | Yes | 30.487 | 1.02 | 1.04 | 4.04 | 14.03 | 1.00 | 1.00 | 1.40 | 1.04 | 3.74 | 1.12 | 1.06 | 43 | | google | udp | 52.4 | Yes | Yes | 19.354 | 1.02 | 1.04 | 1.10 | 3.10 | 1.00 | 1.00 | 1.40 | 1.04 | 6.48 | 1.12 | 1.06 | 44 | | he | rfc8484 | not available | | | | | | | | | | | | | | | 45 | | he | tcp | 444.6 | No | No | 149.887 | 23.25 | 20.63 | 24.84 | 14.03 | 22.04 | 20.56 | 3.91 | 1.96 | 12.70 | 4.85 | 1.09 | 46 | | he | udp | 238.4 | Yes | No | 150.435 | 23.25 | 20.63 | 24.84 | 14.03 | 22.04 | 20.56 | 4.46 | 1.96 | 12.70 | 4.85 | 1.09 | 47 | | neustar | tcp | 17.6 | No | No | 45.740 | 1.02 | 1.04 | 19.78 | 14.03 | 1.00 | 1.01 | 3.63 | 1.04 | 1.00 | 1.12 | 1.06 | 48 | | neustar | udp | 8.6 | No | No | 50.354 | 1.02 | 1.04 | 19.78 | 14.03 | 1.00 | 1.01 | 2.77 | 1.04 | 6.48 | 1.12 | 1.06 | 49 | | nextdns | rfc8484 | 225.8 | No | No | 70.747 | 11.64 | 11.48 | 4.65 | 8.84 | 4.78 | 10.47 | 2.14 | 1.96 | 12.70 | 1.00 | 1.09 | 50 | | nextdns | tcp | 101.4 | No | No | 70.747 | 11.64 | 11.48 | 4.65 | 8.84 | 4.78 | 10.47 | 2.14 | 1.96 | 12.70 | 1.00 | 1.09 | 51 | | nextdns | tls | 261.4 | No | No | 70.747 | 11.64 | 11.48 | 4.65 | 8.84 | 4.78 | 10.47 | 2.14 | 1.96 | 12.70 | 1.00 | 1.09 | 52 | | nextdns | udp | 52.4 | Yes | No | 70.720 | 11.64 | 11.45 | 4.65 | 8.84 | 4.78 | 10.47 | 2.14 | 1.96 | 12.70 | 1.00 | 1.09 | 53 | | onedns | udp | 39.4 | Yes | No | 13.284 | 1.02 | 1.04 | 1.10 | 1.03 | 1.00 | 1.01 | 2.86 | 1.04 | 1.00 | 1.12 | 1.06 | 54 | | opendns | rfc8484 | 234.4 | No | No | 48.697 | 5.72 | 5.64 | 12.68 | 3.10 | 4.78 | 4.96 | 1.01 | 1.96 | 6.48 | 1.29 | 1.09 | 55 | | opendns | tcp | 138.2 | No | No | 16.625 | 1.02 | 1.04 | 1.10 | 1.03 | 4.78 | 1.01 | 1.40 | 1.04 | 1.00 | 2.14 | 1.06 | 56 | | opendns | udp | 59.2 | Yes | No | 15.881 | 1.02 | 1.04 | 1.10 | 1.03 | 4.78 | 1.01 | 1.07 | 1.04 | 1.00 | 1.73 | 1.06 | 57 | | opennic | tcp | 268.8 | No | No | 1723.151 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 1.88 | 1.96 | 12.70 | 2.33 | 1.09 | 58 | | opennic | udp | 72.2 | Yes | No | 1723.151 | 839.44 | 828.27 | 10.32 | 8.84 | 4.78 | 11.53 | 1.88 | 1.96 | 12.70 | 2.33 | 1.09 | 59 | | quad9 | rfc8484 | 394.8 | No | No | 108.257 | 23.25 | 22.94 | 17.76 | 8.84 | 4.78 | 11.53 | 2.09 | 1.96 | 12.70 | 1.31 | 1.09 | 60 | | quad9 | tcp | 178.8 | No | No | 109.874 | 23.25 | 22.94 | 17.76 | 8.84 | 4.78 | 11.53 | 3.70 | 1.96 | 12.70 | 1.31 | 1.09 | 61 | | quad9 | tls | 324.0 | No | No | 109.058 | 23.25 | 22.94 | 17.76 | 8.84 | 4.78 | 11.53 | 2.89 | 1.96 | 12.70 | 1.31 | 1.09 | 62 | | quad9 | udp | 95.0 | Yes | No | 108.245 | 23.25 | 22.94 | 17.76 | 8.84 | 4.78 | 11.53 | 2.07 | 1.96 | 12.70 | 1.31 | 1.09 | 63 | | safedns | tcp | 626.6 | No | No | 202.060 | 44.56 | 43.96 | 38.32 | 14.03 | 4.78 | 29.94 | 1.07 | 1.96 | 12.70 | 9.64 | 1.09 | 64 | | safedns | udp | 199.8 | Yes | No | 202.061 | 44.56 | 43.96 | 38.32 | 14.03 | 4.78 | 29.94 | 1.07 | 1.96 | 12.70 | 9.64 | 1.09 | 65 | | twnic | rfc8484 | not available | | | | | | | | | | | | | | | 66 | | twnic | tcp | 953.0 | No | No | 77.977 | 14.53 | 14.33 | 10.17 | 3.10 | 4.78 | 9.94 | 1.88 | 1.96 | 12.70 | 3.49 | 1.09 | 67 | | twnic | tls | not available | | | | | | | | | | | | | | | 68 | | twnic | udp | 193.0 | Yes | No | 78.965 | 14.53 | 14.33 | 10.17 | 3.10 | 4.78 | 9.94 | 2.86 | 1.96 | 12.70 | 3.49 | 1.09 | 69 | | verisign | tcp | 67.8 | No | No | 72.744 | 5.72 | 5.42 | 19.78 | 14.03 | 4.78 | 4.96 | 1.00 | 1.96 | 12.70 | 1.31 | 1.09 | 70 | | verisign | udp | 36.0 | Yes | No | 73.826 | 5.72 | 5.42 | 19.78 | 14.03 | 4.78 | 4.96 | 2.08 | 1.96 | 12.70 | 1.31 | 1.09 | 71 | | yandex | tcp | 588.0 | No | No | 211.649 | 41.16 | 40.06 | 40.29 | 3.10 | 4.78 | 36.86 | 6.76 | 1.96 | 24.69 | 10.90 | 1.09 | 72 | | yandex | udp | 305.0 | Yes | No | 560.894 | 41.16 | 40.06 | 40.29 | 3.10 | 4.78 | 36.86 | 6.26 | 1.96 | 36.67 | 10.90 | 338.85 | 73 | -------------------------------------------------------------------------------- /data/jp.md: -------------------------------------------------------------------------------- 1 | | vendor | protocol | latency | poisoned | edns-client-subnet | accuracy | taobao | tmall | qq | baidu | sohu | jd | amazon | bing | linkedin | weibo | meituan | 2 | | ------ | -------- | ------- | -------- | ------------------ | -------- | ------ | ----- | -- | ----- | ---- | -- | ------ | ---- | -------- | ----- | ------- | 3 | | 114 | tcp | 292.0 | No | No | 1321.684 | 116.20 | 116.20 | 132.18 | 71.09 | 2.12 | 115.57 | 187.41 | 1.06 | 1.00 | 577.87 | 1.00 | 4 | | 114 | udp | 146.0 | No | No | 1321.684 | 116.20 | 116.20 | 132.18 | 71.09 | 2.12 | 115.57 | 187.41 | 1.06 | 1.00 | 577.87 | 1.00 | 5 | | adguard | rfc8484 | 67.4 | No | No | 14.881 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 3.79 | 1.00 | 6 | | adguard | tcp | 0.4 | No | No | 15.874 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 4.78 | 1.00 | 7 | | adguard | tls | 84.6 | No | No | 15.428 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.45 | 1.06 | 1.00 | 4.78 | 1.00 | 8 | | adguard | udp | 0.0 | No | No | 13.887 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 2.80 | 1.00 | 9 | | alidns | rfc8484 | 981.8 | No | Yes | 1514.231 | 94.60 | 92.83 | 118.41 | 71.09 | 3.40 | 77.84 | 263.78 | 1.06 | 1.00 | 789.23 | 1.00 | 10 | | alidns | tcp | 237.8 | No | Yes | 1493.444 | 94.60 | 69.46 | 146.07 | 71.09 | 3.40 | 73.82 | 242.72 | 1.06 | 1.00 | 789.23 | 1.00 | 11 | | alidns | tls | 7109.8 | No | Yes | 43240.094 | 94.60 | 92.83 | 118.41 | 71.09 | 3.40 | 81.86 | 221.66 | 1.06 | 1.00 | 42553.19 | 1.00 | 12 | | alidns | udp | 128.25 | Yes | Yes | 1574.122 | 116.20 | 92.83 | 173.74 | 71.09 | 3.40 | 81.86 | 242.72 | 1.06 | 1.00 | 789.23 | 1.00 | 13 | | baidu | udp | 65.6 | No | No | 1083.755 | 28.57 | 28.56 | 107.71 | 31.99 | 1.00 | 27.58 | 112.62 | 172.83 | 193.83 | 378.07 | 1.00 | 14 | | cloudflare | rfc8484 | 99.6 | No | No | 16.228 | 1.01 | 1.01 | 1.50 | 1.13 | 1.00 | 1.00 | 1.74 | 1.06 | 1.00 | 4.78 | 1.00 | 15 | | cloudflare | tcp | 1.6 | No | No | 16.378 | 1.01 | 1.01 | 1.50 | 1.13 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 4.78 | 1.00 | 16 | | cloudflare | tls | 165.4 | No | No | 16.142 | 1.01 | 1.01 | 1.27 | 1.13 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 4.78 | 1.00 | 17 | | cloudflare | udp | 1.6 | No | No | 16.154 | 1.02 | 1.01 | 1.27 | 1.13 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 4.78 | 1.00 | 18 | | cnnic | udp | 134.33333333333334 | Yes | No | 1488.834 | 59.15 | 59.33 | 107.71 | 105.03 | 1.80 | 98.37 | 1.86 | 172.83 | 193.83 | 649.45 | 39.48 | 19 | | comodo | tcp | 2.6 | No | No | 82.953 | 1.01 | 1.01 | 1.00 | 71.09 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 20 | | comodo | udp | 39.2 | No | No | 82.953 | 1.01 | 1.01 | 1.00 | 71.09 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 21 | | containerpi | google | 84.8 | No | No | 716.897 | 1.01 | 2.94 | 1.00 | 1.13 | 1.00 | 55.87 | 1.45 | 1.06 | 1.00 | 649.45 | 1.00 | 22 | | containerpi | rfc8484 | 115.0 | No | Yes | 733.503 | 1.01 | 2.94 | 1.25 | 1.13 | 1.00 | 110.73 | 124.10 | 1.06 | 1.00 | 488.28 | 1.00 | 23 | | containerpi | tls | 71.8 | No | No | 16.378 | 1.01 | 1.01 | 1.50 | 1.13 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 4.78 | 1.00 | 24 | | dnslify | rfc8484 | 962.2 | No | No | 382.521 | 119.07 | 119.07 | 1.00 | 69.59 | 1.00 | 63.26 | 1.61 | 1.06 | 1.00 | 4.86 | 1.00 | 25 | | dnslify | tcp | 609.4 | No | No | 497.008 | 119.07 | 119.07 | 1.00 | 69.59 | 1.00 | 63.26 | 1.61 | 1.06 | 1.00 | 4.86 | 115.49 | 26 | | dnslify | udp | 298.2 | No | No | 382.521 | 119.07 | 119.07 | 1.00 | 69.59 | 1.00 | 63.26 | 1.61 | 1.06 | 1.00 | 4.86 | 1.00 | 27 | | dnspai | udp | 206.0 | No | No | 2064.772 | 123.86 | 136.83 | 197.57 | 138.67 | 4.34 | 130.94 | 276.97 | 172.83 | 193.83 | 649.45 | 39.48 | 28 | | dnspod | tcp | 240.6 | Yes | No | 1441.552 | 74.48 | 51.29 | 107.71 | 41.78 | 2.50 | 35.31 | 72.89 | 172.83 | 193.83 | 649.45 | 39.48 | 29 | | dnspod | udp | 128.4 | Yes | Yes | 251.782 | 1.01 | 1.01 | 240.73 | 1.13 | 1.00 | 1.00 | 1.86 | 1.06 | 1.00 | 1.00 | 1.00 | 30 | | dns-watch | tcp | 590.0 | No | No | 2325.898 | 168.83 | 168.83 | 253.06 | 31.99 | 1.00 | 184.59 | 410.89 | 1.06 | 1.00 | 1103.66 | 1.00 | 31 | | dns-watch | udp | 272.0 | No | No | 2325.898 | 168.83 | 168.83 | 253.06 | 31.99 | 1.00 | 184.59 | 410.89 | 1.06 | 1.00 | 1103.66 | 1.00 | 32 | | doh.li | rfc8484 | 1059.2 | No | No | 1490.153 | 1.01 | 1.01 | 213.17 | 1.13 | 1.00 | 1.00 | 333.12 | 1.06 | 1.00 | 935.66 | 1.00 | 33 | | doh.li | tls | 722.6 | No | No | 8095.619 | 185.60 | 79.23 | 213.17 | 138.67 | 3.40 | 6165.23 | 333.12 | 1.06 | 1.00 | 935.66 | 39.48 | 34 | | dyn | tcp | not available | | | | | | | | | | | | | | | 35 | | dyn | udp | 11.8 | No | No | 218.203 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 34.44 | 172.83 | 1.00 | 2.80 | 1.00 | 36 | | freedns | udp | 274.6 | No | No | 2258.441 | 168.83 | 164.50 | 217.36 | 71.09 | 1.00 | 162.94 | 285.78 | 1.06 | 1.00 | 1183.90 | 1.00 | 37 | | freenom | tcp | 737.8 | No | No | 1017.869 | 119.07 | 119.07 | 1.50 | 69.59 | 1.00 | 63.26 | 160.03 | 1.06 | 1.00 | 481.29 | 1.00 | 38 | | freenom | udp | 67.0 | No | No | 1017.919 | 119.12 | 119.07 | 1.50 | 69.59 | 1.00 | 63.26 | 160.03 | 1.06 | 1.00 | 481.29 | 1.00 | 39 | | google | google | 106.2 | No | Yes | 903.830 | 1.01 | 12.80 | 1.00 | 1.13 | 1.00 | 110.73 | 123.65 | 1.06 | 1.00 | 649.45 | 1.00 | 40 | | google | rfc8484 | 109.2 | No | Yes | 1027.259 | 1.01 | 13.58 | 1.00 | 1.13 | 1.00 | 110.73 | 246.31 | 1.06 | 1.00 | 649.45 | 1.00 | 41 | | google | tcp | 4.0 | No | Yes | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 42 | | google | tls | 98.8 | No | Yes | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 43 | | google | udp | 4.4 | No | Yes | 13.441 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.45 | 1.06 | 1.00 | 2.80 | 1.00 | 44 | | he | rfc8484 | 81.8 | No | No | 18.283 | 1.01 | 1.01 | 1.50 | 1.13 | 1.00 | 1.00 | 1.74 | 1.06 | 1.00 | 6.84 | 1.00 | 45 | | he | tcp | 22.4 | No | No | 6182.512 | 1.01 | 1.01 | 1.50 | 1.13 | 1.00 | 6165.23 | 1.74 | 1.06 | 1.00 | 6.84 | 1.00 | 46 | | he | udp | 0.2 | No | No | 18.283 | 1.01 | 1.01 | 1.50 | 1.13 | 1.00 | 1.00 | 1.74 | 1.06 | 1.00 | 6.84 | 1.00 | 47 | | neustar | tcp | 63.4 | No | No | 322.388 | 20.86 | 20.86 | 49.79 | 71.09 | 1.00 | 19.71 | 1.86 | 1.06 | 1.00 | 134.16 | 1.00 | 48 | | neustar | udp | 31.6 | No | No | 322.388 | 20.86 | 20.86 | 49.79 | 71.09 | 1.00 | 19.71 | 1.86 | 1.06 | 1.00 | 134.16 | 1.00 | 49 | | nextdns | rfc8484 | 140.2 | No | No | 191.669 | 1.01 | 4.88 | 1.00 | 1.13 | 1.00 | 1.00 | 175.80 | 1.06 | 1.00 | 2.80 | 1.00 | 50 | | nextdns | tcp | 1.0 | No | No | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 51 | | nextdns | tls | 70.8 | No | No | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 52 | | nextdns | udp | 0.4 | No | No | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 53 | | onedns | udp | 173.0 | No | No | 17224.710 | 6435.01 | 154.47 | 124.63 | 135.40 | 4.72 | 126.00 | 1.86 | 172.83 | 9380.86 | 649.45 | 39.48 | 54 | | opendns | rfc8484 | 76.0 | No | No | 45.518 | 1.01 | 1.01 | 1.27 | 31.99 | 1.00 | 1.00 | 2.33 | 1.06 | 1.00 | 2.86 | 1.00 | 55 | | opendns | tcp | 15.4 | No | No | 13.441 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.45 | 1.06 | 1.00 | 2.80 | 1.00 | 56 | | opendns | udp | 3.4 | No | No | 13.441 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.45 | 1.06 | 1.00 | 2.80 | 1.00 | 57 | | opennic | tcp | 63.2 | No | No | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 58 | | opennic | udp | 141.4 | No | No | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 59 | | quad9 | rfc8484 | 98.4 | No | No | 84.835 | 1.01 | 1.01 | 1.50 | 69.59 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 4.78 | 1.00 | 60 | | quad9 | tcp | 240.2 | No | No | 1454.735 | 73.00 | 73.00 | 1.00 | 69.59 | 1.00 | 63.26 | 160.43 | 1.06 | 1.00 | 1010.39 | 1.00 | 61 | | quad9 | tls | 114.4 | No | No | 84.760 | 1.01 | 1.01 | 1.50 | 69.59 | 1.00 | 1.00 | 1.82 | 1.06 | 1.00 | 4.78 | 1.00 | 62 | | quad9 | udp | 110.0 | No | No | 1194.354 | 73.00 | 73.00 | 1.33 | 69.59 | 1.00 | 63.26 | 168.40 | 1.06 | 1.00 | 741.71 | 1.00 | 63 | | safedns | tcp | 1.8 | No | No | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 64 | | safedns | udp | 72.6 | No | No | 12.995 | 1.01 | 1.01 | 1.00 | 1.13 | 1.00 | 1.00 | 1.00 | 1.06 | 1.00 | 2.80 | 1.00 | 65 | | twnic | rfc8484 | 2329.0 | No | No | 323.071 | 20.86 | 20.86 | 30.24 | 31.99 | 1.00 | 19.71 | 47.61 | 1.06 | 1.00 | 147.74 | 1.00 | 66 | | twnic | tcp | 670.0 | No | No | 323.071 | 20.86 | 20.86 | 30.24 | 31.99 | 1.00 | 19.71 | 47.61 | 1.06 | 1.00 | 147.74 | 1.00 | 67 | | twnic | tls | 321.2 | No | Yes | 373.363 | 20.86 | 20.86 | 30.24 | 31.99 | 1.00 | 19.71 | 97.90 | 1.06 | 1.00 | 147.74 | 1.00 | 68 | | twnic | udp | 32.2 | No | No | 373.363 | 20.86 | 20.86 | 30.24 | 31.99 | 1.00 | 19.71 | 97.90 | 1.06 | 1.00 | 147.74 | 1.00 | 69 | | verisign | tcp | 16.8 | No | No | 84.418 | 1.01 | 1.01 | 1.50 | 71.09 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 2.86 | 1.00 | 70 | | verisign | udp | 2.2 | No | No | 84.413 | 1.01 | 1.01 | 1.50 | 71.09 | 1.00 | 1.00 | 1.89 | 1.06 | 1.00 | 2.86 | 1.00 | 71 | | yandex | tcp | 669.2 | No | No | 2431.797 | 175.66 | 176.74 | 251.43 | 31.99 | 1.00 | 168.96 | 428.65 | 1.06 | 1.00 | 1194.30 | 1.00 | 72 | | yandex | udp | 287.8 | No | No | 2503.845 | 175.66 | 176.74 | 264.27 | 31.99 | 1.00 | 168.96 | 385.79 | 1.06 | 103.07 | 1194.30 | 1.00 | 73 | -------------------------------------------------------------------------------- /data/seattle.md: -------------------------------------------------------------------------------- 1 | | vendor | protocol | latency | poisoned | edns-client-subnet | accuracy | taobao | tmall | qq | baidu | sohu | jd | amazon | bing | linkedin | weibo | meituan | 2 | | ------ | -------- | ------- | -------- | ------------------ | -------- | ------ | ----- | -- | ----- | ---- | -- | ------ | ---- | -------- | ----- | ------- | 3 | | 114 | tcp | 106.0 | No | No | 502.171 | 2.96 | 202.35 | 107.64 | 1.00 | 1.00 | 60.36 | 1.00 | 1.04 | 1.00 | 122.82 | 1.00 | 4 | | 114 | udp | 53.6 | No | No | 502.171 | 2.96 | 202.35 | 107.64 | 1.00 | 1.00 | 60.36 | 1.00 | 1.04 | 1.00 | 122.82 | 1.00 | 5 | | adguard | rfc8484 | 91.0 | No | No | 214.401 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.04 | 1.00 | 1.05 | 1.00 | 6 | | adguard | tcp | 0.8 | No | No | 214.401 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.04 | 1.00 | 1.05 | 1.00 | 7 | | adguard | tls | 133.6 | No | No | 214.613 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.21 | 1.04 | 1.00 | 1.05 | 1.00 | 8 | | adguard | udp | 0.0 | No | No | 214.401 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.04 | 1.00 | 1.05 | 1.00 | 9 | | alidns | rfc8484 | 1751.2 | Yes | Yes | 446.354 | 1.06 | 129.28 | 38.48 | 1.00 | 10.35 | 50.91 | 88.66 | 1.04 | 1.00 | 123.56 | 1.00 | 10 | | alidns | tcp | 1292.6 | No | Yes | 1024.992 | 2.01 | 202.35 | 148.09 | 1.00 | 10.35 | 50.91 | 113.07 | 1.04 | 371.61 | 123.56 | 1.00 | 11 | | alidns | tls | 3940.4 | No | Yes | 1061.799 | 2.01 | 202.35 | 93.29 | 1.00 | 10.35 | 38.20 | 140.36 | 1.04 | 371.61 | 200.59 | 1.00 | 12 | | alidns | udp | 182.8 | Yes | Yes | 834.843 | 2.96 | 202.35 | 148.09 | 1.00 | 10.35 | 38.20 | 119.98 | 1.04 | 186.30 | 123.56 | 1.00 | 13 | | baidu | udp | 152.0 | No | No | 2148.733 | 6.18 | 423.33 | 405.49 | 8.22 | 8.74 | 213.03 | 296.21 | 381.61 | 1.00 | 403.91 | 1.00 | 14 | | cloudflare | rfc8484 | 163.2 | No | No | 215.643 | 2.96 | 202.35 | 1.61 | 1.00 | 1.00 | 1.00 | 1.14 | 1.04 | 1.00 | 1.53 | 1.00 | 15 | | cloudflare | tcp | 1.4 | No | No | 215.643 | 2.96 | 202.35 | 1.61 | 1.00 | 1.00 | 1.00 | 1.14 | 1.04 | 1.00 | 1.53 | 1.00 | 16 | | cloudflare | tls | 92.6 | No | No | 215.643 | 2.96 | 202.35 | 1.61 | 1.00 | 1.00 | 1.00 | 1.14 | 1.04 | 1.00 | 1.53 | 1.00 | 17 | | cloudflare | udp | 0.8 | No | No | 215.643 | 2.96 | 202.35 | 1.61 | 1.00 | 1.00 | 1.00 | 1.14 | 1.04 | 1.00 | 1.53 | 1.00 | 18 | | cnnic | udp | 201.5 | Yes | No | 2908.146 | 7.49 | 533.90 | 405.49 | 11.01 | 11.86 | 285.68 | 412.85 | 381.61 | 371.61 | 465.87 | 20.79 | 19 | | comodo | tcp | 7.0 | No | No | 511.675 | 1.06 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 300.05 | 1.04 | 1.00 | 1.17 | 1.00 | 20 | | comodo | udp | 1.6 | No | No | 511.675 | 1.06 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 300.05 | 1.04 | 1.00 | 1.17 | 1.00 | 21 | | containerpi | google | 601.0 | No | No | 1297.206 | 4.44 | 253.33 | 128.30 | 6.91 | 1.00 | 167.95 | 300.05 | 1.04 | 1.00 | 432.18 | 1.00 | 22 | | containerpi | rfc8484 | 480.2 | No | No | 1514.383 | 2.96 | 304.30 | 255.60 | 6.91 | 8.74 | 200.60 | 300.05 | 1.04 | 1.00 | 432.18 | 1.00 | 23 | | containerpi | tls | 367.4 | No | No | 1454.738 | 4.44 | 304.41 | 328.07 | 6.91 | 8.74 | 167.95 | 300.05 | 1.04 | 1.00 | 331.12 | 1.00 | 24 | | dnslify | rfc8484 | 159.2 | No | No | 40880.245 | 1.06 | 72.54 | 39.27 | 530.11 | 574.42 | 13908.21 | 44.66 | 1.04 | 1.00 | 25706.94 | 1.00 | 25 | | dnslify | tcp | 43.6 | No | No | 89855.117 | 400.14 | 27397.26 | 21231.42 | 530.11 | 574.42 | 13908.21 | 44.66 | 1.04 | 1.00 | 25706.94 | 59.91 | 26 | | dnslify | udp | 19.4 | No | No | 40939.156 | 1.06 | 72.54 | 39.27 | 530.11 | 574.42 | 13908.21 | 44.66 | 1.04 | 1.00 | 25706.94 | 59.91 | 27 | | dnspai | udp | 172.8 | Yes | No | 2374.501 | 7.65 | 450.03 | 380.79 | 9.47 | 12.10 | 233.25 | 46.82 | 381.61 | 366.13 | 465.87 | 20.79 | 28 | | dnspod | tcp | not available | | | | | | | | | | | | | | | 29 | | dnspod | udp | 217.0 | Yes | Yes | 523.060 | 1.06 | 202.35 | 56.63 | 1.00 | 8.74 | 190.32 | 11.90 | 1.04 | 1.00 | 48.00 | 1.00 | 30 | | dns-watch | tcp | 305.6666666666667 | No | No | 1631.270 | 6.02 | 412.45 | 291.39 | 8.22 | 8.74 | 197.44 | 346.04 | 1.04 | 1.00 | 357.91 | 1.00 | 31 | | dns-watch | udp | 142.8 | No | No | 1631.270 | 6.02 | 412.45 | 291.39 | 8.22 | 8.74 | 197.44 | 346.04 | 1.04 | 1.00 | 357.91 | 1.00 | 32 | | doh.li | rfc8484 | 616.6 | No | No | 1131.461 | 2.96 | 202.35 | 283.38 | 1.00 | 1.00 | 1.00 | 311.56 | 1.04 | 1.00 | 325.16 | 1.00 | 33 | | doh.li | tls | 453.4 | No | No | 42706.468 | 6.17 | 27397.26 | 283.38 | 9.47 | 10.35 | 13908.21 | 602.92 | 1.04 | 1.00 | 465.87 | 20.79 | 34 | | dyn | tcp | 92.4 | No | No | 219.219 | 2.01 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 6.56 | 1.04 | 1.00 | 1.26 | 1.00 | 35 | | dyn | udp | 0.2 | No | No | 219.219 | 2.01 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 6.56 | 1.04 | 1.00 | 1.26 | 1.00 | 36 | | freedns | udp | 156.8 | No | No | 1517.475 | 6.02 | 420.35 | 312.35 | 1.00 | 8.74 | 191.17 | 188.66 | 1.04 | 1.00 | 386.13 | 1.00 | 37 | | freenom | tcp | 368.75 | No | No | 1733.547 | 8.11 | 555.45 | 56.65 | 8.87 | 8.74 | 256.03 | 405.87 | 1.04 | 1.00 | 430.78 | 1.00 | 38 | | freenom | udp | 184.2 | No | No | 1947.400 | 8.11 | 555.45 | 270.51 | 8.87 | 8.74 | 256.03 | 405.87 | 1.04 | 1.00 | 430.78 | 1.00 | 39 | | google | google | 100.6 | No | Yes | 920.366 | 2.01 | 202.35 | 1.00 | 1.00 | 1.00 | 233.25 | 10.84 | 1.04 | 1.00 | 465.87 | 1.00 | 40 | | google | rfc8484 | 112.4 | No | No | 911.684 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 233.25 | 1.21 | 1.04 | 1.00 | 465.87 | 1.00 | 41 | | google | tcp | 13.8 | No | No | 223.615 | 1.06 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 11.90 | 1.04 | 1.00 | 1.26 | 1.00 | 42 | | google | tls | 121.8 | No | Yes | 212.928 | 1.06 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.21 | 1.04 | 1.00 | 1.26 | 1.00 | 43 | | google | udp | 41.4 | No | No | 225.511 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 11.90 | 1.04 | 1.00 | 1.26 | 1.00 | 44 | | he | rfc8484 | not available | | | | | | | | | | | | | | | 45 | | he | tcp | 7.6 | No | No | 13.668 | 2.96 | 1.20 | 1.00 | 1.00 | 1.00 | 1.00 | 1.21 | 1.04 | 1.00 | 1.26 | 1.00 | 46 | | he | udp | 4.4 | No | No | 11.703 | 1.06 | 1.20 | 1.00 | 1.00 | 1.00 | 1.00 | 1.14 | 1.04 | 1.00 | 1.26 | 1.00 | 47 | | neustar | tcp | 1.4 | No | No | 213.390 | 1.06 | 202.35 | 1.10 | 1.00 | 1.00 | 1.00 | 1.32 | 1.04 | 1.00 | 1.51 | 1.00 | 48 | | neustar | udp | 0.6 | No | No | 213.390 | 1.06 | 202.35 | 1.10 | 1.00 | 1.00 | 1.00 | 1.32 | 1.04 | 1.00 | 1.51 | 1.00 | 49 | | nextdns | rfc8484 | 115.0 | No | No | 322.157 | 1.06 | 137.45 | 52.61 | 1.00 | 1.00 | 20.93 | 36.70 | 1.04 | 1.00 | 68.37 | 1.00 | 50 | | nextdns | tcp | 1.0 | No | No | 40399.233 | 1.06 | 202.35 | 1.00 | 1.00 | 574.42 | 13908.21 | 1.21 | 1.04 | 1.00 | 25706.94 | 1.00 | 51 | | nextdns | tls | 86.6 | No | No | 40468.831 | 1.06 | 202.35 | 1.00 | 1.00 | 574.42 | 13908.21 | 11.90 | 1.04 | 1.00 | 25706.94 | 59.91 | 52 | | nextdns | udp | 0.6 | No | No | 14864.233 | 2.96 | 202.35 | 1.00 | 1.00 | 574.42 | 13908.21 | 169.72 | 1.04 | 1.00 | 1.53 | 1.00 | 53 | | onedns | udp | 183.2 | Yes | No | 3124.801 | 400.14 | 524.22 | 368.21 | 9.88 | 9.83 | 266.58 | 317.02 | 381.61 | 360.66 | 465.87 | 20.79 | 54 | | opendns | rfc8484 | 112.2 | No | No | 14128.196 | 2.01 | 202.35 | 1.00 | 8.22 | 1.00 | 13908.21 | 1.11 | 1.04 | 1.00 | 1.26 | 1.00 | 55 | | opendns | tcp | 12.8 | No | No | 220.481 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 6.56 | 1.04 | 1.00 | 1.57 | 1.00 | 56 | | opendns | udp | 36.8 | No | No | 219.376 | 2.01 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 6.56 | 1.04 | 1.00 | 1.41 | 1.00 | 57 | | opennic | tcp | 41.2 | No | No | 275.519 | 1.06 | 72.54 | 38.48 | 1.00 | 1.00 | 38.20 | 73.66 | 1.04 | 1.00 | 46.53 | 1.00 | 58 | | opennic | udp | 19.4 | No | No | 275.519 | 1.06 | 72.54 | 38.48 | 1.00 | 1.00 | 38.20 | 73.66 | 1.04 | 1.00 | 46.53 | 1.00 | 59 | | quad9 | rfc8484 | 128.4 | No | No | 214.864 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.04 | 1.00 | 1.51 | 1.00 | 60 | | quad9 | tcp | 1.2 | No | No | 215.007 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.14 | 1.04 | 1.00 | 1.51 | 1.00 | 61 | | quad9 | tls | 101.6 | No | Yes | 215.076 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.21 | 1.04 | 1.00 | 1.51 | 1.00 | 62 | | quad9 | udp | 0.6 | No | No | 214.970 | 2.96 | 202.35 | 1.00 | 1.00 | 1.00 | 1.00 | 1.11 | 1.04 | 1.00 | 1.51 | 1.00 | 63 | | safedns | tcp | 1.0 | No | No | 213.112 | 1.06 | 202.35 | 1.61 | 1.00 | 1.00 | 1.00 | 1.04 | 1.04 | 1.00 | 1.00 | 1.00 | 64 | | safedns | udp | 0.8 | No | No | 213.282 | 1.06 | 202.35 | 1.61 | 1.00 | 1.00 | 1.00 | 1.04 | 1.04 | 1.00 | 1.17 | 1.00 | 65 | | twnic | rfc8484 | 680.4 | No | No | 1732.219 | 6.09 | 417.07 | 303.48 | 8.22 | 8.74 | 196.71 | 413.96 | 1.04 | 1.00 | 374.89 | 1.00 | 66 | | twnic | tcp | 1098.2 | No | No | 1732.219 | 6.09 | 417.07 | 303.48 | 8.22 | 8.74 | 196.71 | 413.96 | 1.04 | 1.00 | 374.89 | 1.00 | 67 | | twnic | tls | 698.6 | No | Yes | 1701.584 | 6.09 | 417.07 | 303.48 | 8.22 | 8.74 | 196.71 | 383.33 | 1.04 | 1.00 | 374.89 | 1.00 | 68 | | twnic | udp | 145.4 | No | No | 1732.219 | 6.09 | 417.07 | 303.48 | 8.22 | 8.74 | 196.71 | 413.96 | 1.04 | 1.00 | 374.89 | 1.00 | 69 | | verisign | tcp | 254.2 | No | No | 303.978 | 1.06 | 72.54 | 57.60 | 1.00 | 1.00 | 38.20 | 55.06 | 1.04 | 1.00 | 74.47 | 1.00 | 70 | | verisign | udp | 25.6 | No | No | 366.459 | 1.06 | 72.54 | 57.60 | 1.00 | 1.00 | 38.20 | 117.54 | 1.04 | 1.00 | 74.47 | 1.00 | 71 | | yandex | tcp | 406.4 | No | No | 29079.533 | 7.05 | 27397.26 | 285.73 | 8.22 | 8.74 | 248.11 | 377.64 | 1.04 | 260.68 | 484.05 | 1.00 | 72 | | yandex | udp | 201.4 | No | No | 1898.528 | 7.05 | 475.94 | 285.73 | 8.22 | 8.74 | 248.11 | 377.64 | 1.04 | 1.00 | 484.05 | 1.00 | 73 | -------------------------------------------------------------------------------- /drivers/google.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "encoding/json" 7 | "fmt" 8 | "net" 9 | "net/http" 10 | "strconv" 11 | "strings" 12 | "time" 13 | 14 | "github.com/miekg/dns" 15 | ) 16 | 17 | func ParseUint(s string) (n uint64) { 18 | n, err := strconv.ParseUint(s, 10, 32) 19 | if err != nil { 20 | logger.Error("ParseUint error.") 21 | return 22 | } 23 | return 24 | } 25 | 26 | type GoogleClient struct { 27 | URL string 28 | Insecure bool 29 | Timeout int 30 | transport *http.Transport 31 | } 32 | 33 | func NewGoogleClient(URL string, body json.RawMessage) (cli *GoogleClient) { 34 | cli = &GoogleClient{} 35 | if body != nil { 36 | err := json.Unmarshal(body, &cli) 37 | if err != nil { 38 | panic(err.Error()) 39 | } 40 | } 41 | 42 | cli.URL = URL 43 | if Insecure { 44 | cli.Insecure = Insecure 45 | } 46 | if Timeout != 0 { 47 | cli.Timeout = Timeout 48 | } 49 | 50 | cli.transport = &http.Transport{ 51 | Proxy: http.ProxyFromEnvironment, 52 | } 53 | if cli.Insecure { 54 | cli.transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} 55 | } 56 | 57 | return 58 | } 59 | 60 | func (cli *GoogleClient) Url() (u string) { 61 | return cli.URL 62 | } 63 | 64 | func (cli *GoogleClient) Exchange(ctx context.Context, quiz *dns.Msg) (ans *dns.Msg, err error) { 65 | if cli.Timeout != 0 { 66 | ctx, _ = context.WithTimeout(ctx, time.Duration(cli.Timeout)*time.Millisecond) 67 | } 68 | 69 | req, err := http.NewRequestWithContext(ctx, "GET", cli.URL, nil) 70 | if err != nil { 71 | return 72 | } 73 | 74 | query := req.URL.Query() 75 | query.Add("name", quiz.Question[0].Name) 76 | query.Add("type", dns.TypeToString[quiz.Question[0].Qtype]) 77 | 78 | opt := quiz.IsEdns0() 79 | if opt != nil { 80 | for _, o := range opt.Option { 81 | if e, ok := o.(*dns.EDNS0_SUBNET); ok { 82 | subnet := fmt.Sprintf("%s/%d", e.Address.String(), e.SourceNetmask) 83 | query.Add("edns_client_subnet", subnet) 84 | break 85 | } 86 | } 87 | } 88 | 89 | req.URL.RawQuery = query.Encode() 90 | logger.Debugf("query: %s", req.URL.RawQuery) 91 | 92 | resp, err := cli.transport.RoundTrip(req) 93 | if err != nil { 94 | return 95 | } 96 | defer resp.Body.Close() 97 | 98 | if resp.StatusCode < 200 || resp.StatusCode >= 300 { 99 | err = ErrRequest 100 | return 101 | } 102 | 103 | jsonresp := &DNSMsg{} 104 | err = json.NewDecoder(resp.Body).Decode(&jsonresp) 105 | if err != nil { 106 | return 107 | } 108 | 109 | ans, err = jsonresp.TranslateAnswer(quiz) 110 | if err != nil { 111 | return 112 | } 113 | 114 | return 115 | } 116 | 117 | type GoogleHandler struct { 118 | EdnsClientSubnet string 119 | cli Client 120 | } 121 | 122 | func NewGoogleHandler(cli Client, EdnsClientSubnet string) (handler *GoogleHandler) { 123 | handler = &GoogleHandler{ 124 | EdnsClientSubnet: EdnsClientSubnet, 125 | cli: cli, 126 | } 127 | return 128 | } 129 | 130 | func (handler *GoogleHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 131 | defer req.Body.Close() 132 | 133 | err := req.ParseForm() 134 | if err != nil { 135 | logger.Error(err.Error()) 136 | w.WriteHeader(http.StatusBadRequest) 137 | return 138 | } 139 | 140 | quiz := &dns.Msg{} 141 | 142 | name := req.Form.Get("name") 143 | stype := req.Form.Get("type") 144 | qtype, ok := dns.StringToType[stype] 145 | if !ok { 146 | qtype = dns.TypeA 147 | } 148 | quiz.SetQuestion(dns.Fqdn(name), qtype) 149 | 150 | ecs := req.Form.Get("edns_client_subnet") 151 | err = HttpSetEdns0Subnet(w, req, ecs, handler.EdnsClientSubnet, quiz) 152 | if err != nil { 153 | return 154 | } 155 | 156 | if req.Form.Get("do") != "" { 157 | quiz.SetEdns0(4096, true) 158 | } 159 | 160 | logger.Infof("google server query: %s", quiz.Question[0].Name) 161 | 162 | ctx := context.Background() 163 | ans, err := handler.cli.Exchange(ctx, quiz) 164 | if err != nil { 165 | logger.Error(err.Error()) 166 | w.WriteHeader(http.StatusBadGateway) 167 | return 168 | } 169 | 170 | var bresp []byte 171 | if req.Form.Get("ct") == "application/dns-message" { 172 | bresp, err = ans.Pack() 173 | if err != nil { 174 | logger.Error(err.Error()) 175 | w.WriteHeader(http.StatusBadGateway) 176 | return 177 | } 178 | 179 | } else { 180 | jsonresp := &DNSMsg{} 181 | err = jsonresp.FromAnswer(quiz, ans) 182 | if err != nil { 183 | logger.Error(err.Error()) 184 | w.WriteHeader(http.StatusBadGateway) 185 | return 186 | } 187 | 188 | bresp, err = json.Marshal(jsonresp) 189 | if err != nil { 190 | logger.Error(err.Error()) 191 | w.WriteHeader(http.StatusInternalServerError) 192 | return 193 | } 194 | } 195 | 196 | w.Header().Add("Content-Type", "application/dns-message") 197 | w.Header().Add("Cache-Control", "no-cache, max-age=0") 198 | w.WriteHeader(http.StatusOK) 199 | 200 | err = WriteFull(w, bresp) 201 | if err != nil { 202 | logger.Error(err.Error()) 203 | w.WriteHeader(http.StatusBadGateway) 204 | return 205 | } 206 | 207 | return 208 | } 209 | 210 | type DNSMsg struct { 211 | Status int32 `json:"Status"` 212 | TC bool `json:"TC"` 213 | RD bool `json:"RD"` 214 | RA bool `json:"RA"` 215 | AD bool `json:"AD"` 216 | CD bool `json:"CD"` 217 | Question []DNSQuestion `json:"Question"` 218 | Answer []DNSRR `json:"Answer"` 219 | Authority []DNSRR `json:"Authority"` 220 | Additional []DNSRR `json:"Additional"` 221 | Edns_client_subnet string `json:"edns_client_subnet,omitempty"` 222 | Comment string `json:"Comment,omitempty"` 223 | } 224 | 225 | type DNSQuestion struct { 226 | Name string `json:"name"` 227 | Type int32 `json:"type"` 228 | } 229 | 230 | type DNSRR struct { 231 | Name string `json:"name"` 232 | Type int32 `json:"type"` 233 | TTL int32 `json:"TTL"` 234 | Data string `json:"data"` 235 | } 236 | 237 | func (msg *DNSMsg) TranslateAnswer(quiz *dns.Msg) (ans *dns.Msg, err error) { 238 | ans = &dns.Msg{ 239 | MsgHdr: dns.MsgHdr{ 240 | Id: quiz.Id, 241 | Response: (msg.Status == 0), 242 | Opcode: dns.OpcodeQuery, 243 | Authoritative: false, 244 | Truncated: msg.TC, 245 | RecursionDesired: msg.RD, 246 | RecursionAvailable: msg.RA, 247 | AuthenticatedData: msg.AD, 248 | CheckingDisabled: msg.CD, 249 | Rcode: int(msg.Status), 250 | }, 251 | Compress: quiz.Compress, 252 | } 253 | 254 | for idx, q := range msg.Question { 255 | ans.Question = append(ans.Question, 256 | dns.Question{ 257 | q.Name, 258 | uint16(q.Type), 259 | quiz.Question[idx].Qclass, 260 | }) 261 | } 262 | 263 | err = TranslateRRs(&msg.Answer, &ans.Answer) 264 | if err != nil { 265 | return 266 | } 267 | 268 | err = TranslateRRs(&msg.Authority, &ans.Ns) 269 | if err != nil { 270 | return 271 | } 272 | 273 | err = TranslateRRs(&msg.Additional, &ans.Extra) 274 | if err != nil { 275 | return 276 | } 277 | 278 | if msg.Edns_client_subnet != "" { 279 | var addr net.IP 280 | var mask uint8 281 | addr, mask, err = ParseSubnet(msg.Edns_client_subnet) 282 | if err != nil { 283 | logger.Errorf("can't parse subnet %s", msg.Edns_client_subnet) 284 | return 285 | } 286 | AppendEdns0Subnet(ans, addr, mask) 287 | } 288 | 289 | return 290 | } 291 | 292 | func TranslateRRs(jrs *[]DNSRR, rrs *[]dns.RR) (err error) { 293 | var rr dns.RR 294 | for _, jr := range *jrs { 295 | rr, err = jr.Translate() 296 | if err != nil { 297 | return 298 | } 299 | if rr != nil { 300 | *rrs = append(*rrs, rr) 301 | } 302 | } 303 | return 304 | } 305 | 306 | func (msg *DNSMsg) FromAnswer(quiz, ans *dns.Msg) (err error) { 307 | msg.Status = int32(ans.MsgHdr.Rcode) 308 | msg.TC = ans.MsgHdr.Truncated 309 | msg.RD = ans.MsgHdr.RecursionDesired 310 | msg.RA = ans.MsgHdr.RecursionAvailable 311 | msg.AD = ans.MsgHdr.AuthenticatedData 312 | msg.CD = ans.MsgHdr.CheckingDisabled 313 | 314 | for _, q := range ans.Question { 315 | msg.Question = append(msg.Question, 316 | DNSQuestion{ 317 | Name: q.Name, 318 | Type: int32(q.Qtype), 319 | }) 320 | } 321 | 322 | FromRRs(&msg.Answer, &ans.Answer) 323 | FromRRs(&msg.Authority, &ans.Ns) 324 | FromRRs(&msg.Additional, &ans.Extra) 325 | 326 | opt := quiz.IsEdns0() 327 | if opt != nil { 328 | for _, o := range opt.Option { 329 | if e, ok := o.(*dns.EDNS0_SUBNET); ok { 330 | msg.Edns_client_subnet = fmt.Sprintf("%s/%d", e.Address.String(), e.SourceNetmask) 331 | break 332 | } 333 | } 334 | } 335 | 336 | return 337 | } 338 | 339 | func FromRRs(jrs *[]DNSRR, rrs *[]dns.RR) { 340 | *jrs = make([]DNSRR, 0) 341 | for _, rr := range *rrs { 342 | jr := FromRR(rr) 343 | if jr != nil { 344 | *jrs = append(*jrs, *jr) 345 | } 346 | } 347 | } 348 | 349 | func (jr *DNSRR) Translate() (rr dns.RR, err error) { 350 | switch uint16(jr.Type) { 351 | case dns.TypeA: 352 | rr = &dns.A{ 353 | A: net.ParseIP(jr.Data), 354 | } 355 | case dns.TypeNS: 356 | rr = &dns.NS{ 357 | Ns: jr.Data, 358 | } 359 | case dns.TypeMD: 360 | rr = &dns.MD{ 361 | Md: jr.Data, 362 | } 363 | case dns.TypeMF: 364 | rr = &dns.MF{ 365 | Mf: jr.Data, 366 | } 367 | case dns.TypeCNAME: 368 | rr = &dns.CNAME{ 369 | Target: jr.Data, 370 | } 371 | case dns.TypeSOA: 372 | parts := strings.Split(jr.Data, " ") 373 | if len(parts) < 7 { 374 | return 375 | } 376 | rr = &dns.SOA{ 377 | Ns: parts[0], 378 | Mbox: parts[1], 379 | Serial: uint32(ParseUint(parts[2])), 380 | Refresh: uint32(ParseUint(parts[3])), 381 | Retry: uint32(ParseUint(parts[4])), 382 | Expire: uint32(ParseUint(parts[5])), 383 | Minttl: uint32(ParseUint(parts[6])), 384 | } 385 | case dns.TypeMB: 386 | rr = &dns.MB{ 387 | Mb: jr.Data, 388 | } 389 | case dns.TypeMG: 390 | rr = &dns.MG{ 391 | Mg: jr.Data, 392 | } 393 | case dns.TypeMR: 394 | rr = &dns.MR{ 395 | Mr: jr.Data, 396 | } 397 | case dns.TypeNULL: 398 | case dns.TypePTR: 399 | rr = &dns.PTR{ 400 | Ptr: jr.Data, 401 | } 402 | case dns.TypeHINFO: 403 | case dns.TypeMINFO: 404 | case dns.TypeMX: 405 | parts := strings.Split(jr.Data, " ") 406 | if len(parts) < 2 { 407 | return 408 | } 409 | rr = &dns.MX{ 410 | Preference: uint16(ParseUint(parts[0])), 411 | Mx: parts[1], 412 | } 413 | case dns.TypeTXT: 414 | rr = &dns.TXT{ 415 | Txt: strings.Split(jr.Data, " "), 416 | } 417 | case dns.TypeRP: 418 | parts := strings.Split(jr.Data, " ") 419 | if len(parts) < 2 { 420 | return 421 | } 422 | rr = &dns.RP{ 423 | Mbox: parts[0], 424 | Txt: parts[1], 425 | } 426 | case dns.TypeAAAA: 427 | rr = &dns.AAAA{ 428 | AAAA: net.ParseIP(jr.Data), 429 | } 430 | case dns.TypeSRV: 431 | parts := strings.Split(jr.Data, " ") 432 | if len(parts) < 4 { 433 | return 434 | } 435 | rr = &dns.SRV{ 436 | Priority: uint16(ParseUint(parts[0])), 437 | Weight: uint16(ParseUint(parts[1])), 438 | Port: uint16(ParseUint(parts[2])), 439 | Target: parts[3], 440 | } 441 | case dns.TypeSPF: 442 | rr = &dns.SPF{ 443 | Txt: strings.Split(jr.Data, " "), 444 | } 445 | case dns.TypeOPT: 446 | rr = &dns.OPT{} // FIXME: dummy 447 | case dns.TypeDS: 448 | parts := strings.Split(jr.Data, " ") 449 | if len(parts) < 4 { 450 | return 451 | } 452 | rr = &dns.DS{ 453 | KeyTag: uint16(ParseUint(parts[0])), 454 | Algorithm: uint8(ParseUint(parts[1])), 455 | DigestType: uint8(ParseUint(parts[2])), 456 | Digest: parts[3], 457 | } 458 | case dns.TypeSSHFP: 459 | parts := strings.Split(jr.Data, " ") 460 | if len(parts) < 3 { 461 | return 462 | } 463 | rr = &dns.SSHFP{ 464 | Algorithm: uint8(ParseUint(parts[0])), 465 | Type: uint8(ParseUint(parts[1])), 466 | FingerPrint: parts[2], 467 | } 468 | case dns.TypeRRSIG: 469 | parts := strings.Split(jr.Data, " ") 470 | if len(parts) < 9 { 471 | return 472 | } 473 | rrsig := &dns.RRSIG{ 474 | Algorithm: uint8(ParseUint(parts[1])), 475 | Labels: uint8(ParseUint(parts[2])), 476 | OrigTtl: uint32(ParseUint(parts[3])), 477 | Expiration: uint32(ParseUint(parts[4])), 478 | Inception: uint32(ParseUint(parts[5])), 479 | KeyTag: uint16(ParseUint(parts[6])), 480 | SignerName: parts[7], 481 | Signature: parts[8], 482 | } 483 | var ok bool 484 | if rrsig.TypeCovered, ok = dns.StringToType[strings.ToUpper(parts[0])]; !ok { 485 | return 486 | } 487 | rr = rrsig 488 | case dns.TypeNSEC: 489 | nsec := &dns.NSEC{} 490 | parts := strings.Split(jr.Data, " ") 491 | nsec.NextDomain = parts[0] 492 | for _, d := range parts[1:] { 493 | if typeBit, ok := dns.StringToType[strings.ToUpper(d)]; ok { 494 | nsec.TypeBitMap = append(nsec.TypeBitMap, typeBit) 495 | } 496 | } 497 | rr = nsec 498 | case dns.TypeDNSKEY: 499 | parts := strings.Split(jr.Data, " ") 500 | if len(parts) < 4 { 501 | return 502 | } 503 | rr = &dns.DNSKEY{ 504 | Flags: uint16(ParseUint(parts[0])), 505 | Protocol: uint8(ParseUint(parts[1])), 506 | Algorithm: uint8(ParseUint(parts[2])), 507 | PublicKey: parts[3], 508 | } 509 | case dns.TypeNSEC3: 510 | parts := strings.Split(jr.Data, " ") 511 | if len(parts) < 7 { 512 | return 513 | } 514 | nsec3 := &dns.NSEC3{ 515 | Hash: uint8(ParseUint(parts[0])), 516 | Flags: uint8(ParseUint(parts[1])), 517 | Iterations: uint16(ParseUint(parts[2])), 518 | SaltLength: uint8(ParseUint(parts[3])), 519 | Salt: parts[4], 520 | HashLength: uint8(ParseUint(parts[5])), 521 | NextDomain: parts[6], 522 | } 523 | for _, d := range parts[7:] { 524 | if t, ok := dns.StringToType[strings.ToUpper(d)]; ok { 525 | nsec3.TypeBitMap = append(nsec3.TypeBitMap, t) 526 | } 527 | } 528 | rr = nsec3 529 | case dns.TypeNSEC3PARAM: 530 | parts := strings.Split(jr.Data, " ") 531 | if len(parts) < 5 { 532 | return 533 | } 534 | rr = &dns.NSEC3PARAM{ 535 | Hash: uint8(ParseUint(parts[0])), 536 | Flags: uint8(ParseUint(parts[1])), 537 | Iterations: uint16(ParseUint(parts[2])), 538 | SaltLength: uint8(ParseUint(parts[3])), 539 | Salt: parts[4], 540 | } 541 | default: 542 | // panic(fmt.Sprintf("unknown type %s", jr.Type)) 543 | err = ErrBadQtype 544 | return 545 | } 546 | hdr := &dns.RR_Header{ 547 | Name: jr.Name, 548 | Rrtype: uint16(jr.Type), 549 | Ttl: uint32(jr.TTL), 550 | Class: dns.ClassINET, 551 | Rdlength: uint16(len(jr.Data)), 552 | } 553 | *(rr.Header()) = *hdr 554 | return 555 | } 556 | 557 | func FromRR(rr dns.RR) (jr *DNSRR) { 558 | jr = &DNSRR{ 559 | Name: rr.Header().Name, 560 | Type: int32(rr.Header().Rrtype), 561 | TTL: int32(rr.Header().Ttl), 562 | } 563 | switch v := rr.(type) { 564 | case *dns.A: 565 | jr.Data = v.A.String() 566 | case *dns.NS: 567 | jr.Data = v.Ns 568 | case *dns.MD: 569 | jr.Data = v.Md 570 | case *dns.MF: 571 | jr.Data = v.Mf 572 | case *dns.CNAME: 573 | jr.Data = v.Target 574 | case *dns.SOA: 575 | jr.Data = fmt.Sprintf("%s %s %d %d %d %d %d", v.Ns, v.Mbox, v.Serial, v.Refresh, v.Retry, v.Expire, v.Minttl) 576 | case *dns.MB: 577 | jr.Data = v.Mb 578 | case *dns.MG: 579 | jr.Data = v.Mg 580 | case *dns.MR: 581 | jr.Data = v.Mr 582 | case *dns.NULL: 583 | case *dns.PTR: 584 | jr.Data = v.Ptr 585 | case *dns.HINFO: 586 | case *dns.MINFO: 587 | case *dns.MX: 588 | jr.Data = fmt.Sprintf("%d %s", v.Preference, v.Mx) 589 | case *dns.TXT: 590 | jr.Data = strings.Join(v.Txt, " ") 591 | case *dns.RP: 592 | jr.Data = fmt.Sprintf("%s %s", v.Mbox, v.Txt) 593 | case *dns.AAAA: 594 | jr.Data = v.AAAA.String() 595 | case *dns.SRV: 596 | jr.Data = fmt.Sprintf("%d %d %d %s", v.Priority, v.Weight, v.Port, v.Target) 597 | case *dns.SPF: 598 | jr.Data = strings.Join(v.Txt, " ") 599 | case *dns.DS: 600 | jr.Data = fmt.Sprintf("%d %d %d %s", v.KeyTag, v.Algorithm, v.DigestType, v.Digest) 601 | case *dns.SSHFP: 602 | jr.Data = fmt.Sprintf("%d %d %s", v.Algorithm, v.Type, v.FingerPrint) 603 | case *dns.RRSIG: 604 | jr.Data = fmt.Sprintf("%d %d %d %d %d %d %s %s", v.Algorithm, v.Labels, v.OrigTtl, v.Expiration, v.Inception, v.KeyTag, v.SignerName, v.Signature) 605 | case *dns.NSEC: 606 | var datas []string = make([]string, 1) 607 | datas[0] = fmt.Sprintf("%s", v.NextDomain) 608 | for _, b := range v.TypeBitMap { 609 | if s, ok := dns.TypeToString[b]; ok { 610 | datas = append(datas, s) 611 | } 612 | } 613 | jr.Data = strings.Join(datas, " ") 614 | case *dns.DNSKEY: 615 | jr.Data = fmt.Sprintf("%d %d %d %s", v.Flags, v.Protocol, v.Algorithm, v.PublicKey) 616 | case *dns.NSEC3: 617 | var datas []string = make([]string, 1) 618 | datas[0] = fmt.Sprintf("%d %d %d %d %s %d %s", v.Hash, v.Flags, v.Iterations, v.SaltLength, v.SaltLength, v.HashLength, v.NextDomain) 619 | for _, b := range v.TypeBitMap { 620 | if s, ok := dns.TypeToString[b]; ok { 621 | datas = append(datas, s) 622 | } 623 | } 624 | jr.Data = strings.Join(datas, " ") 625 | case *dns.NSEC3PARAM: 626 | jr.Data = fmt.Sprintf("%d %d %d %d %s", v.Hash, v.Flags, v.Iterations, v.SaltLength, v.Salt) 627 | } 628 | return 629 | } 630 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # LICENSE 2 | 3 | Copyright (C) 2012 Shell.E.Xu 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | # GNU GENERAL PUBLIC LICENSE 20 | 21 | Version 2, June 1991 22 | 23 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 24 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 25 | Everyone is permitted to copy and distribute verbatim copies 26 | of this license document, but changing it is not allowed. 27 | 28 | Preamble 29 | 30 | The licenses for most software are designed to take away your 31 | freedom to share and change it. By contrast, the GNU General Public 32 | License is intended to guarantee your freedom to share and change free 33 | software--to make sure the software is free for all its users. This 34 | General Public License applies to most of the Free Software 35 | Foundation's software and to any other program whose authors commit to 36 | using it. (Some other Free Software Foundation software is covered by 37 | the GNU Lesser General Public License instead.) You can apply it to 38 | your programs, too. 39 | 40 | When we speak of free software, we are referring to freedom, not 41 | price. Our General Public Licenses are designed to make sure that you 42 | have the freedom to distribute copies of free software (and charge for 43 | this service if you wish), that you receive source code or can get it 44 | if you want it, that you can change the software or use pieces of it 45 | in new free programs; and that you know you can do these things. 46 | 47 | To protect your rights, we need to make restrictions that forbid 48 | anyone to deny you these rights or to ask you to surrender the rights. 49 | These restrictions translate to certain responsibilities for you if you 50 | distribute copies of the software, or if you modify it. 51 | 52 | For example, if you distribute copies of such a program, whether 53 | gratis or for a fee, you must give the recipients all the rights that 54 | you have. You must make sure that they, too, receive or can get the 55 | source code. And you must show them these terms so they know their 56 | rights. 57 | 58 | We protect your rights with two steps: (1) copyright the software, and 59 | (2) offer you this license which gives you legal permission to copy, 60 | distribute and/or modify the software. 61 | 62 | Also, for each author's protection and ours, we want to make certain 63 | that everyone understands that there is no warranty for this free 64 | software. If the software is modified by someone else and passed on, we 65 | want its recipients to know that what they have is not the original, so 66 | that any problems introduced by others will not reflect on the original 67 | authors' reputations. 68 | 69 | Finally, any free program is threatened constantly by software 70 | patents. We wish to avoid the danger that redistributors of a free 71 | program will individually obtain patent licenses, in effect making the 72 | program proprietary. To prevent this, we have made it clear that any 73 | patent must be licensed for everyone's free use or not licensed at all. 74 | 75 | The precise terms and conditions for copying, distribution and 76 | modification follow. 77 | 78 | GNU GENERAL PUBLIC LICENSE 79 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 80 | 81 | 0. This License applies to any program or other work which contains 82 | a notice placed by the copyright holder saying it may be distributed 83 | under the terms of this General Public License. The "Program", below, 84 | refers to any such program or work, and a "work based on the Program" 85 | means either the Program or any derivative work under copyright law: 86 | that is to say, a work containing the Program or a portion of it, 87 | either verbatim or with modifications and/or translated into another 88 | language. (Hereinafter, translation is included without limitation in 89 | the term "modification".) Each licensee is addressed as "you". 90 | 91 | Activities other than copying, distribution and modification are not 92 | covered by this License; they are outside its scope. The act of 93 | running the Program is not restricted, and the output from the Program 94 | is covered only if its contents constitute a work based on the 95 | Program (independent of having been made by running the Program). 96 | Whether that is true depends on what the Program does. 97 | 98 | 1. You may copy and distribute verbatim copies of the Program's 99 | source code as you receive it, in any medium, provided that you 100 | conspicuously and appropriately publish on each copy an appropriate 101 | copyright notice and disclaimer of warranty; keep intact all the 102 | notices that refer to this License and to the absence of any warranty; 103 | and give any other recipients of the Program a copy of this License 104 | along with the Program. 105 | 106 | You may charge a fee for the physical act of transferring a copy, and 107 | you may at your option offer warranty protection in exchange for a fee. 108 | 109 | 2. You may modify your copy or copies of the Program or any portion 110 | of it, thus forming a work based on the Program, and copy and 111 | distribute such modifications or work under the terms of Section 1 112 | above, provided that you also meet all of these conditions: 113 | 114 | a) You must cause the modified files to carry prominent notices 115 | stating that you changed the files and the date of any change. 116 | 117 | b) You must cause any work that you distribute or publish, that in 118 | whole or in part contains or is derived from the Program or any 119 | part thereof, to be licensed as a whole at no charge to all third 120 | parties under the terms of this License. 121 | 122 | c) If the modified program normally reads commands interactively 123 | when run, you must cause it, when started running for such 124 | interactive use in the most ordinary way, to print or display an 125 | announcement including an appropriate copyright notice and a 126 | notice that there is no warranty (or else, saying that you provide 127 | a warranty) and that users may redistribute the program under 128 | these conditions, and telling the user how to view a copy of this 129 | License. (Exception: if the Program itself is interactive but 130 | does not normally print such an announcement, your work based on 131 | the Program is not required to print an announcement.) 132 | 133 | These requirements apply to the modified work as a whole. If 134 | identifiable sections of that work are not derived from the Program, 135 | and can be reasonably considered independent and separate works in 136 | themselves, then this License, and its terms, do not apply to those 137 | sections when you distribute them as separate works. But when you 138 | distribute the same sections as part of a whole which is a work based 139 | on the Program, the distribution of the whole must be on the terms of 140 | this License, whose permissions for other licensees extend to the 141 | entire whole, and thus to each and every part regardless of who wrote it. 142 | 143 | Thus, it is not the intent of this section to claim rights or contest 144 | your rights to work written entirely by you; rather, the intent is to 145 | exercise the right to control the distribution of derivative or 146 | collective works based on the Program. 147 | 148 | In addition, mere aggregation of another work not based on the Program 149 | with the Program (or with a work based on the Program) on a volume of 150 | a storage or distribution medium does not bring the other work under 151 | the scope of this License. 152 | 153 | 3. You may copy and distribute the Program (or a work based on it, 154 | under Section 2) in object code or executable form under the terms of 155 | Sections 1 and 2 above provided that you also do one of the following: 156 | 157 | a) Accompany it with the complete corresponding machine-readable 158 | source code, which must be distributed under the terms of Sections 159 | 1 and 2 above on a medium customarily used for software interchange; or, 160 | 161 | b) Accompany it with a written offer, valid for at least three 162 | years, to give any third party, for a charge no more than your 163 | cost of physically performing source distribution, a complete 164 | machine-readable copy of the corresponding source code, to be 165 | distributed under the terms of Sections 1 and 2 above on a medium 166 | customarily used for software interchange; or, 167 | 168 | c) Accompany it with the information you received as to the offer 169 | to distribute corresponding source code. (This alternative is 170 | allowed only for noncommercial distribution and only if you 171 | received the program in object code or executable form with such 172 | an offer, in accord with Subsection b above.) 173 | 174 | The source code for a work means the preferred form of the work for 175 | making modifications to it. For an executable work, complete source 176 | code means all the source code for all modules it contains, plus any 177 | associated interface definition files, plus the scripts used to 178 | control compilation and installation of the executable. However, as a 179 | special exception, the source code distributed need not include 180 | anything that is normally distributed (in either source or binary 181 | form) with the major components (compiler, kernel, and so on) of the 182 | operating system on which the executable runs, unless that component 183 | itself accompanies the executable. 184 | 185 | If distribution of executable or object code is made by offering 186 | access to copy from a designated place, then offering equivalent 187 | access to copy the source code from the same place counts as 188 | distribution of the source code, even though third parties are not 189 | compelled to copy the source along with the object code. 190 | 191 | 4. You may not copy, modify, sublicense, or distribute the Program 192 | except as expressly provided under this License. Any attempt 193 | otherwise to copy, modify, sublicense or distribute the Program is 194 | void, and will automatically terminate your rights under this License. 195 | However, parties who have received copies, or rights, from you under 196 | this License will not have their licenses terminated so long as such 197 | parties remain in full compliance. 198 | 199 | 5. You are not required to accept this License, since you have not 200 | signed it. However, nothing else grants you permission to modify or 201 | distribute the Program or its derivative works. These actions are 202 | prohibited by law if you do not accept this License. Therefore, by 203 | modifying or distributing the Program (or any work based on the 204 | Program), you indicate your acceptance of this License to do so, and 205 | all its terms and conditions for copying, distributing or modifying 206 | the Program or works based on it. 207 | 208 | 6. Each time you redistribute the Program (or any work based on the 209 | Program), the recipient automatically receives a license from the 210 | original licensor to copy, distribute or modify the Program subject to 211 | these terms and conditions. You may not impose any further 212 | restrictions on the recipients' exercise of the rights granted herein. 213 | You are not responsible for enforcing compliance by third parties to 214 | this License. 215 | 216 | 7. If, as a consequence of a court judgment or allegation of patent 217 | infringement or for any other reason (not limited to patent issues), 218 | conditions are imposed on you (whether by court order, agreement or 219 | otherwise) that contradict the conditions of this License, they do not 220 | excuse you from the conditions of this License. If you cannot 221 | distribute so as to satisfy simultaneously your obligations under this 222 | License and any other pertinent obligations, then as a consequence you 223 | may not distribute the Program at all. For example, if a patent 224 | license would not permit royalty-free redistribution of the Program by 225 | all those who receive copies directly or indirectly through you, then 226 | the only way you could satisfy both it and this License would be to 227 | refrain entirely from distribution of the Program. 228 | 229 | If any portion of this section is held invalid or unenforceable under 230 | any particular circumstance, the balance of the section is intended to 231 | apply and the section as a whole is intended to apply in other 232 | circumstances. 233 | 234 | It is not the purpose of this section to induce you to infringe any 235 | patents or other property right claims or to contest validity of any 236 | such claims; this section has the sole purpose of protecting the 237 | integrity of the free software distribution system, which is 238 | implemented by public license practices. Many people have made 239 | generous contributions to the wide range of software distributed 240 | through that system in reliance on consistent application of that 241 | system; it is up to the author/donor to decide if he or she is willing 242 | to distribute software through any other system and a licensee cannot 243 | impose that choice. 244 | 245 | This section is intended to make thoroughly clear what is believed to 246 | be a consequence of the rest of this License. 247 | 248 | 8. If the distribution and/or use of the Program is restricted in 249 | certain countries either by patents or by copyrighted interfaces, the 250 | original copyright holder who places the Program under this License 251 | may add an explicit geographical distribution limitation excluding 252 | those countries, so that distribution is permitted only in or among 253 | countries not thus excluded. In such case, this License incorporates 254 | the limitation as if written in the body of this License. 255 | 256 | 9. The Free Software Foundation may publish revised and/or new versions 257 | of the General Public License from time to time. Such new versions will 258 | be similar in spirit to the present version, but may differ in detail to 259 | address new problems or concerns. 260 | 261 | Each version is given a distinguishing version number. If the Program 262 | specifies a version number of this License which applies to it and "any 263 | later version", you have the option of following the terms and conditions 264 | either of that version or of any later version published by the Free 265 | Software Foundation. If the Program does not specify a version number of 266 | this License, you may choose any version ever published by the Free Software 267 | Foundation. 268 | 269 | 10. If you wish to incorporate parts of the Program into other free 270 | programs whose distribution conditions are different, write to the author 271 | to ask for permission. For software which is copyrighted by the Free 272 | Software Foundation, write to the Free Software Foundation; we sometimes 273 | make exceptions for this. Our decision will be guided by the two goals 274 | of preserving the free status of all derivatives of our free software and 275 | of promoting the sharing and reuse of software generally. 276 | 277 | NO WARRANTY 278 | 279 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 280 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 281 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 282 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 283 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 284 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 285 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 286 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 287 | REPAIR OR CORRECTION. 288 | 289 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 290 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 291 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 292 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 293 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 294 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 295 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 296 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 297 | POSSIBILITY OF SUCH DAMAGES. 298 | 299 | END OF TERMS AND CONDITIONS 300 | 301 | # go-logging 302 | 303 | This product includes software developed by the Örjan Persson under 3-Clause BSD. 304 | 305 | You can get it source from [github](https://github.com/op/go-logging). 306 | 307 | Copyright (c) 2013 Örjan Persson. All rights reserved. 308 | 309 | Redistribution and use in source and binary forms, with or without 310 | modification, are permitted provided that the following conditions are 311 | met: 312 | 313 | * Redistributions of source code must retain the above copyright 314 | notice, this list of conditions and the following disclaimer. 315 | * Redistributions in binary form must reproduce the above 316 | copyright notice, this list of conditions and the following disclaimer 317 | in the documentation and/or other materials provided with the 318 | distribution. 319 | * Neither the name of Google Inc. nor the names of its 320 | contributors may be used to endorse or promote products derived from 321 | this software without specific prior written permission. 322 | 323 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 324 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 325 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 326 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 327 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 328 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 329 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 330 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 332 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 333 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 334 | 335 | # dns 336 | 337 | This product includes software developed by the Miek Gieben under 3-Clause BSD. 338 | 339 | You can get it source from [github](https://github.com/miekg/dns). 340 | 341 | Copyright (c) 2009 The Go Authors. All rights reserved. 342 | 343 | Redistribution and use in source and binary forms, with or without 344 | modification, are permitted provided that the following conditions are 345 | met: 346 | 347 | * Redistributions of source code must retain the above copyright 348 | notice, this list of conditions and the following disclaimer. 349 | * Redistributions in binary form must reproduce the above 350 | copyright notice, this list of conditions and the following disclaimer 351 | in the documentation and/or other materials provided with the 352 | distribution. 353 | * Neither the name of Google Inc. nor the names of its 354 | contributors may be used to endorse or promote products derived from 355 | this software without specific prior written permission. 356 | 357 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 358 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 359 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 360 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 361 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 362 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 363 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 364 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 365 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 366 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 367 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368 | 369 | As this is fork of the official Go code the same license applies. 370 | Extensions of the original work are copyright (c) 2011 Miek Gieben 371 | --------------------------------------------------------------------------------