2018-01-29 23:47:04 +01:00
package main
import (
2020-11-25 18:15:48 +01:00
"context"
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"
2020-06-09 09:41:58 +02:00
"runtime"
2021-01-01 14:04:12 +01:00
"strings"
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 {
2020-11-14 14:46:59 +01:00
pluginsGlobals PluginsGlobals
serversInfo ServersInfo
questionSizeEstimator QuestionSizeEstimator
registeredServers [ ] RegisteredServer
dns64Resolvers [ ] string
dns64Prefixes [ ] string
serversBlockingFragments [ ] string
ednsClientSubnets [ ] * net . IPNet
queryLogIgnoredQtypes [ ] string
localDoHListeners [ ] * net . TCPListener
queryMeta [ ] string
2020-04-26 12:52:55 +02:00
udpListeners [ ] * net . UDPConn
2020-11-14 14:46:59 +01:00
sources [ ] * Source
2020-04-26 12:52:55 +02:00
tcpListeners [ ] * net . TCPListener
2020-11-14 14:46:59 +01:00
registeredRelays [ ] RegisteredServer
2020-03-25 20:09:46 +01:00
listenAddresses [ ] string
localDoHListenAddresses [ ] string
2020-11-14 14:46:59 +01:00
xTransport * XTransport
dohCreds * map [ string ] DOHClientCreds
allWeeklyRanges * map [ string ] WeeklyRanges
routes * map [ string ] [ ] string
2021-01-01 21:39:17 +01:00
captivePortalMap * CaptivePortalMap
2020-11-14 14:46:59 +01:00
nxLogFormat string
2020-03-25 20:09:46 +01:00
localDoHCertFile string
localDoHCertKeyFile string
2021-01-02 15:10:04 +01:00
captivePortalMapFile string
2020-11-14 14:46:59 +01:00
localDoHPath string
mainProto string
cloakFile string
forwardFile string
blockIPFormat string
blockIPLogFile string
2020-11-15 20:59:58 +01:00
allowedIPFile string
allowedIPFormat string
allowedIPLogFile string
2020-03-25 20:09:46 +01:00
queryLogFormat string
2020-11-14 14:46:59 +01:00
blockIPFile string
whitelistNameFormat string
2020-03-25 20:09:46 +01:00
whitelistNameLogFile string
2020-11-14 14:46:59 +01:00
blockNameLogFile string
whitelistNameFile string
blockNameFile string
queryLogFile string
blockedQueryResponse string
userName string
nxLogFile string
2020-03-25 20:09:46 +01:00
blockNameFormat string
2020-11-14 14:46:59 +01:00
proxySecretKey [ 32 ] byte
proxyPublicKey [ 32 ] byte
certRefreshDelayAfterFailure time . Duration
timeout time . Duration
certRefreshDelay time . Duration
cacheSize int
logMaxBackups int
logMaxAge int
logMaxSize int
cacheNegMinTTL uint32
rejectTTL uint32
cacheMaxTTL uint32
2020-03-25 20:09:46 +01:00
clientsCount uint32
maxClients uint32
2020-11-14 14:46:59 +01:00
cacheMinTTL uint32
cacheNegMaxTTL uint32
cloakTTL uint32
cache bool
pluginBlockIPv6 bool
ephemeralKeys bool
pluginBlockUnqualified bool
2020-03-25 20:09:46 +01:00
showCerts bool
2020-11-14 14:46:59 +01:00
certIgnoreTimestamp bool
2020-03-26 13:41:57 +01:00
skipAnonIncompatbibleResolvers bool
2020-08-03 18:05:42 +02:00
anonDirectCertFallback bool
2020-11-14 14:46:59 +01:00
pluginBlockUndelegated bool
child bool
daemonize bool
2021-01-01 14:04:12 +01:00
requiredProps stamps . ServerInformalProperties
ServerNames [ ] string
DisabledServerNames [ ] string
SourceIPv4 bool
SourceIPv6 bool
SourceDNSCrypt bool
SourceDoH bool
2018-01-29 23:47:04 +01:00
}
2020-06-19 11:37:53 +02:00
func ( proxy * Proxy ) registerUDPListener ( conn * net . UDPConn ) {
2020-04-26 16:52:50 +02:00
proxy . udpListeners = append ( proxy . udpListeners , conn )
}
2020-06-19 11:37:53 +02:00
func ( proxy * Proxy ) registerTCPListener ( listener * net . TCPListener ) {
2020-04-26 16:52:50 +02:00
proxy . tcpListeners = append ( proxy . tcpListeners , listener )
}
func ( proxy * Proxy ) registerLocalDoHListener ( listener * net . TCPListener ) {
proxy . localDoHListeners = append ( proxy . localDoHListeners , listener )
}
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
2020-06-18 23:51:50 +02:00
listenerUDP , err := net . FilePacketConn ( os . NewFile ( InheritedDescriptorsBase + FileDescriptorNum , "listenerUDP" ) )
2019-11-24 22:12:23 +01:00
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
FileDescriptorNum ++
2018-06-13 16:52:41 +02:00
2020-06-18 23:51:50 +02:00
listenerTCP , err := net . FileListener ( os . NewFile ( InheritedDescriptorsBase + FileDescriptorNum , "listenerTCP" ) )
2019-11-24 22:12:23 +01:00
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 )
2020-06-19 11:37:53 +02:00
proxy . registerUDPListener ( 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 )
2020-06-19 11:37:53 +02:00
proxy . registerTCPListener ( listenerTCP . ( * net . TCPListener ) )
2019-11-24 22:12:23 +01:00
}
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
2020-06-18 23:51:50 +02:00
listenerTCP , err := net . FileListener ( os . NewFile ( InheritedDescriptorsBase + FileDescriptorNum , "listenerTCP" ) )
2019-11-24 22:45:43 +01:00
if err != nil {
dlog . Fatalf ( "Unable to switch to a different user: %v" , err )
}
FileDescriptorNum ++
2020-04-26 16:52:50 +02:00
proxy . registerLocalDoHListener ( listenerTCP . ( * net . TCPListener ) )
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
}
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 )
2020-05-31 13:24:35 +02:00
proxy . startAcceptingClients ( )
2018-01-29 23:47:04 +01:00
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 ) )
2021-01-01 14:04:12 +01:00
proxy . updateRegisteredServers ( )
2020-06-09 09:52:59 +02:00
runtime . GC ( )
2019-10-31 02:22:48 +01:00
}
} ( )
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
}
2020-06-09 09:41:58 +02:00
runtime . GC ( )
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
}
2021-01-01 14:04:12 +01:00
func ( proxy * Proxy ) updateRegisteredServers ( ) error {
for _ , source := range proxy . sources {
registeredServers , err := source . Parse ( )
if err != nil {
if len ( registeredServers ) == 0 {
dlog . Criticalf ( "Unable to use source [%s]: [%s]" , source . name , err )
return err
}
dlog . Warnf ( "Error in source [%s]: [%s] -- Continuing with reduced server count [%d]" , source . name , err , len ( registeredServers ) )
}
for _ , registeredServer := range registeredServers {
if registeredServer . stamp . Proto != stamps . StampProtoTypeDNSCryptRelay && registeredServer . stamp . Proto != stamps . StampProtoTypeODoHRelay {
if len ( proxy . ServerNames ) > 0 {
if ! includesName ( proxy . ServerNames , registeredServer . name ) {
continue
}
} else if registeredServer . stamp . Props & proxy . requiredProps != proxy . requiredProps {
continue
}
}
if includesName ( proxy . DisabledServerNames , registeredServer . name ) {
continue
}
if proxy . SourceIPv4 || proxy . SourceIPv6 {
isIPv4 , isIPv6 := true , false
if registeredServer . stamp . Proto == stamps . StampProtoTypeDoH {
isIPv4 , isIPv6 = true , true
}
if strings . HasPrefix ( registeredServer . stamp . ServerAddrStr , "[" ) {
isIPv4 , isIPv6 = false , true
}
if ! ( proxy . SourceIPv4 == isIPv4 || proxy . SourceIPv6 == isIPv6 ) {
continue
}
}
if registeredServer . stamp . Proto == stamps . StampProtoTypeDNSCryptRelay || registeredServer . stamp . Proto == stamps . StampProtoTypeODoHRelay {
var found bool
for i , currentRegisteredRelay := range proxy . registeredRelays {
if currentRegisteredRelay . name == registeredServer . name {
found = true
if currentRegisteredRelay . stamp . String ( ) != registeredServer . stamp . String ( ) {
dlog . Infof ( "Updating stamp for [%s] was: %s now: %s" , registeredServer . name , currentRegisteredRelay . stamp . String ( ) , registeredServer . stamp . String ( ) )
proxy . registeredRelays [ i ] . stamp = registeredServer . stamp
dlog . Debugf ( "Total count of registered relays %v" , len ( proxy . registeredRelays ) )
}
}
}
if ! found {
dlog . Debugf ( "Adding [%s] to the set of available relays" , registeredServer . name )
proxy . registeredRelays = append ( proxy . registeredRelays , registeredServer )
}
} else {
if ! ( ( proxy . SourceDNSCrypt && registeredServer . stamp . Proto == stamps . StampProtoTypeDNSCrypt ) ||
( proxy . SourceDoH && registeredServer . stamp . Proto == stamps . StampProtoTypeDoH ) ) {
continue
}
var found bool
for i , currentRegisteredServer := range proxy . registeredServers {
if currentRegisteredServer . name == registeredServer . name {
found = true
if currentRegisteredServer . stamp . String ( ) != registeredServer . stamp . String ( ) {
dlog . Infof ( "Updating stamp for [%s] was: %s now: %s" , registeredServer . name , currentRegisteredServer . stamp . String ( ) , registeredServer . stamp . String ( ) )
proxy . registeredServers [ i ] . stamp = registeredServer . stamp
}
}
}
if ! found {
dlog . Debugf ( "Adding [%s] to the set of wanted resolvers" , registeredServer . name )
proxy . registeredServers = append ( proxy . registeredServers , registeredServer )
dlog . Debugf ( "Total count of registered servers %v" , len ( proxy . registeredServers ) )
}
}
}
}
for _ , registeredServer := range proxy . registeredServers {
proxy . serversInfo . registerServer ( registeredServer . name , registeredServer . stamp )
}
return nil
}
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
} ( )
}
}
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 ( )
2020-03-13 18:44:30 +01:00
if err := clientPc . SetDeadline ( time . Now ( ) . Add ( proxy . timeout ) ) ; err != nil {
2019-12-09 12:11:24 +01:00
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
} ( )
}
}
2020-11-25 18:15:48 +01:00
func ( proxy * Proxy ) udpListenerFromAddr ( listenAddr * net . UDPAddr ) error {
listenConfig , err := proxy . udpListenerConfig ( )
if err != nil {
return err
}
clientPc , err := listenConfig . ListenPacket ( context . Background ( ) , "udp" , listenAddr . String ( ) )
if err != nil {
return err
}
proxy . registerUDPListener ( clientPc . ( * net . UDPConn ) )
dlog . Noticef ( "Now listening to %v [UDP]" , listenAddr )
return nil
}
2019-10-31 17:49:48 +01:00
func ( proxy * Proxy ) tcpListenerFromAddr ( listenAddr * net . TCPAddr ) error {
2020-11-25 18:15:48 +01:00
listenConfig , err := proxy . tcpListenerConfig ( )
2018-01-29 23:47:04 +01:00
if err != nil {
2019-10-31 17:49:48 +01:00
return err
2018-01-29 23:47:04 +01:00
}
2020-11-25 18:15:48 +01:00
acceptPc , err := listenConfig . Listen ( context . Background ( ) , "tcp" , listenAddr . String ( ) )
if err != nil {
return err
}
proxy . registerTCPListener ( acceptPc . ( * net . TCPListener ) )
2018-01-29 23:47:04 +01:00
dlog . Noticef ( "Now listening to %v [TCP]" , listenAddr )
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 {
2020-11-25 18:15:48 +01:00
listenConfig , err := proxy . tcpListenerConfig ( )
if err != nil {
return err
}
acceptPc , err := listenConfig . Listen ( context . Background ( ) , "tcp" , listenAddr . String ( ) )
2019-11-24 22:45:43 +01:00
if err != nil {
return err
}
2020-11-25 18:15:48 +01:00
proxy . registerLocalDoHListener ( acceptPc . ( * net . TCPListener ) )
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
return nil
}
2020-04-26 12:52:55 +02:00
func ( proxy * Proxy ) startAcceptingClients ( ) {
for _ , clientPc := range proxy . udpListeners {
2020-04-26 14:26:40 +02:00
go proxy . udpListener ( clientPc )
2020-04-26 12:52:55 +02:00
}
proxy . udpListeners = nil
for _ , acceptPc := range proxy . tcpListeners {
2020-04-26 14:26:40 +02:00
go proxy . tcpListener ( acceptPc )
2020-04-26 12:52:55 +02:00
}
proxy . tcpListeners = nil
for _ , acceptPc := range proxy . localDoHListeners {
2020-04-26 14:26:40 +02:00
go proxy . localDoHListener ( acceptPc )
2020-04-26 12:52:55 +02:00
}
proxy . localDoHListeners = 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
2020-12-12 21:18:32 +01:00
if serverInfo . Relay != nil && serverInfo . Relay . Dnscrypt != nil {
upstreamAddr = serverInfo . Relay . Dnscrypt . RelayUDPAddr
2019-10-14 01:45:38 +02:00
}
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 ( )
2020-03-13 18:44:30 +01:00
if err := pc . SetDeadline ( time . Now ( ) . Add ( serverInfo . Timeout ) ) ; err != nil {
2019-12-09 12:11:24 +01:00
return nil , err
}
2020-12-12 21:18:32 +01:00
if serverInfo . Relay != nil && serverInfo . Relay . Dnscrypt != nil {
2019-10-14 01:45:38 +02:00
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 -- {
2020-03-13 18:44:30 +01:00
if _ , err := pc . Write ( encryptedQuery ) ; err != nil {
2020-01-29 18:14:03 +01:00
return nil , err
}
length , err := pc . Read ( encryptedResponse )
if err == nil {
encryptedResponse = encryptedResponse [ : length ]
break
}
2020-03-26 13:30:39 +01:00
dlog . Debugf ( "[%v] Retry on timeout" , serverInfo . Name )
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
2020-12-12 21:18:32 +01:00
if serverInfo . Relay != nil && serverInfo . Relay . Dnscrypt != nil {
upstreamAddr = serverInfo . Relay . Dnscrypt . RelayTCPAddr
2019-10-14 01:45:38 +02:00
}
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 ( )
2020-03-13 18:44:30 +01:00
if err := pc . SetDeadline ( time . Now ( ) . Add ( serverInfo . Timeout ) ) ; err != nil {
2019-12-09 12:11:24 +01:00
return nil , err
}
2020-12-12 21:18:32 +01:00
if serverInfo . Relay != nil && serverInfo . Relay . Dnscrypt != nil {
2019-10-14 01:45:38 +02:00
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
}
2020-03-13 18:44:30 +01:00
if _ , err := pc . Write ( encryptedQuery ) ; err != nil {
2019-12-09 12:11:24 +01:00
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
}
2020-04-05 20:49:30 +02:00
pluginsState := NewPluginsState ( proxy , clientProto , clientAddr , serverProto , 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 )
2020-03-25 20:09:46 +01:00
if err != nil && serverProto == "udp" {
dlog . Debug ( "Unable to pad for UDP, re-encrypting query for TCP" )
serverProto = "tcp"
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 )
2020-03-25 17:45:59 +01:00
retryOverTCP := false
2019-10-12 20:55:59 +02:00
if err == nil && len ( response ) >= MinDNSPacketSize && response [ 2 ] & 0x02 == 0x02 {
2020-03-25 17:45:59 +01:00
retryOverTCP = true
} else if neterr , ok := err . ( net . Error ) ; ok && neterr . Timeout ( ) {
2020-03-26 13:30:39 +01:00
dlog . Debugf ( "[%v] Retry over TCP after UDP timeouts" , serverName )
2020-03-25 17:45:59 +01:00
retryOverTCP = true
}
if retryOverTCP {
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-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
}
}