Synthesize a truncated response if the response wouldn't fit the local MSS
This commit is contained in:
parent
ab9006e74c
commit
d8f8d561c8
|
@ -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 {
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue