From 60a58067c156160f3f53345f4a181932a3a53089 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 9 Jan 2018 13:27:03 +0100 Subject: [PATCH] Desuglify a bit --- common.go | 32 +++------------------- crypto.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++ dnscrypt-proxy.go | 56 +++++++++++++++----------------------- 3 files changed, 92 insertions(+), 64 deletions(-) create mode 100644 crypto.go diff --git a/common.go b/common.go index 7f7e980f..cbabc74f 100644 --- a/common.go +++ b/common.go @@ -1,7 +1,6 @@ package main import ( - "errors" "time" ) @@ -16,9 +15,9 @@ const ( var ( CertMagic = [4]byte{0x44, 0x4e, 0x53, 0x43} ServerMagic = [8]byte{0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38} - MinDNSPacketSize = uint(12) - MaxDNSPacketSize = uint(4096) - InitialMinQuestionSize = uint(128) + MinDNSPacketSize = 12 + MaxDNSPacketSize = 4096 + InitialMinQuestionSize = 128 TimeoutMin = 1 * time.Second TimeoutMax = 5 * time.Second ) @@ -26,28 +25,3 @@ var ( func HasTCFlag(packet []byte) bool { return packet[2]&2 == 2 } - -func Pad(packet []byte, minSize uint) []byte { - packet = append(packet, 0x80) - for uint(len(packet)) < minSize { - packet = append(packet, 0) - } - return packet -} - -func Unpad(packet []byte) ([]byte, error) { - i := len(packet) - for { - if i == 0 { - return nil, errors.New("Invalid padding (short packet)") - } - i-- - if packet[i] == 0x80 { - break - } - if packet[i] != 0x00 { - return nil, errors.New("Invalid padding (delimiter not found)") - } - } - return packet[:i], nil -} diff --git a/crypto.go b/crypto.go new file mode 100644 index 00000000..37130a3f --- /dev/null +++ b/crypto.go @@ -0,0 +1,68 @@ +package main + +import ( + "bytes" + "crypto/rand" + "errors" + + "github.com/jedisct1/xsecretbox" +) + +const ( + NonceSize = xsecretbox.NonceSize + HalfNonceSize = xsecretbox.NonceSize / 2 + TagSize = xsecretbox.TagSize +) + +func pad(packet []byte, minSize int) []byte { + packet = append(packet, 0x80) + for len(packet) < minSize { + packet = append(packet, 0) + } + return packet +} + +func unpad(packet []byte) ([]byte, error) { + for i := len(packet); ; { + if i == 0 { + return nil, errors.New("Invalid padding (short packet)") + } + i-- + if packet[i] == 0x80 { + return packet[:i], nil + } else if packet[i] != 0x00 { + return nil, errors.New("Invalid padding (delimiter not found)") + } + } +} +func (proxy *Proxy) Crypt(serverInfo *ServerInfo, packet []byte) (encrypted []byte, clientNonce []byte) { + nonce, clientNonce := make([]byte, NonceSize), make([]byte, HalfNonceSize) + rand.Read(clientNonce) + copy(nonce, clientNonce) + encrypted = append(serverInfo.MagicQuery[:], proxy.proxyPublicKey[:]...) + encrypted = append(encrypted, nonce[:HalfNonceSize]...) + encrypted = xsecretbox.Seal(encrypted, nonce, pad(packet, proxy.minQuestionSize), serverInfo.SharedKey[:]) + return +} + +func (proxy *Proxy) Decrypt(serverInfo *ServerInfo, encrypted []byte, nonce []byte) ([]byte, error) { + serverMagicLen := len(ServerMagic) + responseHeaderLen := serverMagicLen + NonceSize + if len(encrypted) < responseHeaderLen+TagSize+int(MinDNSPacketSize) || + !bytes.Equal(encrypted[:serverMagicLen], ServerMagic[:]) { + return encrypted, errors.New("Short message") + } + serverNonce := encrypted[serverMagicLen:responseHeaderLen] + if !bytes.Equal(nonce[:HalfNonceSize], serverNonce[:HalfNonceSize]) { + return encrypted, errors.New("Unexpected nonce") + } + packet, err := xsecretbox.Open(nil, serverNonce, encrypted[responseHeaderLen:], serverInfo.SharedKey[:]) + if err != nil { + return encrypted, errors.New("Incorrect tag") + } + packet, err = unpad(packet) + if err != nil || len(packet) < MinDNSPacketSize { + return encrypted, errors.New("Incorrect padding") + } + return packet, nil +} diff --git a/dnscrypt-proxy.go b/dnscrypt-proxy.go index 2dad6313..7b1752c2 100644 --- a/dnscrypt-proxy.go +++ b/dnscrypt-proxy.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "crypto/rand" "encoding/hex" "fmt" @@ -10,7 +9,6 @@ import ( "strings" "time" - "github.com/jedisct1/xsecretbox" "golang.org/x/crypto/curve25519" "golang.org/x/crypto/ed25519" ) @@ -18,7 +16,7 @@ import ( type Proxy struct { proxyPublicKey [32]byte proxySecretKey [32]byte - minQuestionSize uint + minQuestionSize int serversInfo []ServerInfo } @@ -88,14 +86,19 @@ type ServerInfo struct { 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) { - packet = Pad(packet, proxy.minQuestionSize) - nonce := make([]byte, xsecretbox.NonceSize) - rand.Read(nonce[0 : xsecretbox.NonceSize/2]) - encrypted := serverInfo.MagicQuery[:] - encrypted = append(encrypted, proxy.proxyPublicKey[:]...) - encrypted = append(encrypted, nonce[:xsecretbox.NonceSize/2]...) - encrypted = xsecretbox.Seal(encrypted, nonce, packet, serverInfo.SharedKey[:]) + if len(packet) < MinDNSPacketSize { + return + } + encrypted, clientNonce := proxy.Crypt(serverInfo, packet) pc, err := net.DialUDP("udp", nil, serverInfo.UDPAddr) if err != nil { return @@ -103,38 +106,21 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, packet []byte, defer pc.Close() pc.SetDeadline(time.Now().Add(serverInfo.Timeout)) pc.Write(encrypted) - buffer := make([]byte, MaxDNSPacketSize) - length, err := pc.Read(buffer) + + encrypted = make([]byte, MaxDNSPacketSize) + length, err := pc.Read(encrypted) if err != nil { return } - buffer = buffer[:length] - serverMagicLen := len(ServerMagic) - responseHeaderLen := serverMagicLen + xsecretbox.NonceSize - if len(buffer) < responseHeaderLen+xsecretbox.TagSize || - !bytes.Equal(buffer[:serverMagicLen], ServerMagic[:]) { - return - } - serverNonce := buffer[serverMagicLen:responseHeaderLen] - if !bytes.Equal(nonce[:xsecretbox.NonceSize/2], serverNonce[:xsecretbox.NonceSize/2]) { - return - } - decrypted, err := xsecretbox.Open(nil, serverNonce, buffer[responseHeaderLen:], serverInfo.SharedKey[:]) + encrypted = encrypted[:length] + packet, err = proxy.Decrypt(serverInfo, encrypted, clientNonce) if err != nil { return } - decrypted, err = Unpad(decrypted) - if err != nil || uint(len(decrypted)) < MinDNSPacketSize { - return + clientPc.WriteTo(packet, clientAddr) + if HasTCFlag(packet) { + proxy.adjustMinQuestionSize() } - if HasTCFlag(decrypted) { - if MaxDNSPacketSize-proxy.minQuestionSize < proxy.minQuestionSize { - proxy.minQuestionSize = MaxDNSPacketSize - } else { - proxy.minQuestionSize *= 2 - } - } - clientPc.WriteTo(decrypted, clientAddr) } func main() {