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-02-04 11:31:54 +01:00
|
|
|
"io"
|
2018-01-29 23:47:04 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"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 {
|
2018-07-07 17:39:33 +02:00
|
|
|
userName string
|
2018-06-13 16:52:41 +02:00
|
|
|
child bool
|
2018-01-29 23:47:04 +01:00
|
|
|
proxyPublicKey [32]byte
|
|
|
|
proxySecretKey [32]byte
|
2018-04-09 03:12:34 +02:00
|
|
|
ephemeralKeys bool
|
2018-01-29 23:47:04 +01:00
|
|
|
questionSizeEstimator QuestionSizeEstimator
|
|
|
|
serversInfo ServersInfo
|
|
|
|
timeout time.Duration
|
|
|
|
certRefreshDelay time.Duration
|
|
|
|
certRefreshDelayAfterFailure time.Duration
|
|
|
|
certIgnoreTimestamp bool
|
|
|
|
mainProto string
|
|
|
|
listenAddresses []string
|
|
|
|
daemonize bool
|
|
|
|
registeredServers []RegisteredServer
|
2019-10-20 14:19:21 +02:00
|
|
|
registeredRelays []RegisteredServer
|
2018-01-29 23:47:04 +01:00
|
|
|
pluginBlockIPv6 bool
|
|
|
|
cache bool
|
|
|
|
cacheSize int
|
2018-04-17 00:24:49 +02:00
|
|
|
cacheNegMinTTL uint32
|
|
|
|
cacheNegMaxTTL uint32
|
2018-01-29 23:47:04 +01:00
|
|
|
cacheMinTTL uint32
|
|
|
|
cacheMaxTTL uint32
|
2019-10-21 18:26:49 +02:00
|
|
|
rejectTTL uint32
|
2019-10-17 16:19:07 +02:00
|
|
|
cloakTTL uint32
|
2018-01-29 23:47:04 +01:00
|
|
|
queryLogFile string
|
|
|
|
queryLogFormat string
|
|
|
|
queryLogIgnoredQtypes []string
|
|
|
|
nxLogFile string
|
|
|
|
nxLogFormat string
|
|
|
|
blockNameFile string
|
2018-04-07 23:02:40 +02:00
|
|
|
whitelistNameFile string
|
2018-01-29 23:47:04 +01:00
|
|
|
blockNameLogFile string
|
2018-04-07 23:02:40 +02:00
|
|
|
whitelistNameLogFile string
|
2018-01-29 23:47:04 +01:00
|
|
|
blockNameFormat string
|
2018-04-07 23:02:40 +02:00
|
|
|
whitelistNameFormat string
|
2018-01-29 23:47:04 +01:00
|
|
|
blockIPFile string
|
|
|
|
blockIPLogFile string
|
|
|
|
blockIPFormat string
|
|
|
|
forwardFile string
|
2018-02-04 01:43:37 +01:00
|
|
|
cloakFile string
|
2018-01-29 23:47:04 +01:00
|
|
|
pluginsGlobals PluginsGlobals
|
2019-10-31 02:04:08 +01:00
|
|
|
urlsToPrefetch []*URLToPrefetch
|
2018-01-29 23:47:04 +01:00
|
|
|
clientsCount uint32
|
|
|
|
maxClients uint32
|
2018-01-30 13:29:47 +01:00
|
|
|
xTransport *XTransport
|
2018-01-31 23:08:38 +01:00
|
|
|
allWeeklyRanges *map[string]WeeklyRanges
|
2018-03-02 10:34:00 +01:00
|
|
|
logMaxSize int
|
|
|
|
logMaxAge int
|
|
|
|
logMaxBackups int
|
2019-06-19 18:11:06 +02:00
|
|
|
blockedQueryResponse string
|
2019-09-07 16:19:47 +02:00
|
|
|
queryMeta []string
|
2019-10-14 12:08:47 +02:00
|
|
|
routes *map[string][]string
|
2019-06-07 01:23:48 +02:00
|
|
|
showCerts bool
|
2018-01-29 23:47:04 +01:00
|
|
|
}
|
|
|
|
|
2019-10-31 17:49:48 +01:00
|
|
|
func (proxy *Proxy) StartProxy() {
|
2018-01-29 23:47:04 +01:00
|
|
|
proxy.questionSizeEstimator = NewQuestionSizeEstimator()
|
2019-06-03 16:44:09 +02:00
|
|
|
if _, err := crypto_rand.Read(proxy.proxySecretKey[:]); err != nil {
|
2018-01-29 23:47:04 +01:00
|
|
|
dlog.Fatal(err)
|
|
|
|
}
|
2019-09-09 17:39:38 +02:00
|
|
|
curve25519.ScalarBaseMult(&proxy.proxyPublicKey, &proxy.proxySecretKey)
|
2018-01-29 23:47:04 +01:00
|
|
|
for _, registeredServer := range proxy.registeredServers {
|
2019-10-09 17:25:27 +02:00
|
|
|
proxy.serversInfo.registerServer(registeredServer.name, registeredServer.stamp)
|
2018-01-29 23:47:04 +01:00
|
|
|
}
|
2018-06-13 16:52:41 +02:00
|
|
|
|
2018-01-29 23:47:04 +01:00
|
|
|
for _, listenAddrStr := range proxy.listenAddresses {
|
|
|
|
listenUDPAddr, err := net.ResolveUDPAddr("udp", listenAddrStr)
|
|
|
|
if err != nil {
|
|
|
|
dlog.Fatal(err)
|
|
|
|
}
|
|
|
|
listenTCPAddr, err := net.ResolveTCPAddr("tcp", listenAddrStr)
|
|
|
|
if err != nil {
|
|
|
|
dlog.Fatal(err)
|
|
|
|
}
|
2018-06-13 16:52:41 +02:00
|
|
|
|
2018-07-07 17:39:33 +02:00
|
|
|
// if 'userName' is not set, continue as before
|
|
|
|
if !(len(proxy.userName) > 0) {
|
2019-10-31 17:49:48 +01:00
|
|
|
if err := proxy.udpListenerFromAddr(listenUDPAddr); err != nil {
|
2018-06-13 16:52:41 +02:00
|
|
|
dlog.Fatal(err)
|
|
|
|
}
|
2019-10-31 17:49:48 +01:00
|
|
|
if err := proxy.tcpListenerFromAddr(listenTCPAddr); err != nil {
|
2018-06-13 16:52:41 +02:00
|
|
|
dlog.Fatal(err)
|
|
|
|
}
|
|
|
|
} else {
|
2018-07-07 17:39:33 +02:00
|
|
|
// if 'userName' is set and we are the parent process
|
2018-06-13 16:52:41 +02:00
|
|
|
if !proxy.child {
|
|
|
|
// parent
|
|
|
|
listenerUDP, err := net.ListenUDP("udp", listenUDPAddr)
|
|
|
|
if err != nil {
|
|
|
|
dlog.Fatal(err)
|
|
|
|
}
|
|
|
|
listenerTCP, err := net.ListenTCP("tcp", listenTCPAddr)
|
|
|
|
if err != nil {
|
|
|
|
dlog.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
fdUDP, err := listenerUDP.File() // On Windows, the File method of UDPConn is not implemented.
|
|
|
|
if err != nil {
|
2019-10-25 12:53:59 +02:00
|
|
|
dlog.Fatalf("Unable to switch to a different user: %v", err)
|
2018-06-13 16:52:41 +02:00
|
|
|
}
|
|
|
|
fdTCP, err := listenerTCP.File() // On Windows, the File method of TCPListener is not implemented.
|
|
|
|
if err != nil {
|
2019-10-25 12:53:59 +02:00
|
|
|
dlog.Fatalf("Unable to switch to a different user: %v", err)
|
2018-06-13 16:52:41 +02:00
|
|
|
}
|
2019-10-31 17:36:59 +01:00
|
|
|
defer listenerUDP.Close()
|
|
|
|
defer listenerTCP.Close()
|
2018-06-13 16:52:41 +02:00
|
|
|
FileDescriptors = append(FileDescriptors, fdUDP)
|
|
|
|
FileDescriptors = append(FileDescriptors, fdTCP)
|
|
|
|
|
2018-07-07 17:39:33 +02:00
|
|
|
// if 'userName' is set and we are the child process
|
2018-06-13 16:52:41 +02:00
|
|
|
} else {
|
|
|
|
// child
|
|
|
|
listenerUDP, err := net.FilePacketConn(os.NewFile(uintptr(3+FileDescriptorNum), "listenerUDP"))
|
|
|
|
if err != nil {
|
2019-10-25 12:53:59 +02:00
|
|
|
dlog.Fatalf("Unable to switch to a different user: %v", err)
|
2018-06-13 16:52:41 +02:00
|
|
|
}
|
|
|
|
FileDescriptorNum++
|
|
|
|
|
|
|
|
listenerTCP, err := net.FileListener(os.NewFile(uintptr(3+FileDescriptorNum), "listenerTCP"))
|
|
|
|
if err != nil {
|
2019-10-25 12:53:59 +02:00
|
|
|
dlog.Fatalf("Unable to switch to a different user: %v", err)
|
2018-06-13 16:52:41 +02:00
|
|
|
}
|
|
|
|
FileDescriptorNum++
|
|
|
|
|
|
|
|
dlog.Noticef("Now listening to %v [UDP]", listenUDPAddr)
|
|
|
|
go proxy.udpListener(listenerUDP.(*net.UDPConn))
|
|
|
|
|
|
|
|
dlog.Noticef("Now listening to %v [TCP]", listenAddrStr)
|
|
|
|
go proxy.tcpListener(listenerTCP.(*net.TCPListener))
|
|
|
|
}
|
2018-01-29 23:47:04 +01:00
|
|
|
}
|
|
|
|
}
|
2018-06-13 16:52:41 +02:00
|
|
|
|
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:04:08 +01:00
|
|
|
proxy.prefetcher(proxy.urlsToPrefetch)
|
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
|
|
|
}
|
|
|
|
|
2019-10-31 02:04:08 +01:00
|
|
|
func (proxy *Proxy) prefetcher(urlsToPrefetch []*URLToPrefetch) {
|
2019-10-31 17:49:48 +01:00
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
now := time.Now()
|
2019-10-31 02:04:08 +01:00
|
|
|
for _, urlToPrefetch := range urlsToPrefetch {
|
2019-10-31 17:49:48 +01:00
|
|
|
if now.After(urlToPrefetch.when) {
|
|
|
|
dlog.Debugf("Prefetching [%s]", urlToPrefetch.url)
|
|
|
|
if err := PrefetchSourceURL(proxy.xTransport, urlToPrefetch); err != nil {
|
|
|
|
dlog.Debugf("Prefetching [%s] failed: %s", urlToPrefetch.url, err)
|
|
|
|
} else {
|
|
|
|
dlog.Debugf("Prefetching [%s] succeeded. Next refresh scheduled for %v", urlToPrefetch.url, urlToPrefetch.when)
|
|
|
|
}
|
2018-01-29 23:47:04 +01:00
|
|
|
}
|
|
|
|
}
|
2019-10-31 17:49:48 +01:00
|
|
|
clocksmith.Sleep(60 * time.Second)
|
2018-01-29 23:47:04 +01:00
|
|
|
}
|
2019-10-31 17:49:48 +01: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() {
|
|
|
|
dlog.Warnf("Too many connections (max=%d)", proxy.maxClients)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer proxy.clientsCountDec()
|
2019-05-26 21:16:47 +02:00
|
|
|
proxy.processIncomingQuery(proxy.serversInfo.getOne(), "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() {
|
|
|
|
dlog.Warnf("Too many connections (max=%d)", proxy.maxClients)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer proxy.clientsCountDec()
|
|
|
|
clientPc.SetDeadline(time.Now().Add(proxy.timeout))
|
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()
|
2019-05-26 21:16:47 +02:00
|
|
|
proxy.processIncomingQuery(proxy.serversInfo.getOne(), "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-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
|
|
|
|
}
|
|
|
|
pc, err := net.DialUDP("udp", nil, upstreamAddr)
|
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()
|
2018-01-29 23:47:04 +01:00
|
|
|
pc.SetDeadline(time.Now().Add(serverInfo.Timeout))
|
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
|
|
|
pc.Write(encryptedQuery)
|
|
|
|
encryptedResponse := make([]byte, MaxDNSPacketSize)
|
|
|
|
length, err := pc.Read(encryptedResponse)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
encryptedResponse = encryptedResponse[:length]
|
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 {
|
2019-10-20 21:45:19 +02:00
|
|
|
pc, err = (*proxyDialer).Dial("tcp", serverInfo.TCPAddr.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()
|
2018-06-06 19:06:44 +02:00
|
|
|
pc.SetDeadline(time.Now().Add(serverInfo.Timeout))
|
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
|
|
|
|
}
|
2018-06-06 19:06:44 +02:00
|
|
|
pc.Write(encryptedQuery)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-26 21:16:47 +02:00
|
|
|
func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto string, serverProto string, query []byte, clientAddr *net.Addr, clientPc net.Conn, start time.Time) {
|
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 := "-"
|
|
|
|
if serverInfo != nil {
|
|
|
|
serverName = serverInfo.Name
|
|
|
|
}
|
|
|
|
query, _ = pluginsState.ApplyQueryPlugins(&proxy.pluginsGlobals, query, serverName)
|
2019-06-03 00:47:39 +02:00
|
|
|
if len(query) < MinDNSPacketSize || len(query) > MaxDNSPacketSize {
|
|
|
|
return
|
|
|
|
}
|
2018-01-29 23:47:04 +01:00
|
|
|
var response []byte
|
|
|
|
var err error
|
|
|
|
if pluginsState.action != PluginsActionForward {
|
|
|
|
if pluginsState.synthResponse != nil {
|
|
|
|
response, err = pluginsState.synthResponse.PackBuffer(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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if pluginsState.action == PluginsActionDrop {
|
2018-06-04 23:18:28 +02:00
|
|
|
pluginsState.returnCode = PluginsReturnCodeDrop
|
2019-11-05 00:54:03 +01:00
|
|
|
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
|
2018-01-29 23:47:04 +01:00
|
|
|
return
|
|
|
|
}
|
2018-06-04 23:18:28 +02:00
|
|
|
} else {
|
|
|
|
pluginsState.returnCode = PluginsReturnCodeForward
|
2018-01-29 23:47:04 +01:00
|
|
|
}
|
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
|
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
|
|
|
}
|
|
|
|
if err != nil {
|
2019-10-19 10:15:41 +02:00
|
|
|
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
|
|
|
|
pluginsState.returnCode = PluginsReturnCodeServerTimeout
|
|
|
|
} else {
|
|
|
|
pluginsState.returnCode = PluginsReturnCodeServerError
|
|
|
|
}
|
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)
|
2019-05-28 22:42:22 +02:00
|
|
|
resp, _, err := proxy.xTransport.DoHQuery(serverInfo.useGet, serverInfo.URL, query, proxy.timeout)
|
2018-02-04 12:57:54 +01:00
|
|
|
SetTransactionID(query, tid)
|
2018-01-30 15:46:21 +01:00
|
|
|
if err != nil {
|
2018-06-04 23:18:28 +02:00
|
|
|
pluginsState.returnCode = PluginsReturnCodeServerError
|
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 11:31:54 +01:00
|
|
|
response, err = ioutil.ReadAll(io.LimitReader(resp.Body, int64(MaxDNSPacketSize)))
|
2018-01-29 23:47:04 +01:00
|
|
|
if err != nil {
|
2018-06-04 23:18:28 +02:00
|
|
|
pluginsState.returnCode = PluginsReturnCodeServerError
|
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-10-18 20:51:11 +02:00
|
|
|
if rcode := Rcode(response); rcode == dns.RcodeServerFailure { // SERVFAIL
|
2018-04-12 11:07:34 +02:00
|
|
|
dlog.Infof("Server [%v] returned temporary error code [%v] -- Upstream server may be experiencing connectivity issues", serverInfo.Name, rcode)
|
2018-02-22 14:20:59 +01:00
|
|
|
serverInfo.noticeFailure(proxy)
|
|
|
|
} 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))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
clientPc.Write(response)
|
|
|
|
}
|
2019-11-05 00:54:03 +01:00
|
|
|
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
|
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
|
|
|
}
|
|
|
|
}
|