Better conform message data length to TLS standards

This commit is contained in:
Andy Wang 2020-12-29 00:16:24 +00:00
parent 439b7f0eb3
commit 8dd4ae4bef
No known key found for this signature in database
GPG Key ID: 181B49F9F38F3374
6 changed files with 22 additions and 24 deletions

View File

@ -2,6 +2,7 @@ package common
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"io" "io"
"net" "net"
"sync" "sync"
@ -94,6 +95,9 @@ func (tls *TLSConn) Read(buffer []byte) (n int, err error) {
func (tls *TLSConn) Write(in []byte) (n int, err error) { func (tls *TLSConn) Write(in []byte) (n int, err error) {
msgLen := len(in) msgLen := len(in)
if msgLen > 1<<14+256 { // https://tools.ietf.org/html/rfc8446#section-5.2
return 0, errors.New("message is too long")
}
writeBuf := tls.writeBufPool.Get().(*[]byte) writeBuf := tls.writeBufPool.Get().(*[]byte)
*writeBuf = append(*writeBuf, byte(msgLen>>8), byte(msgLen&0xFF)) *writeBuf = append(*writeBuf, byte(msgLen>>8), byte(msgLen&0xFF))
*writeBuf = append(*writeBuf, in...) *writeBuf = append(*writeBuf, in...)

View File

@ -138,7 +138,7 @@ func BenchmarkObfs(b *testing.B) {
testPayload, testPayload,
} }
obfsBuf := make([]byte, defaultSendRecvBufSize) obfsBuf := make([]byte, len(testPayload)*2)
var key [32]byte var key [32]byte
rand.Read(key[:]) rand.Read(key[:])
@ -211,7 +211,7 @@ func BenchmarkDeobfs(b *testing.B) {
testPayload, testPayload,
} }
obfsBuf := make([]byte, defaultSendRecvBufSize) obfsBuf := make([]byte, len(testPayload)*2)
var key [32]byte var key [32]byte
rand.Read(key[:]) rand.Read(key[:])

View File

@ -25,4 +25,4 @@ type recvBuffer interface {
// size we want the amount of unread data in buffer to grow before recvBuffer.Write blocks. // size we want the amount of unread data in buffer to grow before recvBuffer.Write blocks.
// If the buffer grows larger than what the system's memory can offer at the time of recvBuffer.Write, // If the buffer grows larger than what the system's memory can offer at the time of recvBuffer.Write,
// a panic will happen. // a panic will happen.
const recvBufferSizeLimit = defaultSendRecvBufSize << 12 const recvBufferSizeLimit = 1 << 31

View File

@ -13,10 +13,9 @@ import (
) )
const ( const (
acceptBacklog = 1024 acceptBacklog = 1024
// TODO: will this be a signature?
defaultSendRecvBufSize = 20480
defaultInactivityTimeout = 30 * time.Second defaultInactivityTimeout = 30 * time.Second
defaultMaxOnWireSize = 1<<14 + 256 // https://tools.ietf.org/html/rfc8446#section-5.2
) )
var ErrBrokenSession = errors.New("broken session") var ErrBrokenSession = errors.New("broken session")
@ -40,12 +39,6 @@ type SessionConfig struct {
// maximum size of an obfuscated frame, including headers and overhead // maximum size of an obfuscated frame, including headers and overhead
MsgOnWireSizeLimit int MsgOnWireSizeLimit int
// StreamSendBufferSize sets the buffer size used to send data from a Stream (Stream.obfsBuf)
StreamSendBufferSize int
// ConnReceiveBufferSize sets the buffer size used to receive data from an underlying Conn (allocated in
// switchboard.deplex)
ConnReceiveBufferSize int
// InactivityTimeout sets the duration a Session waits while it has no active streams before it closes itself // InactivityTimeout sets the duration a Session waits while it has no active streams before it closes itself
InactivityTimeout time.Duration InactivityTimeout time.Duration
} }
@ -87,6 +80,11 @@ type Session struct {
// the max size passed to Write calls before it splits it into multiple frames // the max size passed to Write calls before it splits it into multiple frames
// i.e. the max size a piece of data can fit into a Frame.Payload // i.e. the max size a piece of data can fit into a Frame.Payload
maxStreamUnitWrite int maxStreamUnitWrite int
// streamSendBufferSize sets the buffer size used to send data from a Stream (Stream.obfsBuf)
streamSendBufferSize int
// connReceiveBufferSize sets the buffer size used to receive data from an underlying Conn (allocated in
// switchboard.deplex)
connReceiveBufferSize int
} }
func MakeSession(id uint32, config SessionConfig) *Session { func MakeSession(id uint32, config SessionConfig) *Session {
@ -103,23 +101,19 @@ func MakeSession(id uint32, config SessionConfig) *Session {
if config.Valve == nil { if config.Valve == nil {
sesh.Valve = UNLIMITED_VALVE sesh.Valve = UNLIMITED_VALVE
} }
if config.StreamSendBufferSize <= 0 {
sesh.StreamSendBufferSize = defaultSendRecvBufSize
}
if config.ConnReceiveBufferSize <= 0 {
sesh.ConnReceiveBufferSize = defaultSendRecvBufSize
}
if config.MsgOnWireSizeLimit <= 0 { if config.MsgOnWireSizeLimit <= 0 {
sesh.MsgOnWireSizeLimit = defaultSendRecvBufSize - 1024 sesh.MsgOnWireSizeLimit = defaultMaxOnWireSize
} }
if config.InactivityTimeout == 0 { if config.InactivityTimeout == 0 {
sesh.InactivityTimeout = defaultInactivityTimeout sesh.InactivityTimeout = defaultInactivityTimeout
} }
// todo: validation. this must be smaller than StreamSendBufferSize
sesh.maxStreamUnitWrite = sesh.MsgOnWireSizeLimit - frameHeaderLength - sesh.Obfuscator.maxOverhead sesh.maxStreamUnitWrite = sesh.MsgOnWireSizeLimit - frameHeaderLength - sesh.maxOverhead
sesh.streamSendBufferSize = sesh.MsgOnWireSizeLimit
sesh.connReceiveBufferSize = 20480 // for backwards compatibility
sesh.streamObfsBufPool = sync.Pool{New: func() interface{} { sesh.streamObfsBufPool = sync.Pool{New: func() interface{} {
b := make([]byte, sesh.StreamSendBufferSize) b := make([]byte, sesh.streamSendBufferSize)
return &b return &b
}} }}

View File

@ -159,7 +159,7 @@ func (sb *switchboard) closeAll() {
// deplex function costantly reads from a TCP connection // deplex function costantly reads from a TCP connection
func (sb *switchboard) deplex(connId uint32, conn net.Conn) { func (sb *switchboard) deplex(connId uint32, conn net.Conn) {
defer conn.Close() defer conn.Close()
buf := make([]byte, sb.session.ConnReceiveBufferSize) buf := make([]byte, sb.session.connReceiveBufferSize)
for { for {
n, err := conn.Read(buf) n, err := conn.Read(buf)
sb.valve.rxWait(n) sb.valve.rxWait(n)

View File

@ -321,7 +321,7 @@ func TestTCPSingleplex(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
const echoMsgLen = 16384 const echoMsgLen = 1 << 16
go serveTCPEcho(proxyFromCkServerL) go serveTCPEcho(proxyFromCkServerL)
proxyConn1, err := proxyToCkClientD.Dial("", "") proxyConn1, err := proxyToCkClientD.Dial("", "")