mirror of
https://github.com/m13253/dns-over-https.git
synced 2026-03-31 18:25:38 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51b065eed7 | ||
|
|
a58607dc3d | ||
|
|
cf94354b08 | ||
|
|
f2e3a642e3 | ||
|
|
88b3c95710 | ||
|
|
93b70f3941 | ||
|
|
76c40fb4dc | ||
|
|
174a465ac8 | ||
|
|
4cbe7c8c98 | ||
|
|
7839d2c7b1 | ||
|
|
c4b2236cf9 | ||
|
|
1b90731f20 | ||
|
|
20624acf20 | ||
|
|
01385b6d29 | ||
|
|
5afdee6315 | ||
|
|
874a3613e4 | ||
|
|
dc14a70e9d | ||
|
|
58e4018ab2 | ||
|
|
f4516429ee | ||
|
|
12df47f45f | ||
|
|
450c10a594 | ||
|
|
e7c4450787 | ||
|
|
bd5ef5d61e | ||
|
|
ff0e9529cb | ||
|
|
627e2d639d | ||
|
|
7d5cf98d2b | ||
|
|
34adf40b36 | ||
|
|
b9c1bcaad2 | ||
|
|
47df06b6e2 | ||
|
|
1abba72898 | ||
|
|
ce656ac3f7 |
90
Changelog.md
Normal file
90
Changelog.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Changelog
|
||||
|
||||
This Changelog records major changes between versions.
|
||||
|
||||
Not all changes are recorded. Please check git log for details.
|
||||
|
||||
## Version 1.3.6
|
||||
|
||||
- We have a logger for macOS platform now, so logs can be sent to Console.app
|
||||
- Add an option to disable IPv6, this option is available to client only
|
||||
|
||||
## Version 1.3.5
|
||||
|
||||
- Limit the frequency of creating HTTP client on bad network condition
|
||||
|
||||
## Version 1.3.4
|
||||
|
||||
- doh-client now silently fails in case of network error to prevent caching of SERVFAIL
|
||||
- EDNS0 is now inserted to the beginning of OPT section, to ensure DNSSEC signatures are at the end
|
||||
- Improve building system
|
||||
- Update documents
|
||||
|
||||
## Version 1.3.3
|
||||
|
||||
- Take User-Agent out of common library, that would be better for packaging
|
||||
|
||||
## Version 1.3.2
|
||||
|
||||
- Fix version string in HTTP User-Agent
|
||||
|
||||
## Version 1.3.1
|
||||
|
||||
- Fix the "address already in use" issue
|
||||
|
||||
## Version 1.3.0
|
||||
|
||||
- Breaking change: Add client / server support for multiple listen address
|
||||
The `listen` option in the configuration file is a list now
|
||||
|
||||
## Version 1.2.1
|
||||
|
||||
- Update protocol to IETF draft-07
|
||||
- Update installation documentations for Ubuntu / Debian
|
||||
|
||||
## Version 1.2.0
|
||||
|
||||
- Add installation documentations for Ubuntu / Debian
|
||||
- Include CloudFlare DOH server (1.1.1.1, 1.0.0.1) in default configuration
|
||||
- Fix a problem causing `go get` to fail due to relative paths
|
||||
- Add documentation about `/etc/hosts` preloading
|
||||
|
||||
## Version 1.1.4
|
||||
|
||||
- Add `no_cookies` option
|
||||
- Add documentation on privacy issues
|
||||
- Adapt for CloudFlare DNS service
|
||||
- Fix a problem causing a single network failure blocking future requests
|
||||
- Add experimental macOS support
|
||||
|
||||
## Version 1.1.3
|
||||
|
||||
- Unsupported Content-Type now generates HTTP error code 415
|
||||
|
||||
## Version 1.1.2
|
||||
|
||||
- Adapt to IETF protocol
|
||||
- Optimize for HTTP caches
|
||||
|
||||
## Version 1.1.1
|
||||
|
||||
- Adapt to IETF protocol
|
||||
- Optimize for HTTP caches
|
||||
- Add documentation for uninstallation instructions
|
||||
- Fix build issues
|
||||
|
||||
## Version 1.1.0
|
||||
|
||||
- Adpat to IETF protocol
|
||||
- Fix issues regarding to HTTP caching
|
||||
- Require Go 1.9 to build now
|
||||
- Fix systemd issue
|
||||
|
||||
## Version 1.0.1
|
||||
|
||||
- Fix build issues
|
||||
|
||||
## Version 1.0.0
|
||||
|
||||
- First release
|
||||
- Relicense as MIT license
|
||||
14
Makefile
14
Makefile
@@ -2,6 +2,7 @@
|
||||
|
||||
GOBUILD=go build
|
||||
GOGET=go get -d -v
|
||||
GOGET_UPDATE=go get -d -u -v
|
||||
PREFIX=/usr/local
|
||||
ifeq ($(shell uname),Darwin)
|
||||
CONFDIR=/usr/local/etc/dns-over-https
|
||||
@@ -10,9 +11,15 @@ else
|
||||
endif
|
||||
|
||||
all: doh-client/doh-client doh-server/doh-server
|
||||
if [ "`uname`" = "Darwin" ]; then \
|
||||
$(MAKE) -C darwin-wrapper; \
|
||||
fi
|
||||
|
||||
clean:
|
||||
rm -f doh-client/doh-client doh-server/doh-server
|
||||
if [ "`uname`" = "Darwin" ]; then \
|
||||
$(MAKE) -C darwin-wrapper clean; \
|
||||
fi
|
||||
|
||||
install:
|
||||
[ -e doh-client/doh-client ] || $(MAKE) doh-client/doh-client
|
||||
@@ -27,6 +34,7 @@ install:
|
||||
$(MAKE) -C systemd install "DESTDIR=$(DESTDIR)"; \
|
||||
$(MAKE) -C NetworkManager install "DESTDIR=$(DESTDIR)"; \
|
||||
elif [ "`uname`" = "Darwin" ]; then \
|
||||
$(MAKE) -C darwin-wrapper install "DESTDIR=$(DESTDIR)" "PREFIX=$(PREFIX)"; \
|
||||
$(MAKE) -C launchd install "DESTDIR=$(DESTDIR)"; \
|
||||
fi
|
||||
|
||||
@@ -40,10 +48,12 @@ uninstall:
|
||||
fi
|
||||
|
||||
deps:
|
||||
@# I am not sure if it is the correct way to keep the common library updated
|
||||
$(GOGET_UPDATE) github.com/m13253/dns-over-https/json-dns
|
||||
$(GOGET) ./doh-client ./doh-server
|
||||
|
||||
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
|
||||
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 doh-client/version.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/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
|
||||
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 doh-server/version.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)
|
||||
|
||||
@@ -70,6 +70,9 @@ The following is a typical DNS-over-HTTPS architecture:
|
||||
Although DNS-over-HTTPS can work alone, a HTTP service muxer would be useful as
|
||||
you can host DNS-over-HTTPS along with other HTTPS services.
|
||||
|
||||
HTTP/2 with at least TLS v1.3 is recommended. OCSP stapling must be enabled,
|
||||
otherwise DNS recursion may happen.
|
||||
|
||||
## DNSSEC
|
||||
|
||||
DNS-over-HTTPS is compatible with DNSSEC, and requests DNSSEC signatures by
|
||||
@@ -90,8 +93,10 @@ EDNS0-Client-Subnet is affecting your privacy, you can set `no_ecs = true` in
|
||||
`/etc/dns-over-https/doh-client.conf`, with the cost of slower video streaming
|
||||
or software downloading speed.
|
||||
|
||||
If your server is backed by `unbound` or `bind`, you probably want to enable
|
||||
the EDNS0-Client-Subnet feature in their configuration files as well.
|
||||
To ultilize ECS, `X-Forwarded-For` or `X-Real-IP` should be enabled on your
|
||||
HTTP service muxer. If your server is backed by `unbound` or `bind`, you
|
||||
probably want to configure it to enable the EDNS0-Client-Subnet feature as
|
||||
well.
|
||||
|
||||
## Protocol compatibility
|
||||
|
||||
|
||||
19
darwin-wrapper/Makefile
Normal file
19
darwin-wrapper/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
.PHONY: all clean install uninstall
|
||||
|
||||
SWIFTC = swiftc
|
||||
PREFIX = /usr/local
|
||||
|
||||
all: doh-logger
|
||||
|
||||
doh-logger: doh-logger.swift
|
||||
$(SWIFTC) -o $@ -O $<
|
||||
|
||||
clean:
|
||||
rm -f doh-logger
|
||||
|
||||
install: doh-logger
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
install -m0755 doh-logger $(DESTDIR)$(PREFIX)/bin
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(PREFIX)/bin/doh-logger
|
||||
94
darwin-wrapper/doh-logger.swift
Normal file
94
darwin-wrapper/doh-logger.swift
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/swift
|
||||
|
||||
/*
|
||||
DNS-over-HTTPS
|
||||
Copyright (C) 2017-2018 Star Brilliant <m13253@hotmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import os.log
|
||||
|
||||
if CommandLine.arguments.count < 3 {
|
||||
let programName = CommandLine.arguments[0]
|
||||
print("Usage: \(programName) LOG_NAME PROGRAM [ARGUMENTS]\n")
|
||||
exit(1)
|
||||
}
|
||||
let logSubsystem = CommandLine.arguments[1]
|
||||
let logger = OSLog(subsystem: logSubsystem, category: "default")
|
||||
|
||||
let pipe = Pipe()
|
||||
var buffer = Data()
|
||||
NotificationCenter.default.addObserver(forName: FileHandle.readCompletionNotification, object: pipe.fileHandleForReading, queue: nil) { notification in
|
||||
let data = notification.userInfo?["NSFileHandleNotificationDataItem"] as? Data ?? Data()
|
||||
buffer.append(data)
|
||||
var lastIndex = 0
|
||||
for (i, byte) in buffer.enumerated() {
|
||||
if byte == 0x0a {
|
||||
let line = String(data: buffer.subdata(in: lastIndex..<i), encoding: .utf8) ?? ""
|
||||
print(line)
|
||||
os_log("%{public}@", log: logger, line)
|
||||
lastIndex = i + 1
|
||||
}
|
||||
}
|
||||
buffer = buffer.subdata(in: lastIndex..<buffer.count)
|
||||
if data.count == 0 && buffer.count != 0 {
|
||||
let line = String(data: buffer, encoding: .utf8) ?? ""
|
||||
print(line, terminator: "")
|
||||
os_log("%{public}@", log: logger, line)
|
||||
}
|
||||
pipe.fileHandleForReading.readInBackgroundAndNotify()
|
||||
}
|
||||
pipe.fileHandleForReading.readInBackgroundAndNotify()
|
||||
|
||||
let process = Process()
|
||||
process.arguments = Array(CommandLine.arguments[3...])
|
||||
process.executableURL = URL(fileURLWithPath: CommandLine.arguments[2])
|
||||
process.standardError = pipe.fileHandleForWriting
|
||||
process.standardInput = FileHandle.standardInput
|
||||
process.standardOutput = pipe.fileHandleForWriting
|
||||
NotificationCenter.default.addObserver(forName: Process.didTerminateNotification, object: process, queue: nil) { notification in
|
||||
if buffer.count != 0 {
|
||||
let line = String(data: buffer, encoding: .utf8) ?? ""
|
||||
print(line, terminator: "")
|
||||
os_log("%{public}@", log: logger, line)
|
||||
}
|
||||
exit(process.terminationStatus)
|
||||
}
|
||||
|
||||
let SIGINTSource = DispatchSource.makeSignalSource(signal: SIGINT)
|
||||
let SIGTERMSource = DispatchSource.makeSignalSource(signal: SIGTERM)
|
||||
SIGINTSource.setEventHandler(handler: process.interrupt)
|
||||
SIGTERMSource.setEventHandler(handler: process.terminate)
|
||||
signal(SIGINT, SIG_IGN)
|
||||
signal(SIGTERM, SIG_IGN)
|
||||
SIGINTSource.resume()
|
||||
SIGTERMSource.resume()
|
||||
|
||||
do {
|
||||
try process.run()
|
||||
} catch {
|
||||
let errorMessage = error.localizedDescription
|
||||
print(errorMessage)
|
||||
os_log("%{public}@", log: logger, type: .fault, errorMessage)
|
||||
exit(1)
|
||||
}
|
||||
|
||||
RunLoop.current.run()
|
||||
@@ -40,15 +40,16 @@ import (
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
conf *config
|
||||
bootstrap []string
|
||||
udpServer *dns.Server
|
||||
tcpServer *dns.Server
|
||||
bootstrapResolver *net.Resolver
|
||||
cookieJar *cookiejar.Jar
|
||||
httpClientMux *sync.RWMutex
|
||||
httpTransport *http.Transport
|
||||
httpClient *http.Client
|
||||
conf *config
|
||||
bootstrap []string
|
||||
udpServers []*dns.Server
|
||||
tcpServers []*dns.Server
|
||||
bootstrapResolver *net.Resolver
|
||||
cookieJar *cookiejar.Jar
|
||||
httpClientMux *sync.RWMutex
|
||||
httpTransport *http.Transport
|
||||
httpClient *http.Client
|
||||
httpClientLastCreate time.Time
|
||||
}
|
||||
|
||||
type DNSRequest struct {
|
||||
@@ -64,16 +65,21 @@ func NewClient(conf *config) (c *Client, err error) {
|
||||
c = &Client{
|
||||
conf: conf,
|
||||
}
|
||||
c.udpServer = &dns.Server{
|
||||
Addr: conf.Listen,
|
||||
Net: "udp",
|
||||
Handler: dns.HandlerFunc(c.udpHandlerFunc),
|
||||
UDPSize: 4096,
|
||||
}
|
||||
c.tcpServer = &dns.Server{
|
||||
Addr: conf.Listen,
|
||||
Net: "tcp",
|
||||
Handler: dns.HandlerFunc(c.tcpHandlerFunc),
|
||||
|
||||
udpHandler := dns.HandlerFunc(c.udpHandlerFunc)
|
||||
tcpHandler := dns.HandlerFunc(c.tcpHandlerFunc)
|
||||
for _, addr := range conf.Listen {
|
||||
c.udpServers = append(c.udpServers, &dns.Server{
|
||||
Addr: addr,
|
||||
Net: "udp",
|
||||
Handler: udpHandler,
|
||||
UDPSize: dns.DefaultMsgSize,
|
||||
})
|
||||
c.tcpServers = append(c.tcpServers, &dns.Server{
|
||||
Addr: addr,
|
||||
Net: "tcp",
|
||||
Handler: tcpHandler,
|
||||
})
|
||||
}
|
||||
c.bootstrapResolver = net.DefaultResolver
|
||||
if len(conf.Bootstrap) != 0 {
|
||||
@@ -119,16 +125,20 @@ func NewClient(conf *config) (c *Client, err error) {
|
||||
func (c *Client) newHTTPClient() error {
|
||||
c.httpClientMux.Lock()
|
||||
defer c.httpClientMux.Unlock()
|
||||
if !c.httpClientLastCreate.IsZero() && time.Now().Sub(c.httpClientLastCreate) < time.Duration(c.conf.Timeout)*time.Second {
|
||||
return nil
|
||||
}
|
||||
if c.httpTransport != nil {
|
||||
c.httpTransport.CloseIdleConnections()
|
||||
}
|
||||
dialer := &net.Dialer{
|
||||
Timeout: time.Duration(c.conf.Timeout) * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
Resolver: c.bootstrapResolver,
|
||||
}
|
||||
c.httpTransport = &http.Transport{
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: time.Duration(c.conf.Timeout) * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
Resolver: c.bootstrapResolver,
|
||||
}).DialContext,
|
||||
DialContext: dialer.DialContext,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
MaxIdleConns: 100,
|
||||
@@ -137,6 +147,14 @@ func (c *Client) newHTTPClient() error {
|
||||
ResponseHeaderTimeout: time.Duration(c.conf.Timeout) * time.Second,
|
||||
TLSHandshakeTimeout: time.Duration(c.conf.Timeout) * time.Second,
|
||||
}
|
||||
if c.conf.NoIPv6 {
|
||||
c.httpTransport.DialContext = func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
if strings.HasPrefix(network, "tcp") {
|
||||
network = "tcp4"
|
||||
}
|
||||
return dialer.DialContext(ctx, network, address)
|
||||
}
|
||||
}
|
||||
err := http2.ConfigureTransport(c.httpTransport)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -145,31 +163,30 @@ func (c *Client) newHTTPClient() error {
|
||||
Transport: c.httpTransport,
|
||||
Jar: c.cookieJar,
|
||||
}
|
||||
c.httpClientLastCreate = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Start() error {
|
||||
result := make(chan error)
|
||||
go func() {
|
||||
err := c.udpServer.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
result <- err
|
||||
}()
|
||||
go func() {
|
||||
err := c.tcpServer.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
result <- err
|
||||
}()
|
||||
err := <-result
|
||||
if err != nil {
|
||||
return err
|
||||
results := make(chan error, len(c.udpServers)+len(c.tcpServers))
|
||||
for _, srv := range append(c.udpServers, c.tcpServers...) {
|
||||
go func(srv *dns.Server) {
|
||||
err := srv.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
results <- err
|
||||
}(srv)
|
||||
}
|
||||
err = <-result
|
||||
return err
|
||||
|
||||
for i := 0; i < cap(results); i++ {
|
||||
err := <-results
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
close(results)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) handlerFunc(w dns.ResponseWriter, r *dns.Msg, isTCP bool) {
|
||||
|
||||
@@ -30,13 +30,14 @@ import (
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Listen string `toml:"listen"`
|
||||
Listen []string `toml:"listen"`
|
||||
UpstreamGoogle []string `toml:"upstream_google"`
|
||||
UpstreamIETF []string `toml:"upstream_ietf"`
|
||||
Bootstrap []string `toml:"bootstrap"`
|
||||
Timeout uint `toml:"timeout"`
|
||||
NoCookies bool `toml:"no_cookies"`
|
||||
NoECS bool `toml:"no_ecs"`
|
||||
NoIPv6 bool `toml:"no_ipv6"`
|
||||
Verbose bool `toml:"verbose"`
|
||||
}
|
||||
|
||||
@@ -50,8 +51,8 @@ func loadConfig(path string) (*config, error) {
|
||||
return nil, &configError{fmt.Sprintf("unknown option %q", key.String())}
|
||||
}
|
||||
|
||||
if conf.Listen == "" {
|
||||
conf.Listen = "127.0.0.1:53"
|
||||
if len(conf.Listen) == 0 {
|
||||
conf.Listen = []string{"127.0.0.1:53", "[::1]:53"}
|
||||
}
|
||||
if len(conf.UpstreamGoogle) == 0 && len(conf.UpstreamIETF) == 0 {
|
||||
conf.UpstreamGoogle = []string{"https://dns.google.com/resolve"}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# DNS listen port
|
||||
listen = "127.0.0.1:53"
|
||||
listen = [
|
||||
"127.0.0.1:53",
|
||||
"[::1]:53",
|
||||
]
|
||||
|
||||
# HTTP path for upstream resolver
|
||||
# If multiple servers are specified, a random one will be chosen each time.
|
||||
@@ -44,7 +47,7 @@ bootstrap = [
|
||||
]
|
||||
|
||||
# Timeout for upstream request
|
||||
timeout = 10
|
||||
timeout = 30
|
||||
|
||||
# Disable HTTP Cookies
|
||||
#
|
||||
@@ -62,5 +65,13 @@ no_cookies = false
|
||||
# the same configuration as most public DNS servers.
|
||||
no_ecs = false
|
||||
|
||||
# Disable IPv6 when querying upstream
|
||||
#
|
||||
# Only enable this if you really have trouble connecting.
|
||||
# Doh-client uses both IPv4 and IPv6 by default and should not have problems
|
||||
# with an IPv4-only environment.
|
||||
# Note that DNS listening and bootstrapping is not controlled by this option.
|
||||
no_ipv6 = false
|
||||
|
||||
# Enable logging
|
||||
verbose = false
|
||||
|
||||
@@ -92,7 +92,7 @@ func (c *Client) generateRequestGoogle(w dns.ResponseWriter, r *dns.Msg, isTCP b
|
||||
}
|
||||
}
|
||||
req.Header.Set("Accept", "application/json, application/dns-message, application/dns-udpwireformat")
|
||||
req.Header.Set("User-Agent", "DNS-over-HTTPS/1.1 (+https://github.com/m13253/dns-over-https)")
|
||||
req.Header.Set("User-Agent", USER_AGENT)
|
||||
c.httpClientMux.RLock()
|
||||
resp, err := c.httpClient.Do(req)
|
||||
c.httpClientMux.RUnlock()
|
||||
|
||||
@@ -73,9 +73,9 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
|
||||
opt = new(dns.OPT)
|
||||
opt.Hdr.Name = "."
|
||||
opt.Hdr.Rrtype = dns.TypeOPT
|
||||
opt.SetUDPSize(4096)
|
||||
opt.SetUDPSize(dns.DefaultMsgSize)
|
||||
opt.SetDo(false)
|
||||
r.Extra = append(r.Extra, opt)
|
||||
r.Extra = append([]dns.RR{opt}, r.Extra...)
|
||||
} else {
|
||||
udpSize = opt.UDPSize()
|
||||
}
|
||||
@@ -134,9 +134,8 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
|
||||
if len(requestURL) < 2048 {
|
||||
req, err = http.NewRequest("GET", requestURL, nil)
|
||||
if err != nil {
|
||||
// Do not respond, silently fail to prevent caching of SERVFAIL
|
||||
log.Println(err)
|
||||
reply.Rcode = dns.RcodeServerFailure
|
||||
w.WriteMsg(reply)
|
||||
return &DNSRequest{
|
||||
err: err,
|
||||
}
|
||||
@@ -144,9 +143,8 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
|
||||
} else {
|
||||
req, err = http.NewRequest("POST", upstream, bytes.NewReader(requestBinary))
|
||||
if err != nil {
|
||||
// Do not respond, silently fail to prevent caching of SERVFAIL
|
||||
log.Println(err)
|
||||
reply.Rcode = dns.RcodeServerFailure
|
||||
w.WriteMsg(reply)
|
||||
return &DNSRequest{
|
||||
err: err,
|
||||
}
|
||||
@@ -154,7 +152,7 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
|
||||
req.Header.Set("Content-Type", "application/dns-message")
|
||||
}
|
||||
req.Header.Set("Accept", "application/dns-message, application/dns-udpwireformat, application/json")
|
||||
req.Header.Set("User-Agent", "DNS-over-HTTPS/1.1 (+https://github.com/m13253/dns-over-https)")
|
||||
req.Header.Set("User-Agent", USER_AGENT)
|
||||
c.httpClientMux.RLock()
|
||||
resp, err := c.httpClient.Do(req)
|
||||
c.httpClientMux.RUnlock()
|
||||
|
||||
29
doh-client/version.go
Normal file
29
doh-client/version.go
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
DNS-over-HTTPS
|
||||
Copyright (C) 2017-2018 Star Brilliant <m13253@hotmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
const (
|
||||
VERSION = "1.3.6"
|
||||
USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"
|
||||
)
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Listen string `toml:"listen"`
|
||||
Listen []string `toml:"listen"`
|
||||
Cert string `toml:"cert"`
|
||||
Key string `toml:"key"`
|
||||
Path string `toml:"path"`
|
||||
@@ -51,9 +51,10 @@ func loadConfig(path string) (*config, error) {
|
||||
return nil, &configError{fmt.Sprintf("unknown option %q", key.String())}
|
||||
}
|
||||
|
||||
if conf.Listen == "" {
|
||||
conf.Listen = "127.0.0.1:8053"
|
||||
if len(conf.Listen) == 0 {
|
||||
conf.Listen = []string{"127.0.0.1:8053", "[::1]:8053"}
|
||||
}
|
||||
|
||||
if conf.Path == "" {
|
||||
conf.Path = "/dns-query"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# HTTP listen port
|
||||
listen = "127.0.0.1:8053"
|
||||
listen = [
|
||||
"127.0.0.1:8053",
|
||||
"[::1]:8053",
|
||||
]
|
||||
|
||||
# TLS certification file
|
||||
cert = ""
|
||||
|
||||
@@ -150,7 +150,7 @@ func (s *Server) parseRequestGoogle(w http.ResponseWriter, r *http.Request) *DNS
|
||||
opt := new(dns.OPT)
|
||||
opt.Hdr.Name = "."
|
||||
opt.Hdr.Rrtype = dns.TypeOPT
|
||||
opt.SetUDPSize(4096)
|
||||
opt.SetUDPSize(dns.DefaultMsgSize)
|
||||
opt.SetDo(true)
|
||||
if ednsClientAddress != nil {
|
||||
edns0Subnet := new(dns.EDNS0_SUBNET)
|
||||
|
||||
@@ -93,9 +93,9 @@ func (s *Server) parseRequestIETF(w http.ResponseWriter, r *http.Request) *DNSRe
|
||||
opt = new(dns.OPT)
|
||||
opt.Hdr.Name = "."
|
||||
opt.Hdr.Rrtype = dns.TypeOPT
|
||||
opt.SetUDPSize(4096)
|
||||
opt.SetUDPSize(dns.DefaultMsgSize)
|
||||
opt.SetDo(false)
|
||||
msg.Extra = append(msg.Extra, opt)
|
||||
msg.Extra = append([]dns.RR{opt}, msg.Extra...)
|
||||
}
|
||||
var edns0Subnet *dns.EDNS0_SUBNET
|
||||
for _, option := range opt.Option {
|
||||
|
||||
@@ -43,8 +43,5 @@ func main() {
|
||||
}
|
||||
|
||||
server := NewServer(conf)
|
||||
err = server.Start()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
_ = server.Start()
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ func NewServer(conf *config) (s *Server) {
|
||||
conf: conf,
|
||||
udpClient: &dns.Client{
|
||||
Net: "udp",
|
||||
UDPSize: dns.DefaultMsgSize,
|
||||
Timeout: time.Duration(conf.Timeout) * time.Second,
|
||||
},
|
||||
tcpClient: &dns.Client{
|
||||
@@ -75,15 +76,35 @@ func (s *Server) Start() error {
|
||||
if s.conf.Verbose {
|
||||
servemux = handlers.CombinedLoggingHandler(os.Stdout, servemux)
|
||||
}
|
||||
if s.conf.Cert != "" || s.conf.Key != "" {
|
||||
return http.ListenAndServeTLS(s.conf.Listen, s.conf.Cert, s.conf.Key, servemux)
|
||||
results := make(chan error, len(s.conf.Listen))
|
||||
for _, addr := range s.conf.Listen {
|
||||
go func(addr string) {
|
||||
var err error
|
||||
if s.conf.Cert != "" || s.conf.Key != "" {
|
||||
err = http.ListenAndServeTLS(addr, s.conf.Cert, s.conf.Key, servemux)
|
||||
} else {
|
||||
err = http.ListenAndServe(addr, servemux)
|
||||
}
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
results <- err
|
||||
}(addr)
|
||||
}
|
||||
return http.ListenAndServe(s.conf.Listen, servemux)
|
||||
// wait for all handlers
|
||||
for i := 0; i < cap(results); i++ {
|
||||
err := <-results
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
close(results)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handlerFunc(w http.ResponseWriter, r *http.Request) {
|
||||
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)")
|
||||
w.Header().Set("Server", USER_AGENT)
|
||||
w.Header().Set("X-Powered-By", USER_AGENT)
|
||||
|
||||
if r.Form == nil {
|
||||
const maxMemory = 32 << 20 // 32 MB
|
||||
|
||||
29
doh-server/version.go
Normal file
29
doh-server/version.go
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
DNS-over-HTTPS
|
||||
Copyright (C) 2017-2018 Star Brilliant <m13253@hotmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
const (
|
||||
VERSION = "1.3.6"
|
||||
USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"
|
||||
)
|
||||
@@ -6,6 +6,8 @@
|
||||
<string>org.eu.starlab.doh.client</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/doh-logger</string>
|
||||
<string>doh-client</string>
|
||||
<string>/usr/local/bin/doh-client</string>
|
||||
<string>-conf</string>
|
||||
<string>/usr/local/etc/dns-over-https/doh-client.conf</string>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
<string>org.eu.starlab.doh.server</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/doh-logger</string>
|
||||
<string>doh-server</string>
|
||||
<string>/usr/local/bin/doh-server</string>
|
||||
<string>-conf</string>
|
||||
<string>/usr/local/etc/dns-over-https/doh-server.conf</string>
|
||||
|
||||
Reference in New Issue
Block a user