2018-05-01 23:45:06 +00:00
|
|
|
package tunneldns
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
"sync"
|
2024-07-13 07:37:51 +00:00
|
|
|
"os"
|
2018-05-01 23:45:06 +00:00
|
|
|
|
|
|
|
"github.com/coredns/coredns/core/dnsserver"
|
|
|
|
"github.com/coredns/coredns/plugin"
|
|
|
|
"github.com/coredns/coredns/plugin/cache"
|
|
|
|
"github.com/pkg/errors"
|
2020-11-25 06:55:13 +00:00
|
|
|
"github.com/rs/zerolog"
|
2018-05-01 23:45:06 +00:00
|
|
|
)
|
|
|
|
|
2020-12-28 18:10:01 +00:00
|
|
|
const (
|
2021-02-12 17:32:29 +00:00
|
|
|
LogFieldAddress = "address"
|
|
|
|
LogFieldURL = "url"
|
|
|
|
MaxUpstreamConnsDefault = 5
|
2020-12-28 18:10:01 +00:00
|
|
|
)
|
|
|
|
|
2018-05-01 23:45:06 +00:00
|
|
|
// Listener is an adapter between CoreDNS server and Warp runnable
|
|
|
|
type Listener struct {
|
|
|
|
server *dnsserver.Server
|
|
|
|
wg sync.WaitGroup
|
2020-11-25 06:55:13 +00:00
|
|
|
log *zerolog.Logger
|
2018-05-01 23:45:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a CoreDNS server plugin from configuration
|
|
|
|
func createConfig(address string, port uint16, p plugin.Handler) *dnsserver.Config {
|
|
|
|
c := &dnsserver.Config{
|
|
|
|
Zone: ".",
|
|
|
|
Transport: "dns",
|
|
|
|
ListenHosts: []string{address},
|
|
|
|
Port: strconv.FormatUint(uint64(port), 10),
|
|
|
|
}
|
|
|
|
|
|
|
|
c.AddPlugin(func(next plugin.Handler) plugin.Handler { return p })
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start blocks for serving requests
|
|
|
|
func (l *Listener) Start(readySignal chan struct{}) error {
|
|
|
|
defer close(readySignal)
|
2020-12-28 18:10:01 +00:00
|
|
|
l.log.Info().Str(LogFieldAddress, l.server.Address()).Msg("Starting DNS over HTTPS proxy server")
|
2018-05-01 23:45:06 +00:00
|
|
|
|
|
|
|
// Start UDP listener
|
|
|
|
if udp, err := l.server.ListenPacket(); err == nil {
|
|
|
|
l.wg.Add(1)
|
|
|
|
go func() {
|
2020-11-25 06:55:13 +00:00
|
|
|
_ = l.server.ServePacket(udp)
|
2018-05-01 23:45:06 +00:00
|
|
|
l.wg.Done()
|
|
|
|
}()
|
|
|
|
} else {
|
|
|
|
return errors.Wrap(err, "failed to create a UDP listener")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start TCP listener
|
|
|
|
tcp, err := l.server.Listen()
|
|
|
|
if err == nil {
|
|
|
|
l.wg.Add(1)
|
|
|
|
go func() {
|
2020-11-25 06:55:13 +00:00
|
|
|
_ = l.server.Serve(tcp)
|
2018-05-01 23:45:06 +00:00
|
|
|
l.wg.Done()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors.Wrap(err, "failed to create a TCP listener")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop signals server shutdown and blocks until completed
|
|
|
|
func (l *Listener) Stop() error {
|
|
|
|
if err := l.server.Stop(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
l.wg.Wait()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateListener configures the server and bound sockets
|
2021-02-12 17:32:29 +00:00
|
|
|
func CreateListener(address string, port uint16, upstreams []string, bootstraps []string, maxUpstreamConnections int, log *zerolog.Logger) (*Listener, error) {
|
2018-05-01 23:45:06 +00:00
|
|
|
// Build the list of upstreams
|
|
|
|
upstreamList := make([]Upstream, 0)
|
|
|
|
for _, url := range upstreams {
|
2020-12-28 18:10:01 +00:00
|
|
|
log.Info().Str(LogFieldURL, url).Msg("Adding DNS upstream")
|
2021-02-12 17:32:29 +00:00
|
|
|
upstream, err := NewUpstreamHTTPS(url, bootstraps, maxUpstreamConnections, log)
|
2018-05-01 23:45:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "failed to create HTTPS upstream")
|
|
|
|
}
|
|
|
|
upstreamList = append(upstreamList, upstream)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format an endpoint
|
|
|
|
endpoint := "dns://" + net.JoinHostPort(address, strconv.FormatUint(uint64(port), 10))
|
|
|
|
|
2024-07-13 08:00:00 +00:00
|
|
|
// get middlewares for DNS Server
|
|
|
|
middlewares := getMiddlewares(upstreamList)
|
|
|
|
chain := NewMetricsPlugin(middlewares)
|
|
|
|
|
2018-05-01 23:45:06 +00:00
|
|
|
// Create the actual middleware server
|
2024-07-13 08:00:00 +00:00
|
|
|
server, err := dnsserver.NewServer(endpoint, []*dnsserver.Config{createConfig(address, port, chain)})
|
2018-05-01 23:45:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-07-13 08:00:00 +00:00
|
|
|
|
2018-05-01 23:45:06 +00:00
|
|
|
|
2020-11-25 06:55:13 +00:00
|
|
|
return &Listener{server: server, log: log}, nil
|
2018-05-01 23:45:06 +00:00
|
|
|
}
|
2024-07-13 08:00:00 +00:00
|
|
|
|
|
|
|
// getMiddlewares() returns the middleware chain for DNS Server
|
|
|
|
//
|
|
|
|
// Middleware includes features like...
|
|
|
|
// * Response Cache
|
|
|
|
// * HTTP Proxy Settings
|
|
|
|
func getMiddlewares(upstreamList []Upstream) plugin.Handler {
|
|
|
|
proxyPlugin := ProxyPlugin{
|
|
|
|
Upstreams: upstreamList,
|
|
|
|
}
|
|
|
|
cachePlugin := cache.New()
|
|
|
|
cachePlugin.Next = proxyPlugin
|
|
|
|
|
|
|
|
if os.Getenv("DISABLE_TUNNELDNS_CACHE") == "true" {
|
|
|
|
return cachePlugin
|
|
|
|
}
|
|
|
|
return proxyPlugin
|
|
|
|
}
|