Implement Anonymized DNS

This commit is contained in:
Frank Denis 2019-10-14 01:45:38 +02:00
parent 63e6dbdac7
commit 0e8ca9009e
3 changed files with 86 additions and 3 deletions

View File

@ -83,6 +83,7 @@ type Config struct {
RefusedCodeInResponses bool `toml:"refused_code_in_responses"`
BlockedQueryResponse string `toml:"blocked_query_response"`
QueryMeta []string `toml:"query_meta"`
AnonymizedDNS AnonymizedDNSConfig `toml:"anonymized_dns"`
}
func newConfig() Config {
@ -166,6 +167,15 @@ type BlockIPConfig struct {
Format string `toml:"log_format"`
}
type AnonymizedDNSRouteConfig struct {
ServerName string `toml:"server_name"`
RelayName string `toml:"via"`
}
type AnonymizedDNSConfig struct {
Routes []AnonymizedDNSRouteConfig `toml:"routes"`
}
type ServerSummary struct {
Name string `json:"name"`
Proto string `json:"proto"`
@ -422,6 +432,15 @@ func ConfigLoad(proxy *Proxy, svcFlag *string) error {
}
proxy.allWeeklyRanges = allWeeklyRanges
if configRoutes := config.AnonymizedDNS.Routes; configRoutes != nil {
routes := make(map[string]string)
for _, configRoute := range configRoutes {
routes[configRoute.ServerName] = configRoute.RelayName
dlog.Debugf("Routing server [%s] via [%s]", configRoute.ServerName, configRoute.RelayName)
}
proxy.routes = &routes
}
if *listAll {
config.ServerNames = nil
config.DisabledServerNames = nil

View File

@ -2,6 +2,7 @@ package main
import (
crypto_rand "crypto/rand"
"encoding/binary"
"io"
"io/ioutil"
"net"
@ -65,6 +66,7 @@ type Proxy struct {
logMaxBackups int
blockedQueryResponse string
queryMeta []string
routes *map[string]string
showCerts bool
}
@ -268,12 +270,29 @@ func (proxy *Proxy) tcpListenerFromAddr(listenAddr *net.TCPAddr) error {
return nil
}
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) {
pc, err := net.DialUDP("udp", nil, serverInfo.UDPAddr)
upstreamAddr := serverInfo.UDPAddr
if serverInfo.RelayUDPAddr != nil {
upstreamAddr = serverInfo.RelayUDPAddr
}
pc, err := net.DialUDP("udp", nil, upstreamAddr)
if err != nil {
return nil, err
}
pc.SetDeadline(time.Now().Add(serverInfo.Timeout))
if serverInfo.RelayUDPAddr != nil {
proxy.prepareForRelay(serverInfo.UDPAddr.IP, serverInfo.UDPAddr.Port, &encryptedQuery)
}
pc.Write(encryptedQuery)
encryptedResponse := make([]byte, MaxDNSPacketSize)
length, err := pc.Read(encryptedResponse)
@ -286,18 +305,25 @@ func (proxy *Proxy) exchangeWithUDPServer(serverInfo *ServerInfo, sharedKey *[32
}
func (proxy *Proxy) exchangeWithTCPServer(serverInfo *ServerInfo, sharedKey *[32]byte, encryptedQuery []byte, clientNonce []byte) ([]byte, error) {
upstreamAddr := serverInfo.TCPAddr
if serverInfo.RelayUDPAddr != nil {
upstreamAddr = serverInfo.RelayTCPAddr
}
var err error
var pc net.Conn
proxyDialer := proxy.xTransport.proxyDialer
if proxyDialer == nil {
pc, err = net.Dial("tcp", serverInfo.TCPAddr.String())
pc, err = net.DialTCP("tcp", nil, upstreamAddr)
} else {
pc, err = (*proxyDialer).Dial("tcp", serverInfo.TCPAddr.String())
pc, err = (*proxyDialer).Dial("tcp", upstreamAddr.String())
}
if err != nil {
return nil, err
}
pc.SetDeadline(time.Now().Add(serverInfo.Timeout))
if serverInfo.RelayTCPAddr != nil {
proxy.prepareForRelay(serverInfo.TCPAddr.IP, serverInfo.TCPAddr.Port, &encryptedQuery)
}
encryptedQuery, err = PrefixWithSize(encryptedQuery)
if err != nil {
return nil, err

View File

@ -43,6 +43,8 @@ type ServerInfo struct {
HostName string
UDPAddr *net.UDPAddr
TCPAddr *net.TCPAddr
RelayUDPAddr *net.UDPAddr
RelayTCPAddr *net.TCPAddr
lastActionTS time.Time
rtt ewma.MovingAverage
initialRtt int
@ -258,6 +260,40 @@ func (serversInfo *ServersInfo) fetchDNSCryptServerInfo(proxy *Proxy, name strin
if err != nil {
return ServerInfo{}, err
}
var relayUDPAddr *net.UDPAddr
var relayTCPAddr *net.TCPAddr
routes := proxy.routes
if routes != nil {
if relayName, ok := (*routes)[name]; ok {
var relayCandidateStamp *stamps.ServerStamp
if stamp, err = stamps.NewServerStampFromString(relayName); err == nil {
relayCandidateStamp = &stamp
} else if _, err := net.ResolveUDPAddr("udp", relayName); err == nil {
relayCandidateStamp = &stamps.ServerStamp{
ServerAddrStr: relayName,
Proto: stamps.StampProtoTypeDNSCrypt,
}
} else {
for _, registeredServer := range proxy.registeredServers {
if registeredServer.name == relayName {
relayCandidateStamp = &registeredServer.stamp
}
}
}
if relayCandidateStamp != nil && relayCandidateStamp.Proto == stamps.StampProtoTypeDNSCrypt {
relayUDPAddr, err = net.ResolveUDPAddr("udp", relayCandidateStamp.ServerAddrStr)
if err != nil {
return ServerInfo{}, err
}
relayTCPAddr, err = net.ResolveTCPAddr("tcp", relayCandidateStamp.ServerAddrStr)
if err != nil {
return ServerInfo{}, err
}
} else {
dlog.Errorf("Invalid relay [%v] for server [%v]", relayName, name)
}
}
}
return ServerInfo{
Proto: stamps.StampProtoTypeDNSCrypt,
MagicQuery: certInfo.MagicQuery,
@ -268,6 +304,8 @@ func (serversInfo *ServersInfo) fetchDNSCryptServerInfo(proxy *Proxy, name strin
Timeout: proxy.timeout,
UDPAddr: remoteUDPAddr,
TCPAddr: remoteTCPAddr,
RelayUDPAddr: relayUDPAddr,
RelayTCPAddr: relayTCPAddr,
initialRtt: rtt,
}, nil
}