From 83441a93c45adc803594a7c01fc5fc3c5bcebc56 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Mon, 6 Sep 2021 11:42:21 +0200 Subject: [PATCH 01/13] First commit DoH Client Auth --- main.go | 24 ++++++++++++++++++++++++ proxy/config.go | 5 ++++- proxy/upstreams.go | 1 + upstream/bootstrap.go | 16 ++++++++++++++++ upstream/upstream.go | 3 +++ 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 16616f689..274550c1b 100644 --- a/main.go +++ b/main.go @@ -75,6 +75,15 @@ type Options struct { // Upstream DNS servers settings // -- + // DoH Upstream Authentication + ClientAuth bool `short:"a" long:"auth" description:"Enable DoH Client authentication" optional:"yes" optional-value:"false"` + + // Path to the .crt with the clien-side certificate for upstream client authentication + TLSAuthCertPath string `long:"a-tls-crt" description:"Path to a file with the client certificate"` + + // Path to the file with the clien-side private key for upstream client authentication + TLSAuthKeyPath string `long:"a-tls-key" description:"Path to a file with the client private key"` + // DNS upstreams Upstreams []string `short:"u" long:"upstream" description:"An upstream to be used (can be specified multiple times). You can also specify path to a file with the list of servers" required:"true"` @@ -249,6 +258,7 @@ func createProxyConfig(options *Options) proxy.Config { MaxGoroutines: options.MaxGoRoutines, } + initDoHClientTLSConfig(&config, options) initUpstreams(&config, options) initEDNS(&config, options) initBogusNXDomain(&config, options) @@ -262,6 +272,7 @@ func createProxyConfig(options *Options) proxy.Config { // initUpstreams inits upstream-related config func initUpstreams(config *proxy.Config, options *Options) { // Init upstreams + upstreams := loadServersList(options.Upstreams) upstreamConfig, err := proxy.ParseUpstreamsConfig( upstreams, @@ -269,6 +280,7 @@ func initUpstreams(config *proxy.Config, options *Options) { InsecureSkipVerify: options.Insecure, Bootstrap: options.BootstrapDNS, Timeout: defaultTimeout, + DoHClientTLSConfig: config.DoHClientTLSConfig, }) if err != nil { log.Fatalf("error while parsing upstreams configuration: %s", err) @@ -298,6 +310,7 @@ func initUpstreams(config *proxy.Config, options *Options) { } config.Fallbacks = fallbacks } + } // initEDNS inits EDNS-related config @@ -342,6 +355,17 @@ func initTLSConfig(config *proxy.Config, options *Options) { } } +// initTLSConfig inits the DoH Client Auth TLS config +func initDoHClientTLSConfig(config *proxy.Config, options *Options) { + if options.TLSAuthCertPath != "" && options.TLSAuthKeyPath != "" { + tlsConfig, err := newTLSConfig(options) + if err != nil { + log.Fatalf("failed to load DoH Client-auth TLS config: %s", err) + } + config.DoHClientTLSConfig = tlsConfig + } +} + // initDNSCryptConfig inits the DNSCrypt config func initDNSCryptConfig(config *proxy.Config, options *Options) { if options.DNSCryptConfigPath == "" { diff --git a/proxy/config.go b/proxy/config.go index c737b05d0..7e6dc0ffb 100644 --- a/proxy/config.go +++ b/proxy/config.go @@ -53,7 +53,10 @@ type Config struct { // Encryption configuration // -- - TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC + TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC + + DoHClientTLSConfig *tls.Config // necessary for DoH Client Authentication + DNSCryptProviderName string // DNSCrypt provider name DNSCryptResolverCert *dnscrypt.Cert // DNSCrypt resolver certificate diff --git a/proxy/upstreams.go b/proxy/upstreams.go index 0bb2782d0..8c96c4313 100644 --- a/proxy/upstreams.go +++ b/proxy/upstreams.go @@ -86,6 +86,7 @@ func ParseUpstreamsConfig(upstreamConfig []string, options *upstream.Options) (* } } } + return &UpstreamConfig{ Upstreams: upstreams, DomainReservedUpstreams: domainReservedUpstreams, diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index 6c2679bdd..23af9f2ee 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -185,15 +185,31 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { // createTLSConfig creates a client TLS config func (n *bootstrapper) createTLSConfig(host string) *tls.Config { + + //caCert, err := ioutil.ReadFile("/home/marino/certificates/root/ca-full.cert.pem") + //if err != nil { + // log.Println("could not load TLS cert: %s", err) + //} + + //caCertPool := x509.NewCertPool() + //caCertPool.AppendCertsFromPEM(caCert) + + cert, err := tls.LoadX509KeyPair("/home/ivan/certs/root/ca/intermediate/certs/dohclient.cert.pem", "/home/ivan/certs/root/ca/intermediate/private/dohclient.key.pem") + if err != nil { + log.Println("could not load TLS cert: %s", err) + } + tlsConfig := &tls.Config{ ServerName: host, RootCAs: RootCAs, + Certificates: []tls.Certificate{cert}, CipherSuites: CipherSuites, MinVersion: tls.VersionTLS12, InsecureSkipVerify: n.options.InsecureSkipVerify, VerifyPeerCertificate: n.options.VerifyServerCertificate, } + //TLSConfig := p.DoHClientTLSConfig.Clone() // The supported application level protocols should be specified only // for DNS-over-HTTPS and DNS-over-QUIC connections. // diff --git a/upstream/upstream.go b/upstream/upstream.go index 07dc8e81b..cae547b3a 100644 --- a/upstream/upstream.go +++ b/upstream/upstream.go @@ -2,6 +2,7 @@ package upstream import ( + "crypto/tls" "crypto/x509" "fmt" "net" @@ -46,6 +47,8 @@ type Options struct { // VerifyDNSCryptCertificate is callback to which the DNSCrypt server certificate will be passed. // is called in dnsCrypt.exchangeDNSCrypt; if error != nil then Upstream.Exchange() will return it VerifyDNSCryptCertificate func(cert *dnscrypt.Cert) error + + DoHClientTLSConfig *tls.Config // TLS config when DoH Client Authentication is used } // Parse "host:port" string and validate port number From fe8a5e25aa10ebbc28cd5630b704c8111f1a1545 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Wed, 8 Sep 2021 15:33:59 +0200 Subject: [PATCH 02/13] changing bootstrap et uptream --- main.go | 32 +++++++++++++++++++++++++------- proxy/upstreams.go | 3 +++ upstream/bootstrap.go | 6 +++++- upstream/bootstrap_resolver.go | 4 +++- upstream/parallel.go | 2 +- upstream/upstream.go | 9 +++++++++ 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index 274550c1b..6d11c8f2e 100644 --- a/main.go +++ b/main.go @@ -169,6 +169,8 @@ var VersionString = "undefined" // nolint:gochecknoglobals const defaultTimeout = 10 * time.Second +var dohauth = false + // defaultDNS64Prefix is a so-called "Well-Known Prefix" for DNS64. // if dnsproxy operates as a DNS64 server, we'll be using it. const defaultDNS64Prefix = "64:ff9b::/96" @@ -273,6 +275,7 @@ func createProxyConfig(options *Options) proxy.Config { func initUpstreams(config *proxy.Config, options *Options) { // Init upstreams + log.Printf("dohauth : ", dohauth) upstreams := loadServersList(options.Upstreams) upstreamConfig, err := proxy.ParseUpstreamsConfig( upstreams, @@ -281,6 +284,7 @@ func initUpstreams(config *proxy.Config, options *Options) { Bootstrap: options.BootstrapDNS, Timeout: defaultTimeout, DoHClientTLSConfig: config.DoHClientTLSConfig, + DoHClient: dohauth, }) if err != nil { log.Fatalf("error while parsing upstreams configuration: %s", err) @@ -347,7 +351,7 @@ func initBogusNXDomain(config *proxy.Config, options *Options) { // initTLSConfig inits the TLS config func initTLSConfig(config *proxy.Config, options *Options) { if options.TLSCertPath != "" && options.TLSKeyPath != "" { - tlsConfig, err := newTLSConfig(options) + tlsConfig, err := newTLSConfig(options, false) if err != nil { log.Fatalf("failed to load TLS config: %s", err) } @@ -357,11 +361,16 @@ func initTLSConfig(config *proxy.Config, options *Options) { // initTLSConfig inits the DoH Client Auth TLS config func initDoHClientTLSConfig(config *proxy.Config, options *Options) { + log.Printf("Config certificates : ", options.TLSAuthCertPath) + log.Printf("Config certificates : ", options.TLSAuthKeyPath) + if options.TLSAuthCertPath != "" && options.TLSAuthKeyPath != "" { - tlsConfig, err := newTLSConfig(options) + tlsConfig, err := newTLSConfig(options, true) if err != nil { - log.Fatalf("failed to load DoH Client-auth TLS config: %s", err) + log.Fatalf("failed to load DDoH Client-auth TLS config: %s", err) } + dohauth = true + log.Printf("dohauth true") config.DoHClientTLSConfig = tlsConfig } } @@ -495,7 +504,7 @@ func (c *ipv6Configuration) handleDNSRequest(p *proxy.Proxy, ctx *proxy.DNSConte // NewTLSConfig returns a TLS config that includes a certificate // Use for server TLS config or when using a client certificate // If caPath is empty, system CAs will be used -func newTLSConfig(options *Options) (*tls.Config, error) { +func newTLSConfig(options *Options, auth bool) (*tls.Config, error) { // Set default TLS min/max versions tlsMinVersion := tls.VersionTLS10 // Default for crypto/tls tlsMaxVersion := tls.VersionTLS13 // Default for crypto/tls @@ -516,9 +525,18 @@ func newTLSConfig(options *Options) (*tls.Config, error) { tlsMaxVersion = tls.VersionTLS12 } - cert, err := loadX509KeyPair(options.TLSCertPath, options.TLSKeyPath) - if err != nil { - return nil, fmt.Errorf("could not load TLS cert: %s", err) + cert, err := loadX509KeyPair("", "") + + if auth { + cert, err = loadX509KeyPair(options.TLSAuthCertPath, options.TLSAuthKeyPath) + if err != nil { + return nil, fmt.Errorf("could not load TLS cert for DoH auth: %s", err) + } + } else { + cert, err = loadX509KeyPair(options.TLSCertPath, options.TLSKeyPath) + if err != nil { + return nil, fmt.Errorf("could not load TLS cert for TLS server: %s", err) + } } return &tls.Config{Certificates: []tls.Certificate{cert}, MinVersion: uint16(tlsMinVersion), MaxVersion: uint16(tlsMaxVersion)}, nil diff --git a/proxy/upstreams.go b/proxy/upstreams.go index 8c96c4313..d628b33c5 100644 --- a/proxy/upstreams.go +++ b/proxy/upstreams.go @@ -54,12 +54,15 @@ func ParseUpstreamsConfig(upstreamConfig []string, options *upstream.Options) (* dnsUpstream, ok := upstreamsIndex[u] if !ok { // create an upstream + log.Printf("DoHClient :", options.DoHClient) dnsUpstream, err = upstream.AddressToUpstream( u, &upstream.Options{ Bootstrap: options.Bootstrap, Timeout: options.Timeout, InsecureSkipVerify: options.InsecureSkipVerify, + DoHClientTLSConfig: options.DoHClientTLSConfig.Clone(), //TODO Verify i we need an if + DoHClient: options.DoHClient, }) if err != nil { err = fmt.Errorf("cannot prepare the upstream %s (%s): %s", l, options.Bootstrap, err) diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index 23af9f2ee..d80707744 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -68,7 +68,6 @@ func newBootstrapperResolved(upsURL *url.URL, options *Options) (*bootstrapper, } b.dialContext = b.createDialContext(resolverAddresses) b.resolvedConfig = b.createTLSConfig(host) - return b, nil } @@ -77,6 +76,8 @@ func newBootstrapperResolved(upsURL *url.URL, options *Options) (*bootstrapper, // options -- Upstream customization options func newBootstrapper(address *url.URL, options *Options) (*bootstrapper, error) { resolvers := []*Resolver{} + log.Printf("dohauth ??") + log.Printf("url ??", address) if len(options.Bootstrap) != 0 { // Create a list of resolvers for parallel lookup for _, boot := range options.Bootstrap { @@ -180,12 +181,15 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { n.dialContext = n.createDialContext(resolved) n.resolvedConfig = n.createTLSConfig(host) + log.Printf("are we here get?") + log.Printf("are we here get?", addr) return n.resolvedConfig, n.dialContext, nil } // createTLSConfig creates a client TLS config func (n *bootstrapper) createTLSConfig(host string) *tls.Config { + log.Printf("are we here create ?") //caCert, err := ioutil.ReadFile("/home/marino/certificates/root/ca-full.cert.pem") //if err != nil { // log.Println("could not load TLS cert: %s", err) diff --git a/upstream/bootstrap_resolver.go b/upstream/bootstrap_resolver.go index db205e265..17110d639 100644 --- a/upstream/bootstrap_resolver.go +++ b/upstream/bootstrap_resolver.go @@ -26,7 +26,7 @@ type Resolver struct { // options. func NewResolver(resolverAddress string, options *Options) (*Resolver, error) { r := &Resolver{} - + log.Printf("dohauth new resolver??") // set default net.Resolver as a resolver if resolverAddress is empty if resolverAddress == "" { r.resolver = &net.Resolver{} @@ -122,6 +122,7 @@ type resultError struct { } func (r *Resolver) resolve(host string, qtype uint16, ch chan *resultError) { + req := dns.Msg{} req.Id = dns.Id() req.RecursionDesired = true @@ -138,6 +139,7 @@ func (r *Resolver) resolve(host string, qtype uint16, ch chan *resultError) { // LookupIPAddr returns result of LookupIPAddr method of Resolver's net.Resolver func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) { + log.Printf("pass par la?") if r.resolver != nil { // use system resolver addrs, err := r.resolver.LookupIPAddr(ctx, host) diff --git a/upstream/parallel.go b/upstream/parallel.go index 561016148..d800ccf3a 100644 --- a/upstream/parallel.go +++ b/upstream/parallel.go @@ -157,7 +157,7 @@ type lookupResult struct { // Return nil and error if count of errors equals count of resolvers func LookupParallel(ctx context.Context, resolvers []*Resolver, host string) ([]net.IPAddr, error) { size := len(resolvers) - + log.Printf("passe par la??") if size == 0 { return nil, errors.Error("no resolvers specified") } diff --git a/upstream/upstream.go b/upstream/upstream.go index cae547b3a..cb9e560e7 100644 --- a/upstream/upstream.go +++ b/upstream/upstream.go @@ -49,6 +49,8 @@ type Options struct { VerifyDNSCryptCertificate func(cert *dnscrypt.Cert) error DoHClientTLSConfig *tls.Config // TLS config when DoH Client Authentication is used + + DoHClient bool } // Parse "host:port" string and validate port number @@ -75,11 +77,13 @@ func parseHostAndPort(addr string) (string, string, error) { // * sdns://... -- DNS stamp (see https://dnscrypt.info/stamps-specifications) // options -- Upstream customization options, nil means default options. func AddressToUpstream(address string, options *Options) (Upstream, error) { + if options == nil { options = &Options{} } if strings.Contains(address, "://") { + upstreamURL, err := url.Parse(address) if err != nil { return nil, errorx.Decorate(err, "failed to parse %s", address) @@ -154,6 +158,11 @@ func urlToUpstream(upstreamURL *url.URL, opts *Options) (Upstream, error) { upstreamURL.Host += ":443" } + log.Printf("Upstream URL : ", upstreamURL.Host) + log.Printf("dohclient") + + //log.Printf("Certificates : ", opts.DoHClientTLSConfig.Certificates) + b, err := urlToBoot(upstreamURL, opts) if err != nil { return nil, errorx.Decorate(err, "couldn't create tls bootstrapper") From 3c20fc3be8c6f1d784703587174d14184c626c37 Mon Sep 17 00:00:00 2001 From: IvanMtz Date: Thu, 9 Sep 2021 23:05:48 +0200 Subject: [PATCH 03/13] finding get() --- upstream/bootstrap.go | 11 ++++++----- upstream/bootstrap_resolver.go | 2 +- upstream/parallel.go | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index d80707744..b1a300bc2 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -51,6 +51,7 @@ type bootstrapper struct { // options -- Upstream customization options func newBootstrapperResolved(upsURL *url.URL, options *Options) (*bootstrapper, error) { // get a host without port + log.Printf("pass par la newBootstrapper ??") host, port, err := net.SplitHostPort(upsURL.Host) if err != nil { return nil, fmt.Errorf("bootstrapper requires port in address %s", upsURL.String()) @@ -135,6 +136,7 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { defer n.Unlock() n.dialContext = n.createDialContext([]string{resolverAddress}) + log.Printf("pass par la : get:bootstrap.go, call createTLSConfig") n.resolvedConfig = n.createTLSConfig(host) return n.resolvedConfig, n.dialContext, nil } @@ -156,7 +158,7 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { } else { ctx = context.Background() } - + log.Printf("pass par la : get:bootstrap.go, Lookupparallel") addrs, err := LookupParallel(ctx, n.resolvers, host) if err != nil { return nil, nil, errorx.Decorate(err, "failed to lookup %s", host) @@ -180,16 +182,15 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { defer n.Unlock() n.dialContext = n.createDialContext(resolved) + log.Printf("pass par la : get:bootstrap.go, createTLSConfig") n.resolvedConfig = n.createTLSConfig(host) - log.Printf("are we here get?") - log.Printf("are we here get?", addr) return n.resolvedConfig, n.dialContext, nil } // createTLSConfig creates a client TLS config func (n *bootstrapper) createTLSConfig(host string) *tls.Config { - log.Printf("are we here create ?") + log.Printf("pass par la : createTLSConfig:bootstrap.go") //caCert, err := ioutil.ReadFile("/home/marino/certificates/root/ca-full.cert.pem") //if err != nil { // log.Println("could not load TLS cert: %s", err) @@ -198,7 +199,7 @@ func (n *bootstrapper) createTLSConfig(host string) *tls.Config { //caCertPool := x509.NewCertPool() //caCertPool.AppendCertsFromPEM(caCert) - cert, err := tls.LoadX509KeyPair("/home/ivan/certs/root/ca/intermediate/certs/dohclient.cert.pem", "/home/ivan/certs/root/ca/intermediate/private/dohclient.key.pem") + cert, err := tls.LoadX509KeyPair("/home/marino/certificates/root/ca/intermediate/certs/dohclient.cert.pem", "/home/marino/certificates/root/ca/intermediate/private/dohclient.key.pem") if err != nil { log.Println("could not load TLS cert: %s", err) } diff --git a/upstream/bootstrap_resolver.go b/upstream/bootstrap_resolver.go index 17110d639..320107fdb 100644 --- a/upstream/bootstrap_resolver.go +++ b/upstream/bootstrap_resolver.go @@ -139,7 +139,7 @@ func (r *Resolver) resolve(host string, qtype uint16, ch chan *resultError) { // LookupIPAddr returns result of LookupIPAddr method of Resolver's net.Resolver func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) { - log.Printf("pass par la?") + log.Printf("pass par la : LookupIPAddr:bootstrap_resolver.go") if r.resolver != nil { // use system resolver addrs, err := r.resolver.LookupIPAddr(ctx, host) diff --git a/upstream/parallel.go b/upstream/parallel.go index d800ccf3a..5673b6f5a 100644 --- a/upstream/parallel.go +++ b/upstream/parallel.go @@ -156,8 +156,8 @@ type lookupResult struct { // First answer without error will be returned // Return nil and error if count of errors equals count of resolvers func LookupParallel(ctx context.Context, resolvers []*Resolver, host string) ([]net.IPAddr, error) { + log.Printf("pass par la : lookupParallel:parallel.go") size := len(resolvers) - log.Printf("passe par la??") if size == 0 { return nil, errors.Error("no resolvers specified") } @@ -205,6 +205,7 @@ func lookupAsync(ctx context.Context, r *Resolver, host string, res chan *lookup } func lookup(ctx context.Context, r *Resolver, host string) ([]net.IPAddr, error) { + log.Printf("pass par la : lookup:parallel.go") start := time.Now() address, err := r.LookupIPAddr(ctx, host) elapsed := time.Since(start) From fd7147e0e09a593eff2530b6ba041e8c3691b643 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Mon, 13 Sep 2021 13:33:51 +0200 Subject: [PATCH 04/13] adding certificate configuration at bootstrap.go for DoH with client auth --- upstream/bootstrap.go | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index b1a300bc2..cf9cc7762 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -136,7 +136,8 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { defer n.Unlock() n.dialContext = n.createDialContext([]string{resolverAddress}) - log.Printf("pass par la : get:bootstrap.go, call createTLSConfig") + log.Printf("pass par la : get:bootstrap.go, DoH client bool", n.options.DoHClient) + n.resolvedConfig = n.createTLSConfig(host) return n.resolvedConfig, n.dialContext, nil } @@ -182,39 +183,30 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { defer n.Unlock() n.dialContext = n.createDialContext(resolved) - log.Printf("pass par la : get:bootstrap.go, createTLSConfig") - n.resolvedConfig = n.createTLSConfig(host) + + if n.options.DoHClient { + n.resolvedConfig = n.loadTLSConfig(host) + log.Printf("Loading the TLS Configuration for DoH client authentication") + } else { + n.resolvedConfig = n.createTLSConfig(host) + log.Printf("Creating a new TLS configuration without client authentication / Classical DoH") + } return n.resolvedConfig, n.dialContext, nil } // createTLSConfig creates a client TLS config func (n *bootstrapper) createTLSConfig(host string) *tls.Config { - log.Printf("pass par la : createTLSConfig:bootstrap.go") - //caCert, err := ioutil.ReadFile("/home/marino/certificates/root/ca-full.cert.pem") - //if err != nil { - // log.Println("could not load TLS cert: %s", err) - //} - - //caCertPool := x509.NewCertPool() - //caCertPool.AppendCertsFromPEM(caCert) - - cert, err := tls.LoadX509KeyPair("/home/marino/certificates/root/ca/intermediate/certs/dohclient.cert.pem", "/home/marino/certificates/root/ca/intermediate/private/dohclient.key.pem") - if err != nil { - log.Println("could not load TLS cert: %s", err) - } tlsConfig := &tls.Config{ ServerName: host, RootCAs: RootCAs, - Certificates: []tls.Certificate{cert}, CipherSuites: CipherSuites, MinVersion: tls.VersionTLS12, InsecureSkipVerify: n.options.InsecureSkipVerify, VerifyPeerCertificate: n.options.VerifyServerCertificate, } - //TLSConfig := p.DoHClientTLSConfig.Clone() // The supported application level protocols should be specified only // for DNS-over-HTTPS and DNS-over-QUIC connections. // @@ -228,6 +220,20 @@ func (n *bootstrapper) createTLSConfig(host string) *tls.Config { return tlsConfig } +func (n *bootstrapper) loadTLSConfig(host string) *tls.Config { + + tlsConfig := &tls.Config{ + ServerName: host, + Certificates: n.options.DoHClientTLSConfig.Clone().Certificates, + RootCAs: RootCAs, + CipherSuites: CipherSuites, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: n.options.InsecureSkipVerify, + VerifyPeerCertificate: n.options.VerifyServerCertificate, + } + return tlsConfig +} + // createDialContext returns dialContext function that tries to establish connection with all given addresses one by one func (n *bootstrapper) createDialContext(addresses []string) (dialContext dialHandler) { dialer := &net.Dialer{ From 4035dd82eb480b852f3849ee1db1bb3ba495167b Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Mon, 13 Sep 2021 16:02:12 +0200 Subject: [PATCH 05/13] changing readme --- README.md | 7 +++++++ main.go | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 99cc0a27d..f77bb9c92 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ Application Options: --udp-buf-size= Set the size of the UDP buffer in bytes. A value <= 0 will use the system default. (default: 0) --max-go-routines= Set the maximum number of go routines. A value <= 0 will not not set a maximum. (default: 0) --version Prints the program version + --a-tls-crt= Path to the file to the tls certificate used to DoH Client when client-authentication is enabled + --a-tls-key= Path to the file to the tls key used to DoH Client when client-authentication is enabled Help Options: -h, --help Show this help message @@ -115,6 +117,11 @@ DNS-over-TLS upstream: DNS-over-HTTPS upstream with specified bootstrap DNS: ```shell +./dnsproxy -l 127.0.0.1 -u https://dns.plido.net/dns-query --a-tls-crt=/home/.../dohclient.cert.pem --a-tls-key=/home/.../dohclient.key.pem -b 1.1.1.1:53 +``` + +DNS-over-HTTPS upstream with specified bootstrap DNS and Client authentication: +```shell ./dnsproxy -u https://dns.adguard.com/dns-query -b 1.1.1.1:53 ``` diff --git a/main.go b/main.go index 6d11c8f2e..2db3126c5 100644 --- a/main.go +++ b/main.go @@ -76,7 +76,6 @@ type Options struct { // -- // DoH Upstream Authentication - ClientAuth bool `short:"a" long:"auth" description:"Enable DoH Client authentication" optional:"yes" optional-value:"false"` // Path to the .crt with the clien-side certificate for upstream client authentication TLSAuthCertPath string `long:"a-tls-crt" description:"Path to a file with the client certificate"` From d681a1c255d27c0aae9c3037b3c68e6abc47eb59 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Mon, 13 Sep 2021 16:04:50 +0200 Subject: [PATCH 06/13] editing README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f77bb9c92..6a74f95dc 100644 --- a/README.md +++ b/README.md @@ -115,14 +115,14 @@ DNS-over-TLS upstream: ./dnsproxy -u tls://dns.adguard.com ``` -DNS-over-HTTPS upstream with specified bootstrap DNS: +DNS-over-HTTPS upstream with specified bootstrap DNS and Client authentication: ```shell -./dnsproxy -l 127.0.0.1 -u https://dns.plido.net/dns-query --a-tls-crt=/home/.../dohclient.cert.pem --a-tls-key=/home/.../dohclient.key.pem -b 1.1.1.1:53 +./dnsproxy -u https://dns.adguard.com/dns-query -b 1.1.1.1:53 ``` -DNS-over-HTTPS upstream with specified bootstrap DNS and Client authentication: +DNS-over-HTTPS upstream with specified bootstrap DNS: ```shell -./dnsproxy -u https://dns.adguard.com/dns-query -b 1.1.1.1:53 +./dnsproxy -l 127.0.0.1 -u https://dns.plido.net/dns-query --a-tls-crt=/home/.../dohclient.cert.pem --a-tls-key=/home/.../dohclient.key.pem -b 1.1.1.1:53 ``` DNS-over-QUIC upstream: From ead3a69c558754ab2b0d04e887e529e31de3f240 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Mon, 13 Sep 2021 16:06:27 +0200 Subject: [PATCH 07/13] aditing readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a74f95dc..37c14e049 100644 --- a/README.md +++ b/README.md @@ -115,12 +115,12 @@ DNS-over-TLS upstream: ./dnsproxy -u tls://dns.adguard.com ``` -DNS-over-HTTPS upstream with specified bootstrap DNS and Client authentication: +DNS-over-HTTPS upstream with specified bootstrap DNS: ```shell ./dnsproxy -u https://dns.adguard.com/dns-query -b 1.1.1.1:53 ``` -DNS-over-HTTPS upstream with specified bootstrap DNS: +DNS-over-HTTPS upstream with specified bootstrap DNS and Client authentication: ```shell ./dnsproxy -l 127.0.0.1 -u https://dns.plido.net/dns-query --a-tls-crt=/home/.../dohclient.cert.pem --a-tls-key=/home/.../dohclient.key.pem -b 1.1.1.1:53 ``` From 1eb329237f4c20eaaf28f1a659ef89bf1c9ac4c6 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Tue, 5 Oct 2021 13:04:32 +0200 Subject: [PATCH 08/13] Addig support to TLS client authentication --- .gitignore | 4 +++- README.md | 5 +++-- main.go | 32 +++++++++++++------------------- proxy/config.go | 6 ++---- proxy/upstreams.go | 5 ++--- upstream/bootstrap.go | 24 ++++++++---------------- upstream/bootstrap_resolver.go | 2 -- upstream/parallel.go | 2 -- upstream/upstream.go | 9 ++------- 9 files changed, 33 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index 7ab789568..7c8ae4395 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ dnsproxy dnsproxy.exe example.crt example.key -coverage.txt \ No newline at end of file +coverage.txt +client.crt +client.key diff --git a/README.md b/README.md index 37c14e049..5ddca1509 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A simple DNS proxy server that supports all existing DNS protocols including `DNS-over-TLS`, `DNS-over-HTTPS`, `DNSCrypt`, and `DNS-over-QUIC`. Moreover, it can work as a `DNS-over-HTTPS`, `DNS-over-TLS` or `DNS-over-QUIC` server. > Note that `DNS-over-QUIC` support is experimental, don't use it in production. +> Note that `DoH/DoT/DoQ` client authentication support is experimental, only DoH authentication has been tested - [How to build](#how-to-build) - [Usage](#usage) @@ -77,8 +78,8 @@ Application Options: --udp-buf-size= Set the size of the UDP buffer in bytes. A value <= 0 will use the system default. (default: 0) --max-go-routines= Set the maximum number of go routines. A value <= 0 will not not set a maximum. (default: 0) --version Prints the program version - --a-tls-crt= Path to the file to the tls certificate used to DoH Client when client-authentication is enabled - --a-tls-key= Path to the file to the tls key used to DoH Client when client-authentication is enabled + --a-tls-crt= Path to the file to the tls certificate used to DoH/DoT/DoQ Client when client-authentication is enabled + --a-tls-key= Path to the file to the tls key used to DoH/DoT/DoQ Client when client-authentication is enabled Help Options: -h, --help Show this help message diff --git a/main.go b/main.go index 2db3126c5..17c142480 100644 --- a/main.go +++ b/main.go @@ -168,7 +168,7 @@ var VersionString = "undefined" // nolint:gochecknoglobals const defaultTimeout = 10 * time.Second -var dohauth = false +var tlsclient = false // defaultDNS64Prefix is a so-called "Well-Known Prefix" for DNS64. // if dnsproxy operates as a DNS64 server, we'll be using it. @@ -259,7 +259,7 @@ func createProxyConfig(options *Options) proxy.Config { MaxGoroutines: options.MaxGoRoutines, } - initDoHClientTLSConfig(&config, options) + initClientTLSConfig(&config, options) initUpstreams(&config, options) initEDNS(&config, options) initBogusNXDomain(&config, options) @@ -273,8 +273,6 @@ func createProxyConfig(options *Options) proxy.Config { // initUpstreams inits upstream-related config func initUpstreams(config *proxy.Config, options *Options) { // Init upstreams - - log.Printf("dohauth : ", dohauth) upstreams := loadServersList(options.Upstreams) upstreamConfig, err := proxy.ParseUpstreamsConfig( upstreams, @@ -282,8 +280,8 @@ func initUpstreams(config *proxy.Config, options *Options) { InsecureSkipVerify: options.Insecure, Bootstrap: options.BootstrapDNS, Timeout: defaultTimeout, - DoHClientTLSConfig: config.DoHClientTLSConfig, - DoHClient: dohauth, + TLSClientConfig: config.TLSClientConfig, + TLSClient: tlsclient, }) if err != nil { log.Fatalf("error while parsing upstreams configuration: %s", err) @@ -350,7 +348,7 @@ func initBogusNXDomain(config *proxy.Config, options *Options) { // initTLSConfig inits the TLS config func initTLSConfig(config *proxy.Config, options *Options) { if options.TLSCertPath != "" && options.TLSKeyPath != "" { - tlsConfig, err := newTLSConfig(options, false) + tlsConfig, err := newTLSConfig(options) if err != nil { log.Fatalf("failed to load TLS config: %s", err) } @@ -359,18 +357,14 @@ func initTLSConfig(config *proxy.Config, options *Options) { } // initTLSConfig inits the DoH Client Auth TLS config -func initDoHClientTLSConfig(config *proxy.Config, options *Options) { - log.Printf("Config certificates : ", options.TLSAuthCertPath) - log.Printf("Config certificates : ", options.TLSAuthKeyPath) - +func initClientTLSConfig(config *proxy.Config, options *Options) { if options.TLSAuthCertPath != "" && options.TLSAuthKeyPath != "" { - tlsConfig, err := newTLSConfig(options, true) + tlsConfig, err := newTLSConfig(options) if err != nil { - log.Fatalf("failed to load DDoH Client-auth TLS config: %s", err) + log.Fatalf("failed to load Client-auth TLS config: %s", err) } - dohauth = true - log.Printf("dohauth true") - config.DoHClientTLSConfig = tlsConfig + tlsclient = true + config.TLSClientConfig = tlsConfig } } @@ -503,7 +497,7 @@ func (c *ipv6Configuration) handleDNSRequest(p *proxy.Proxy, ctx *proxy.DNSConte // NewTLSConfig returns a TLS config that includes a certificate // Use for server TLS config or when using a client certificate // If caPath is empty, system CAs will be used -func newTLSConfig(options *Options, auth bool) (*tls.Config, error) { +func newTLSConfig(options *Options) (*tls.Config, error) { // Set default TLS min/max versions tlsMinVersion := tls.VersionTLS10 // Default for crypto/tls tlsMaxVersion := tls.VersionTLS13 // Default for crypto/tls @@ -526,10 +520,10 @@ func newTLSConfig(options *Options, auth bool) (*tls.Config, error) { cert, err := loadX509KeyPair("", "") - if auth { + if options.TLSAuthCertPath != "" { cert, err = loadX509KeyPair(options.TLSAuthCertPath, options.TLSAuthKeyPath) if err != nil { - return nil, fmt.Errorf("could not load TLS cert for DoH auth: %s", err) + return nil, fmt.Errorf("could not load TLS cert for TLS client authentication: %s", err) } } else { cert, err = loadX509KeyPair(options.TLSCertPath, options.TLSKeyPath) diff --git a/proxy/config.go b/proxy/config.go index 7e6dc0ffb..0fc1cb424 100644 --- a/proxy/config.go +++ b/proxy/config.go @@ -53,10 +53,8 @@ type Config struct { // Encryption configuration // -- - TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC - - DoHClientTLSConfig *tls.Config // necessary for DoH Client Authentication - + TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC + TLSClientConfig *tls.Config // necessary for DoH/DoT/DoQ Client Authentication DNSCryptProviderName string // DNSCrypt provider name DNSCryptResolverCert *dnscrypt.Cert // DNSCrypt resolver certificate diff --git a/proxy/upstreams.go b/proxy/upstreams.go index d628b33c5..2159916e4 100644 --- a/proxy/upstreams.go +++ b/proxy/upstreams.go @@ -54,15 +54,14 @@ func ParseUpstreamsConfig(upstreamConfig []string, options *upstream.Options) (* dnsUpstream, ok := upstreamsIndex[u] if !ok { // create an upstream - log.Printf("DoHClient :", options.DoHClient) dnsUpstream, err = upstream.AddressToUpstream( u, &upstream.Options{ Bootstrap: options.Bootstrap, Timeout: options.Timeout, InsecureSkipVerify: options.InsecureSkipVerify, - DoHClientTLSConfig: options.DoHClientTLSConfig.Clone(), //TODO Verify i we need an if - DoHClient: options.DoHClient, + TLSClientConfig: options.TLSClientConfig.Clone(), //TODO Verify i we need an if + TLSClient: options.TLSClient, }) if err != nil { err = fmt.Errorf("cannot prepare the upstream %s (%s): %s", l, options.Bootstrap, err) diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index cf9cc7762..0a1807ed3 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -51,7 +51,6 @@ type bootstrapper struct { // options -- Upstream customization options func newBootstrapperResolved(upsURL *url.URL, options *Options) (*bootstrapper, error) { // get a host without port - log.Printf("pass par la newBootstrapper ??") host, port, err := net.SplitHostPort(upsURL.Host) if err != nil { return nil, fmt.Errorf("bootstrapper requires port in address %s", upsURL.String()) @@ -77,8 +76,6 @@ func newBootstrapperResolved(upsURL *url.URL, options *Options) (*bootstrapper, // options -- Upstream customization options func newBootstrapper(address *url.URL, options *Options) (*bootstrapper, error) { resolvers := []*Resolver{} - log.Printf("dohauth ??") - log.Printf("url ??", address) if len(options.Bootstrap) != 0 { // Create a list of resolvers for parallel lookup for _, boot := range options.Bootstrap { @@ -136,8 +133,6 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { defer n.Unlock() n.dialContext = n.createDialContext([]string{resolverAddress}) - log.Printf("pass par la : get:bootstrap.go, DoH client bool", n.options.DoHClient) - n.resolvedConfig = n.createTLSConfig(host) return n.resolvedConfig, n.dialContext, nil } @@ -159,7 +154,6 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { } else { ctx = context.Background() } - log.Printf("pass par la : get:bootstrap.go, Lookupparallel") addrs, err := LookupParallel(ctx, n.resolvers, host) if err != nil { return nil, nil, errorx.Decorate(err, "failed to lookup %s", host) @@ -178,25 +172,17 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { // couldn't find any suitable IP address return nil, nil, fmt.Errorf("couldn't find any suitable IP address for host %s", host) } - n.Lock() defer n.Unlock() n.dialContext = n.createDialContext(resolved) + n.resolvedConfig = n.createTLSConfig(host) - if n.options.DoHClient { - n.resolvedConfig = n.loadTLSConfig(host) - log.Printf("Loading the TLS Configuration for DoH client authentication") - } else { - n.resolvedConfig = n.createTLSConfig(host) - log.Printf("Creating a new TLS configuration without client authentication / Classical DoH") - } return n.resolvedConfig, n.dialContext, nil } // createTLSConfig creates a client TLS config func (n *bootstrapper) createTLSConfig(host string) *tls.Config { - log.Printf("pass par la : createTLSConfig:bootstrap.go") tlsConfig := &tls.Config{ ServerName: host, @@ -207,6 +193,12 @@ func (n *bootstrapper) createTLSConfig(host string) *tls.Config { VerifyPeerCertificate: n.options.VerifyServerCertificate, } + if n.options.TLSClient { + log.Printf("Creating a new TLS configuration with client authentication") + tlsConfig = &tls.Config{ + Certificates: n.options.TLSClientConfig.Clone().Certificates, + } + } // The supported application level protocols should be specified only // for DNS-over-HTTPS and DNS-over-QUIC connections. // @@ -224,7 +216,7 @@ func (n *bootstrapper) loadTLSConfig(host string) *tls.Config { tlsConfig := &tls.Config{ ServerName: host, - Certificates: n.options.DoHClientTLSConfig.Clone().Certificates, + Certificates: n.options.TLSClientConfig.Clone().Certificates, RootCAs: RootCAs, CipherSuites: CipherSuites, MinVersion: tls.VersionTLS12, diff --git a/upstream/bootstrap_resolver.go b/upstream/bootstrap_resolver.go index 320107fdb..243831dc6 100644 --- a/upstream/bootstrap_resolver.go +++ b/upstream/bootstrap_resolver.go @@ -26,7 +26,6 @@ type Resolver struct { // options. func NewResolver(resolverAddress string, options *Options) (*Resolver, error) { r := &Resolver{} - log.Printf("dohauth new resolver??") // set default net.Resolver as a resolver if resolverAddress is empty if resolverAddress == "" { r.resolver = &net.Resolver{} @@ -139,7 +138,6 @@ func (r *Resolver) resolve(host string, qtype uint16, ch chan *resultError) { // LookupIPAddr returns result of LookupIPAddr method of Resolver's net.Resolver func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) { - log.Printf("pass par la : LookupIPAddr:bootstrap_resolver.go") if r.resolver != nil { // use system resolver addrs, err := r.resolver.LookupIPAddr(ctx, host) diff --git a/upstream/parallel.go b/upstream/parallel.go index 5673b6f5a..0374b5605 100644 --- a/upstream/parallel.go +++ b/upstream/parallel.go @@ -156,7 +156,6 @@ type lookupResult struct { // First answer without error will be returned // Return nil and error if count of errors equals count of resolvers func LookupParallel(ctx context.Context, resolvers []*Resolver, host string) ([]net.IPAddr, error) { - log.Printf("pass par la : lookupParallel:parallel.go") size := len(resolvers) if size == 0 { return nil, errors.Error("no resolvers specified") @@ -205,7 +204,6 @@ func lookupAsync(ctx context.Context, r *Resolver, host string, res chan *lookup } func lookup(ctx context.Context, r *Resolver, host string) ([]net.IPAddr, error) { - log.Printf("pass par la : lookup:parallel.go") start := time.Now() address, err := r.LookupIPAddr(ctx, host) elapsed := time.Since(start) diff --git a/upstream/upstream.go b/upstream/upstream.go index cb9e560e7..cd7469271 100644 --- a/upstream/upstream.go +++ b/upstream/upstream.go @@ -48,9 +48,9 @@ type Options struct { // is called in dnsCrypt.exchangeDNSCrypt; if error != nil then Upstream.Exchange() will return it VerifyDNSCryptCertificate func(cert *dnscrypt.Cert) error - DoHClientTLSConfig *tls.Config // TLS config when DoH Client Authentication is used + TLSClientConfig *tls.Config // TLS config when DoH/DoT/DoQ Client Authentication is used - DoHClient bool + TLSClient bool // TLS client authentication flag when DoH/DoT/DoQ Client Authentication is used } // Parse "host:port" string and validate port number @@ -158,11 +158,6 @@ func urlToUpstream(upstreamURL *url.URL, opts *Options) (Upstream, error) { upstreamURL.Host += ":443" } - log.Printf("Upstream URL : ", upstreamURL.Host) - log.Printf("dohclient") - - //log.Printf("Certificates : ", opts.DoHClientTLSConfig.Certificates) - b, err := urlToBoot(upstreamURL, opts) if err != nil { return nil, errorx.Decorate(err, "couldn't create tls bootstrapper") From ef9166908473d647941c56c12046a6cf60a4f203 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Tue, 5 Oct 2021 13:38:41 +0200 Subject: [PATCH 09/13] deleating LoadTLS --- upstream/bootstrap.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index 0a1807ed3..eed8ff2b0 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -212,20 +212,6 @@ func (n *bootstrapper) createTLSConfig(host string) *tls.Config { return tlsConfig } -func (n *bootstrapper) loadTLSConfig(host string) *tls.Config { - - tlsConfig := &tls.Config{ - ServerName: host, - Certificates: n.options.TLSClientConfig.Clone().Certificates, - RootCAs: RootCAs, - CipherSuites: CipherSuites, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: n.options.InsecureSkipVerify, - VerifyPeerCertificate: n.options.VerifyServerCertificate, - } - return tlsConfig -} - // createDialContext returns dialContext function that tries to establish connection with all given addresses one by one func (n *bootstrapper) createDialContext(addresses []string) (dialContext dialHandler) { dialer := &net.Dialer{ From df8a8189f0272cba66ba4b53204adc769e16a0d9 Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Wed, 13 Oct 2021 18:44:53 +0200 Subject: [PATCH 10/13] Passing certs instead of a whole tlsconfig --- .gitignore | 2 + README.md | 90 ++++++++++++++++------------------ main.go | 39 +++++---------- proxy/config.go | 8 +-- proxy/upstreams.go | 9 ++-- upstream/bootstrap.go | 5 +- upstream/bootstrap_resolver.go | 2 +- upstream/upstream.go | 5 +- 8 files changed, 69 insertions(+), 91 deletions(-) diff --git a/.gitignore b/.gitignore index 7c8ae4395..a4f6cde86 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ example.key coverage.txt client.crt client.key +tlsclient.crt +tlsclient.key \ No newline at end of file diff --git a/README.md b/README.md index 5ddca1509..84926fe7e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ A simple DNS proxy server that supports all existing DNS protocols including `DNS-over-TLS`, `DNS-over-HTTPS`, `DNSCrypt`, and `DNS-over-QUIC`. Moreover, it can work as a `DNS-over-HTTPS`, `DNS-over-TLS` or `DNS-over-QUIC` server. > Note that `DNS-over-QUIC` support is experimental, don't use it in production. -> Note that `DoH/DoT/DoQ` client authentication support is experimental, only DoH authentication has been tested - [How to build](#how-to-build) - [Usage](#usage) @@ -38,51 +37,49 @@ Usage: dnsproxy [OPTIONS] Application Options: - -v, --verbose Verbose output (optional) - -o, --output= Path to the log file. If not set, write to stdout. - -l, --listen= Listening addresses (default: 0.0.0.0) - -p, --port= Listening ports. Zero value disables TCP and UDP listeners (default: 53) - -s, --https-port= Listening ports for DNS-over-HTTPS - -t, --tls-port= Listening ports for DNS-over-TLS - -q, --quic-port= Listening ports for DNS-over-QUIC - -y, --dnscrypt-port= Listening ports for DNSCrypt - -c, --tls-crt= Path to a file with the certificate chain - -k, --tls-key= Path to a file with the private key - --tls-min-version= Minimum TLS version, for example 1.0 - --tls-max-version= Maximum TLS version, for example 1.3 - --insecure Disable secure TLS certificate validation - -g, --dnscrypt-config= Path to a file with DNSCrypt configuration. You can generate one using - https://github.com/ameshkov/dnscrypt - -u, --upstream= An upstream to be used (can be specified multiple times). You can also specify path to a file with - the list of servers - -b, --bootstrap= Bootstrap DNS for DoH and DoT, can be specified multiple times (default: 8.8.8.8:53) - -f, --fallback= Fallback resolvers to use when regular ones are unavailable, can be specified multiple times. You can - also specify path to a file with the list of servers - --all-servers If specified, parallel queries to all configured upstream servers are enabled - --fastest-addr Respond to A or AAAA requests only with the fastest IP address - --cache If specified, DNS cache is enabled - --cache-size= Cache size (in bytes). Default: 64k - --cache-min-ttl= Minimum TTL value for DNS entries, in seconds. Capped at 3600. Artificially extending TTLs should - only be done with careful consideration. - --cache-max-ttl= Maximum TTL value for DNS entries, in seconds. - -r, --ratelimit= Ratelimit (requests per second) (default: 0) - --refuse-any If specified, refuse ANY requests - --edns Use EDNS Client Subnet extension - --edns-addr= Send EDNS Client Address - --dns64 If specified, dnsproxy will act as a DNS64 server - --dns64-prefix= If specified, this is the DNS64 prefix dnsproxy will be using when it works as a DNS64 server. If not - specified, dnsproxy uses the 'Well-Known Prefix' 64:ff9b:: - --ipv6-disabled If specified, all AAAA requests will be replied with NoError RCode and empty answer - --bogus-nxdomain= Transform responses that contain at least one of the given IP addresses into NXDOMAIN. Can be - specified multiple times. - --udp-buf-size= Set the size of the UDP buffer in bytes. A value <= 0 will use the system default. (default: 0) - --max-go-routines= Set the maximum number of go routines. A value <= 0 will not not set a maximum. (default: 0) - --version Prints the program version - --a-tls-crt= Path to the file to the tls certificate used to DoH/DoT/DoQ Client when client-authentication is enabled - --a-tls-key= Path to the file to the tls key used to DoH/DoT/DoQ Client when client-authentication is enabled + --config-path= yaml configuration file. Minimal working configuration in config.yaml.dist. Options passed through command line will override the + ones from this file. + -v, --verbose Verbose output (optional) + -o, --output= Path to the log file. If not set, write to stdout. + -l, --listen= Listening addresses + -p, --port= Listening ports. Zero value disables TCP and UDP listeners + -s, --https-port= Listening ports for DNS-over-HTTPS + -t, --tls-port= Listening ports for DNS-over-TLS + -q, --quic-port= Listening ports for DNS-over-QUIC + -y, --dnscrypt-port= Listening ports for DNSCrypt + -c, --tls-crt= Path to a file with the certificate chain + -k, --tls-key= Path to a file with the private key + --tls-min-version= Minimum TLS version, for example 1.0 + --tls-max-version= Maximum TLS version, for example 1.3 + --insecure Disable secure TLS certificate validation + -g, --dnscrypt-config= Path to a file with DNSCrypt configuration. You can generate one using https://github.com/ameshkov/dnscrypt + -u, --upstream= An upstream to be used (can be specified multiple times). You can also specify path to a file with the list of servers + -b, --bootstrap= Bootstrap DNS for DoH and DoT, can be specified multiple times (default: 8.8.8.8:53) + -f, --fallback= Fallback resolvers to use when regular ones are unavailable, can be specified multiple times. You can also specify path to a file + with the list of servers + --all-servers If specified, parallel queries to all configured upstream servers are enabled + --fastest-addr Respond to A or AAAA requests only with the fastest IP address + --cache If specified, DNS cache is enabled + --cache-size= Cache size (in bytes). Default: 64k + --cache-min-ttl= Minimum TTL value for DNS entries, in seconds. Capped at 3600. Artificially extending TTLs should only be done with careful + consideration. + --cache-max-ttl= Maximum TTL value for DNS entries, in seconds. + --cache-optimistic If specified, optimistic DNS cache is enabled + -r, --ratelimit= Ratelimit (requests per second) + --refuse-any If specified, refuse ANY requests + --edns Use EDNS Client Subnet extension + --edns-addr= Send EDNS Client Address + --dns64 If specified, dnsproxy will act as a DNS64 server + --dns64-prefix= If specified, this is the DNS64 prefix dnsproxy will be using when it works as a DNS64 server. If not specified, dnsproxy uses the + 'Well-Known Prefix' 64:ff9b:: + --ipv6-disabled If specified, all AAAA requests will be replied with NoError RCode and empty answer + --bogus-nxdomain= Transform responses that contain at least one of the given IP addresses into NXDOMAIN. Can be specified multiple times. + --udp-buf-size= Set the size of the UDP buffer in bytes. A value <= 0 will use the system default. + --max-go-routines= Set the maximum number of go routines. A value <= 0 will not not set a maximum. + --version Prints the program version Help Options: - -h, --help Show this help message + -h, --help Show this help message ``` ## Examples @@ -121,11 +118,6 @@ DNS-over-HTTPS upstream with specified bootstrap DNS: ./dnsproxy -u https://dns.adguard.com/dns-query -b 1.1.1.1:53 ``` -DNS-over-HTTPS upstream with specified bootstrap DNS and Client authentication: -```shell -./dnsproxy -l 127.0.0.1 -u https://dns.plido.net/dns-query --a-tls-crt=/home/.../dohclient.cert.pem --a-tls-key=/home/.../dohclient.key.pem -b 1.1.1.1:53 -``` - DNS-over-QUIC upstream: ```shell ./dnsproxy -u quic://dns.adguard.com diff --git a/main.go b/main.go index 17c142480..b542afec8 100644 --- a/main.go +++ b/main.go @@ -77,10 +77,10 @@ type Options struct { // DoH Upstream Authentication - // Path to the .crt with the clien-side certificate for upstream client authentication + // Path to the .crt with the client-side certificate for upstream client authentication TLSAuthCertPath string `long:"a-tls-crt" description:"Path to a file with the client certificate"` - // Path to the file with the clien-side private key for upstream client authentication + // Path to the file with the client-side private key for upstream client authentication TLSAuthKeyPath string `long:"a-tls-key" description:"Path to a file with the client private key"` // DNS upstreams @@ -168,8 +168,6 @@ var VersionString = "undefined" // nolint:gochecknoglobals const defaultTimeout = 10 * time.Second -var tlsclient = false - // defaultDNS64Prefix is a so-called "Well-Known Prefix" for DNS64. // if dnsproxy operates as a DNS64 server, we'll be using it. const defaultDNS64Prefix = "64:ff9b::/96" @@ -277,11 +275,10 @@ func initUpstreams(config *proxy.Config, options *Options) { upstreamConfig, err := proxy.ParseUpstreamsConfig( upstreams, &upstream.Options{ - InsecureSkipVerify: options.Insecure, - Bootstrap: options.BootstrapDNS, - Timeout: defaultTimeout, - TLSClientConfig: config.TLSClientConfig, - TLSClient: tlsclient, + InsecureSkipVerify: options.Insecure, + Bootstrap: options.BootstrapDNS, + Timeout: defaultTimeout, + TLSClientCertificates: config.TLSClientCertificates, }) if err != nil { log.Fatalf("error while parsing upstreams configuration: %s", err) @@ -359,12 +356,12 @@ func initTLSConfig(config *proxy.Config, options *Options) { // initTLSConfig inits the DoH Client Auth TLS config func initClientTLSConfig(config *proxy.Config, options *Options) { if options.TLSAuthCertPath != "" && options.TLSAuthKeyPath != "" { - tlsConfig, err := newTLSConfig(options) + cert, err := loadX509KeyPair(options.TLSAuthCertPath, options.TLSAuthKeyPath) if err != nil { - log.Fatalf("failed to load Client-auth TLS config: %s", err) + log.Fatalf("could not load TLS cert for TLS client authentication: %s", err) + return } - tlsclient = true - config.TLSClientConfig = tlsConfig + config.TLSClientCertificates = &cert } } @@ -518,20 +515,10 @@ func newTLSConfig(options *Options) (*tls.Config, error) { tlsMaxVersion = tls.VersionTLS12 } - cert, err := loadX509KeyPair("", "") - - if options.TLSAuthCertPath != "" { - cert, err = loadX509KeyPair(options.TLSAuthCertPath, options.TLSAuthKeyPath) - if err != nil { - return nil, fmt.Errorf("could not load TLS cert for TLS client authentication: %s", err) - } - } else { - cert, err = loadX509KeyPair(options.TLSCertPath, options.TLSKeyPath) - if err != nil { - return nil, fmt.Errorf("could not load TLS cert for TLS server: %s", err) - } + cert, err := loadX509KeyPair(options.TLSCertPath, options.TLSKeyPath) + if err != nil { + return nil, fmt.Errorf("could not load TLS cert for TLS server: %s", err) } - return &tls.Config{Certificates: []tls.Certificate{cert}, MinVersion: uint16(tlsMinVersion), MaxVersion: uint16(tlsMaxVersion)}, nil } diff --git a/proxy/config.go b/proxy/config.go index 0fc1cb424..26eff7d0e 100644 --- a/proxy/config.go +++ b/proxy/config.go @@ -53,10 +53,10 @@ type Config struct { // Encryption configuration // -- - TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC - TLSClientConfig *tls.Config // necessary for DoH/DoT/DoQ Client Authentication - DNSCryptProviderName string // DNSCrypt provider name - DNSCryptResolverCert *dnscrypt.Cert // DNSCrypt resolver certificate + TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC + TLSClientCertificates *tls.Certificate // necessary for DoH/DoT/DoQ Client Authentication + DNSCryptProviderName string // DNSCrypt provider name + DNSCryptResolverCert *dnscrypt.Cert // DNSCrypt resolver certificate // Rate-limiting and anti-DNS amplification measures // -- diff --git a/proxy/upstreams.go b/proxy/upstreams.go index 2159916e4..cf0f7f2b2 100644 --- a/proxy/upstreams.go +++ b/proxy/upstreams.go @@ -57,11 +57,10 @@ func ParseUpstreamsConfig(upstreamConfig []string, options *upstream.Options) (* dnsUpstream, err = upstream.AddressToUpstream( u, &upstream.Options{ - Bootstrap: options.Bootstrap, - Timeout: options.Timeout, - InsecureSkipVerify: options.InsecureSkipVerify, - TLSClientConfig: options.TLSClientConfig.Clone(), //TODO Verify i we need an if - TLSClient: options.TLSClient, + Bootstrap: options.Bootstrap, + Timeout: options.Timeout, + InsecureSkipVerify: options.InsecureSkipVerify, + TLSClientCertificates: options.TLSClientCertificates, }) if err != nil { err = fmt.Errorf("cannot prepare the upstream %s (%s): %s", l, options.Bootstrap, err) diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index eed8ff2b0..892acad93 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -193,12 +193,13 @@ func (n *bootstrapper) createTLSConfig(host string) *tls.Config { VerifyPeerCertificate: n.options.VerifyServerCertificate, } - if n.options.TLSClient { + if n.options.TLSClientCertificates != nil { log.Printf("Creating a new TLS configuration with client authentication") tlsConfig = &tls.Config{ - Certificates: n.options.TLSClientConfig.Clone().Certificates, + Certificates: []tls.Certificate{*n.options.TLSClientCertificates}, } } + // The supported application level protocols should be specified only // for DNS-over-HTTPS and DNS-over-QUIC connections. // diff --git a/upstream/bootstrap_resolver.go b/upstream/bootstrap_resolver.go index 243831dc6..db205e265 100644 --- a/upstream/bootstrap_resolver.go +++ b/upstream/bootstrap_resolver.go @@ -26,6 +26,7 @@ type Resolver struct { // options. func NewResolver(resolverAddress string, options *Options) (*Resolver, error) { r := &Resolver{} + // set default net.Resolver as a resolver if resolverAddress is empty if resolverAddress == "" { r.resolver = &net.Resolver{} @@ -121,7 +122,6 @@ type resultError struct { } func (r *Resolver) resolve(host string, qtype uint16, ch chan *resultError) { - req := dns.Msg{} req.Id = dns.Id() req.RecursionDesired = true diff --git a/upstream/upstream.go b/upstream/upstream.go index cd7469271..dc4316941 100644 --- a/upstream/upstream.go +++ b/upstream/upstream.go @@ -48,9 +48,7 @@ type Options struct { // is called in dnsCrypt.exchangeDNSCrypt; if error != nil then Upstream.Exchange() will return it VerifyDNSCryptCertificate func(cert *dnscrypt.Cert) error - TLSClientConfig *tls.Config // TLS config when DoH/DoT/DoQ Client Authentication is used - - TLSClient bool // TLS client authentication flag when DoH/DoT/DoQ Client Authentication is used + TLSClientCertificates *tls.Certificate // TLS certificates when DoH/DoT/DoQ Client Authentication is used } // Parse "host:port" string and validate port number @@ -77,7 +75,6 @@ func parseHostAndPort(addr string) (string, string, error) { // * sdns://... -- DNS stamp (see https://dnscrypt.info/stamps-specifications) // options -- Upstream customization options, nil means default options. func AddressToUpstream(address string, options *Options) (Upstream, error) { - if options == nil { options = &Options{} } From 5b507be240c0258141d59e032296dda6dab62c3b Mon Sep 17 00:00:00 2001 From: IvanMtz Date: Thu, 14 Oct 2021 10:04:03 +0200 Subject: [PATCH 11/13] changing variables name for consistency --- README.md | 2 ++ main.go | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 84926fe7e..8dac149a0 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ Application Options: --bogus-nxdomain= Transform responses that contain at least one of the given IP addresses into NXDOMAIN. Can be specified multiple times. --udp-buf-size= Set the size of the UDP buffer in bytes. A value <= 0 will use the system default. --max-go-routines= Set the maximum number of go routines. A value <= 0 will not not set a maximum. + --tls-client-crt= Path to the file with the TLS certificate used for TLS client authentication (supported by DoH/DoT/DoQ) + --tls-client-key= Path to the file with the TLS certificate used for TLS client authentication (supported by DoH/DoT/DoQ) --version Prints the program version Help Options: diff --git a/main.go b/main.go index b542afec8..c6fac1f08 100644 --- a/main.go +++ b/main.go @@ -78,10 +78,10 @@ type Options struct { // DoH Upstream Authentication // Path to the .crt with the client-side certificate for upstream client authentication - TLSAuthCertPath string `long:"a-tls-crt" description:"Path to a file with the client certificate"` + TLSClientCertPath string `long:"tls-client-crt" description:"Path to the file with the TLS certificate used for TLS client authentication (supported by DoH/DoT/DoQ)"` // Path to the file with the client-side private key for upstream client authentication - TLSAuthKeyPath string `long:"a-tls-key" description:"Path to a file with the client private key"` + TLSClientKeyPath string `long:"tls-client-key" description:"Path to the file with the TLS certificate used for TLS client authentication (supported by DoH/DoT/DoQ)"` // DNS upstreams Upstreams []string `short:"u" long:"upstream" description:"An upstream to be used (can be specified multiple times). You can also specify path to a file with the list of servers" required:"true"` @@ -257,7 +257,7 @@ func createProxyConfig(options *Options) proxy.Config { MaxGoroutines: options.MaxGoRoutines, } - initClientTLSConfig(&config, options) + initTLSClient(&config, options) initUpstreams(&config, options) initEDNS(&config, options) initBogusNXDomain(&config, options) @@ -354,9 +354,9 @@ func initTLSConfig(config *proxy.Config, options *Options) { } // initTLSConfig inits the DoH Client Auth TLS config -func initClientTLSConfig(config *proxy.Config, options *Options) { - if options.TLSAuthCertPath != "" && options.TLSAuthKeyPath != "" { - cert, err := loadX509KeyPair(options.TLSAuthCertPath, options.TLSAuthKeyPath) +func initTLSClient(config *proxy.Config, options *Options) { + if options.TLSClientCertPath != "" && options.TLSClientKeyPath != "" { + cert, err := loadX509KeyPair(options.TLSClientCertPath, options.TLSClientKeyPath) if err != nil { log.Fatalf("could not load TLS cert for TLS client authentication: %s", err) return From f6bdc467b78b91e98cd417b3f098ec9988f62fa3 Mon Sep 17 00:00:00 2001 From: IvanMtz Date: Thu, 14 Oct 2021 11:13:31 +0200 Subject: [PATCH 12/13] updating bootstrap --- upstream/bootstrap.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index 892acad93..d89c4911c 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -183,7 +183,6 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) { // createTLSConfig creates a client TLS config func (n *bootstrapper) createTLSConfig(host string) *tls.Config { - tlsConfig := &tls.Config{ ServerName: host, RootCAs: RootCAs, @@ -194,7 +193,7 @@ func (n *bootstrapper) createTLSConfig(host string) *tls.Config { } if n.options.TLSClientCertificates != nil { - log.Printf("Creating a new TLS configuration with client authentication") + log.Printf("Passing TLS configuration with client authentication") tlsConfig = &tls.Config{ Certificates: []tls.Certificate{*n.options.TLSClientCertificates}, } From 2fef216fec40a5bca46a2a14f3e04c81c4ef4d8c Mon Sep 17 00:00:00 2001 From: MarinoMtz Date: Mon, 15 Nov 2021 17:54:12 +0100 Subject: [PATCH 13/13] Merge with last TLS changes for Client Auth --- main.go | 17 +++++++---------- upstream/bootstrap.go | 7 +++---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/main.go b/main.go index 0506712fa..575113f93 100644 --- a/main.go +++ b/main.go @@ -297,18 +297,16 @@ func createProxyConfig(options *Options) proxy.Config { return config } -// initUpstreams inits upstream-related config func initUpstreams(config *proxy.Config, options *Options) { // Init upstreams upstreams := loadServersList(options.Upstreams) - upstreamConfig, err := proxy.ParseUpstreamsConfig( - upstreams, - &upstream.Options{ - InsecureSkipVerify: options.Insecure, - Bootstrap: options.BootstrapDNS, - Timeout: defaultTimeout, - TLSClientCertificates: config.TLSClientCertificates, - }) + upsOpts := &upstream.Options{ + InsecureSkipVerify: options.Insecure, + Bootstrap: options.BootstrapDNS, + Timeout: defaultTimeout, + TLSClientCertificates: config.TLSClientCertificates, + } + upstreamConfig, err := proxy.ParseUpstreamsConfig(upstreams, upsOpts) if err != nil { log.Fatalf("error while parsing upstreams configuration: %s", err) } @@ -339,7 +337,6 @@ func initUpstreams(config *proxy.Config, options *Options) { } config.Fallbacks = fallbacks } - } // initEDNS inits EDNS-related config diff --git a/upstream/bootstrap.go b/upstream/bootstrap.go index 0016664f3..4ab32a647 100755 --- a/upstream/bootstrap.go +++ b/upstream/bootstrap.go @@ -214,12 +214,11 @@ func (n *bootstrapper) createTLSConfig(host string) *tls.Config { tlsConfig.NextProtos = []string{http2.NextProtoTLS, "http/1.1"} case "quic": tlsConfig.NextProtos = compatProtoDQ + } - if n.options.TLSClientCertificates != nil { + if n.options.TLSClientCertificates != nil { log.Printf("Passing TLS configuration with client authentication") - tlsConfig = &tls.Config{ - Certificates: []tls.Certificate{*n.options.TLSClientCertificates}, - } + tlsConfig.Certificates = []tls.Certificate{*n.options.TLSClientCertificates} } // The supported application level protocols should be specified only