mirror of https://github.com/cbeuw/Cloak
Set frame size limit through multiplexer
This commit is contained in:
parent
780d607436
commit
e41394c83c
|
|
@ -11,6 +11,8 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const appDataMaxLength = 16401
|
||||
|
||||
type clientHelloFields struct {
|
||||
random []byte
|
||||
sessionId []byte
|
||||
|
|
|
|||
|
|
@ -63,9 +63,10 @@ func MakeSession(connConfig remoteConnConfig, authInfo authInfo, dialer common.D
|
|||
}
|
||||
|
||||
seshConfig := mux.SessionConfig{
|
||||
Obfuscator: obfuscator,
|
||||
Valve: nil,
|
||||
Unordered: authInfo.Unordered,
|
||||
Obfuscator: obfuscator,
|
||||
Valve: nil,
|
||||
Unordered: authInfo.Unordered,
|
||||
MaxFrameSize: appDataMaxLength,
|
||||
}
|
||||
sesh := mux.MakeSession(authInfo.SessionId, seshConfig)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"github.com/cbeuw/Cloak/internal/common"
|
||||
"io"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
mux "github.com/cbeuw/Cloak/internal/multiplex"
|
||||
"github.com/cbeuw/Cloak/internal/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
|
@ -136,8 +136,15 @@ func RouteTCP(localConfig localConnConfig, newSeshFunc func() *mux.Session) {
|
|||
stream.Close()
|
||||
return
|
||||
}
|
||||
go util.Pipe(localConn, stream, 0)
|
||||
util.Pipe(stream, localConn, localConfig.Timeout)
|
||||
go func() {
|
||||
if _, err := common.Copy(localConn, stream, 0); err != nil {
|
||||
log.Debugf("copying stream to proxy client: %v", err)
|
||||
}
|
||||
}()
|
||||
//util.Pipe(stream, localConn, localConfig.Timeout)
|
||||
if _, err = common.Copy(stream, localConn, localConfig.Timeout); err != nil {
|
||||
log.Debugf("copying proxy client to stream: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
Forked from https://golang.org/src/io/io.go
|
||||
*/
|
||||
package common
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// copyBuffer is the actual implementation of Copy and CopyBuffer.
|
||||
// if buf is nil, one is allocated.
|
||||
func Copy(dst net.Conn, src net.Conn, srcReadTimeout time.Duration) (written int64, err error) {
|
||||
/*
|
||||
// If the reader has a WriteTo method, use it to do the copy.
|
||||
// Avoids an allocation and a copy.
|
||||
if wt, ok := src.(WriterTo); ok {
|
||||
return wt.WriteTo(dst)
|
||||
}
|
||||
// Similarly, if the writer has a ReadFrom method, use it to do the copy.
|
||||
if rt, ok := dst.(ReaderFrom); ok {
|
||||
return rt.ReadFrom(src)
|
||||
}
|
||||
|
||||
*/
|
||||
//if buf == nil {
|
||||
size := 32 * 1024
|
||||
/*
|
||||
if l, ok := src.(*LimitedReader); ok && int64(size) > l.N {
|
||||
if l.N < 1 {
|
||||
size = 1
|
||||
} else {
|
||||
size = int(l.N)
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
buf := make([]byte, size)
|
||||
//}
|
||||
for {
|
||||
if srcReadTimeout != 0 {
|
||||
src.SetReadDeadline(time.Now().Add(srcReadTimeout))
|
||||
/*
|
||||
err =
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
nr, er := src.Read(buf)
|
||||
if nr > 0 {
|
||||
var offset int
|
||||
for offset < nr {
|
||||
nw, ew := dst.Write(buf[offset:nr])
|
||||
if nw > 0 {
|
||||
written += int64(nw)
|
||||
}
|
||||
if ew != nil {
|
||||
err = ew
|
||||
break
|
||||
}
|
||||
offset += nw
|
||||
}
|
||||
}
|
||||
if er != nil {
|
||||
if er != io.EOF {
|
||||
err = er
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return written, err
|
||||
}
|
||||
|
|
@ -33,8 +33,9 @@ type Obfuscator struct {
|
|||
// Used in Stream.Write. Add multiplexing headers, encrypt and add TLS header
|
||||
Obfs Obfser
|
||||
// Remove TLS header, decrypt and unmarshall frames
|
||||
Deobfs Deobfser
|
||||
SessionKey [32]byte
|
||||
Deobfs Deobfser
|
||||
SessionKey [32]byte
|
||||
minOverhead int
|
||||
}
|
||||
|
||||
func MakeObfs(salsaKey [32]byte, payloadCipher cipher.AEAD) Obfser {
|
||||
|
|
@ -137,10 +138,14 @@ func MakeDeobfs(salsaKey [32]byte, payloadCipher cipher.AEAD) Deobfser {
|
|||
}
|
||||
|
||||
func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (obfuscator *Obfuscator, err error) {
|
||||
obfuscator = &Obfuscator{
|
||||
SessionKey: sessionKey,
|
||||
}
|
||||
var payloadCipher cipher.AEAD
|
||||
switch encryptionMethod {
|
||||
case E_METHOD_PLAIN:
|
||||
payloadCipher = nil
|
||||
obfuscator.minOverhead = 0
|
||||
case E_METHOD_AES_GCM:
|
||||
var c cipher.Block
|
||||
c, err = aes.NewCipher(sessionKey[:])
|
||||
|
|
@ -151,19 +156,18 @@ func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (obfuscator *Obf
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
obfuscator.minOverhead = payloadCipher.Overhead()
|
||||
case E_METHOD_CHACHA20_POLY1305:
|
||||
payloadCipher, err = chacha20poly1305.New(sessionKey[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
obfuscator.minOverhead = payloadCipher.Overhead()
|
||||
default:
|
||||
return nil, errors.New("Unknown encryption method")
|
||||
}
|
||||
|
||||
obfuscator = &Obfuscator{
|
||||
MakeObfs(sessionKey, payloadCipher),
|
||||
MakeDeobfs(sessionKey, payloadCipher),
|
||||
sessionKey,
|
||||
}
|
||||
obfuscator.Obfs = MakeObfs(sessionKey, payloadCipher)
|
||||
obfuscator.Deobfs = MakeDeobfs(sessionKey, payloadCipher)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
acceptBacklog = 1024
|
||||
acceptBacklog = 1024
|
||||
// TODO: will this be a signature?
|
||||
defaultSendRecvBufSize = 20480
|
||||
)
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ type SessionConfig struct {
|
|||
|
||||
Unordered bool
|
||||
|
||||
MaxFrameSize int // maximum size of the frame, including the header
|
||||
SendBufferSize int
|
||||
ReceiveBufferSize int
|
||||
}
|
||||
|
|
@ -77,6 +79,9 @@ func MakeSession(id uint32, config SessionConfig) *Session {
|
|||
if config.ReceiveBufferSize <= 0 {
|
||||
sesh.ReceiveBufferSize = defaultSendRecvBufSize
|
||||
}
|
||||
if config.MaxFrameSize <= 0 {
|
||||
sesh.MaxFrameSize = defaultSendRecvBufSize - 1024
|
||||
}
|
||||
|
||||
sbConfig := switchboardConfig{
|
||||
valve: sesh.Valve,
|
||||
|
|
|
|||
|
|
@ -96,11 +96,19 @@ func (s *Stream) Write(in []byte) (n int, err error) {
|
|||
return 0, ErrBrokenStream
|
||||
}
|
||||
|
||||
var payload []byte
|
||||
maxDataLen := s.session.MaxFrameSize - HEADER_LEN - s.session.minOverhead
|
||||
if len(in) <= maxDataLen {
|
||||
payload = in
|
||||
} else {
|
||||
payload = in[:maxDataLen]
|
||||
}
|
||||
|
||||
f := &Frame{
|
||||
StreamID: s.id,
|
||||
Seq: atomic.AddUint64(&s.nextSendSeq, 1) - 1,
|
||||
Closing: C_NOOP,
|
||||
Payload: in,
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
i, err := s.session.Obfs(f, s.obfsBuf)
|
||||
|
|
@ -108,7 +116,7 @@ func (s *Stream) Write(in []byte) (n int, err error) {
|
|||
return i, err
|
||||
}
|
||||
n, err = s.session.sb.send(s.obfsBuf[:i], &s.assignedConnId)
|
||||
log.Tracef("%v sent to remote through stream %v with err %v", len(in), s.id, err)
|
||||
log.Tracef("%v sent to remote through stream %v with err %v", len(payload), s.id, err)
|
||||
if err != nil {
|
||||
if err == errBrokenSwitchboard {
|
||||
s.session.SetTerminalMsg(err.Error())
|
||||
|
|
@ -116,7 +124,7 @@ func (s *Stream) Write(in []byte) (n int, err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
return len(in), nil
|
||||
return len(payload), nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const appDataMaxLength = 16401
|
||||
|
||||
type TLS struct{}
|
||||
|
||||
var ErrBadClientHello = errors.New("non (or malformed) ClientHello")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"github.com/cbeuw/Cloak/internal/common"
|
||||
"github.com/cbeuw/Cloak/internal/util"
|
||||
"io"
|
||||
"net"
|
||||
|
|
@ -72,6 +73,13 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
|||
return
|
||||
}
|
||||
|
||||
seshConfig := mux.SessionConfig{
|
||||
Obfuscator: obfuscator,
|
||||
Valve: nil,
|
||||
Unordered: ci.Unordered,
|
||||
MaxFrameSize: appDataMaxLength,
|
||||
}
|
||||
|
||||
// adminUID can use the server as normal with unlimited QoS credits. The adminUID is not
|
||||
// added to the userinfo database. The distinction between going into the admin mode
|
||||
// and normal proxy mode is that sessionID needs == 0 for admin mode
|
||||
|
|
@ -82,10 +90,6 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
|||
return
|
||||
}
|
||||
log.Trace("finished handshake")
|
||||
seshConfig := mux.SessionConfig{
|
||||
Obfuscator: obfuscator,
|
||||
Valve: nil,
|
||||
}
|
||||
sesh := mux.MakeSession(0, seshConfig)
|
||||
sesh.AddConnection(preparedConn)
|
||||
//TODO: Router could be nil in cnc mode
|
||||
|
|
@ -113,11 +117,7 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
|||
return
|
||||
}
|
||||
|
||||
sesh, existing, err := user.GetSession(ci.SessionId, mux.SessionConfig{
|
||||
Obfuscator: obfuscator,
|
||||
Valve: nil,
|
||||
Unordered: ci.Unordered,
|
||||
})
|
||||
sesh, existing, err := user.GetSession(ci.SessionId, seshConfig)
|
||||
if err != nil {
|
||||
user.CloseSession(ci.SessionId, "")
|
||||
log.Error(err)
|
||||
|
|
@ -173,9 +173,17 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
|||
}
|
||||
log.Tracef("%v endpoint has been successfully connected", ci.ProxyMethod)
|
||||
|
||||
go util.Pipe(localConn, newStream, sta.Timeout)
|
||||
go util.Pipe(newStream, localConn, 0)
|
||||
|
||||
//TODO: stream timeout
|
||||
go func() {
|
||||
if _, err := common.Copy(localConn, newStream, sta.Timeout); err != nil {
|
||||
log.Debugf("copying stream to proxy client: %v", err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
if _, err := common.Copy(newStream, localConn, 0); err != nil {
|
||||
log.Debugf("copying proxy client to stream: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import (
|
|||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
|
@ -58,18 +56,12 @@ func CryptoRandRead(buf []byte) {
|
|||
log.Fatal("Cannot get cryptographic random bytes after 10 retries")
|
||||
}
|
||||
|
||||
// ReadTLS reads TLS data according to its record layer
|
||||
//func ReadTLS(conn net.Conn, buffer []byte) (n int, err error) {
|
||||
//}
|
||||
|
||||
/*
|
||||
func Pipe(dst net.Conn, src net.Conn, srcReadTimeout time.Duration) {
|
||||
// The maximum size of TLS message will be 16380+14+16. 14 because of the stream header and 16
|
||||
// because of the salt/mac
|
||||
// 16408 is the max TLS message size on Firefox
|
||||
buf := make([]byte, 16378)
|
||||
if srcReadTimeout != 0 {
|
||||
src.SetReadDeadline(time.Now().Add(srcReadTimeout))
|
||||
}
|
||||
for {
|
||||
if srcReadTimeout != 0 {
|
||||
src.SetReadDeadline(time.Now().Add(srcReadTimeout))
|
||||
|
|
@ -88,3 +80,5 @@ func Pipe(dst net.Conn, src net.Conn, srcReadTimeout time.Duration) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue