Synthesize a truncated response if the response wouldn't fit the local MSS

This commit is contained in:
Frank Denis 2018-01-10 02:52:09 +01:00
parent ab9006e74c
commit d8f8d561c8
5 changed files with 47 additions and 20 deletions

View File

@ -27,10 +27,6 @@ var (
CertRefreshDelay = 30 * time.Minute
)
func HasTCFlag(packet []byte) bool {
return packet[2]&2 == 2
}
func PrefixWithSize(packet []byte) ([]byte, error) {
packet_len := len(packet)
if packet_len > 0xffff {

View File

@ -12,6 +12,7 @@ const (
NonceSize = xsecretbox.NonceSize
HalfNonceSize = xsecretbox.NonceSize / 2
TagSize = xsecretbox.TagSize
ResponseOverhead = len(ServerMagic) + NonceSize + TagSize
)
func pad(packet []byte, minSize int) []byte {
@ -40,22 +41,22 @@ func (proxy *Proxy) Encrypt(serverInfo *ServerInfo, packet []byte, proto string)
nonce, clientNonce := make([]byte, NonceSize), make([]byte, HalfNonceSize)
rand.Read(clientNonce)
copy(nonce, clientNonce)
minQuestionSize := len(packet)
minQuestionSize := ResponseOverhead + len(packet)
if proto == "udp" {
minQuestionSize = proxy.questionSizeEstimator.MinQuestionSize()
minQuestionSize = Max(proxy.questionSizeEstimator.MinQuestionSize(), minQuestionSize)
} else {
var xpad [1]byte
rand.Read(xpad[:])
minQuestionSize += int(xpad[0])
}
paddedLength := Min((minQuestionSize+63)&^63, MaxDNSUDPPacketSize-1)
if paddedLength <= 0 || len(packet) >= paddedLength {
paddedLength := Min(MaxDNSUDPPacketSize, (Max(minQuestionSize, ResponseOverhead)+63) & ^63)
if ResponseOverhead+len(packet)+1 > paddedLength {
err = errors.New("Question too large; cannot be padded")
return
}
encrypted = append(serverInfo.MagicQuery[:], proxy.proxyPublicKey[:]...)
encrypted = append(encrypted, nonce[:HalfNonceSize]...)
encrypted = xsecretbox.Seal(encrypted, nonce, pad(packet, paddedLength), serverInfo.SharedKey[:])
encrypted = xsecretbox.Seal(encrypted, nonce, pad(packet, paddedLength-ResponseOverhead), serverInfo.SharedKey[:])
return
}
@ -63,8 +64,9 @@ func (proxy *Proxy) Decrypt(serverInfo *ServerInfo, encrypted []byte, nonce []by
serverMagicLen := len(ServerMagic)
responseHeaderLen := serverMagicLen + NonceSize
if len(encrypted) < responseHeaderLen+TagSize+int(MinDNSPacketSize) ||
len(encrypted) > responseHeaderLen+TagSize+int(MaxDNSPacketSize) ||
!bytes.Equal(encrypted[:serverMagicLen], ServerMagic[:]) {
return encrypted, errors.New("Short message")
return encrypted, errors.New("Invalid message size or prefix")
}
serverNonce := encrypted[serverMagicLen:responseHeaderLen]
if !bytes.Equal(nonce[:HalfNonceSize], serverNonce[:HalfNonceSize]) {

View File

@ -0,0 +1,23 @@
package main
import (
"github.com/miekg/dns"
)
func TruncatedResponse(packet []byte) ([]byte, error) {
srcMsg := new(dns.Msg)
if err := srcMsg.Unpack(packet); err != nil {
return nil, err
}
dstMsg := srcMsg
dstMsg.Response = true
dstMsg.Answer = make([]dns.RR, 0)
dstMsg.Ns = make([]dns.RR, 0)
dstMsg.Extra = make([]dns.RR, 0)
dstMsg.Truncated = true
return dstMsg.Pack()
}
func HasTCFlag(packet []byte) bool {
return packet[2]&2 == 2
}

View File

@ -20,7 +20,7 @@ func (questionSizeEstimator *QuestionSizeEstimator) MinQuestionSize() int {
func (questionSizeEstimator *QuestionSizeEstimator) blindAdjust() {
questionSizeEstimator.Lock()
if MaxDNSPacketSize-questionSizeEstimator.minQuestionSize < questionSizeEstimator.minQuestionSize {
if MaxDNSUDPPacketSize-questionSizeEstimator.minQuestionSize < questionSizeEstimator.minQuestionSize {
questionSizeEstimator.minQuestionSize = MaxDNSUDPPacketSize
} else {
questionSizeEstimator.minQuestionSize *= 2

View File

@ -142,22 +142,28 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, serverProto str
if err != nil {
return
}
var encryptedResponse []byte
var response []byte
if serverProto == "udp" {
encryptedResponse, err = proxy.exchangeWithUDPServer(serverInfo, encryptedQuery, clientNonce)
response, err = proxy.exchangeWithUDPServer(serverInfo, encryptedQuery, clientNonce)
} else {
encryptedResponse, err = proxy.exchangeWithTCPServer(serverInfo, encryptedQuery, clientNonce)
response, err = proxy.exchangeWithTCPServer(serverInfo, encryptedQuery, clientNonce)
}
if err != nil {
return
}
if clientAddr != nil {
clientPc.(net.PacketConn).WriteTo(encryptedResponse, *clientAddr)
if HasTCFlag(encryptedResponse) {
if len(response) > MaxDNSUDPPacketSize {
response, err = TruncatedResponse(response)
if err != nil {
return
}
}
clientPc.(net.PacketConn).WriteTo(response, *clientAddr)
if HasTCFlag(response) {
proxy.questionSizeEstimator.blindAdjust()
}
} else {
response, err := PrefixWithSize(encryptedResponse)
response, err = PrefixWithSize(response)
if err != nil {
return
}