mirror of
https://github.com/m13253/dns-over-https.git
synced 2026-03-31 14:05:38 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e480251e67 | ||
|
|
027480afeb | ||
|
|
4839498ad5 | ||
|
|
a303c21036 | ||
|
|
3586688aa6 | ||
|
|
ffe5573552 | ||
|
|
f40116b1f8 | ||
|
|
58e6cdfb71 | ||
|
|
1491138f69 | ||
|
|
83df8964d8 | ||
|
|
07f39088d4 | ||
|
|
db007fbded | ||
|
|
89d809d469 | ||
|
|
5ca6813801 | ||
|
|
033865e508 | ||
|
|
7e7cd1ee90 | ||
|
|
e19250dc99 | ||
|
|
a64df3f048 | ||
|
|
f54b49c090 | ||
|
|
87436b7cbf | ||
|
|
11056bcad5 | ||
|
|
ca33027e04 | ||
|
|
6ff0a6a9ab | ||
|
|
359c81a019 | ||
|
|
07143d5890 | ||
|
|
1d367cb7e7 |
19
Changelog.md
19
Changelog.md
@@ -4,6 +4,25 @@ This Changelog records major changes between versions.
|
|||||||
|
|
||||||
Not all changes are recorded. Please check git log for details.
|
Not all changes are recorded. Please check git log for details.
|
||||||
|
|
||||||
|
## Version 1.3.10
|
||||||
|
|
||||||
|
- Enable application/dns-message (draft-13) by default, since Google has finally supported it
|
||||||
|
|
||||||
|
## Version 1.3.9
|
||||||
|
|
||||||
|
- Fix client crash with `no_cookies = true`
|
||||||
|
- Add 5380 as an additional default doh-client port
|
||||||
|
- If `$GOROOT` is defined, Makefile now respects the value for the convenience of Debian/Ubuntu users
|
||||||
|
- Change the ECS prefix length from /48 to /56 for IPv6, per RFC 7871
|
||||||
|
|
||||||
|
## Version 1.3.8
|
||||||
|
|
||||||
|
- Workaround a bug causing Firefox 61-62 to reject responses with Content-Type = application/dns-message
|
||||||
|
- Workaround a bug causing DNSCrypt-Proxy to expect a response with TransactionID = 0xcafe
|
||||||
|
- TransactionID is now preserved to maintain compatibility with some clients
|
||||||
|
- Turn on `no_cookies` by default according to the IETF draft
|
||||||
|
- Update Documentation
|
||||||
|
|
||||||
## Version 1.3.7
|
## Version 1.3.7
|
||||||
|
|
||||||
- Add CloudFlare DNS resolver for Tor to the preset
|
- Add CloudFlare DNS resolver for Tor to the preset
|
||||||
|
|||||||
22
Makefile
22
Makefile
@@ -1,13 +1,21 @@
|
|||||||
.PHONY: all clean install uninstall deps
|
.PHONY: all clean install uninstall deps
|
||||||
|
|
||||||
GOBUILD=go build
|
PREFIX = /usr/local
|
||||||
GOGET=go get -d -v
|
|
||||||
GOGET_UPDATE=go get -d -u -v
|
ifeq ($(GOROOT),)
|
||||||
PREFIX=/usr/local
|
GOBUILD = go build
|
||||||
ifeq ($(shell uname),Darwin)
|
GOGET = go get -d -v
|
||||||
CONFDIR=/usr/local/etc/dns-over-https
|
GOGET_UPDATE = go get -d -u -v
|
||||||
else
|
else
|
||||||
CONFDIR=/etc/dns-over-https
|
GOBUILD = $(GOROOT)/bin/go build
|
||||||
|
GOGET = $(GOROOT)/bin/go get -d -v
|
||||||
|
GOGET_UPDATE = $(GOROOT)/bin/go get -d -u -v
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(shell uname),Darwin)
|
||||||
|
CONFDIR = /usr/local/etc/dns-over-https
|
||||||
|
else
|
||||||
|
CONFDIR = /etc/dns-over-https
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: doh-client/doh-client doh-server/doh-server
|
all: doh-client/doh-client doh-server/doh-server
|
||||||
|
|||||||
12
Readme.md
12
Readme.md
@@ -8,6 +8,8 @@ and [draft-ietf-doh-dns-over-https](https://github.com/dohwg/draft-ietf-doh-dns-
|
|||||||
|
|
||||||
Install [Go](https://golang.org), at least version 1.9.
|
Install [Go](https://golang.org), at least version 1.9.
|
||||||
|
|
||||||
|
(Note for Debian/Ubuntu users: You need to set `$GOROOT` if you could not get your new version of Go selected by the Makefile.)
|
||||||
|
|
||||||
First create an empty directory, used for `$GOPATH`:
|
First create an empty directory, used for `$GOPATH`:
|
||||||
|
|
||||||
mkdir ~/gopath
|
mkdir ~/gopath
|
||||||
@@ -83,7 +85,7 @@ records.
|
|||||||
## EDNS0-Client-Subnet (GeoDNS)
|
## EDNS0-Client-Subnet (GeoDNS)
|
||||||
|
|
||||||
DNS-over-HTTPS supports EDNS0-Client-Subnet protocol, which submits part of the
|
DNS-over-HTTPS supports EDNS0-Client-Subnet protocol, which submits part of the
|
||||||
client's IP address (/24 for IPv4, /48 for IPv6 by default) to the upstream
|
client's IP address (/24 for IPv4, /56 for IPv6 by default) to the upstream
|
||||||
server. This is useful for GeoDNS and CDNs to work, and is exactly the same
|
server. This is useful for GeoDNS and CDNs to work, and is exactly the same
|
||||||
configuration as most public DNS servers.
|
configuration as most public DNS servers.
|
||||||
|
|
||||||
@@ -119,7 +121,13 @@ Currently supported features are:
|
|||||||
|
|
||||||
- [X] IPv4 / IPv6
|
- [X] IPv4 / IPv6
|
||||||
- [X] EDNS0 large UDP packet (4 KiB by default)
|
- [X] EDNS0 large UDP packet (4 KiB by default)
|
||||||
- [X] EDNS0-Client-Subnet (/24 for IPv4, /48 for IPv6 by default)
|
- [X] EDNS0-Client-Subnet (/24 for IPv4, /56 for IPv6 by default)
|
||||||
|
|
||||||
|
## The name of the project
|
||||||
|
|
||||||
|
This project is named "DNS-over-HTTPS" because it was written before the IETF DoH project. Although this project is compatible with IETF DoH, the project is not affiliated with IETF.
|
||||||
|
|
||||||
|
To avoid confusion, you may also call this project "m13253/DNS-over-HTTPS" or anything you like.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ type Client struct {
|
|||||||
udpServers []*dns.Server
|
udpServers []*dns.Server
|
||||||
tcpServers []*dns.Server
|
tcpServers []*dns.Server
|
||||||
bootstrapResolver *net.Resolver
|
bootstrapResolver *net.Resolver
|
||||||
cookieJar *cookiejar.Jar
|
cookieJar http.CookieJar
|
||||||
httpClientMux *sync.RWMutex
|
httpClientMux *sync.RWMutex
|
||||||
httpTransport *http.Transport
|
httpTransport *http.Transport
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
@@ -259,7 +259,7 @@ func (c *Client) tcpHandlerFunc(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ipv4Mask24 = net.IPMask{255, 255, 255, 0}
|
ipv4Mask24 = net.IPMask{255, 255, 255, 0}
|
||||||
ipv6Mask48 = net.CIDRMask(48, 128)
|
ipv6Mask56 = net.CIDRMask(56, 128)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) findClientIP(w dns.ResponseWriter, r *dns.Msg) (ednsClientAddress net.IP, ednsClientNetmask uint8) {
|
func (c *Client) findClientIP(w dns.ResponseWriter, r *dns.Msg) (ednsClientAddress net.IP, ednsClientNetmask uint8) {
|
||||||
@@ -286,8 +286,8 @@ func (c *Client) findClientIP(w dns.ResponseWriter, r *dns.Msg) (ednsClientAddre
|
|||||||
ednsClientAddress = ipv4.Mask(ipv4Mask24)
|
ednsClientAddress = ipv4.Mask(ipv4Mask24)
|
||||||
ednsClientNetmask = 24
|
ednsClientNetmask = 24
|
||||||
} else {
|
} else {
|
||||||
ednsClientAddress = ip.Mask(ipv6Mask48)
|
ednsClientAddress = ip.Mask(ipv6Mask56)
|
||||||
ednsClientNetmask = 48
|
ednsClientNetmask = 56
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# DNS listen port
|
# DNS listen port
|
||||||
listen = [
|
listen = [
|
||||||
"127.0.0.1:53",
|
"127.0.0.1:53",
|
||||||
|
"127.0.0.1:5380",
|
||||||
"[::1]:53",
|
"[::1]:53",
|
||||||
|
"[::1]:5380",
|
||||||
]
|
]
|
||||||
|
|
||||||
# HTTP path for upstream resolver
|
# HTTP path for upstream resolver
|
||||||
@@ -65,12 +67,12 @@ timeout = 30
|
|||||||
# anti-DDoS services to identify clients.
|
# anti-DDoS services to identify clients.
|
||||||
# Note that DNS Cookies (an DNS protocol extension to DNS) also has the ability
|
# Note that DNS Cookies (an DNS protocol extension to DNS) also has the ability
|
||||||
# to track uesrs and is not controlled by doh-client.
|
# to track uesrs and is not controlled by doh-client.
|
||||||
no_cookies = false
|
no_cookies = true
|
||||||
|
|
||||||
# Disable EDNS0-Client-Subnet (ECS)
|
# Disable EDNS0-Client-Subnet (ECS)
|
||||||
#
|
#
|
||||||
# DNS-over-HTTPS supports EDNS0-Client-Subnet protocol, which submits part of
|
# DNS-over-HTTPS supports EDNS0-Client-Subnet protocol, which submits part of
|
||||||
# the client's IP address (/24 for IPv4, /48 for IPv6 by default) to the
|
# the client's IP address (/24 for IPv4, /56 for IPv6 by default) to the
|
||||||
# upstream server. This is useful for GeoDNS and CDNs to work, and is exactly
|
# upstream server. This is useful for GeoDNS and CDNs to work, and is exactly
|
||||||
# the same configuration as most public DNS servers.
|
# the same configuration as most public DNS servers.
|
||||||
no_ecs = false
|
no_ecs = false
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ func (c *Client) generateRequestGoogle(w dns.ResponseWriter, r *dns.Msg, isTCP b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
question := &r.Question[0]
|
question := &r.Question[0]
|
||||||
// knot-resolver scrambles capitalization, I think it is unfriendly to cache
|
questionName := question.Name
|
||||||
questionName := strings.ToLower(question.Name)
|
|
||||||
questionType := ""
|
questionType := ""
|
||||||
if qtype, ok := dns.TypeToString[question.Qtype]; ok {
|
if qtype, ok := dns.TypeToString[question.Qtype]; ok {
|
||||||
questionType = qtype
|
questionType = qtype
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
question := &r.Question[0]
|
question := &r.Question[0]
|
||||||
// knot-resolver scrambles capitalization, I think it is unfriendly to cache
|
questionName := question.Name
|
||||||
questionName := strings.ToLower(question.Name)
|
|
||||||
questionType := ""
|
questionType := ""
|
||||||
if qtype, ok := dns.TypeToString[question.Qtype]; ok {
|
if qtype, ok := dns.TypeToString[question.Qtype]; ok {
|
||||||
questionType = qtype
|
questionType = qtype
|
||||||
@@ -97,7 +96,7 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
|
|||||||
ednsClientNetmask = 24
|
ednsClientNetmask = 24
|
||||||
} else {
|
} else {
|
||||||
ednsClientFamily = 2
|
ednsClientFamily = 2
|
||||||
ednsClientNetmask = 48
|
ednsClientNetmask = 56
|
||||||
}
|
}
|
||||||
edns0Subnet = new(dns.EDNS0_SUBNET)
|
edns0Subnet = new(dns.EDNS0_SUBNET)
|
||||||
edns0Subnet.Code = dns.EDNS0SUBNET
|
edns0Subnet.Code = dns.EDNS0SUBNET
|
||||||
@@ -127,8 +126,7 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
|
|||||||
|
|
||||||
numServers := len(c.conf.UpstreamIETF)
|
numServers := len(c.conf.UpstreamIETF)
|
||||||
upstream := c.conf.UpstreamIETF[rand.Intn(numServers)]
|
upstream := c.conf.UpstreamIETF[rand.Intn(numServers)]
|
||||||
requestURL := fmt.Sprintf("%s?ct=application/dns-udpwireformat&dns=%s", upstream, requestBase64)
|
requestURL := fmt.Sprintf("%s?ct=application/dns-message&dns=%s", upstream, requestBase64)
|
||||||
//requestURL := fmt.Sprintf("%s?ct=application/dns-message&dns=%s", upstream, requestBase64)
|
|
||||||
|
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
if len(requestURL) < 2048 {
|
if len(requestURL) < 2048 {
|
||||||
|
|||||||
@@ -24,6 +24,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VERSION = "1.3.7"
|
VERSION = "1.3.10"
|
||||||
USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"
|
USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,9 +5,14 @@ listen = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
# TLS certification file
|
# TLS certification file
|
||||||
|
# If left empty, plain-text HTTP will be used.
|
||||||
|
# You are recommended to leave empty and to use a server load balancer (e.g.
|
||||||
|
# Caddy, Nginx) and set up TLS there, because this program does not do OCSP
|
||||||
|
# Stapling, which is necessary for client bootstrapping in a network
|
||||||
|
# environment with completely no traditional DNS service.
|
||||||
cert = ""
|
cert = ""
|
||||||
|
|
||||||
# TLS key file
|
# TLS private key file
|
||||||
key = ""
|
key = ""
|
||||||
|
|
||||||
# HTTP path for resolve application
|
# HTTP path for resolve application
|
||||||
@@ -16,6 +21,8 @@ path = "/dns-query"
|
|||||||
# Upstream DNS resolver
|
# Upstream DNS resolver
|
||||||
# If multiple servers are specified, a random one will be chosen each time.
|
# If multiple servers are specified, a random one will be chosen each time.
|
||||||
upstream = [
|
upstream = [
|
||||||
|
"1.1.1.1:53",
|
||||||
|
"1.0.0.1:53",
|
||||||
"8.8.8.8:53",
|
"8.8.8.8:53",
|
||||||
"8.8.4.4:53",
|
"8.8.4.4:53",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ func (s *Server) parseRequestGoogle(w http.ResponseWriter, r *http.Request) *DNS
|
|||||||
errtext: "Invalid argument value: \"name\"",
|
errtext: "Invalid argument value: \"name\"",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
name = strings.ToLower(name)
|
|
||||||
if punycode, err := idna.ToASCII(name); err == nil {
|
if punycode, err := idna.ToASCII(name); err == nil {
|
||||||
name = punycode
|
name = punycode
|
||||||
} else {
|
} else {
|
||||||
@@ -105,7 +104,7 @@ func (s *Server) parseRequestGoogle(w http.ResponseWriter, r *http.Request) *DNS
|
|||||||
ednsClientNetmask = 24
|
ednsClientNetmask = 24
|
||||||
} else {
|
} else {
|
||||||
ednsClientFamily = 2
|
ednsClientFamily = 2
|
||||||
ednsClientNetmask = 48
|
ednsClientNetmask = 56
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ednsClientAddress = net.ParseIP(ednsClientSubnet[:slash])
|
ednsClientAddress = net.ParseIP(ednsClientSubnet[:slash])
|
||||||
@@ -140,7 +139,7 @@ func (s *Server) parseRequestGoogle(w http.ResponseWriter, r *http.Request) *DNS
|
|||||||
ednsClientNetmask = 24
|
ednsClientNetmask = 24
|
||||||
} else {
|
} else {
|
||||||
ednsClientFamily = 2
|
ednsClientFamily = 2
|
||||||
ednsClientNetmask = 48
|
ednsClientNetmask = 56
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +181,7 @@ func (s *Server) generateResponseGoogle(w http.ResponseWriter, r *http.Request,
|
|||||||
now := time.Now().UTC().Format(http.TimeFormat)
|
now := time.Now().UTC().Format(http.TimeFormat)
|
||||||
w.Header().Set("Date", now)
|
w.Header().Set("Date", now)
|
||||||
w.Header().Set("Last-Modified", now)
|
w.Header().Set("Last-Modified", now)
|
||||||
|
w.Header().Set("Vary", "Accept")
|
||||||
if respJSON.HaveTTL {
|
if respJSON.HaveTTL {
|
||||||
if req.isTailored {
|
if req.isTailored {
|
||||||
w.Header().Set("Cache-Control", "private, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
w.Header().Set("Cache-Control", "private, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/m13253/dns-over-https/json-dns"
|
"github.com/m13253/dns-over-https/json-dns"
|
||||||
@@ -62,7 +63,7 @@ func (s *Server) parseRequestIETF(w http.ResponseWriter, r *http.Request) *DNSRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.patchDNSCryptProxyReqID(requestBinary, w) {
|
if s.patchDNSCryptProxyReqID(w, r, requestBinary) {
|
||||||
return &DNSRequest{
|
return &DNSRequest{
|
||||||
errcode: 444,
|
errcode: 444,
|
||||||
}
|
}
|
||||||
@@ -95,6 +96,7 @@ func (s *Server) parseRequestIETF(w http.ResponseWriter, r *http.Request) *DNSRe
|
|||||||
fmt.Printf("%s - - [%s] \"%s %s %s\"\n", r.RemoteAddr, time.Now().Format("02/Jan/2006:15:04:05 -0700"), questionName, questionClass, questionType)
|
fmt.Printf("%s - - [%s] \"%s %s %s\"\n", r.RemoteAddr, time.Now().Format("02/Jan/2006:15:04:05 -0700"), questionName, questionClass, questionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transactionID := msg.Id
|
||||||
msg.Id = dns.Id()
|
msg.Id = dns.Id()
|
||||||
opt := msg.IsEdns0()
|
opt := msg.IsEdns0()
|
||||||
if opt == nil {
|
if opt == nil {
|
||||||
@@ -124,7 +126,7 @@ func (s *Server) parseRequestIETF(w http.ResponseWriter, r *http.Request) *DNSRe
|
|||||||
ednsClientNetmask = 24
|
ednsClientNetmask = 24
|
||||||
} else {
|
} else {
|
||||||
ednsClientFamily = 2
|
ednsClientFamily = 2
|
||||||
ednsClientNetmask = 48
|
ednsClientNetmask = 56
|
||||||
}
|
}
|
||||||
edns0Subnet = new(dns.EDNS0_SUBNET)
|
edns0Subnet = new(dns.EDNS0_SUBNET)
|
||||||
edns0Subnet.Code = dns.EDNS0SUBNET
|
edns0Subnet.Code = dns.EDNS0SUBNET
|
||||||
@@ -137,14 +139,15 @@ func (s *Server) parseRequestIETF(w http.ResponseWriter, r *http.Request) *DNSRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &DNSRequest{
|
return &DNSRequest{
|
||||||
request: msg,
|
request: msg,
|
||||||
isTailored: isTailored,
|
transactionID: transactionID,
|
||||||
|
isTailored: isTailored,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) generateResponseIETF(w http.ResponseWriter, r *http.Request, req *DNSRequest) {
|
func (s *Server) generateResponseIETF(w http.ResponseWriter, r *http.Request, req *DNSRequest) {
|
||||||
respJSON := jsonDNS.Marshal(req.response)
|
respJSON := jsonDNS.Marshal(req.response)
|
||||||
req.response.Id = 0
|
req.response.Id = req.transactionID
|
||||||
respBytes, err := req.response.Pack()
|
respBytes, err := req.response.Pack()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@@ -156,6 +159,10 @@ func (s *Server) generateResponseIETF(w http.ResponseWriter, r *http.Request, re
|
|||||||
now := time.Now().UTC().Format(http.TimeFormat)
|
now := time.Now().UTC().Format(http.TimeFormat)
|
||||||
w.Header().Set("Date", now)
|
w.Header().Set("Date", now)
|
||||||
w.Header().Set("Last-Modified", now)
|
w.Header().Set("Last-Modified", now)
|
||||||
|
w.Header().Set("Vary", "Accept")
|
||||||
|
|
||||||
|
_ = s.patchFirefoxContentType(w, r, req)
|
||||||
|
|
||||||
if respJSON.HaveTTL {
|
if respJSON.HaveTTL {
|
||||||
if req.isTailored {
|
if req.isTailored {
|
||||||
w.Header().Set("Cache-Control", "private, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
w.Header().Set("Cache-Control", "private, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||||
@@ -164,6 +171,7 @@ func (s *Server) generateResponseIETF(w http.ResponseWriter, r *http.Request, re
|
|||||||
}
|
}
|
||||||
w.Header().Set("Expires", respJSON.EarliestExpires.Format(http.TimeFormat))
|
w.Header().Set("Expires", respJSON.EarliestExpires.Format(http.TimeFormat))
|
||||||
}
|
}
|
||||||
|
|
||||||
if respJSON.Status == dns.RcodeServerFailure {
|
if respJSON.Status == dns.RcodeServerFailure {
|
||||||
w.WriteHeader(503)
|
w.WriteHeader(503)
|
||||||
}
|
}
|
||||||
@@ -171,13 +179,26 @@ func (s *Server) generateResponseIETF(w http.ResponseWriter, r *http.Request, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Workaround a bug causing DNSCrypt-Proxy to expect a response with TransactionID = 0xcafe
|
// Workaround a bug causing DNSCrypt-Proxy to expect a response with TransactionID = 0xcafe
|
||||||
func (s *Server) patchDNSCryptProxyReqID(requestBinary []byte, w http.ResponseWriter) bool {
|
func (s *Server) patchDNSCryptProxyReqID(w http.ResponseWriter, r *http.Request, requestBinary []byte) bool {
|
||||||
if bytes.Equal(requestBinary, []byte("\xca\xfe\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x00\x02\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00\x00\x00")) {
|
if strings.Contains(r.UserAgent(), "dnscrypt-proxy") && bytes.Equal(requestBinary, []byte("\xca\xfe\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x00\x02\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00\x00\x00")) {
|
||||||
log.Println("DNSCrypt-Proxy detected. Patching response.")
|
log.Println("DNSCrypt-Proxy detected. Patching response.")
|
||||||
w.Header().Set("Content-Type", "application/octet-stream")
|
w.Header().Set("Content-Type", "application/dns-message")
|
||||||
|
w.Header().Set("Vary", "Accept, User-Agent")
|
||||||
now := time.Now().UTC().Format(http.TimeFormat)
|
now := time.Now().UTC().Format(http.TimeFormat)
|
||||||
w.Header().Set("Date", now)
|
w.Header().Set("Date", now)
|
||||||
w.Write([]byte("\xca\xfe\x81\x01\x00\x01\r\nWorkaround a bug causing DNSCrypt-Proxy to expect a response with TransactionID = 0xcafe\r\nDo you know it is a violation of the protocol you fxxking DNSCrypt-Proxy?!\r\n"))
|
w.Write([]byte("\xca\xfe\x81\x05\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x02\x00\x01\x00\x00\x10\x00\x01\x00\x00\x00\x00\x00\xa8\xa7\r\nWorkaround a bug causing DNSCrypt-Proxy to expect a response with TransactionID = 0xcafe\r\nRefer to https://github.com/jedisct1/dnscrypt-proxy/issues/526 for details."))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround a bug causing Firefox 61-62 to reject responses with Content-Type = application/dns-message
|
||||||
|
func (s *Server) patchFirefoxContentType(w http.ResponseWriter, r *http.Request, req *DNSRequest) bool {
|
||||||
|
if strings.Contains(r.UserAgent(), "Firefox") && strings.Contains(r.Header.Get("Accept"), "application/dns-udpwireformat") && !strings.Contains(r.Header.Get("Accept"), "application/dns-message") {
|
||||||
|
log.Println("Firefox 61-62 detected. Patching response.")
|
||||||
|
w.Header().Set("Content-Type", "application/dns-udpwireformat")
|
||||||
|
w.Header().Set("Vary", "Accept, User-Agent")
|
||||||
|
req.isTailored = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type Server struct {
|
|||||||
type DNSRequest struct {
|
type DNSRequest struct {
|
||||||
request *dns.Msg
|
request *dns.Msg
|
||||||
response *dns.Msg
|
response *dns.Msg
|
||||||
|
transactionID uint16
|
||||||
currentUpstream string
|
currentUpstream string
|
||||||
isTailored bool
|
isTailored bool
|
||||||
errcode int
|
errcode int
|
||||||
|
|||||||
@@ -24,6 +24,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VERSION = "1.3.7"
|
VERSION = "1.3.10"
|
||||||
USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"
|
USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func Unmarshal(msg *dns.Msg, resp *Response, udpSize uint16, ednsClientNetmask u
|
|||||||
if ednsClientFamily == 1 {
|
if ednsClientFamily == 1 {
|
||||||
ednsClientNetmask = 24
|
ednsClientNetmask = 24
|
||||||
} else {
|
} else {
|
||||||
ednsClientNetmask = 48
|
ednsClientNetmask = 56
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
edns0Subnet := new(dns.EDNS0_SUBNET)
|
edns0Subnet := new(dns.EDNS0_SUBNET)
|
||||||
|
|||||||
Reference in New Issue
Block a user