mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2024-04-21 12:21:34 +00:00
fix shadow, add obfs key
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -216,7 +216,6 @@ func (s *Server) Run() error {
|
||||
}
|
||||
return
|
||||
}
|
||||
defer tlsConn.Close()
|
||||
s.handleConn(tlsConn)
|
||||
}(conn)
|
||||
}
|
||||
|
||||
+65
-25
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user