Files

539 lines
13 KiB
Go

package scenario
import (
"bytes"
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"os"
"sync"
"testing"
"time"
netproxy "golang.org/x/net/proxy"
_ "github.com/p4gefau1t/trojan-go/api"
_ "github.com/p4gefau1t/trojan-go/api/service"
"github.com/p4gefau1t/trojan-go/common"
_ "github.com/p4gefau1t/trojan-go/log/golog"
"github.com/p4gefau1t/trojan-go/proxy"
_ "github.com/p4gefau1t/trojan-go/proxy/client"
_ "github.com/p4gefau1t/trojan-go/proxy/forward"
_ "github.com/p4gefau1t/trojan-go/proxy/nat"
_ "github.com/p4gefau1t/trojan-go/proxy/server"
_ "github.com/p4gefau1t/trojan-go/statistic/memory"
"github.com/p4gefau1t/trojan-go/test/util"
)
// test key and cert
var cert = `
-----BEGIN CERTIFICATE-----
MIIC5TCCAc2gAwIBAgIJAJqNVe6g/10vMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0yMTA5MTQwNjE1MTFaFw0yNjA5MTMwNjE1MTFaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAK7bupJ8tmHM3shQ/7N730jzpRsXdNiBxq/Jxx8j+vB3AcxuP5bjXQZqS6YR
5W5vrfLlegtq1E/mmaI3Ht0RfIlzev04Dua9PWmIQJD801nEPknbfgCLXDh+pYr2
sfg8mUh3LjGtrxyH+nmbTjWg7iWSKohmZ8nUDcX94Llo5FxibMAz8OsAwOmUueCH
jP3XswZYHEy+OOP3K0ZEiJy0f5T6ZXk9OWYuPN4VQKJx1qrc9KzZtSPHwqVdkGUi
ase9tOPA4aMutzt0btgW7h7UrvG6C1c/Rr1BxdiYq1EQ+yypnAlyToVQSNbo67zz
wGQk4GeruIkOgJOLdooN/HjhbHMCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B
AQsFAAOCAQEASsBzHHYiWDDiBVWUEwVZAduTrslTLNOxG0QHBKsHWIlz/3QlhQil
ywb3OhfMTUR1dMGY5Iq5432QiCHO4IMCOv7tDIkgb4Bc3v/3CRlBlnurtAmUfNJ6
pTRSlK4AjWpGHAEEd/8aCaOE86hMP8WDht8MkJTRrQqpJ1HeDISoKt9nepHOIsj+
I2zLZZtw0pg7FuR4MzWuqOt071iRS46Pupryb3ZEGIWNz5iLrDQod5Iz2ZGSRGqE
rB8idX0mlj5AHRRanVR3PAes+eApsW9JvYG/ImuCOs+ZsukY614zQZdR+SyFm85G
4NICyeQsmiypNHHgw+xZmGqZg65bXNGoyg==
-----END CERTIFICATE-----
`
var key = `
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu27qSfLZhzN7I
UP+ze99I86UbF3TYgcavyccfI/rwdwHMbj+W410GakumEeVub63y5XoLatRP5pmi
Nx7dEXyJc3r9OA7mvT1piECQ/NNZxD5J234Ai1w4fqWK9rH4PJlIdy4xra8ch/p5
m041oO4lkiqIZmfJ1A3F/eC5aORcYmzAM/DrAMDplLngh4z917MGWBxMvjjj9ytG
RIictH+U+mV5PTlmLjzeFUCicdaq3PSs2bUjx8KlXZBlImrHvbTjwOGjLrc7dG7Y
Fu4e1K7xugtXP0a9QcXYmKtREPssqZwJck6FUEjW6Ou888BkJOBnq7iJDoCTi3aK
Dfx44WxzAgMBAAECggEBAKYhib/H0ZhWB4yWuHqUxG4RXtrAjHlvw5Acy5zgmHiC
+Sh7ztrTJf0EXN9pvWwRm1ldgXj7hMBtPaaLbD1pccM9/qo66p17Sq/LjlyyeTOe
affOHIbz4Sij2zCOdkR9fr0EztTQScF3yBhl4Aa/4cO8fcCeWxm86WEldq9x4xWJ
s5WMR4CnrOJhDINLNPQPKX92KyxEQ/RfuBWovx3M0nl3fcUWfESY134t5g/UBFId
In19tZ+pGIpCkxP0U1AZWrlZRA8Q/3sO2orUpoAOdCrGk/DcCTMh0c1pMzbYZ1/i
cYXn38MpUo8QeG4FElUhAv6kzeBIl2tRBMVzIigo+AECgYEA3No1rHdFu6Ox9vC8
E93PTZevYVcL5J5yx6x7khCaOLKKuRXpjOX/h3Ll+hlN2DVAg5Jli/JVGCco4GeK
kbFLSyxG1+E63JbgsVpaEOgvFT3bHHSPSRJDnIU+WkcNQ2u4Ky5ahZzbNdV+4fj2
NO2iMgkm7hoJANrm3IqqW8epenMCgYEAyq+qdNj5DiDzBcDvLwY+4/QmMOOgDqeh
/TzhbDRyr+m4xNT7LLS4s/3wcbkQC33zhMUI3YvOHnYq5Ze/iL/TSloj0QCp1I7L
J7sZeM1XimMBQIpCfOC7lf4tU76Fz0DTHAL+CmX1DgmRJdYO09843VsKkscC968R
4cwL5oGxxgECgYAM4TTsH/CTJtLEIfn19qOWVNhHhvoMlSkAeBCkzg8Qa2knrh12
uBsU3SCIW11s1H40rh758GICDJaXr7InGP3ZHnXrNRlnr+zeqvRBtCi6xma23B1X
F5eV0zd1sFsXqXqOGh/xVtp54z+JEinZoForLNl2XVJVGG8KQZP50kUR/QKBgH4O
8zzpFT0sUPlrHVdp0wODfZ06dPmoWJ9flfPuSsYN3tTMgcs0Owv3C+wu5UPAegxB
X1oq8W8Qn21cC8vJQmgj19LNTtLcXI3BV/5B+Aghu02gr+lq/EA1bYuAG0jjUGlD
kyx0bQzl9lhJ4b70PjGtxc2z6KyTPdPpTB143FABAoGAQDoIUdc77/IWcjzcaXeJ
8abak5rAZA7cu2g2NVfs+Km+njsB0pbTwMnV1zGoFABdaHLdqbthLWtX7WOb1PDD
MQ+kbiLw5uj8IY2HEqJhDGGEdXBqxbW7kyuIAN9Mw+mwKzkikNcFQdxgchWH1d1o
lVkr92iEX+IhIeYb4DN1vQw=
-----END PRIVATE KEY-----
`
func init() {
os.WriteFile("server.crt", []byte(cert), 0o777)
os.WriteFile("server.key", []byte(key), 0o777)
}
func CheckClientServer(clientData, serverData string, socksPort int) (ok bool) {
server, err := proxy.NewProxyFromConfigData([]byte(serverData), false)
common.Must(err)
go server.Run()
client, err := proxy.NewProxyFromConfigData([]byte(clientData), false)
common.Must(err)
go client.Run()
time.Sleep(time.Second * 2)
dialer, err := netproxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", socksPort), nil, netproxy.Direct)
common.Must(err)
ok = true
const num = 100
wg := sync.WaitGroup{}
wg.Add(num)
for i := 0; i < num; i++ {
go func() {
const payloadSize = 1024
payload := util.GeneratePayload(payloadSize)
buf := [payloadSize]byte{}
conn, err := dialer.Dial("tcp", util.EchoAddr)
common.Must(err)
common.Must2(conn.Write(payload))
common.Must2(conn.Read(buf[:]))
if !bytes.Equal(payload, buf[:]) {
ok = false
}
conn.Close()
wg.Done()
}()
}
wg.Wait()
client.Close()
server.Close()
return
}
func TestClientServerWebsocketSubTree(t *testing.T) {
serverPort := common.PickPort("tcp", "127.0.0.1")
socksPort := common.PickPort("tcp", "127.0.0.1")
clientData := fmt.Sprintf(`
run-type: client
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %d
password:
- password
ssl:
verify: false
fingerprint: firefox
sni: localhost
websocket:
enabled: true
path: /ws
host: somedomainname.com
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
mux:
enabled: true
`, socksPort, serverPort)
serverData := fmt.Sprintf(`
run-type: server
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %s
disable-http-check: true
password:
- password
ssl:
verify-hostname: false
key: server.key
cert: server.crt
sni: localhost
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
websocket:
enabled: true
path: /ws
host: 127.0.0.1
`, serverPort, util.HTTPPort)
if !CheckClientServer(clientData, serverData, socksPort) {
t.Fail()
}
}
func TestClientServerTrojanSubTree(t *testing.T) {
serverPort := common.PickPort("tcp", "127.0.0.1")
socksPort := common.PickPort("tcp", "127.0.0.1")
clientData := fmt.Sprintf(`
run-type: client
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %d
password:
- password
ssl:
verify: false
fingerprint: firefox
sni: localhost
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
mux:
enabled: true
`, socksPort, serverPort)
serverData := fmt.Sprintf(`
run-type: server
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %s
disable-http-check: true
password:
- password
ssl:
verify-hostname: false
key: server.key
cert: server.crt
sni: localhost
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
`, serverPort, util.HTTPPort)
if !CheckClientServer(clientData, serverData, socksPort) {
t.Fail()
}
}
func TestWebsocketDetection(t *testing.T) {
serverPort := common.PickPort("tcp", "127.0.0.1")
socksPort := common.PickPort("tcp", "127.0.0.1")
clientData := fmt.Sprintf(`
run-type: client
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %d
password:
- password
ssl:
verify: false
fingerprint: firefox
sni: localhost
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
mux:
enabled: true
`, socksPort, serverPort)
serverData := fmt.Sprintf(`
run-type: server
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %s
disable-http-check: true
password:
- password
ssl:
verify-hostname: false
key: server.key
cert: server.crt
sni: localhost
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
websocket:
enabled: true
path: /ws
hostname: 127.0.0.1
`, serverPort, util.HTTPPort)
if !CheckClientServer(clientData, serverData, socksPort) {
t.Fail()
}
}
func TestPluginWebsocket(t *testing.T) {
serverPort := common.PickPort("tcp", "127.0.0.1")
socksPort := common.PickPort("tcp", "127.0.0.1")
clientData := fmt.Sprintf(`
run-type: client
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %d
password:
- password
transport-plugin:
enabled: true
type: plaintext
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
mux:
enabled: true
websocket:
enabled: true
path: /ws
hostname: 127.0.0.1
`, socksPort, serverPort)
serverData := fmt.Sprintf(`
run-type: server
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %s
disable-http-check: true
password:
- password
transport-plugin:
enabled: true
type: plaintext
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
websocket:
enabled: true
path: /ws
hostname: 127.0.0.1
`, serverPort, util.HTTPPort)
if !CheckClientServer(clientData, serverData, socksPort) {
t.Fail()
}
}
func TestForward(t *testing.T) {
serverPort := common.PickPort("tcp", "127.0.0.1")
clientPort := common.PickPort("tcp", "127.0.0.1")
_, targetPort, _ := net.SplitHostPort(util.EchoAddr)
clientData := fmt.Sprintf(`
run-type: forward
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %d
target-addr: 127.0.0.1
target-port: %s
password:
- password
ssl:
verify: false
fingerprint: firefox
sni: localhost
websocket:
enabled: true
path: /ws
hostname: 127.0.0.1
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
mux:
enabled: true
`, clientPort, serverPort, targetPort)
go func() {
proxy, err := proxy.NewProxyFromConfigData([]byte(clientData), false)
common.Must(err)
common.Must(proxy.Run())
}()
serverData := fmt.Sprintf(`
run-type: server
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %s
disable-http-check: true
password:
- password
ssl:
verify-hostname: false
key: server.key
cert: server.crt
sni: "localhost"
websocket:
enabled: true
path: /ws
hostname: 127.0.0.1
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
`, serverPort, util.HTTPPort)
go func() {
proxy, err := proxy.NewProxyFromConfigData([]byte(serverData), false)
common.Must(err)
common.Must(proxy.Run())
}()
time.Sleep(time.Second * 2)
payload := util.GeneratePayload(1024)
buf := [1024]byte{}
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", clientPort))
common.Must(err)
common.Must2(conn.Write(payload))
common.Must2(conn.Read(buf[:]))
if !bytes.Equal(payload, buf[:]) {
t.Fail()
}
packet, err := net.ListenPacket("udp", "")
common.Must(err)
common.Must2(packet.WriteTo(payload, &net.UDPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: clientPort,
}))
_, _, err = packet.ReadFrom(buf[:])
common.Must(err)
if !bytes.Equal(payload, buf[:]) {
t.Fail()
}
}
func TestLeak(t *testing.T) {
serverPort := common.PickPort("tcp", "127.0.0.1")
socksPort := common.PickPort("tcp", "127.0.0.1")
clientData := fmt.Sprintf(`
run-type: client
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %d
log-level: 0
password:
- password
ssl:
verify: false
fingerprint: firefox
sni: localhost
shadowsocks:
enabled: true
method: AEAD_CHACHA20_POLY1305
password: 12345678
mux:
enabled: true
api:
enabled: true
api-port: 0
`, socksPort, serverPort)
client, err := proxy.NewProxyFromConfigData([]byte(clientData), false)
common.Must(err)
go client.Run()
time.Sleep(time.Second * 3)
client.Close()
time.Sleep(time.Second * 3)
// http.ListenAndServe("localhost:6060", nil)
}
func SingleThreadBenchmark(clientData, serverData string, socksPort int) {
server, err := proxy.NewProxyFromConfigData([]byte(clientData), false)
common.Must(err)
go server.Run()
client, err := proxy.NewProxyFromConfigData([]byte(serverData), false)
common.Must(err)
go client.Run()
time.Sleep(time.Second * 2)
dialer, err := netproxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", socksPort), nil, netproxy.Direct)
common.Must(err)
const num = 100
wg := sync.WaitGroup{}
wg.Add(num)
const payloadSize = 1024 * 1024 * 1024
payload := util.GeneratePayload(payloadSize)
for i := 0; i < 100; i++ {
conn, err := dialer.Dial("tcp", util.BlackHoleAddr)
common.Must(err)
t1 := time.Now()
common.Must2(conn.Write(payload))
t2 := time.Now()
speed := float64(payloadSize) / (float64(t2.Sub(t1).Nanoseconds()) / float64(time.Second))
fmt.Printf("speed: %f Gbps\n", speed/1024/1024/1024)
conn.Close()
}
client.Close()
server.Close()
}
func BenchmarkClientServer(b *testing.B) {
go func() {
fmt.Println(http.ListenAndServe("localhost:6060", nil))
}()
serverPort := common.PickPort("tcp", "127.0.0.1")
socksPort := common.PickPort("tcp", "127.0.0.1")
clientData := fmt.Sprintf(`
run-type: client
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %d
log-level: 0
password:
- password
ssl:
verify: false
fingerprint: firefox
sni: localhost
`, socksPort, serverPort)
serverData := fmt.Sprintf(`
run-type: server
local-addr: 127.0.0.1
local-port: %d
remote-addr: 127.0.0.1
remote-port: %s
log-level: 0
disable-http-check: true
password:
- password
ssl:
verify-hostname: false
key: server.key
cert: server.crt
sni: localhost
`, serverPort, util.HTTPPort)
SingleThreadBenchmark(clientData, serverData, socksPort)
}