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"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const appDataMaxLength = 16401
|
||||||
|
|
||||||
type clientHelloFields struct {
|
type clientHelloFields struct {
|
||||||
random []byte
|
random []byte
|
||||||
sessionId []byte
|
sessionId []byte
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ func MakeSession(connConfig remoteConnConfig, authInfo authInfo, dialer common.D
|
||||||
Obfuscator: obfuscator,
|
Obfuscator: obfuscator,
|
||||||
Valve: nil,
|
Valve: nil,
|
||||||
Unordered: authInfo.Unordered,
|
Unordered: authInfo.Unordered,
|
||||||
|
MaxFrameSize: appDataMaxLength,
|
||||||
}
|
}
|
||||||
sesh := mux.MakeSession(authInfo.SessionId, seshConfig)
|
sesh := mux.MakeSession(authInfo.SessionId, seshConfig)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/cbeuw/Cloak/internal/common"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mux "github.com/cbeuw/Cloak/internal/multiplex"
|
mux "github.com/cbeuw/Cloak/internal/multiplex"
|
||||||
"github.com/cbeuw/Cloak/internal/util"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -136,8 +136,15 @@ func RouteTCP(localConfig localConnConfig, newSeshFunc func() *mux.Session) {
|
||||||
stream.Close()
|
stream.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
go util.Pipe(localConn, stream, 0)
|
go func() {
|
||||||
util.Pipe(stream, localConn, localConfig.Timeout)
|
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
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,7 @@ type Obfuscator struct {
|
||||||
// Remove TLS header, decrypt and unmarshall frames
|
// Remove TLS header, decrypt and unmarshall frames
|
||||||
Deobfs Deobfser
|
Deobfs Deobfser
|
||||||
SessionKey [32]byte
|
SessionKey [32]byte
|
||||||
|
minOverhead int
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeObfs(salsaKey [32]byte, payloadCipher cipher.AEAD) Obfser {
|
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) {
|
func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (obfuscator *Obfuscator, err error) {
|
||||||
|
obfuscator = &Obfuscator{
|
||||||
|
SessionKey: sessionKey,
|
||||||
|
}
|
||||||
var payloadCipher cipher.AEAD
|
var payloadCipher cipher.AEAD
|
||||||
switch encryptionMethod {
|
switch encryptionMethod {
|
||||||
case E_METHOD_PLAIN:
|
case E_METHOD_PLAIN:
|
||||||
payloadCipher = nil
|
payloadCipher = nil
|
||||||
|
obfuscator.minOverhead = 0
|
||||||
case E_METHOD_AES_GCM:
|
case E_METHOD_AES_GCM:
|
||||||
var c cipher.Block
|
var c cipher.Block
|
||||||
c, err = aes.NewCipher(sessionKey[:])
|
c, err = aes.NewCipher(sessionKey[:])
|
||||||
|
|
@ -151,19 +156,18 @@ func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (obfuscator *Obf
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
obfuscator.minOverhead = payloadCipher.Overhead()
|
||||||
case E_METHOD_CHACHA20_POLY1305:
|
case E_METHOD_CHACHA20_POLY1305:
|
||||||
payloadCipher, err = chacha20poly1305.New(sessionKey[:])
|
payloadCipher, err = chacha20poly1305.New(sessionKey[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
obfuscator.minOverhead = payloadCipher.Overhead()
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("Unknown encryption method")
|
return nil, errors.New("Unknown encryption method")
|
||||||
}
|
}
|
||||||
|
|
||||||
obfuscator = &Obfuscator{
|
obfuscator.Obfs = MakeObfs(sessionKey, payloadCipher)
|
||||||
MakeObfs(sessionKey, payloadCipher),
|
obfuscator.Deobfs = MakeDeobfs(sessionKey, payloadCipher)
|
||||||
MakeDeobfs(sessionKey, payloadCipher),
|
|
||||||
sessionKey,
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
acceptBacklog = 1024
|
acceptBacklog = 1024
|
||||||
|
// TODO: will this be a signature?
|
||||||
defaultSendRecvBufSize = 20480
|
defaultSendRecvBufSize = 20480
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,6 +30,7 @@ type SessionConfig struct {
|
||||||
|
|
||||||
Unordered bool
|
Unordered bool
|
||||||
|
|
||||||
|
MaxFrameSize int // maximum size of the frame, including the header
|
||||||
SendBufferSize int
|
SendBufferSize int
|
||||||
ReceiveBufferSize int
|
ReceiveBufferSize int
|
||||||
}
|
}
|
||||||
|
|
@ -77,6 +79,9 @@ func MakeSession(id uint32, config SessionConfig) *Session {
|
||||||
if config.ReceiveBufferSize <= 0 {
|
if config.ReceiveBufferSize <= 0 {
|
||||||
sesh.ReceiveBufferSize = defaultSendRecvBufSize
|
sesh.ReceiveBufferSize = defaultSendRecvBufSize
|
||||||
}
|
}
|
||||||
|
if config.MaxFrameSize <= 0 {
|
||||||
|
sesh.MaxFrameSize = defaultSendRecvBufSize - 1024
|
||||||
|
}
|
||||||
|
|
||||||
sbConfig := switchboardConfig{
|
sbConfig := switchboardConfig{
|
||||||
valve: sesh.Valve,
|
valve: sesh.Valve,
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,19 @@ func (s *Stream) Write(in []byte) (n int, err error) {
|
||||||
return 0, ErrBrokenStream
|
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{
|
f := &Frame{
|
||||||
StreamID: s.id,
|
StreamID: s.id,
|
||||||
Seq: atomic.AddUint64(&s.nextSendSeq, 1) - 1,
|
Seq: atomic.AddUint64(&s.nextSendSeq, 1) - 1,
|
||||||
Closing: C_NOOP,
|
Closing: C_NOOP,
|
||||||
Payload: in,
|
Payload: payload,
|
||||||
}
|
}
|
||||||
|
|
||||||
i, err := s.session.Obfs(f, s.obfsBuf)
|
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
|
return i, err
|
||||||
}
|
}
|
||||||
n, err = s.session.sb.send(s.obfsBuf[:i], &s.assignedConnId)
|
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 != nil {
|
||||||
if err == errBrokenSwitchboard {
|
if err == errBrokenSwitchboard {
|
||||||
s.session.SetTerminalMsg(err.Error())
|
s.session.SetTerminalMsg(err.Error())
|
||||||
|
|
@ -116,7 +124,7 @@ func (s *Stream) Write(in []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return len(in), nil
|
return len(payload), nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const appDataMaxLength = 16401
|
||||||
|
|
||||||
type TLS struct{}
|
type TLS struct{}
|
||||||
|
|
||||||
var ErrBadClientHello = errors.New("non (or malformed) ClientHello")
|
var ErrBadClientHello = errors.New("non (or malformed) ClientHello")
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package server
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"github.com/cbeuw/Cloak/internal/common"
|
||||||
"github.com/cbeuw/Cloak/internal/util"
|
"github.com/cbeuw/Cloak/internal/util"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
|
@ -72,6 +73,13 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
||||||
return
|
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
|
// 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
|
// 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
|
// and normal proxy mode is that sessionID needs == 0 for admin mode
|
||||||
|
|
@ -82,10 +90,6 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("finished handshake")
|
log.Trace("finished handshake")
|
||||||
seshConfig := mux.SessionConfig{
|
|
||||||
Obfuscator: obfuscator,
|
|
||||||
Valve: nil,
|
|
||||||
}
|
|
||||||
sesh := mux.MakeSession(0, seshConfig)
|
sesh := mux.MakeSession(0, seshConfig)
|
||||||
sesh.AddConnection(preparedConn)
|
sesh.AddConnection(preparedConn)
|
||||||
//TODO: Router could be nil in cnc mode
|
//TODO: Router could be nil in cnc mode
|
||||||
|
|
@ -113,11 +117,7 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sesh, existing, err := user.GetSession(ci.SessionId, mux.SessionConfig{
|
sesh, existing, err := user.GetSession(ci.SessionId, seshConfig)
|
||||||
Obfuscator: obfuscator,
|
|
||||||
Valve: nil,
|
|
||||||
Unordered: ci.Unordered,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user.CloseSession(ci.SessionId, "")
|
user.CloseSession(ci.SessionId, "")
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
|
@ -173,9 +173,17 @@ func DispatchConnection(conn net.Conn, sta *State) {
|
||||||
}
|
}
|
||||||
log.Tracef("%v endpoint has been successfully connected", ci.ProxyMethod)
|
log.Tracef("%v endpoint has been successfully connected", ci.ProxyMethod)
|
||||||
|
|
||||||
go util.Pipe(localConn, newStream, sta.Timeout)
|
//TODO: stream timeout
|
||||||
go util.Pipe(newStream, localConn, 0)
|
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/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
@ -58,18 +56,12 @@ func CryptoRandRead(buf []byte) {
|
||||||
log.Fatal("Cannot get cryptographic random bytes after 10 retries")
|
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) {
|
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
|
// The maximum size of TLS message will be 16380+14+16. 14 because of the stream header and 16
|
||||||
// because of the salt/mac
|
// because of the salt/mac
|
||||||
// 16408 is the max TLS message size on Firefox
|
// 16408 is the max TLS message size on Firefox
|
||||||
buf := make([]byte, 16378)
|
buf := make([]byte, 16378)
|
||||||
if srcReadTimeout != 0 {
|
|
||||||
src.SetReadDeadline(time.Now().Add(srcReadTimeout))
|
|
||||||
}
|
|
||||||
for {
|
for {
|
||||||
if srcReadTimeout != 0 {
|
if srcReadTimeout != 0 {
|
||||||
src.SetReadDeadline(time.Now().Add(srcReadTimeout))
|
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