diff --git a/dnscrypt-proxy/config.go b/dnscrypt-proxy/config.go index 5fa64fe64d..94218b880e 100644 --- a/dnscrypt-proxy/config.go +++ b/dnscrypt-proxy/config.go @@ -92,6 +92,7 @@ type Config struct { BlockedQueryResponse string `toml:"blocked_query_response"` QueryMeta []string `toml:"query_meta"` AnonymizedDNS AnonymizedDNSConfig `toml:"anonymized_dns"` + TLSClientAuth TLSClientAuthConfig `toml:"tls_client_auth"` } func newConfig() Config { @@ -214,6 +215,16 @@ type ServerSummary struct { Stamp string `json:"stamp"` } +type TLSClientAuthCredsConfig struct { + ServerName string `toml:"server_name"` + ClientCert string `toml:"client_cert"` + ClientKey string `toml:"client_key"` +} + +type TLSClientAuthConfig struct { + Creds []TLSClientAuthCredsConfig `toml:"creds"` +} + type ConfigFlags struct { List *bool ListAll *bool @@ -472,6 +483,17 @@ func ConfigLoad(proxy *Proxy, flags *ConfigFlags) error { } proxy.routes = &routes } + configClientCreds := config.TLSClientAuth.Creds + creds := make(map[string]DOHClientCreds) + for _, configClientCred := range configClientCreds { + credFiles := DOHClientCreds{ + clientCert: configClientCred.ClientCert, + clientKey: configClientCred.ClientKey, + } + creds[configClientCred.ServerName] = credFiles + } + proxy.dohCreds = &creds + proxy.serversWithBrokenQueryPadding = config.BrokenImplementations.BrokenQueryPadding if *flags.ListAll { diff --git a/dnscrypt-proxy/example-dnscrypt-proxy.toml b/dnscrypt-proxy/example-dnscrypt-proxy.toml index 390a6d48c6..0780dd9348 100644 --- a/dnscrypt-proxy/example-dnscrypt-proxy.toml +++ b/dnscrypt-proxy/example-dnscrypt-proxy.toml @@ -674,3 +674,14 @@ broken_query_padding = ['cisco', 'cisco-ipv6', 'cisco-familyshield', "quad9-dnsc # [static.'myserver'] # stamp = 'sdns:AQcAAAAAAAAAAAAQMi5kbnNjcnlwdC1jZXJ0Lg' + + +################################ +# TLS Client Authentication # +################################ + +[tls_client_auth] + +# creds = [ +# { server_name='myserver', client_cert='client.crt', client_key='client.key' }, +# ] diff --git a/dnscrypt-proxy/proxy.go b/dnscrypt-proxy/proxy.go index 291f674978..56ea16309f 100644 --- a/dnscrypt-proxy/proxy.go +++ b/dnscrypt-proxy/proxy.go @@ -77,6 +77,7 @@ type Proxy struct { routes *map[string][]string serversWithBrokenQueryPadding []string showCerts bool + dohCreds *map[string]DOHClientCreds } func (proxy *Proxy) addDNSListener(listenAddrStr string) { diff --git a/dnscrypt-proxy/serversInfo.go b/dnscrypt-proxy/serversInfo.go index e8c38c4cff..1a6ace0398 100644 --- a/dnscrypt-proxy/serversInfo.go +++ b/dnscrypt-proxy/serversInfo.go @@ -35,6 +35,11 @@ type ServerBugs struct { incorrectPadding bool } +type DOHClientCreds struct { + clientCert string + clientKey string +} + type ServerInfo struct { Proto stamps.StampProtoType MagicQuery [8]byte @@ -54,6 +59,7 @@ type ServerInfo struct { rtt ewma.MovingAverage initialRtt int useGet bool + DOHClientCreds DOHClientCreds } type LBStrategy int @@ -378,6 +384,15 @@ func fetchDoHServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp, isN Path: stamp.Path, } body := dohTestPacket(0xcafe) + dohClientCreds, ok := (*proxy.dohCreds)[name] + if !ok { + dohClientCreds, ok = (*proxy.dohCreds)["*"] + } + if ok { + dlog.Noticef("[%s] Cert: %s, Key: %s", name, dohClientCreds.clientCert, dohClientCreds.clientKey) + proxy.xTransport.tlsClientCreds = dohClientCreds + proxy.xTransport.rebuildTransport() + } useGet := false if _, _, _, err := proxy.xTransport.DoHQuery(useGet, url, body, proxy.timeout); err != nil { useGet = true diff --git a/dnscrypt-proxy/xtransport.go b/dnscrypt-proxy/xtransport.go index 927ab9d55a..7cb02ede87 100644 --- a/dnscrypt-proxy/xtransport.go +++ b/dnscrypt-proxy/xtransport.go @@ -59,6 +59,7 @@ type XTransport struct { tlsCipherSuite []uint16 proxyDialer *netproxy.Dialer httpProxyFunction func(*http.Request) (*url.URL, error) + tlsClientCreds DOHClientCreds } func NewXTransport() *XTransport { @@ -156,10 +157,17 @@ func (xTransport *XTransport) rebuildTransport() { if xTransport.httpProxyFunction != nil { transport.Proxy = xTransport.httpProxyFunction } - if xTransport.tlsDisableSessionTickets || xTransport.tlsCipherSuite != nil { - tlsClientConfig := tls.Config{ - SessionTicketsDisabled: xTransport.tlsDisableSessionTickets, + tlsClientConfig := tls.Config{} + clientCreds := xTransport.tlsClientCreds + if (clientCreds != DOHClientCreds{}) { + cert, err := tls.LoadX509KeyPair(clientCreds.clientCert, clientCreds.clientKey) + if err != nil { + dlog.Error(err) } + tlsClientConfig.Certificates = []tls.Certificate{cert} + } + if xTransport.tlsDisableSessionTickets || xTransport.tlsCipherSuite != nil { + tlsClientConfig.SessionTicketsDisabled = xTransport.tlsDisableSessionTickets if !xTransport.tlsDisableSessionTickets { tlsClientConfig.ClientSessionCache = tls.NewLRUClientSessionCache(10) } @@ -167,8 +175,8 @@ func (xTransport *XTransport) rebuildTransport() { tlsClientConfig.PreferServerCipherSuites = false tlsClientConfig.CipherSuites = xTransport.tlsCipherSuite } - transport.TLSClientConfig = &tlsClientConfig } + transport.TLSClientConfig = &tlsClientConfig http2.ConfigureTransport(transport) xTransport.transport = transport }