fix shadow, add obfs key

This commit is contained in:
p4gefau1t
2020-04-25 06:26:54 -04:00
parent 4bb5b31e91
commit 4bc09bedff
8 changed files with 106 additions and 58 deletions
+2
View File
@@ -41,6 +41,8 @@ func (s *ClientAPIService) calcSpeed() {
sent, recv := s.meter.Query("")
s.uploadSpeed = sent - s.lastSent
s.downloadSpeed = recv - s.lastRecv
s.lastSent = sent
s.lastRecv = recv
case <-s.ctx.Done():
return
}
+2 -2
View File
@@ -62,8 +62,8 @@ func (r *RewindReader) Discard(n int) (int, error) {
}
func (r *RewindReader) Rewind() {
if !r.buffered {
panic("not buffered yet")
if r.bufferSize == 0 {
panic("has no buffer")
}
r.rewinded = true
r.bufReadIdx = 0
+8 -6
View File
@@ -100,12 +100,14 @@ type RouterConfig struct {
}
type WebsocketConfig struct {
Enabled bool `json:"enabled"`
HostName string `json:"hostname"`
Path string `json:"path"`
Obfuscation bool `json:"obfuscation"`
DoubleTLS bool `json:"double_tls"`
DoubleTLSVerify bool `json:"double_tls_verify"`
Enabled bool `json:"enabled"`
HostName string `json:"hostname"`
Path string `json:"path"`
ObfuscationPassword string `json:"obfuscation_password"`
DoubleTLS bool `json:"double_tls"`
DoubleTLSVerify bool `json:"double_tls_verify"`
ObfuscationKey []byte
}
type APIConfig struct {
+10 -1
View File
@@ -1,6 +1,8 @@
package conf
import (
"crypto/aes"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/json"
@@ -12,6 +14,7 @@ import (
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/log"
"golang.org/x/crypto/pbkdf2"
)
func loadCommonConfig(config *GlobalConfig) error {
@@ -104,6 +107,12 @@ func loadCommonConfig(config *GlobalConfig) error {
config.Websocket.HostName = "[" + config.RemoteHost + "]"
}
}
if config.Websocket.ObfuscationPassword != "" {
log.Info("websocket obfs enabled")
password := []byte(config.Websocket.ObfuscationPassword)
salt := []byte{48, 149, 6, 18, 13, 193, 247, 116, 197, 135, 236, 175, 190, 209, 146, 48}
config.Websocket.ObfuscationKey = pbkdf2.Key(password, salt, 32, aes.BlockSize, sha256.New)
}
}
return nil
}
@@ -292,7 +301,7 @@ func ParseJSON(data []byte) (*GlobalConfig, error) {
config.Router.GeoSiteFilename = common.GetProgramDir() + "/geosite.dat"
config.Websocket.DoubleTLS = true
config.Websocket.DoubleTLSVerify = true
config.Websocket.Obfuscation = true
config.Websocket.ObfuscationPassword = ""
err := json.Unmarshal(data, config)
if err != nil {
+2 -2
View File
@@ -92,9 +92,8 @@ func (i *TrojanInboundConnSession) SetMeter(meter stat.TrafficMeter) {
func NewInboundConnSession(ctx context.Context, conn net.Conn, config *conf.GlobalConfig, auth stat.Authenticator, shadowMan *shadow.ShadowManager) (protocol.ConnSession, *protocol.Request, error) {
ctx, cancel := context.WithCancel(context.Background())
//rwc := common.NewRewindReadWriteCloser(conn)
rewindConn := common.NewRewindConn(conn)
i := &TrojanInboundConnSession{
config: config,
auth: auth,
@@ -103,6 +102,7 @@ func NewInboundConnSession(ctx context.Context, conn net.Conn, config *conf.Glob
cancel: cancel,
rwc: rewindConn,
}
//start buffering
rewindConn.R.SetBufferSize(512)
defer rewindConn.R.StopBuffering()
+17 -21
View File
@@ -6,7 +6,6 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha1"
"crypto/tls"
"io"
"net"
@@ -18,7 +17,6 @@ import (
"github.com/p4gefau1t/trojan-go/log"
"github.com/p4gefau1t/trojan-go/protocol"
"github.com/p4gefau1t/trojan-go/shadow"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/net/websocket"
)
@@ -44,16 +42,14 @@ func (rwc *obfReadWriteCloser) Close() error {
return rwc.Conn.Close()
}
func NewOutboundObfReadWriteCloser(password string, conn *websocket.Conn) *obfReadWriteCloser {
func NewOutboundObfReadWriteCloser(key []byte, conn *websocket.Conn) *obfReadWriteCloser {
//use bufio to avoid fixed ws packet length
bufrw := common.NewBufioReadWriter(conn)
randomBytes := [aes.BlockSize + 8]byte{}
common.Must2(io.ReadFull(rand.Reader, randomBytes[:]))
bufrw.Write(randomBytes[:])
iv := [aes.BlockSize]byte{}
common.Must2(io.ReadFull(rand.Reader, iv[:]))
bufrw.Write(iv[:])
log.Debug("obfs sent iv", iv)
iv := randomBytes[:aes.BlockSize]
salt := randomBytes[aes.BlockSize:]
key := pbkdf2.Key([]byte(password), salt, 32, aes.BlockSize, sha1.New)
block, err := aes.NewCipher(key)
common.Must(err)
@@ -71,17 +67,15 @@ func NewOutboundObfReadWriteCloser(password string, conn *websocket.Conn) *obfRe
}
}
func NewInboundObfReadWriteCloser(password string, conn net.Conn) (*obfReadWriteCloser, error) {
func NewInboundObfReadWriteCloser(key []byte, conn net.Conn) (*obfReadWriteCloser, error) {
bufrw := common.NewBufioReadWriter(conn)
randomBytes := [aes.BlockSize + 8]byte{}
_, err := bufrw.Read(randomBytes[:])
iv := [aes.BlockSize]byte{}
_, err := bufrw.Read(iv[:])
if err != nil {
return nil, err
}
log.Debug("obfs recv iv", iv)
iv := randomBytes[:aes.BlockSize]
salt := randomBytes[aes.BlockSize:]
key := pbkdf2.Key([]byte(password), salt, 32, aes.BlockSize, sha1.New)
block, err := aes.NewCipher(key)
common.Must(err)
@@ -128,9 +122,9 @@ func NewOutboundWebosocket(conn net.Conn, config *conf.GlobalConfig) (io.ReadWri
return nil, err
}
var transport net.Conn = wsConn
if config.Websocket.Obfuscation {
if config.Websocket.ObfuscationPassword != "" {
log.Debug("ws obfs enabled")
transport = NewOutboundObfReadWriteCloser(config.Passwords[0], wsConn)
transport = NewOutboundObfReadWriteCloser(config.Websocket.ObfuscationKey, wsConn)
}
if !config.Websocket.DoubleTLS {
return transport, nil
@@ -194,7 +188,7 @@ func NewInboundWebsocket(ctx context.Context, conn net.Conn, config *conf.Global
rewindConn.R.SetBufferSize(512)
defer rewindConn.R.StopBuffering()
bufrw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
bufrw := bufio.NewReadWriter(bufio.NewReader(rewindConn), bufio.NewWriter(rewindConn))
httpRequest, obfErr := http.ReadRequest(bufrw.Reader)
if obfErr != nil {
log.Debug(common.NewError("not a http request:").Base(obfErr))
@@ -258,19 +252,21 @@ func NewInboundWebsocket(ctx context.Context, conn net.Conn, config *conf.Global
return nil, common.NewError("failed to perform websocket handshake")
}
//use ws to transport
var transport net.Conn
transport = common.NewRewindConn(wsConn)
rewindConn = common.NewRewindConn(wsConn)
transport = rewindConn
//start buffering the websocket payload
rewindConn.R.SetBufferSize(512)
defer rewindConn.R.StopBuffering()
if config.Websocket.Obfuscation {
if config.Websocket.ObfuscationPassword != "" {
log.Debug("ws obfs")
//deadline for sending the iv and hash
rewindConn.SetDeadline(time.Now().Add(protocol.TCPTimeout))
transport, obfErr = NewInboundObfReadWriteCloser(config.Passwords[0], rewindConn)
transport, obfErr = NewInboundObfReadWriteCloser(config.Websocket.ObfuscationKey, transport)
rewindConn.SetDeadline(time.Time{})
if obfErr != nil {
-1
View File
@@ -216,7 +216,6 @@ func (s *Server) Run() error {
}
return
}
defer tlsConn.Close()
s.handleConn(tlsConn)
}(conn)
}
+65 -25
View File
@@ -3,9 +3,9 @@ package test
import (
"bytes"
"context"
"crypto/md5"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net"
"testing"
@@ -97,7 +97,7 @@ func getTLSConfig() conf.TLSConfig {
VerifyHostname: true,
ReuseSession: true,
SessionTicket: true,
FallbackAddress: common.NewAddress("127.0.0.1", 80, "tcp"),
FallbackAddress: common.NewAddress("127.0.0.1", 10080, "tcp"),
}
return c
}
@@ -139,12 +139,15 @@ func getBasicClientConfig() *conf.GlobalConfig {
func addWsConfig(config *conf.GlobalConfig) *conf.GlobalConfig {
config.Websocket = conf.WebsocketConfig{
Enabled: true,
HostName: "127.0.0.1",
Path: "/websocket",
Obfuscation: false,
DoubleTLS: true,
Enabled: true,
HostName: "127.0.0.1",
Path: "/websocket",
ObfuscationPassword: "123456789",
DoubleTLS: true,
}
hash := md5.New()
hash.Write([]byte(config.Websocket.ObfuscationPassword))
config.Websocket.ObfuscationKey = hash.Sum(nil)
return config
}
@@ -326,13 +329,60 @@ func BenchmarkWebsocket(b *testing.B) {
SingleThreadSpeedTestClientServer(b, clientConfig, serverConfig)
}
func TestHTTPProxy(t *testing.T) {
func BenchmarkMuxWebsocket(b *testing.B) {
clientConfig := addMuxConfig(addWsConfig(getBasicClientConfig()))
serverConfig := addWsConfig(getBasicServerConfig())
SingleThreadSpeedTestClientServer(b, clientConfig, serverConfig)
}
func TestWebsocketShadow(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go RunHelloHTTPServer(ctx)
serverConfig := addWsConfig(getBasicServerConfig())
go RunServer(ctx, serverConfig)
time.Sleep(time.Second)
//test http
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
}
resp, err := httpClient.Get("https://127.0.0.1:4445")
common.Must(err)
body, err := ioutil.ReadAll(resp.Body)
common.Must(err)
if string(body) != "HelloWorld" {
t.Fatal("http shadow")
}
//test websocket
conn, err := tls.Dial("tcp", "127.0.0.1:4445", &tls.Config{InsecureSkipVerify: true})
common.Must(err)
wsConfig, err := websocket.NewConfig("wss://127.0.0.1/websocket", "https://127.0.0.1")
common.Must(err)
wsClient, err := websocket.NewClient(wsConfig, conn)
common.Must(err)
buf := [100]byte{}
common.Must2(wsClient.Write([]byte("I'm GFW1231231231231212391273871283719823791237912398721933123")))
n, err := wsClient.Read(buf[:])
common.Must(err)
if string(buf[:n]) != "HelloWorld" {
t.Fatal("ws shadow")
}
conn.Close()
cancel()
}
func TestShadow(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go RunHelloHTTPServer(ctx)
serverConfig := getBasicServerConfig()
go RunServer(ctx, serverConfig)
time.Sleep(time.Second)
//test http
httpClient := &http.Client{
//some config
@@ -347,26 +397,16 @@ func TestHTTPProxy(t *testing.T) {
body, err := ioutil.ReadAll(resp.Body)
common.Must(err)
if string(body) != "HelloWorld" {
t.Fatal("server http proxy failed")
t.Fatal("http shadow")
}
//test websocket
conn, err := tls.Dial("tcp", "127.0.0.1:4445", &tls.Config{InsecureSkipVerify: true})
common.Must(err)
wsConfig, err := websocket.NewConfig("wss://127.0.0.1/websocket", "https://127.0.0.1")
common.Must(err)
wsClient, err := websocket.NewClient(wsConfig, conn)
common.Must(err)
buf := [100]byte{}
common.Must2(wsClient.Write([]byte("I'm GFW1231231231231212391273871283719823791237912398721933123")))
common.Must2(wsClient.Read(buf[:]))
fmt.Println(buf)
common.Must(err)
conn.Close()
//fallback
resp, err = http.Get("http://127.0.0.1:4445")
common.Must(err)
resp.Body.Read(buf[:])
fmt.Println(buf)
body, err = ioutil.ReadAll(resp.Body)
common.Must(err)
if string(body) != "HelloWorld" {
t.Fatal("http shadow")
}
cancel()
}