Compare commits

...

5 Commits

Author SHA1 Message Date
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
7 changed files with 132 additions and 43 deletions

62
Changelog.md Normal file
View File

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

@@ -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) result := 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 }
}() result <- 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(result); i++ {
err := <-result
if err != nil {
return err
}
}
close(result)
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

@@ -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

@@ -75,10 +75,27 @@ 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 != "" { listeners := 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 {
if s.conf.Cert != "" || s.conf.Key != "" {
go func() {
listeners <- http.ListenAndServeTLS(addr, s.conf.Cert, s.conf.Key, servemux)
}()
continue
}
go func() {
listeners <- http.ListenAndServe(addr, servemux)
}()
} }
return http.ListenAndServe(s.conf.Listen, servemux) // wait for all handlers
for i := 0; i < cap(listeners); i++ {
err := <-listeners
if err != nil {
return err
}
}
close(listeners)
return nil
} }
func (s *Server) handlerFunc(w http.ResponseWriter, r *http.Request) { func (s *Server) handlerFunc(w http.ResponseWriter, r *http.Request) {