dnscrypt-proxy/dnscrypt-proxy/proxy.go

678 lines
21 KiB
Go
Raw Normal View History

2018-01-29 23:47:04 +01:00
package main
import (
"context"
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"
2018-01-29 23:47:04 +01:00
"sync/atomic"
"time"
"github.com/jedisct1/dlog"
clocksmith "github.com/jedisct1/go-clocksmith"
stamps "github.com/jedisct1/go-dnsstamps"
"github.com/miekg/dns"
"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
udpListeners []*net.UDPConn
2020-11-14 14:46:59 +01:00
sources []*Source
tcpListeners []*net.TCPListener
2020-11-14 14:46:59 +01:00
registeredRelays []RegisteredServer
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
nxLogFormat string
localDoHCertFile string
localDoHCertKeyFile string
2020-11-14 14:46:59 +01:00
captivePortalFile string
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
queryLogFormat string
2020-11-14 14:46:59 +01:00
blockIPFile string
whitelistNameFormat string
whitelistNameLogFile string
2020-11-14 14:46:59 +01:00
blockNameLogFile string
whitelistNameFile string
blockNameFile string
queryLogFile string
blockedQueryResponse string
userName string
nxLogFile string
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
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
showCerts bool
2020-11-14 14:46:59 +01:00
certIgnoreTimestamp bool
skipAnonIncompatbibleResolvers bool
anonDirectCertFallback bool
2020-11-14 14:46:59 +01:00
pluginBlockUndelegated bool
child bool
daemonize bool
2018-01-29 23:47:04 +01:00
}
2020-06-19 11:37:53 +02:00
func (proxy *Proxy) registerUDPListener(conn *net.UDPConn) {
proxy.udpListeners = append(proxy.udpListeners, conn)
}
2020-06-19 11:37:53 +02:00
func (proxy *Proxy) registerTCPListener(listener *net.TCPListener) {
proxy.tcpListeners = append(proxy.tcpListeners, listener)
}
func (proxy *Proxy) registerLocalDoHListener(listener *net.TCPListener) {
proxy.localDoHListeners = append(proxy.localDoHListeners, listener)
}
func (proxy *Proxy) addDNSListener(listenAddrStr string) {
listenUDPAddr, err := net.ResolveUDPAddr("udp", listenAddrStr)
if err != nil {
2018-01-29 23:47:04 +01:00
dlog.Fatal(err)
}
listenTCPAddr, err := net.ResolveTCPAddr("tcp", listenAddrStr)
if err != nil {
dlog.Fatal(err)
2018-01-29 23:47:04 +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)
}
listenerTCP, err := net.ListenTCP("tcp", listenTCPAddr)
2018-01-29 23:47:04 +01:00
if err != nil {
dlog.Fatal(err)
}
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
}
// child
listenerUDP, err := net.FilePacketConn(os.NewFile(InheritedDescriptorsBase+FileDescriptorNum, "listenerUDP"))
if err != nil {
dlog.Fatalf("Unable to switch to a different user: %v", err)
}
FileDescriptorNum++
listenerTCP, err := net.FileListener(os.NewFile(InheritedDescriptorsBase+FileDescriptorNum, "listenerTCP"))
if err != nil {
dlog.Fatalf("Unable to switch to a different user: %v", err)
}
FileDescriptorNum++
dlog.Noticef("Now listening to %v [UDP]", listenUDPAddr)
2020-06-19 11:37:53 +02:00
proxy.registerUDPListener(listenerUDP.(*net.UDPConn))
dlog.Noticef("Now listening to %v [TCP]", listenAddrStr)
2020-06-19 11:37:53 +02:00
proxy.registerTCPListener(listenerTCP.(*net.TCPListener))
}
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(InheritedDescriptorsBase+FileDescriptorNum, "listenerTCP"))
if err != nil {
dlog.Fatalf("Unable to switch to a different user: %v", err)
}
FileDescriptorNum++
proxy.registerLocalDoHListener(listenerTCP.(*net.TCPListener))
dlog.Noticef("Now listening to https://%v%v [DoH]", listenAddrStr, proxy.localDoHPath)
}
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)
}
proxy.startAcceptingClients()
2018-01-29 23:47:04 +01:00
liveServers, err := proxy.serversInfo.refresh(proxy)
if liveServers > 0 {
proxy.certIgnoreTimestamp = false
}
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)
if !proxy.child {
if err := ServiceManagerReadyNotify(); err != nil {
dlog.Fatal(err)
}
}
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")
}
go func() {
for {
clocksmith.Sleep(PrefetchSources(proxy.xTransport, proxy.sources))
2020-06-09 09:52:59 +02:00
runtime.GC()
}
}()
2018-07-05 18:05:24 +02:00
if len(proxy.serversInfo.registeredServers) > 0 {
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()
}
}()
2018-07-05 18:05:24 +02:00
}
2018-01-29 23:47:04 +01:00
}
func (proxy *Proxy) udpListener(clientPc *net.UDPConn) {
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() {
start := time.Now()
2018-01-29 23:47:04 +01:00
if !proxy.clientsCountInc() {
dlog.Warnf("Too many incoming connections (max=%d)", proxy.maxClients)
2018-01-29 23:47:04 +01:00
return
}
defer proxy.clientsCountDec()
proxy.processIncomingQuery("udp", proxy.mainProto, packet, &clientAddr, clientPc, start)
2018-01-29 23:47:04 +01:00
}()
}
}
func (proxy *Proxy) tcpListener(acceptPc *net.TCPListener) {
defer acceptPc.Close()
2018-01-29 23:47:04 +01:00
for {
clientPc, err := acceptPc.Accept()
if err != nil {
continue
}
go func() {
start := time.Now()
2018-01-29 23:47:04 +01:00
defer clientPc.Close()
if !proxy.clientsCountInc() {
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)
if err != nil {
2018-01-29 23:47:04 +01:00
return
}
clientAddr := clientPc.RemoteAddr()
proxy.processIncomingQuery("tcp", "tcp", packet, &clientAddr, clientPc, start)
2018-01-29 23:47:04 +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
}
func (proxy *Proxy) tcpListenerFromAddr(listenAddr *net.TCPAddr) error {
listenConfig, err := proxy.tcpListenerConfig()
2018-01-29 23:47:04 +01:00
if err != nil {
return err
2018-01-29 23:47:04 +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)
return nil
2018-01-29 23:47:04 +01:00
}
func (proxy *Proxy) localDoHListenerFromAddr(listenAddr *net.TCPAddr) error {
listenConfig, err := proxy.tcpListenerConfig()
if err != nil {
return err
}
acceptPc, err := listenConfig.Listen(context.Background(), "tcp", listenAddr.String())
if err != nil {
return err
}
proxy.registerLocalDoHListener(acceptPc.(*net.TCPListener))
dlog.Noticef("Now listening to https://%v%v [DoH]", listenAddr, proxy.localDoHPath)
return nil
}
func (proxy *Proxy) startAcceptingClients() {
for _, clientPc := range proxy.udpListeners {
2020-04-26 14:26:40 +02:00
go proxy.udpListener(clientPc)
}
proxy.udpListeners = nil
for _, acceptPc := range proxy.tcpListeners {
2020-04-26 14:26:40 +02:00
go proxy.tcpListener(acceptPc)
}
proxy.tcpListeners = nil
for _, acceptPc := range proxy.localDoHListeners {
2020-04-26 14:26:40 +02:00
go proxy.localDoHListener(acceptPc)
}
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
}
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
}
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
}
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
}
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-- {
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
}
return proxy.Decrypt(serverInfo, sharedKey, encryptedResponse, clientNonce)
2018-01-29 23:47:04 +01: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
}
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 {
pc, err = (*proxyDialer).Dial("tcp", upstreamAddr.String())
2018-01-29 23:47:04 +01:00
}
if err != nil {
return nil, err
}
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
}
2019-10-14 01:45:38 +02:00
if serverInfo.RelayTCPAddr != nil {
proxy.prepareForRelay(serverInfo.TCPAddr.IP, serverInfo.TCPAddr.Port, &encryptedQuery)
}
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
}
encryptedResponse, err := ReadPrefixed(&pc)
2018-07-09 15:49:36 +02:00
if err != nil {
return nil, err
}
return proxy.Decrypt(serverInfo, sharedKey, encryptedResponse, clientNonce)
2018-01-29 23:47:04 +01:00
}
func (proxy *Proxy) clientsCountInc() bool {
for {
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) {
dlog.Debugf("clients count: %d", count+1)
2018-01-29 23:47:04 +01:00
return true
}
}
}
func (proxy *Proxy) clientsCountDec() {
for {
if count := atomic.LoadUint32(&proxy.clientsCount); count == 0 || atomic.CompareAndSwapUint32(&proxy.clientsCount, count, count-1) {
2018-01-29 23:47:04 +01:00
break
}
}
}
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
}
pluginsState := NewPluginsState(proxy, clientProto, clientAddr, serverProto, start)
serverName := "-"
2019-12-23 11:37:45 +01:00
needsEDNS0Padding := false
serverInfo := proxy.serversInfo.getOne()
if serverInfo != nil {
serverName = serverInfo.Name
2019-12-23 11:37:45 +01:00
needsEDNS0Padding = (serverInfo.Proto == stamps.StampProtoTypeDoH || serverInfo.Proto == stamps.StampProtoTypeTLS)
}
query, _ = pluginsState.ApplyQueryPlugins(&proxy.pluginsGlobals, query, needsEDNS0Padding)
if len(query) < MinDNSPacketSize || len(query) > MaxDNSPacketSize {
return
}
if pluginsState.action == PluginsActionDrop {
pluginsState.returnCode = PluginsReturnCodeDrop
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
return
}
2018-01-29 23:47:04 +01:00
var err error
if pluginsState.synthResponse != nil {
response, err = pluginsState.synthResponse.PackBuffer(response)
if err != nil {
pluginsState.returnCode = PluginsReturnCodeParseError
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 {
var ttl *uint32
pluginsState.serverName = serverName
2018-04-14 15:03:21 +02:00
if serverInfo.Proto == stamps.StampProtoTypeDNSCrypt {
sharedKey, encryptedQuery, clientNonce, err := proxy.Encrypt(serverInfo, query, serverProto)
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)
}
if err != nil {
2018-06-04 23:18:28 +02:00
pluginsState.returnCode = PluginsReturnCodeParseError
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
return
}
serverInfo.noticeBegin(proxy)
if serverProto == "udp" {
response, err = proxy.exchangeWithUDPServer(serverInfo, sharedKey, encryptedQuery, clientNonce)
2020-03-25 17:45:59 +01:00
retryOverTCP := false
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"
sharedKey, encryptedQuery, clientNonce, err = proxy.Encrypt(serverInfo, query, serverProto)
2019-10-20 02:04:32 +02:00
if err != nil {
pluginsState.returnCode = PluginsReturnCodeParseError
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
2019-10-20 23:07:36 +02:00
return
2019-10-20 02:04:32 +02:00
}
response, err = proxy.exchangeWithTCPServer(serverInfo, sharedKey, encryptedQuery, clientNonce)
}
} else {
response, err = proxy.exchangeWithTCPServer(serverInfo, sharedKey, encryptedQuery, clientNonce)
}
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()
}
}
if err != nil {
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
pluginsState.returnCode = PluginsReturnCodeServerTimeout
} else {
2019-11-17 19:48:15 +01:00
pluginsState.returnCode = PluginsReturnCodeNetworkError
}
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
serverInfo.noticeFailure(proxy)
return
}
2018-04-14 15:03:21 +02:00
} else if serverInfo.Proto == stamps.StampProtoTypeDoH {
tid := TransactionID(query)
SetTransactionID(query, 0)
serverInfo.noticeBegin(proxy)
serverResponse, tls, _, err := proxy.xTransport.DoHQuery(serverInfo.useGet, serverInfo.URL, query, proxy.timeout)
SetTransactionID(query, tid)
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()
}
if err != nil {
2019-11-17 19:48:15 +01:00
pluginsState.returnCode = PluginsReturnCodeNetworkError
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
serverInfo.noticeFailure(proxy)
2018-01-29 23:47:04 +01:00
return
}
2020-01-30 13:15:29 +01:00
if response == nil {
response = serverResponse
2020-01-30 13:15:29 +01:00
}
if len(response) >= MinDNSPacketSize {
SetTransactionID(response, tid)
}
2018-01-29 23:47:04 +01:00
} else {
dlog.Fatal("Unsupported protocol")
}
if len(response) < MinDNSPacketSize || len(response) > MaxDNSPacketSize {
2018-06-04 23:18:28 +02:00
pluginsState.returnCode = PluginsReturnCodeParseError
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
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
pluginsState.ApplyLoggingPlugins(&proxy.pluginsGlobals)
2018-01-29 23:47:04 +01:00
serverInfo.noticeFailure(proxy)
return
}
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
}
}
if rcode := Rcode(response); rcode == dns.RcodeServerFailure { // SERVFAIL
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)
}
} 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
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" {
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
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
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
}
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
}
2019-10-09 17:59:46 +02:00
func NewProxy() *Proxy {
return &Proxy{
serversInfo: NewServersInfo(),
}
}