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
|
CertRefreshDelay = 30 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
func HasTCFlag(packet []byte) bool {
|
|
||||||
return packet[2]&2 == 2
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrefixWithSize(packet []byte) ([]byte, error) {
|
func PrefixWithSize(packet []byte) ([]byte, error) {
|
||||||
packet_len := len(packet)
|
packet_len := len(packet)
|
||||||
if packet_len > 0xffff {
|
if packet_len > 0xffff {
|
||||||
|
|
|
@ -12,6 +12,7 @@ const (
|
||||||
NonceSize = xsecretbox.NonceSize
|
NonceSize = xsecretbox.NonceSize
|
||||||
HalfNonceSize = xsecretbox.NonceSize / 2
|
HalfNonceSize = xsecretbox.NonceSize / 2
|
||||||
TagSize = xsecretbox.TagSize
|
TagSize = xsecretbox.TagSize
|
||||||
|
ResponseOverhead = len(ServerMagic) + NonceSize + TagSize
|
||||||
)
|
)
|
||||||
|
|
||||||
func pad(packet []byte, minSize int) []byte {
|
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)
|
nonce, clientNonce := make([]byte, NonceSize), make([]byte, HalfNonceSize)
|
||||||
rand.Read(clientNonce)
|
rand.Read(clientNonce)
|
||||||
copy(nonce, clientNonce)
|
copy(nonce, clientNonce)
|
||||||
minQuestionSize := len(packet)
|
minQuestionSize := ResponseOverhead + len(packet)
|
||||||
if proto == "udp" {
|
if proto == "udp" {
|
||||||
minQuestionSize = proxy.questionSizeEstimator.MinQuestionSize()
|
minQuestionSize = Max(proxy.questionSizeEstimator.MinQuestionSize(), minQuestionSize)
|
||||||
} else {
|
} else {
|
||||||
var xpad [1]byte
|
var xpad [1]byte
|
||||||
rand.Read(xpad[:])
|
rand.Read(xpad[:])
|
||||||
minQuestionSize += int(xpad[0])
|
minQuestionSize += int(xpad[0])
|
||||||
}
|
}
|
||||||
paddedLength := Min((minQuestionSize+63)&^63, MaxDNSUDPPacketSize-1)
|
paddedLength := Min(MaxDNSUDPPacketSize, (Max(minQuestionSize, ResponseOverhead)+63) & ^63)
|
||||||
if paddedLength <= 0 || len(packet) >= paddedLength {
|
if ResponseOverhead+len(packet)+1 > paddedLength {
|
||||||
err = errors.New("Question too large; cannot be padded")
|
err = errors.New("Question too large; cannot be padded")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
encrypted = append(serverInfo.MagicQuery[:], proxy.proxyPublicKey[:]...)
|
encrypted = append(serverInfo.MagicQuery[:], proxy.proxyPublicKey[:]...)
|
||||||
encrypted = append(encrypted, nonce[:HalfNonceSize]...)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +64,9 @@ func (proxy *Proxy) Decrypt(serverInfo *ServerInfo, encrypted []byte, nonce []by
|
||||||
serverMagicLen := len(ServerMagic)
|
serverMagicLen := len(ServerMagic)
|
||||||
responseHeaderLen := serverMagicLen + NonceSize
|
responseHeaderLen := serverMagicLen + NonceSize
|
||||||
if len(encrypted) < responseHeaderLen+TagSize+int(MinDNSPacketSize) ||
|
if len(encrypted) < responseHeaderLen+TagSize+int(MinDNSPacketSize) ||
|
||||||
|
len(encrypted) > responseHeaderLen+TagSize+int(MaxDNSPacketSize) ||
|
||||||
!bytes.Equal(encrypted[:serverMagicLen], ServerMagic[:]) {
|
!bytes.Equal(encrypted[:serverMagicLen], ServerMagic[:]) {
|
||||||
return encrypted, errors.New("Short message")
|
return encrypted, errors.New("Invalid message size or prefix")
|
||||||
}
|
}
|
||||||
serverNonce := encrypted[serverMagicLen:responseHeaderLen]
|
serverNonce := encrypted[serverMagicLen:responseHeaderLen]
|
||||||
if !bytes.Equal(nonce[:HalfNonceSize], serverNonce[:HalfNonceSize]) {
|
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() {
|
func (questionSizeEstimator *QuestionSizeEstimator) blindAdjust() {
|
||||||
questionSizeEstimator.Lock()
|
questionSizeEstimator.Lock()
|
||||||
if MaxDNSPacketSize-questionSizeEstimator.minQuestionSize < questionSizeEstimator.minQuestionSize {
|
if MaxDNSUDPPacketSize-questionSizeEstimator.minQuestionSize < questionSizeEstimator.minQuestionSize {
|
||||||
questionSizeEstimator.minQuestionSize = MaxDNSUDPPacketSize
|
questionSizeEstimator.minQuestionSize = MaxDNSUDPPacketSize
|
||||||
} else {
|
} else {
|
||||||
questionSizeEstimator.minQuestionSize *= 2
|
questionSizeEstimator.minQuestionSize *= 2
|
||||||
|
|
|
@ -142,22 +142,28 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, serverProto str
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var encryptedResponse []byte
|
var response []byte
|
||||||
if serverProto == "udp" {
|
if serverProto == "udp" {
|
||||||
encryptedResponse, err = proxy.exchangeWithUDPServer(serverInfo, encryptedQuery, clientNonce)
|
response, err = proxy.exchangeWithUDPServer(serverInfo, encryptedQuery, clientNonce)
|
||||||
} else {
|
} else {
|
||||||
encryptedResponse, err = proxy.exchangeWithTCPServer(serverInfo, encryptedQuery, clientNonce)
|
response, err = proxy.exchangeWithTCPServer(serverInfo, encryptedQuery, clientNonce)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if clientAddr != nil {
|
if clientAddr != nil {
|
||||||
clientPc.(net.PacketConn).WriteTo(encryptedResponse, *clientAddr)
|
if len(response) > MaxDNSUDPPacketSize {
|
||||||
if HasTCFlag(encryptedResponse) {
|
response, err = TruncatedResponse(response)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clientPc.(net.PacketConn).WriteTo(response, *clientAddr)
|
||||||
|
if HasTCFlag(response) {
|
||||||
proxy.questionSizeEstimator.blindAdjust()
|
proxy.questionSizeEstimator.blindAdjust()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
response, err := PrefixWithSize(encryptedResponse)
|
response, err = PrefixWithSize(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue