diff --git a/common.go b/common.go index cbabc74f..84273a45 100644 --- a/common.go +++ b/common.go @@ -1,6 +1,7 @@ package main import ( + "net" "time" ) @@ -22,6 +23,16 @@ var ( TimeoutMax = 5 * time.Second ) +type ServerInfo struct { + MagicQuery [8]byte + ServerPk [32]byte + SharedKey [32]byte + CryptoConstruction CryptoConstruction + Timeout time.Duration + UDPAddr *net.UDPAddr + TCPAddr *net.TCPAddr +} + func HasTCFlag(packet []byte) bool { return packet[2]&2 == 2 } diff --git a/dnscrypt-proxy.go b/dnscrypt-proxy.go index 7b1752c2..2266d086 100644 --- a/dnscrypt-proxy.go +++ b/dnscrypt-proxy.go @@ -20,6 +20,79 @@ type Proxy struct { serversInfo []ServerInfo } +func main() { + log.SetFlags(0) + _ = NewProxy("127.0.0.1:5399", "212.47.228.136:443", "E801:B84E:A606:BFB0:BAC0:CE43:445B:B15E:BA64:B02F:A3C4:AA31:AE10:636A:0790:324D", "2.dnscrypt-cert.fr.dnscrypt.org") +} + +func NewProxy(listenAddrStr string, serverAddrStr string, serverPkStr string, providerName string) Proxy { + proxy := Proxy{minQuestionSize: InitialMinQuestionSize} + if _, err := rand.Read(proxy.proxySecretKey[:]); err != nil { + log.Fatal(err) + } + curve25519.ScalarBaseMult(&proxy.proxyPublicKey, &proxy.proxySecretKey) + proxy.fetchServerInfo(serverAddrStr, serverPkStr, providerName) + proxy.udpListener(listenAddrStr) + return proxy +} + +func (proxy *Proxy) adjustMinQuestionSize() { + if MaxDNSPacketSize-proxy.minQuestionSize < proxy.minQuestionSize { + proxy.minQuestionSize = MaxDNSPacketSize + } else { + proxy.minQuestionSize *= 2 + } +} + +func (proxy *Proxy) udpListener(listenAddrStr string) error { + clientPc, err := net.ListenPacket("udp", listenAddrStr) + if err != nil { + return err + } + defer clientPc.Close() + fmt.Printf("Now listening to %v [UDP]\n", listenAddrStr) + for { + buffer := make([]byte, MaxDNSPacketSize) + length, clientAddr, err := clientPc.ReadFrom(buffer) + if err != nil { + return err + } + packet := buffer[:length] + go func() { + proxy.processIncomingUDPQuery(&proxy.serversInfo[0], packet, clientAddr, clientPc) + }() + } +} + +func (proxy *Proxy) processIncomingUDPQuery(serverInfo *ServerInfo, packet []byte, clientAddr net.Addr, clientPc net.PacketConn) { + if len(packet) < MinDNSPacketSize { + return + } + encrypted, clientNonce := proxy.Crypt(serverInfo, packet) + pc, err := net.DialUDP("udp", nil, serverInfo.UDPAddr) + if err != nil { + return + } + defer pc.Close() + pc.SetDeadline(time.Now().Add(serverInfo.Timeout)) + pc.Write(encrypted) + + encrypted = make([]byte, MaxDNSPacketSize) + length, err := pc.Read(encrypted) + if err != nil { + return + } + encrypted = encrypted[:length] + packet, err = proxy.Decrypt(serverInfo, encrypted, clientNonce) + if err != nil { + return + } + clientPc.WriteTo(packet, clientAddr) + if HasTCFlag(packet) { + proxy.adjustMinQuestionSize() + } +} + func (proxy *Proxy) fetchServerInfo(serverAddrStr string, serverPkStr string, providerName string) { serverPublicKey, err := hex.DecodeString(strings.Replace(serverPkStr, ":", "", -1)) if err != nil || len(serverPublicKey) != ed25519.PublicKeySize { @@ -48,82 +121,3 @@ func (proxy *Proxy) fetchServerInfo(serverAddrStr string, serverPkStr string, pr } proxy.serversInfo = append(proxy.serversInfo, serverInfo) } - -func NewProxy(listenAddrStr string, serverAddrStr string, serverPkStr string, providerName string) Proxy { - proxy := Proxy{minQuestionSize: InitialMinQuestionSize} - if _, err := rand.Read(proxy.proxySecretKey[:]); err != nil { - log.Fatal(err) - } - curve25519.ScalarBaseMult(&proxy.proxyPublicKey, &proxy.proxySecretKey) - proxy.fetchServerInfo(serverAddrStr, serverPkStr, providerName) - clientPc, err := net.ListenPacket("udp", listenAddrStr) - if err != nil { - log.Fatal(err) - } - defer clientPc.Close() - fmt.Printf("Now listening to %v [UDP]\n", listenAddrStr) - for { - buffer := make([]byte, MaxDNSPacketSize) - length, clientAddr, err := clientPc.ReadFrom(buffer) - if err != nil { - break - } - packet := buffer[:length] - go func() { - proxy.processIncomingQuery(&proxy.serversInfo[0], packet, clientAddr, clientPc) - }() - } - return proxy -} - -type ServerInfo struct { - MagicQuery [8]byte - ServerPk [32]byte - SharedKey [32]byte - CryptoConstruction CryptoConstruction - Timeout time.Duration - UDPAddr *net.UDPAddr - TCPAddr *net.TCPAddr -} - -func (proxy *Proxy) adjustMinQuestionSize() { - if MaxDNSPacketSize-proxy.minQuestionSize < proxy.minQuestionSize { - proxy.minQuestionSize = MaxDNSPacketSize - } else { - proxy.minQuestionSize *= 2 - } -} - -func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, packet []byte, clientAddr net.Addr, clientPc net.PacketConn) { - if len(packet) < MinDNSPacketSize { - return - } - encrypted, clientNonce := proxy.Crypt(serverInfo, packet) - pc, err := net.DialUDP("udp", nil, serverInfo.UDPAddr) - if err != nil { - return - } - defer pc.Close() - pc.SetDeadline(time.Now().Add(serverInfo.Timeout)) - pc.Write(encrypted) - - encrypted = make([]byte, MaxDNSPacketSize) - length, err := pc.Read(encrypted) - if err != nil { - return - } - encrypted = encrypted[:length] - packet, err = proxy.Decrypt(serverInfo, encrypted, clientNonce) - if err != nil { - return - } - clientPc.WriteTo(packet, clientAddr) - if HasTCFlag(packet) { - proxy.adjustMinQuestionSize() - } -} - -func main() { - log.SetFlags(0) - _ = NewProxy("127.0.0.1:5399", "212.47.228.136:443", "E801:B84E:A606:BFB0:BAC0:CE43:445B:B15E:BA64:B02F:A3C4:AA31:AE10:636A:0790:324D", "2.dnscrypt-cert.fr.dnscrypt.org") -}