2018-01-29 23:47:04 +01:00
package main
import (
2019-06-03 16:44:09 +02:00
crypto_rand "crypto/rand"
2019-10-14 01:45:38 +02:00
"encoding/binary"
2018-01-29 23:47:04 +01:00
"net"
2018-07-05 18:05:24 +02:00
"os"
2018-01-29 23:47:04 +01:00
"sync/atomic"
"time"
"github.com/jedisct1/dlog"
2018-03-07 18:29:53 +01:00
clocksmith "github.com/jedisct1/go-clocksmith"
2018-06-04 20:52:16 +02:00
stamps "github.com/jedisct1/go-dnsstamps"
2019-10-03 19:25:20 +02:00
"github.com/miekg/dns"
2019-09-09 17:39:38 +02:00
"golang.org/x/crypto/curve25519"
2018-01-29 23:47:04 +01:00
)
type Proxy struct {
2019-11-17 21:28:26 +01:00
userName string
child bool
proxyPublicKey [ 32 ] byte
proxySecretKey [ 32 ] byte
ephemeralKeys bool
questionSizeEstimator QuestionSizeEstimator
serversInfo ServersInfo
timeout time . Duration
certRefreshDelay time . Duration
certRefreshDelayAfterFailure time . Duration
certIgnoreTimestamp bool
mainProto string
listenAddresses [ ] string
2019-11-24 22:45:43 +01:00
localDoHListenAddresses [ ] string
2019-11-28 23:49:28 +01:00
localDoHPath string
2019-11-28 16:46:25 +01:00
localDoHCertFile string
localDoHCertKeyFile string
2019-11-17 21:28:26 +01:00
daemonize bool
registeredServers [ ] RegisteredServer
registeredRelays [ ] RegisteredServer
pluginBlockIPv6 bool
2019-12-09 20:25:38 +01:00
pluginBlockUnqualified bool
2019-12-16 16:13:18 +01:00
pluginBlockUndelegated bool
2019-11-17 21:28:26 +01:00
cache bool
cacheSize int
cacheNegMinTTL uint32
cacheNegMaxTTL uint32
cacheMinTTL uint32
cacheMaxTTL uint32
rejectTTL uint32
cloakTTL uint32
queryLogFile string
queryLogFormat string
queryLogIgnoredQtypes [ ] string
nxLogFile string
nxLogFormat string
blockNameFile string
whitelistNameFile string
blockNameLogFile string
whitelistNameLogFile string
blockNameFormat string
whitelistNameFormat string
blockIPFile string
blockIPLogFile string
blockIPFormat string
forwardFile string
cloakFile string
pluginsGlobals PluginsGlobals
sources [ ] * Source
clientsCount uint32
maxClients uint32
xTransport * XTransport
allWeeklyRanges * map [ string ] WeeklyRanges
logMaxSize int
logMaxAge int
logMaxBackups int
blockedQueryResponse string
queryMeta [ ] string
routes * map [ string ] [ ] string
serversWithBrokenQueryPadding [ ] string
showCerts bool
2020-03-09 22:11:53 +01:00
dohCreds * map [ string ] DOHClientCreds
2018-01-29 23:47:04 +01:00
}
2019-11-24 22:45:43 +01:00
func ( proxy * Proxy ) addDNSListener ( listenAddrStr string ) {
2019-11-24 22:12:23 +01:00
listenUDPAddr , err := net . ResolveUDPAddr ( "udp" , listenAddrStr )
if err != nil {
2018-01-29 23:47:04 +01:00
dlog . Fatal ( err )
}
2019-11-24 22:12:23 +01:00
listenTCPAddr , err := net . ResolveTCPAddr ( "tcp" , listenAddrStr )
if err != nil {
dlog . Fatal ( err )
2018-01-29 23:47:04 +01:00
}
2018-06-13 16:52:41 +02:00
2019-11-24 22:12:23 +01:00
// if 'userName' is not set, continue as before
if len ( proxy . userName ) <= 0 {
if err := proxy . udpListenerFromAddr ( listenUDPAddr ) ; err != nil {
dlog . Fatal ( err )
}
if err := proxy . tcpListenerFromAddr ( listenTCPAddr ) ; err != nil {
dlog . Fatal ( err )
}
return
}
// if 'userName' is set and we are the parent process
if ! proxy . child {
// parent
listenerUDP , err := net . ListenUDP ( "udp" , listenUDPAddr )
2018-01-29 23:47:04 +01:00
if err != nil {
dlog . Fatal ( err )
}
2019-11-24 22:12:23 +01:00
listenerTCP , err := net . ListenTCP ( "tcp" , listenTCPAddr )
2018-01-29 23:47:04 +01:00
if err != nil {
dlog . Fatal ( err )
}
2018-06-13 16:52:41 +02:00
2019-11-24 22:12:23 +01:00
fdUDP , err := listenerUDP . File ( ) // On Windows, the File method of UDPConn is not implemented.
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
fdTCP , err := listenerTCP . File ( ) // On Windows, the File method of TCPListener is not implemented.
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
defer listenerUDP . Close ( )
defer listenerTCP . Close ( )
FileDescriptors = append ( FileDescriptors , fdUDP )
FileDescriptors = append ( FileDescriptors , fdTCP )
return
}
2018-06-13 16:52:41 +02:00
2019-11-24 22:12:23 +01:00
// child
listenerUDP , err := net . FilePacketConn ( os . NewFile ( uintptr ( 3 + FileDescriptorNum ) , "listenerUDP" ) )
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
FileDescriptorNum ++
2018-06-13 16:52:41 +02:00
2019-11-24 22:12:23 +01:00
listenerTCP , err := net . FileListener ( os . NewFile ( uintptr ( 3 + FileDescriptorNum ) , "listenerTCP" ) )
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
FileDescriptorNum ++
2018-06-13 16:52:41 +02:00
2019-11-24 22:12:23 +01:00
dlog . Noticef ( "Now listening to %v [UDP]" , listenUDPAddr )
go proxy . udpListener ( listenerUDP . ( * net . UDPConn ) )
2018-06-13 16:52:41 +02:00
2019-11-24 22:12:23 +01:00
dlog . Noticef ( "Now listening to %v [TCP]" , listenAddrStr )
go proxy . tcpListener ( listenerTCP . ( * net . TCPListener ) )
}
2018-06-13 16:52:41 +02:00
2019-11-24 22:45:43 +01:00
func ( proxy * Proxy ) addLocalDoHListener ( listenAddrStr string ) {
listenTCPAddr , err := net . ResolveTCPAddr ( "tcp" , listenAddrStr )
if err != nil {
dlog . Fatal ( err )
}
// if 'userName' is not set, continue as before
if len ( proxy . userName ) <= 0 {
if err := proxy . localDoHListenerFromAddr ( listenTCPAddr ) ; err != nil {
dlog . Fatal ( err )
}
return
}
// if 'userName' is set and we are the parent process
if ! proxy . child {
// parent
listenerTCP , err := net . ListenTCP ( "tcp" , listenTCPAddr )
if err != nil {
dlog . Fatal ( err )
}
fdTCP , err := listenerTCP . File ( ) // On Windows, the File method of TCPListener is not implemented.
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
defer listenerTCP . Close ( )
FileDescriptors = append ( FileDescriptors , fdTCP )
return
}
// child
listenerTCP , err := net . FileListener ( os . NewFile ( uintptr ( 3 + FileDescriptorNum ) , "listenerTCP" ) )
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
FileDescriptorNum ++
2019-11-29 08:53:13 +01:00
dlog . Noticef ( "Now listening to https://%v%v [DoH]" , listenAddrStr , proxy . localDoHPath )
2019-11-24 22:45:43 +01:00
go proxy . localDoHListener ( listenerTCP . ( * net . TCPListener ) )
}
2019-11-24 22:12:23 +01:00
func ( proxy * Proxy ) StartProxy ( ) {
proxy . questionSizeEstimator = NewQuestionSizeEstimator ( )
if _ , err := crypto_rand . Read ( proxy . proxySecretKey [ : ] ) ; err != nil {
dlog . Fatal ( err )
}
curve25519 . ScalarBaseMult ( & proxy . proxyPublicKey , & proxy . proxySecretKey )
for _ , registeredServer := range proxy . registeredServers {
proxy . serversInfo . registerServer ( registeredServer . name , registeredServer . stamp )
}
for _ , listenAddrStr := range proxy . listenAddresses {
2019-11-24 22:45:43 +01:00
proxy . addDNSListener ( listenAddrStr )
2019-11-24 22:12:23 +01:00
}
2019-11-24 22:45:43 +01:00
for _ , listenAddrStr := range proxy . localDoHListenAddresses {
proxy . addLocalDoHListener ( listenAddrStr )
}
2018-07-07 17:39:33 +02:00
// if 'userName' is set and we are the parent process drop privilege and exit
if len ( proxy . userName ) > 0 && ! proxy . child {
proxy . dropPrivilege ( proxy . userName , FileDescriptors )
2018-06-13 16:52:41 +02:00
}
2019-10-31 17:49:48 +01:00
if err := proxy . SystemDListeners ( ) ; err != nil {
2018-01-29 23:47:04 +01:00
dlog . Fatal ( err )
}
liveServers , err := proxy . serversInfo . refresh ( proxy )
2019-10-18 20:30:41 +02:00
if liveServers > 0 {
proxy . certIgnoreTimestamp = false
}
2019-06-07 01:23:48 +02:00
if proxy . showCerts {
os . Exit ( 0 )
}
2018-01-29 23:47:04 +01:00
if liveServers > 0 {
dlog . Noticef ( "dnscrypt-proxy is ready - live servers: %d" , liveServers )
2018-07-07 17:21:21 +02:00
if ! proxy . child {
2019-10-03 14:39:09 +02:00
if err := ServiceManagerReadyNotify ( ) ; err != nil {
dlog . Fatal ( err )
}
2018-07-07 17:21:21 +02:00
}
2018-01-29 23:47:04 +01:00
} else if err != nil {
dlog . Error ( err )
dlog . Notice ( "dnscrypt-proxy is waiting for at least one server to be reachable" )
}
2019-10-31 02:22:48 +01:00
go func ( ) {
for {
clocksmith . Sleep ( PrefetchSources ( proxy . xTransport , proxy . sources ) )
}
} ( )
2018-07-05 18:05:24 +02:00
if len ( proxy . serversInfo . registeredServers ) > 0 {
2019-10-31 17:36:59 +01:00
go func ( ) {
for {
delay := proxy . certRefreshDelay
if liveServers == 0 {
delay = proxy . certRefreshDelayAfterFailure
}
clocksmith . Sleep ( delay )
liveServers , _ = proxy . serversInfo . refresh ( proxy )
if liveServers > 0 {
proxy . certIgnoreTimestamp = false
}
2019-10-31 12:02:20 +01:00
}
2019-10-31 17:36:59 +01:00
} ( )
2018-07-05 18:05:24 +02:00
}
2018-01-29 23:47:04 +01:00
}
func ( proxy * Proxy ) udpListener ( clientPc * net . UDPConn ) {
2019-10-31 17:49:48 +01:00
defer clientPc . Close ( )
2018-01-29 23:47:04 +01:00
for {
buffer := make ( [ ] byte , MaxDNSPacketSize - 1 )
length , clientAddr , err := clientPc . ReadFrom ( buffer )
if err != nil {
return
}
packet := buffer [ : length ]
go func ( ) {
2019-05-26 21:16:47 +02:00
start := time . Now ( )
2018-01-29 23:47:04 +01:00
if ! proxy . clientsCountInc ( ) {
2019-12-03 13:04:58 +01:00
dlog . Warnf ( "Too many incoming connections (max=%d)" , proxy . maxClients )
2018-01-29 23:47:04 +01:00
return
}
defer proxy . clientsCountDec ( )
2020-03-13 17:50:58 +01:00
proxy . processIncomingQuery ( "udp" , proxy . mainProto , packet , & clientAddr , clientPc , start )
2018-01-29 23:47:04 +01:00
} ( )
}
}
2019-10-31 17:49:48 +01:00
func ( proxy * Proxy ) udpListenerFromAddr ( listenAddr * net . UDPAddr ) error {
2018-01-29 23:47:04 +01:00
clientPc , err := net . ListenUDP ( "udp" , listenAddr )
if err != nil {
2019-10-31 17:49:48 +01:00
return err
2018-01-29 23:47:04 +01:00
}
dlog . Noticef ( "Now listening to %v [UDP]" , listenAddr )
go proxy . udpListener ( clientPc )
2019-10-31 17:49:48 +01:00
return nil
2018-01-29 23:47:04 +01:00
}
func ( proxy * Proxy ) tcpListener ( acceptPc * net . TCPListener ) {
2019-10-31 17:49:48 +01:00
defer acceptPc . Close ( )
2018-01-29 23:47:04 +01:00
for {
clientPc , err := acceptPc . Accept ( )
if err != nil {
continue
}
go func ( ) {
2019-05-26 21:16:47 +02:00
start := time . Now ( )
2018-01-29 23:47:04 +01:00
defer clientPc . Close ( )
if ! proxy . clientsCountInc ( ) {
2019-12-03 13:04:58 +01:00
dlog . Warnf ( "Too many incoming connections (max=%d)" , proxy . maxClients )
2018-01-29 23:47:04 +01:00
return
}
defer proxy . clientsCountDec ( )
2019-12-09 12:11:24 +01:00
if err = clientPc . SetDeadline ( time . Now ( ) . Add ( proxy . timeout ) ) ; err != nil {
return
}
2018-06-06 15:54:51 +02:00
packet , err := ReadPrefixed ( & clientPc )
2019-10-15 18:37:24 +02:00
if err != nil {
2018-01-29 23:47:04 +01:00
return
}
clientAddr := clientPc . RemoteAddr ( )
2020-03-13 17:50:58 +01:00
proxy . processIncomingQuery ( "tcp" , "tcp" , packet , & clientAddr , clientPc , start )
2018-01-29 23:47:04 +01:00
} ( )
}
}
2019-10-31 17:49:48 +01:00
func ( proxy * Proxy ) tcpListenerFromAddr ( listenAddr * net . TCPAddr ) error {
2018-01-29 23:47:04 +01:00
acceptPc , err := net . ListenTCP ( "tcp" , listenAddr )
if err != nil {
2019-10-31 17:49:48 +01:00
return err
2018-01-29 23:47:04 +01:00
}
dlog . Noticef ( "Now listening to %v [TCP]" , listenAddr )
go proxy . tcpListener ( acceptPc )
2019-10-31 17:49:48 +01:00
return nil
2018-01-29 23:47:04 +01:00
}
2019-11-24 22:45:43 +01:00
func ( proxy * Proxy ) localDoHListenerFromAddr ( listenAddr * net . TCPAddr ) error {
acceptPc , err := net . ListenTCP ( "tcp" , listenAddr )
if err != nil {
return err
}
2019-11-29 08:53:13 +01:00
dlog . Noticef ( "Now listening to https://%v%v [DoH]" , listenAddr , proxy . localDoHPath )
2019-11-24 22:45:43 +01:00
go proxy . localDoHListener ( acceptPc )
return nil
}
2019-10-14 01:45:38 +02:00
func ( proxy * Proxy ) prepareForRelay ( ip net . IP , port int , encryptedQuery * [ ] byte ) {
anonymizedDNSHeader := [ ] byte { 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x00 , 0x00 }
relayedQuery := append ( anonymizedDNSHeader , ip . To16 ( ) ... )
var tmp [ 2 ] byte
binary . BigEndian . PutUint16 ( tmp [ 0 : 2 ] , uint16 ( port ) )
relayedQuery = append ( relayedQuery , tmp [ : ] ... )
relayedQuery = append ( relayedQuery , * encryptedQuery ... )
* encryptedQuery = relayedQuery
}
2018-04-09 03:12:34 +02:00
func ( proxy * Proxy ) exchangeWithUDPServer ( serverInfo * ServerInfo , sharedKey * [ 32 ] byte , encryptedQuery [ ] byte , clientNonce [ ] byte ) ( [ ] byte , error ) {
2019-10-14 01:45:38 +02:00
upstreamAddr := serverInfo . UDPAddr
if serverInfo . RelayUDPAddr != nil {
upstreamAddr = serverInfo . RelayUDPAddr
}
2020-01-27 16:07:08 +01:00
var err error
var pc net . Conn
proxyDialer := proxy . xTransport . proxyDialer
if proxyDialer == nil {
pc , err = net . DialUDP ( "udp" , nil , upstreamAddr )
} else {
pc , err = ( * proxyDialer ) . Dial ( "udp" , upstreamAddr . String ( ) )
}
2018-01-29 23:47:04 +01:00
if err != nil {
return nil , err
}
2019-10-19 22:08:02 +02:00
defer pc . Close ( )
2019-12-09 12:11:24 +01:00
if err = pc . SetDeadline ( time . Now ( ) . Add ( serverInfo . Timeout ) ) ; err != nil {
return nil , err
}
2019-10-14 01:45:38 +02:00
if serverInfo . RelayUDPAddr != nil {
proxy . prepareForRelay ( serverInfo . UDPAddr . IP , serverInfo . UDPAddr . Port , & encryptedQuery )
}
2018-01-29 23:47:04 +01:00
encryptedResponse := make ( [ ] byte , MaxDNSPacketSize )
2020-01-29 18:14:03 +01:00
for tries := 2 ; tries > 0 ; tries -- {
if _ , err = pc . Write ( encryptedQuery ) ; err != nil {
return nil , err
}
length , err := pc . Read ( encryptedResponse )
if err == nil {
encryptedResponse = encryptedResponse [ : length ]
break
}
dlog . Debug ( "Retry on timeout" )
2018-01-29 23:47:04 +01:00
}
2018-04-09 03:12:34 +02:00
return proxy . Decrypt ( serverInfo , sharedKey , encryptedResponse , clientNonce )
2018-01-29 23:47:04 +01:00
}
2018-04-09 03:12:34 +02:00
func ( proxy * Proxy ) exchangeWithTCPServer ( serverInfo * ServerInfo , sharedKey * [ 32 ] byte , encryptedQuery [ ] byte , clientNonce [ ] byte ) ( [ ] byte , error ) {
2019-10-14 01:45:38 +02:00
upstreamAddr := serverInfo . TCPAddr
if serverInfo . RelayUDPAddr != nil {
upstreamAddr = serverInfo . RelayTCPAddr
}
2018-06-06 19:06:44 +02:00
var err error
var pc net . Conn
2018-06-06 15:54:51 +02:00
proxyDialer := proxy . xTransport . proxyDialer
if proxyDialer == nil {
2019-10-14 01:45:38 +02:00
pc , err = net . DialTCP ( "tcp" , nil , upstreamAddr )
2018-06-06 15:54:51 +02:00
} else {
2020-01-27 16:07:08 +01:00
pc , err = ( * proxyDialer ) . Dial ( "tcp" , upstreamAddr . String ( ) )
2018-01-29 23:47:04 +01:00
}
2018-06-18 19:19:53 +02:00
if err != nil {
return nil , err
}
2019-10-19 22:08:02 +02:00
defer pc . Close ( )
2019-12-09 12:11:24 +01:00
if err = pc . SetDeadline ( time . Now ( ) . Add ( serverInfo . Timeout ) ) ; err != nil {
return nil , err
}
2019-10-14 01:45:38 +02:00
if serverInfo . RelayTCPAddr != nil {
proxy . prepareForRelay ( serverInfo . TCPAddr . IP , serverInfo . TCPAddr . Port , & encryptedQuery )
}
2018-06-06 19:06:44 +02:00
encryptedQuery , err = PrefixWithSize ( encryptedQuery )
2018-01-29 23:47:04 +01:00
if err != nil {
return nil , err
}
2019-12-09 12:11:24 +01:00
if _ , err = pc . Write ( encryptedQuery ) ; err != nil {
return nil , err
}
2018-06-06 19:06:44 +02:00
encryptedResponse , err := ReadPrefixed ( & pc )
2018-07-09 15:49:36 +02:00
if err != nil {
return nil , err
}
2018-04-09 03:12:34 +02:00
return proxy . Decrypt ( serverInfo , sharedKey , encryptedResponse , clientNonce )
2018-01-29 23:47:04 +01:00
}
func ( proxy * Proxy ) clientsCountInc ( ) bool {
for {
2018-03-02 09:41:12 +01:00
count := atomic . LoadUint32 ( & proxy . clientsCount )
2018-01-29 23:47:04 +01:00
if count >= proxy . maxClients {
return false
}
if atomic . CompareAndSwapUint32 ( & proxy . clientsCount , count , count + 1 ) {
2018-02-05 19:03:04 +01:00
dlog . Debugf ( "clients count: %d" , count + 1 )
2018-01-29 23:47:04 +01:00
return true
}
}
}
func ( proxy * Proxy ) clientsCountDec ( ) {
for {
2018-03-02 09:41:12 +01:00
if count := atomic . LoadUint32 ( & proxy . clientsCount ) ; count == 0 || atomic . CompareAndSwapUint32 ( & proxy . clientsCount , count , count - 1 ) {
2018-01-29 23:47:04 +01:00
break
}
}
}
2020-03-13 17:50:58 +01:00
func ( proxy * Proxy ) processIncomingQuery ( clientProto string , serverProto string , query [ ] byte , clientAddr * net . Addr , clientPc net . Conn , start time . Time ) ( response [ ] byte ) {
2018-07-05 18:05:24 +02:00
if len ( query ) < MinDNSPacketSize {
2018-01-29 23:47:04 +01:00
return
}
2019-05-26 21:16:47 +02:00
pluginsState := NewPluginsState ( proxy , clientProto , clientAddr , start )
2019-06-03 18:51:21 +02:00
serverName := "-"
2019-12-23 11:37:45 +01:00
needsEDNS0Padding := false
2020-03-13 17:50:58 +01:00
serverInfo := proxy . serversInfo . getOne ( )
2019-06-03 18:51:21 +02:00
if serverInfo != nil {
serverName = serverInfo . Name
2019-12-23 11:37:45 +01:00
needsEDNS0Padding = ( serverInfo . Proto == stamps . StampProtoTypeDoH || serverInfo . Proto == stamps . StampProtoTypeTLS )
2019-06-03 18:51:21 +02:00
}
2020-03-13 17:50:58 +01:00
query , _ = pluginsState . ApplyQueryPlugins ( & proxy . pluginsGlobals , query , needsEDNS0Padding )
2019-06-03 00:47:39 +02:00
if len ( query ) < MinDNSPacketSize || len ( query ) > MaxDNSPacketSize {
return
}
2019-12-17 16:28:12 +01:00
if pluginsState . action == PluginsActionDrop {
pluginsState . returnCode = PluginsReturnCodeDrop
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
return
}
2018-01-29 23:47:04 +01:00
var err error
2019-12-17 16:28:12 +01:00
if pluginsState . synthResponse != nil {
response , err = pluginsState . synthResponse . PackBuffer ( response )
if err != nil {
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-01-29 23:47:04 +01:00
return
}
}
2018-07-05 18:05:24 +02:00
if len ( response ) == 0 && serverInfo != nil {
2018-02-04 13:35:40 +01:00
var ttl * uint32
2020-03-13 17:50:58 +01:00
pluginsState . serverName = serverName
2018-04-14 15:03:21 +02:00
if serverInfo . Proto == stamps . StampProtoTypeDNSCrypt {
2018-04-09 03:12:34 +02:00
sharedKey , encryptedQuery , clientNonce , err := proxy . Encrypt ( serverInfo , query , serverProto )
2018-04-01 16:35:32 +02:00
if err != nil {
2018-06-04 23:18:28 +02:00
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-04-01 16:35:32 +02:00
return
}
serverInfo . noticeBegin ( proxy )
if serverProto == "udp" {
2018-04-09 03:12:34 +02:00
response , err = proxy . exchangeWithUDPServer ( serverInfo , sharedKey , encryptedQuery , clientNonce )
2019-10-12 20:55:59 +02:00
if err == nil && len ( response ) >= MinDNSPacketSize && response [ 2 ] & 0x02 == 0x02 {
2019-10-20 02:04:32 +02:00
serverProto = "tcp"
2019-10-31 02:40:42 +01:00
sharedKey , encryptedQuery , clientNonce , err = proxy . Encrypt ( serverInfo , query , serverProto )
2019-10-20 02:04:32 +02:00
if err != nil {
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2019-10-20 23:07:36 +02:00
return
2019-10-20 02:04:32 +02:00
}
2019-10-12 20:55:59 +02:00
response , err = proxy . exchangeWithTCPServer ( serverInfo , sharedKey , encryptedQuery , clientNonce )
}
2018-04-01 16:35:32 +02:00
} else {
2018-04-09 03:12:34 +02:00
response , err = proxy . exchangeWithTCPServer ( serverInfo , sharedKey , encryptedQuery , clientNonce )
2018-04-01 16:35:32 +02:00
}
2020-01-30 13:15:29 +01:00
if err != nil {
if stale , ok := pluginsState . sessionData [ "stale" ] ; ok {
dlog . Debug ( "Serving stale response" )
response , err = ( stale . ( * dns . Msg ) ) . Pack ( )
}
}
2018-04-01 16:35:32 +02:00
if err != nil {
2019-10-19 10:15:41 +02:00
if neterr , ok := err . ( net . Error ) ; ok && neterr . Timeout ( ) {
pluginsState . returnCode = PluginsReturnCodeServerTimeout
} else {
2019-11-17 19:48:15 +01:00
pluginsState . returnCode = PluginsReturnCodeNetworkError
2019-10-19 10:15:41 +02:00
}
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-04-01 16:35:32 +02:00
serverInfo . noticeFailure ( proxy )
return
}
2018-04-14 15:03:21 +02:00
} else if serverInfo . Proto == stamps . StampProtoTypeDoH {
2018-02-04 12:57:54 +01:00
tid := TransactionID ( query )
SetTransactionID ( query , 0 )
2018-02-19 18:30:26 +01:00
serverInfo . noticeBegin ( proxy )
2020-02-21 22:33:34 +01:00
serverResponse , tls , _ , err := proxy . xTransport . DoHQuery ( serverInfo . useGet , serverInfo . URL , query , proxy . timeout )
2018-02-04 12:57:54 +01:00
SetTransactionID ( query , tid )
2020-02-21 22:33:34 +01:00
if err == nil || tls == nil || ! tls . HandshakeComplete {
2020-01-30 13:15:29 +01:00
response = nil
} else if stale , ok := pluginsState . sessionData [ "stale" ] ; ok {
dlog . Debug ( "Serving stale response" )
response , err = ( stale . ( * dns . Msg ) ) . Pack ( )
}
2018-01-30 15:46:21 +01:00
if err != nil {
2019-11-17 19:48:15 +01:00
pluginsState . returnCode = PluginsReturnCodeNetworkError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-02-22 14:20:59 +01:00
serverInfo . noticeFailure ( proxy )
2018-01-29 23:47:04 +01:00
return
}
2020-01-30 13:15:29 +01:00
if response == nil {
2020-02-21 22:33:34 +01:00
response = serverResponse
2020-01-30 13:15:29 +01:00
}
2018-01-29 23:47:04 +01:00
if err != nil {
2019-11-17 19:48:15 +01:00
pluginsState . returnCode = PluginsReturnCodeNetworkError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-02-22 14:20:59 +01:00
serverInfo . noticeFailure ( proxy )
2018-01-29 23:47:04 +01:00
return
}
2018-02-04 12:57:54 +01:00
if len ( response ) >= MinDNSPacketSize {
SetTransactionID ( response , tid )
}
2018-01-29 23:47:04 +01:00
} else {
dlog . Fatal ( "Unsupported protocol" )
}
2018-02-22 14:20:59 +01:00
if len ( response ) < MinDNSPacketSize || len ( response ) > MaxDNSPacketSize {
2018-06-04 23:18:28 +02:00
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-02-22 14:20:59 +01:00
serverInfo . noticeFailure ( proxy )
return
}
response , err = pluginsState . ApplyResponsePlugins ( & proxy . pluginsGlobals , response , ttl )
2018-01-29 23:47:04 +01:00
if err != nil {
2018-06-04 23:18:28 +02:00
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-01-29 23:47:04 +01:00
serverInfo . noticeFailure ( proxy )
return
}
2019-12-17 16:28:12 +01:00
if pluginsState . action == PluginsActionDrop {
pluginsState . returnCode = PluginsReturnCodeDrop
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
return
}
if pluginsState . synthResponse != nil {
response , err = pluginsState . synthResponse . PackBuffer ( response )
if err != nil {
pluginsState . returnCode = PluginsReturnCodeParseError
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
return
}
}
2019-10-18 20:51:11 +02:00
if rcode := Rcode ( response ) ; rcode == dns . RcodeServerFailure { // SERVFAIL
2020-01-31 10:53:35 +01:00
if pluginsState . dnssec {
dlog . Debug ( "A response had an invalid DNSSEC signature" )
} else {
dlog . Infof ( "Server [%v] returned temporary error code SERVFAIL -- Invalid DNSSEC signature received or server may be experiencing connectivity issues" , serverInfo . Name )
serverInfo . noticeFailure ( proxy )
}
2018-02-22 14:20:59 +01:00
} else {
serverInfo . noticeSuccess ( proxy )
}
2018-01-29 23:47:04 +01:00
}
2018-07-05 18:05:24 +02:00
if len ( response ) < MinDNSPacketSize || len ( response ) > MaxDNSPacketSize {
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-07-05 18:05:24 +02:00
if serverInfo != nil {
serverInfo . noticeFailure ( proxy )
}
return
}
2018-01-29 23:47:04 +01:00
if clientProto == "udp" {
2019-10-12 21:15:39 +02:00
if len ( response ) > pluginsState . maxUnencryptedUDPSafePayloadSize {
2018-01-29 23:47:04 +01:00
response , err = TruncatedResponse ( response )
if err != nil {
2018-06-04 23:18:28 +02:00
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-01-29 23:47:04 +01:00
return
}
}
clientPc . ( net . PacketConn ) . WriteTo ( response , * clientAddr )
if HasTCFlag ( response ) {
proxy . questionSizeEstimator . blindAdjust ( )
} else {
proxy . questionSizeEstimator . adjust ( ResponseOverhead + len ( response ) )
}
2019-11-26 01:36:35 +01:00
} else if clientProto == "tcp" {
2018-01-29 23:47:04 +01:00
response , err = PrefixWithSize ( response )
if err != nil {
2018-06-04 23:18:28 +02:00
pluginsState . returnCode = PluginsReturnCodeParseError
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2018-07-05 18:05:24 +02:00
if serverInfo != nil {
serverInfo . noticeFailure ( proxy )
}
2018-01-29 23:47:04 +01:00
return
}
2019-11-28 16:46:25 +01:00
if clientPc != nil {
clientPc . Write ( response )
}
2018-01-29 23:47:04 +01:00
}
2019-11-05 00:54:03 +01:00
pluginsState . ApplyLoggingPlugins ( & proxy . pluginsGlobals )
2019-11-28 16:46:25 +01:00
2019-11-26 01:36:35 +01:00
return response
2018-01-29 23:47:04 +01:00
}
2018-02-04 13:35:40 +01:00
2019-10-09 17:59:46 +02:00
func NewProxy ( ) * Proxy {
return & Proxy {
2019-06-03 16:44:09 +02:00
serversInfo : NewServersInfo ( ) ,
2018-02-04 21:13:54 +01:00
}
}