Compare commits

...

13 Commits

Author SHA1 Message Date
Star Brilliant
f4516429ee Take User-Agent out of common library, that would be better for packaging 2018-04-24 14:25:33 +08:00
Star Brilliant
12df47f45f Release 1.3.2 2018-04-17 03:28:36 +08:00
Star Brilliant
450c10a594 Fix version number in User-Agent 2018-04-17 03:27:42 +08:00
Star Brilliant
e7c4450787 Fix build system 2018-04-17 03:27:21 +08:00
Star Brilliant
bd5ef5d61e Fix build 2018-04-16 21:36:26 +08:00
Star Brilliant
ff0e9529cb Update User-Agent 2018-04-16 21:35:33 +08:00
Star Brilliant
627e2d639d Release 1.3.1 2018-04-16 13:59:03 +08:00
Star Brilliant
7d5cf98d2b Fix the "address already in use" issue 2018-04-16 13:58:38 +08:00
Star Brilliant
34adf40b36 Release 1.3.0 2018-04-16 13:35:38 +08:00
Star Brilliant
b9c1bcaad2 Put [::1] into default listen addresses 2018-04-16 13:18:51 +08:00
Star Brilliant
47df06b6e2 Merge pull request #9 from gdm85/master
Add client/server support for multiple listen addresses
2018-04-16 03:36:30 +08:00
gdm85
1abba72898 Add server support for multiple listen addresses 2018-04-15 19:57:17 +02:00
gdm85
ce656ac3f7 Add client support for multiple listen addresses 2018-04-15 19:57:01 +02:00
13 changed files with 209 additions and 51 deletions

74
Changelog.md Normal file
View File

@@ -0,0 +1,74 @@
# Changelog
This Changelog records major changes between versions.
Not all changes are recorded. Please check git log for details.
## 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

View File

@@ -2,6 +2,7 @@
GOBUILD=go build GOBUILD=go build
GOGET=go get -d -v GOGET=go get -d -v
GOGET_UPDATE=go get -d -u -v
PREFIX=/usr/local PREFIX=/usr/local
ifeq ($(shell uname),Darwin) ifeq ($(shell uname),Darwin)
CONFDIR=/usr/local/etc/dns-over-https CONFDIR=/usr/local/etc/dns-over-https
@@ -40,6 +41,8 @@ uninstall:
fi fi
deps: 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 $(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 json-dns/error.go json-dns/globalip.go json-dns/marshal.go json-dns/response.go json-dns/unmarshal.go

View File

@@ -42,8 +42,8 @@ import (
type Client struct { type Client struct {
conf *config conf *config
bootstrap []string bootstrap []string
udpServer *dns.Server udpServers []*dns.Server
tcpServer *dns.Server tcpServers []*dns.Server
bootstrapResolver *net.Resolver bootstrapResolver *net.Resolver
cookieJar *cookiejar.Jar cookieJar *cookiejar.Jar
httpClientMux *sync.RWMutex httpClientMux *sync.RWMutex
@@ -64,16 +64,21 @@ func NewClient(conf *config) (c *Client, err error) {
c = &Client{ c = &Client{
conf: conf, conf: conf,
} }
c.udpServer = &dns.Server{
Addr: conf.Listen, udpH := dns.HandlerFunc(c.udpHandlerFunc)
Net: "udp", tcpH := dns.HandlerFunc(c.tcpHandlerFunc)
Handler: dns.HandlerFunc(c.udpHandlerFunc), for _, addr := range conf.Listen {
UDPSize: 4096, c.udpServers = append(c.udpServers, &dns.Server{
} Addr: addr,
c.tcpServer = &dns.Server{ Net: "udp",
Addr: conf.Listen, Handler: udpH,
Net: "tcp", UDPSize: 4096,
Handler: dns.HandlerFunc(c.tcpHandlerFunc), })
c.tcpServers = append(c.tcpServers, &dns.Server{
Addr: addr,
Net: "tcp",
Handler: tcpH,
})
} }
c.bootstrapResolver = net.DefaultResolver c.bootstrapResolver = net.DefaultResolver
if len(conf.Bootstrap) != 0 { if len(conf.Bootstrap) != 0 {
@@ -149,27 +154,25 @@ func (c *Client) newHTTPClient() error {
} }
func (c *Client) Start() error { func (c *Client) Start() error {
result := make(chan error) results := make(chan error, len(c.udpServers)+len(c.tcpServers))
go func() { for _, srv := range append(c.udpServers, c.tcpServers...) {
err := c.udpServer.ListenAndServe() go func(srv *dns.Server) {
if err != nil { err := srv.ListenAndServe()
log.Println(err) if err != nil {
} log.Println(err)
result <- err }
}() results <- err
go func() { }(srv)
err := c.tcpServer.ListenAndServe()
if err != nil {
log.Println(err)
}
result <- err
}()
err := <-result
if err != nil {
return err
} }
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) { func (c *Client) handlerFunc(w dns.ResponseWriter, r *dns.Msg, isTCP bool) {

View File

@@ -30,7 +30,7 @@ import (
) )
type config struct { type config struct {
Listen string `toml:"listen"` Listen []string `toml:"listen"`
UpstreamGoogle []string `toml:"upstream_google"` UpstreamGoogle []string `toml:"upstream_google"`
UpstreamIETF []string `toml:"upstream_ietf"` UpstreamIETF []string `toml:"upstream_ietf"`
Bootstrap []string `toml:"bootstrap"` Bootstrap []string `toml:"bootstrap"`
@@ -50,8 +50,8 @@ func loadConfig(path string) (*config, error) {
return nil, &configError{fmt.Sprintf("unknown option %q", key.String())} return nil, &configError{fmt.Sprintf("unknown option %q", key.String())}
} }
if conf.Listen == "" { if len(conf.Listen) == 0 {
conf.Listen = "127.0.0.1:53" conf.Listen = []string{"127.0.0.1:53", "[::1]:53"}
} }
if len(conf.UpstreamGoogle) == 0 && len(conf.UpstreamIETF) == 0 { if len(conf.UpstreamGoogle) == 0 && len(conf.UpstreamIETF) == 0 {
conf.UpstreamGoogle = []string{"https://dns.google.com/resolve"} conf.UpstreamGoogle = []string{"https://dns.google.com/resolve"}

View File

@@ -1,5 +1,8 @@
# DNS listen port # DNS listen port
listen = "127.0.0.1:53" listen = [
"127.0.0.1:53",
"[::1]:53",
]
# HTTP path for upstream resolver # HTTP path for upstream 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.

View File

@@ -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("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() c.httpClientMux.RLock()
resp, err := c.httpClient.Do(req) resp, err := c.httpClient.Do(req)
c.httpClientMux.RUnlock() c.httpClientMux.RUnlock()

View File

@@ -154,7 +154,7 @@ func (c *Client) generateRequestIETF(w dns.ResponseWriter, r *dns.Msg, isTCP boo
req.Header.Set("Content-Type", "application/dns-message") req.Header.Set("Content-Type", "application/dns-message")
} }
req.Header.Set("Accept", "application/dns-message, application/dns-udpwireformat, application/json") 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() c.httpClientMux.RLock()
resp, err := c.httpClient.Do(req) resp, err := c.httpClient.Do(req)
c.httpClientMux.RUnlock() c.httpClientMux.RUnlock()

27
doh-client/version.go Normal file
View File

@@ -0,0 +1,27 @@
/*
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.3"
const USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"

View File

@@ -30,7 +30,7 @@ import (
) )
type config struct { type config struct {
Listen string `toml:"listen"` Listen []string `toml:"listen"`
Cert string `toml:"cert"` Cert string `toml:"cert"`
Key string `toml:"key"` Key string `toml:"key"`
Path string `toml:"path"` Path string `toml:"path"`
@@ -51,9 +51,10 @@ func loadConfig(path string) (*config, error) {
return nil, &configError{fmt.Sprintf("unknown option %q", key.String())} return nil, &configError{fmt.Sprintf("unknown option %q", key.String())}
} }
if conf.Listen == "" { if len(conf.Listen) == 0 {
conf.Listen = "127.0.0.1:8053" conf.Listen = []string{"127.0.0.1:8053", "[::1]:8053"}
} }
if conf.Path == "" { if conf.Path == "" {
conf.Path = "/dns-query" conf.Path = "/dns-query"
} }

View File

@@ -1,5 +1,8 @@
# HTTP listen port # HTTP listen port
listen = "127.0.0.1:8053" listen = [
"127.0.0.1:8053",
"[::1]:8053",
]
# TLS certification file # TLS certification file
cert = "" cert = ""

View File

@@ -43,8 +43,5 @@ func main() {
} }
server := NewServer(conf) server := NewServer(conf)
err = server.Start() _ = server.Start()
if err != nil {
log.Fatalln(err)
}
} }

View File

@@ -75,15 +75,35 @@ func (s *Server) Start() error {
if s.conf.Verbose { if s.conf.Verbose {
servemux = handlers.CombinedLoggingHandler(os.Stdout, servemux) servemux = handlers.CombinedLoggingHandler(os.Stdout, servemux)
} }
if s.conf.Cert != "" || s.conf.Key != "" { results := make(chan error, len(s.conf.Listen))
return http.ListenAndServeTLS(s.conf.Listen, s.conf.Cert, s.conf.Key, servemux) 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) { 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("Server", USER_AGENT)
w.Header().Set("X-Powered-By", "DNS-over-HTTPS/1.1 (+https://github.com/m13253/dns-over-https)") w.Header().Set("X-Powered-By", USER_AGENT)
if r.Form == nil { if r.Form == nil {
const maxMemory = 32 << 20 // 32 MB const maxMemory = 32 << 20 // 32 MB

27
doh-server/version.go Normal file
View File

@@ -0,0 +1,27 @@
/*
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.3"
const USER_AGENT = "DNS-over-HTTPS/" + VERSION + " (+https://github.com/m13253/dns-over-https)"