mirror of
https://github.com/m13253/dns-over-https.git
synced 2026-03-31 01:05:38 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5723558934 | ||
|
|
2176e14e65 | ||
|
|
1be3052cda | ||
|
|
2b3a261247 | ||
|
|
5f96e35f29 | ||
|
|
8034d5417d | ||
|
|
b3f495e50f | ||
|
|
cefa3a6ba8 | ||
|
|
a81a7eff58 | ||
|
|
26d4cd413d | ||
|
|
fba928e4e4 | ||
|
|
78e40722e8 | ||
|
|
ebaaa7ff71 |
4
Makefile
4
Makefile
@@ -25,8 +25,8 @@ uninstall:
|
||||
deps:
|
||||
$(GOGET) ./doh-client ./doh-server
|
||||
|
||||
doh-client/doh-client: deps doh-client/client.go doh-client/config.go doh-client/main.go json-dns/error.go json-dns/globalip.go json-dns/marshal.go json-dns/response.go json-dns/unmarshal.go
|
||||
doh-client/doh-client: deps doh-client/client.go doh-client/config.go doh-client/google.go doh-client/ietf.go doh-client/main.go json-dns/error.go json-dns/globalip.go json-dns/marshal.go json-dns/response.go json-dns/unmarshal.go
|
||||
cd doh-client && $(GOBUILD)
|
||||
|
||||
doh-server/doh-server: deps doh-server/config.go doh-server/main.go doh-server/server.go json-dns/error.go json-dns/globalip.go json-dns/marshal.go json-dns/response.go json-dns/unmarshal.go
|
||||
doh-server/doh-server: deps doh-server/config.go doh-server/google.go doh-server/ietf.go doh-server/main.go doh-server/server.go json-dns/error.go json-dns/globalip.go json-dns/marshal.go json-dns/response.go json-dns/unmarshal.go
|
||||
cd doh-server && $(GOBUILD)
|
||||
|
||||
15
Readme.md
15
Readme.md
@@ -42,6 +42,14 @@ If it is OK, you will wee:
|
||||
|
||||
;; SERVER: 127.0.0.1#53(127.0.0.1)
|
||||
|
||||
### Uninstalling
|
||||
|
||||
To uninstall, type:
|
||||
|
||||
sudo make uninstall
|
||||
|
||||
The configuration files are kept at `/etc/dns-over-https`. Remove them manually if you want.
|
||||
|
||||
## Server Configuration
|
||||
|
||||
The following is a typical DNS-over-HTTPS architecture:
|
||||
@@ -72,17 +80,16 @@ Client Subnet during your configuring `unbound` or `bind`.
|
||||
|
||||
## Protocol compatibility
|
||||
|
||||
### Google DNS-over-HTTPS
|
||||
### Google DNS-over-HTTPS Protocol
|
||||
|
||||
DNS-over-HTTPS uses a protocol compatible to [Google DNS-over-HTTPS](https://developers.google.com/speed/public-dns/docs/dns-over-https),
|
||||
except for absolute expire time is preferred to relative TTL value. Refer to
|
||||
[json-dns/response.go](json-dns/response.go) for a complete description of the
|
||||
API.
|
||||
|
||||
### IETF DNS-over-HTTPS (Draft)
|
||||
### IETF DNS-over-HTTPS Protocol (Draft)
|
||||
|
||||
DNS-over-HTTPS uses a protocol compatible to [draft-ietf-doh-dns-over-https
|
||||
](https://github.com/dohwg/draft-ietf-doh-dns-over-https).
|
||||
DNS-over-HTTPS uses a protocol compatible to [draft-ietf-doh-dns-over-https](https://github.com/dohwg/draft-ietf-doh-dns-over-https).
|
||||
This protocol is in draft stage. Any incompatibility may be introduced before
|
||||
it is finished.
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ func (c *Client) handlerFuncGoogle(w dns.ResponseWriter, r *dns.Msg, isTCP bool)
|
||||
w.WriteMsg(reply)
|
||||
return
|
||||
}
|
||||
question := r.Question[0]
|
||||
question := &r.Question[0]
|
||||
// knot-resolver scrambles capitalization, I think it is unfriendly to cache
|
||||
questionName := strings.ToLower(question.Name)
|
||||
questionType := ""
|
||||
@@ -88,7 +88,7 @@ func (c *Client) handlerFuncGoogle(w dns.ResponseWriter, r *dns.Msg, isTCP bool)
|
||||
return
|
||||
}
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("User-Agent", "DNS-over-HTTPS/1.0 (+https://github.com/m13253/dns-over-https)")
|
||||
req.Header.Set("User-Agent", "DNS-over-HTTPS/1.1 (+https://github.com/m13253/dns-over-https)")
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
||||
@@ -49,7 +49,7 @@ func (c *Client) handlerFuncIETF(w dns.ResponseWriter, r *dns.Msg, isTCP bool) {
|
||||
return
|
||||
}
|
||||
|
||||
question := r.Question[0]
|
||||
question := &r.Question[0]
|
||||
// knot-resolver scrambles capitalization, I think it is unfriendly to cache
|
||||
questionName := strings.ToLower(question.Name)
|
||||
questionType := ""
|
||||
@@ -140,7 +140,7 @@ func (c *Client) handlerFuncIETF(w dns.ResponseWriter, r *dns.Msg, isTCP bool) {
|
||||
req.Header.Set("Content-Type", "application/dns-udpwireformat")
|
||||
}
|
||||
req.Header.Set("Accept", "application/dns-udpwireformat")
|
||||
req.Header.Set("User-Agent", "DNS-over-HTTPS/1.0 (+https://github.com/m13253/dns-over-https)")
|
||||
req.Header.Set("User-Agent", "DNS-over-HTTPS/1.1 (+https://github.com/m13253/dns-over-https)")
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -166,17 +166,25 @@ func (c *Client) handlerFuncIETF(w dns.ResponseWriter, r *dns.Msg, isTCP bool) {
|
||||
w.WriteMsg(reply)
|
||||
return
|
||||
}
|
||||
lastModified := resp.Header.Get("Last-Modified")
|
||||
if lastModified == "" {
|
||||
lastModified = resp.Header.Get("Date")
|
||||
headerNow := resp.Header.Get("Date")
|
||||
now := time.Now().UTC()
|
||||
if headerNow != "" {
|
||||
if nowDate, err := time.Parse(http.TimeFormat, headerNow); err == nil {
|
||||
now = nowDate
|
||||
} else {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
lastModifiedDate, err := time.Parse(http.TimeFormat, lastModified)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
lastModifiedDate = now
|
||||
headerLastModified := resp.Header.Get("Last-Modified")
|
||||
lastModified := now
|
||||
if headerLastModified != "" {
|
||||
if lastModifiedDate, err := time.Parse(http.TimeFormat, headerLastModified); err == nil {
|
||||
lastModified = lastModifiedDate
|
||||
} else {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
timeDelta := now.Sub(lastModifiedDate)
|
||||
timeDelta := now.Sub(lastModified)
|
||||
if timeDelta < 0 {
|
||||
timeDelta = 0
|
||||
}
|
||||
@@ -227,7 +235,7 @@ func fixRecordTTL(rr dns.RR, delta time.Duration) dns.RR {
|
||||
rrHeader := rr.Header()
|
||||
oldTTL := time.Duration(rrHeader.Ttl) * time.Second
|
||||
newTTL := oldTTL - delta
|
||||
if newTTL >= 0 {
|
||||
if newTTL > 0 {
|
||||
rrHeader.Ttl = uint32(newTTL / time.Second)
|
||||
} else {
|
||||
rrHeader.Ttl = 0
|
||||
|
||||
@@ -180,9 +180,9 @@ func (s *Server) generateResponseGoogle(w http.ResponseWriter, r *http.Request,
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
if respJSON.HaveTTL {
|
||||
if req.isTailored {
|
||||
w.Header().Set("Cache-Control", "public, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", "private, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", "public, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||
}
|
||||
w.Header().Set("Expires", respJSON.EarliestExpires.Format(http.TimeFormat))
|
||||
}
|
||||
|
||||
@@ -68,6 +68,25 @@ func (s *Server) parseRequestIETF(w http.ResponseWriter, r *http.Request) *DNSRe
|
||||
errtext: fmt.Sprintf("DNS packet parse failure (%s)", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
if s.conf.Verbose && len(msg.Question) > 0 {
|
||||
question := &msg.Question[0]
|
||||
questionName := question.Name
|
||||
questionClass := ""
|
||||
if qclass, ok := dns.ClassToString[question.Qclass]; ok {
|
||||
questionClass = qclass
|
||||
} else {
|
||||
questionClass = strconv.Itoa(int(question.Qclass))
|
||||
}
|
||||
questionType := ""
|
||||
if qtype, ok := dns.TypeToString[question.Qtype]; ok {
|
||||
questionType = qtype
|
||||
} else {
|
||||
questionType = strconv.Itoa(int(question.Qtype))
|
||||
}
|
||||
fmt.Printf("%s - - [%s] \"%s %s %s\"\n", r.RemoteAddr, time.Now().Format("02/Jan/2006:15:04:05 -0700"), questionName, questionClass, questionType)
|
||||
}
|
||||
|
||||
msg.Id = dns.Id()
|
||||
opt := msg.IsEdns0()
|
||||
if opt == nil {
|
||||
@@ -126,14 +145,14 @@ func (s *Server) generateResponseIETF(w http.ResponseWriter, r *http.Request, re
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/dns-udpwireformat")
|
||||
now := time.Now().Format(http.TimeFormat)
|
||||
now := time.Now().UTC().Format(http.TimeFormat)
|
||||
w.Header().Set("Date", now)
|
||||
w.Header().Set("Last-Modified", now)
|
||||
if respJSON.HaveTTL {
|
||||
if req.isTailored {
|
||||
w.Header().Set("Cache-Control", "public, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", "private, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", "public, max-age="+strconv.Itoa(int(respJSON.LeastTTL)))
|
||||
}
|
||||
w.Header().Set("Expires", respJSON.EarliestExpires.Format(http.TimeFormat))
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ func (s *Server) Start() error {
|
||||
}
|
||||
|
||||
func (s *Server) handlerFunc(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Server", "DNS-over-HTTPS/1.0 (+https://github.com/m13253/dns-over-https)")
|
||||
w.Header().Set("X-Powered-By", "DNS-over-HTTPS/1.0 (+https://github.com/m13253/dns-over-https)")
|
||||
w.Header().Set("Server", "DNS-over-HTTPS/1.1 (+https://github.com/m13253/dns-over-https)")
|
||||
w.Header().Set("X-Powered-By", "DNS-over-HTTPS/1.1 (+https://github.com/m13253/dns-over-https)")
|
||||
|
||||
if r.Form == nil {
|
||||
const maxMemory = 32 << 20 // 32 MB
|
||||
@@ -142,7 +142,7 @@ func (s *Server) handlerFunc(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if contentType == "application/x-www-form-urlencoded" {
|
||||
if responseType == "application/json" {
|
||||
s.generateResponseGoogle(w, r, req)
|
||||
} else if contentType == "application/dns-udpwireformat" {
|
||||
s.generateResponseIETF(w, r, req)
|
||||
|
||||
Reference in New Issue
Block a user