mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2026-10-19 16:15:38 +00:00
fix ss fallback, redirector nil interface
This commit is contained in:
+20
-2
@@ -2,14 +2,31 @@ package custom
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"github.com/p4gefau1t/trojan-go/config"
|
||||
"github.com/p4gefau1t/trojan-go/proxy"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
"gopkg.in/yaml.v2"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func convert(i interface{}) interface{} {
|
||||
switch x := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
m2 := map[string]interface{}{}
|
||||
for k, v := range x {
|
||||
m2[k.(string)] = convert(v)
|
||||
}
|
||||
return m2
|
||||
case []interface{}:
|
||||
for i, v := range x {
|
||||
x[i] = convert(v)
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func buildNodes(ctx context.Context, nodeConfigList []NodeConfig) (map[string]*proxy.Node, error) {
|
||||
nodes := make(map[string]*proxy.Node)
|
||||
for _, nodeCfg := range nodeConfigList {
|
||||
@@ -18,10 +35,11 @@ func buildNodes(ctx context.Context, nodeConfigList []NodeConfig) (map[string]*p
|
||||
return nil, common.NewError("invalid protocol name:" + nodeCfg.Protocol)
|
||||
}
|
||||
data, err := yaml.Marshal(nodeCfg.Config)
|
||||
common.Must(err)
|
||||
nodeContext, err := config.WithYAMLConfig(ctx, data)
|
||||
if err != nil {
|
||||
return nil, common.NewError("failed to parse config data for " + nodeCfg.Tag + " with protocol" + nodeCfg.Protocol).Base(err)
|
||||
}
|
||||
nodeContext, err := config.WithYAMLConfig(ctx, data)
|
||||
node := &proxy.Node{
|
||||
Name: nodeCfg.Protocol,
|
||||
Next: make(map[string]*proxy.Node),
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"reflect"
|
||||
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"github.com/p4gefau1t/trojan-go/log"
|
||||
@@ -42,7 +43,7 @@ func (r *Redirector) worker() {
|
||||
if redirection.Dial == nil {
|
||||
redirection.Dial = defaultDial
|
||||
}
|
||||
if redirection.RedirectTo == nil {
|
||||
if reflect.ValueOf(redirection.RedirectTo).IsNil() {
|
||||
log.Error("nil redirection addr")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCustom(t *testing.T) {
|
||||
func TestCustom1(t *testing.T) {
|
||||
serverPort := common.PickPort("tcp", "127.0.0.1")
|
||||
socksPort := common.PickPort("tcp", "127.0.0.1")
|
||||
clientData := fmt.Sprintf(`
|
||||
@@ -48,7 +48,7 @@ outbound:
|
||||
tag: trojan
|
||||
config:
|
||||
password:
|
||||
- 12345678
|
||||
- "12345678"
|
||||
|
||||
path:
|
||||
-
|
||||
@@ -83,7 +83,7 @@ inbound:
|
||||
config:
|
||||
disable-http-check: true
|
||||
password:
|
||||
- 12345678
|
||||
- "12345678"
|
||||
|
||||
- protocol: mux
|
||||
tag: mux
|
||||
@@ -119,3 +119,175 @@ outbound:
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustom2(t *testing.T) {
|
||||
serverPort := common.PickPort("tcp", "127.0.0.1")
|
||||
socksPort := common.PickPort("tcp", "127.0.0.1")
|
||||
clientData := fmt.Sprintf(`
|
||||
run-type: custom
|
||||
log-level: 0
|
||||
|
||||
inbound:
|
||||
node:
|
||||
- protocol: transport
|
||||
tag: transport
|
||||
config:
|
||||
local-addr: 127.0.0.1
|
||||
local-port: %d
|
||||
- protocol: socks
|
||||
tag: socks
|
||||
path:
|
||||
-
|
||||
- transport
|
||||
- socks
|
||||
|
||||
outbound:
|
||||
node:
|
||||
- protocol: transport
|
||||
tag: transport
|
||||
config:
|
||||
remote-addr: 127.0.0.1
|
||||
remote-port: %d
|
||||
|
||||
- protocol: tls
|
||||
tag: tls
|
||||
config:
|
||||
ssl:
|
||||
sni: localhost
|
||||
key: server.key
|
||||
cert: server.crt
|
||||
|
||||
- protocol: trojan
|
||||
tag: trojan
|
||||
config:
|
||||
password:
|
||||
- "12345678"
|
||||
|
||||
- protocol: shadowsocks
|
||||
tag: shadowsocks
|
||||
config:
|
||||
remote-addr: 127.0.0.1
|
||||
remote-port: 80
|
||||
shadowsocks:
|
||||
enabled: true
|
||||
password: "12345678"
|
||||
|
||||
- protocol: websocket
|
||||
tag: websocket
|
||||
config:
|
||||
websocket:
|
||||
hostname: localhost
|
||||
path: /ws
|
||||
|
||||
path:
|
||||
-
|
||||
- transport
|
||||
- tls
|
||||
- websocket
|
||||
- shadowsocks
|
||||
- trojan
|
||||
|
||||
`, socksPort, serverPort)
|
||||
serverData := fmt.Sprintf(`
|
||||
run-type: custom
|
||||
log-level: 0
|
||||
|
||||
inbound:
|
||||
node:
|
||||
- protocol: transport
|
||||
tag: transport
|
||||
config:
|
||||
local-addr: 127.0.0.1
|
||||
local-port: %d
|
||||
remote-addr: 127.0.0.1
|
||||
remote-port: %s
|
||||
|
||||
- protocol: tls
|
||||
tag: tls
|
||||
config:
|
||||
ssl:
|
||||
sni: localhost
|
||||
key: server.key
|
||||
cert: server.crt
|
||||
|
||||
- protocol: trojan
|
||||
tag: trojan
|
||||
config:
|
||||
disable-http-check: true
|
||||
password:
|
||||
- "12345678"
|
||||
|
||||
- protocol: trojan
|
||||
tag: trojan2
|
||||
config:
|
||||
disable-http-check: true
|
||||
password:
|
||||
- "12345678"
|
||||
|
||||
- protocol: websocket
|
||||
tag: websocket
|
||||
config:
|
||||
websocket:
|
||||
enabled: true
|
||||
hostname: localhost
|
||||
path: /ws
|
||||
|
||||
- protocol: mux
|
||||
tag: mux
|
||||
|
||||
- protocol: simplesocks
|
||||
tag: simplesocks
|
||||
|
||||
- protocol: shadowsocks
|
||||
tag: shadowsocks
|
||||
config:
|
||||
remote-addr: 127.0.0.1
|
||||
remote-port: 80
|
||||
shadowsocks:
|
||||
enabled: true
|
||||
password: "12345678"
|
||||
|
||||
- protocol: shadowsocks
|
||||
tag: shadowsocks2
|
||||
config:
|
||||
remote-addr: 127.0.0.1
|
||||
remote-port: 80
|
||||
shadowsocks:
|
||||
enabled: true
|
||||
password: "12345678"
|
||||
|
||||
path:
|
||||
-
|
||||
- transport
|
||||
- tls
|
||||
- shadowsocks
|
||||
- trojan
|
||||
-
|
||||
- transport
|
||||
- tls
|
||||
- websocket
|
||||
- shadowsocks2
|
||||
- trojan2
|
||||
-
|
||||
- transport
|
||||
- tls
|
||||
- shadowsocks
|
||||
- trojan
|
||||
- mux
|
||||
- simplesocks
|
||||
|
||||
outbound:
|
||||
node:
|
||||
- protocol: freedom
|
||||
tag: freedom
|
||||
|
||||
path:
|
||||
-
|
||||
- freedom
|
||||
|
||||
`, serverPort, util.HTTPPort)
|
||||
|
||||
if !CheckClientServer(clientData, serverData, socksPort) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,11 +85,11 @@ func init() {
|
||||
}
|
||||
|
||||
func CheckClientServer(clientData, serverData string, socksPort int) (ok bool) {
|
||||
server, err := proxy.NewProxyFromConfigData([]byte(clientData), false)
|
||||
server, err := proxy.NewProxyFromConfigData([]byte(serverData), false)
|
||||
common.Must(err)
|
||||
go server.Run()
|
||||
|
||||
client, err := proxy.NewProxyFromConfigData([]byte(serverData), false)
|
||||
client, err := proxy.NewProxyFromConfigData([]byte(clientData), false)
|
||||
common.Must(err)
|
||||
go client.Run()
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ type ShadowsocksConfig struct {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
RemoteHost string `json:"remote_addr", yaml:"remote-addr"`
|
||||
RemotePort int `json:"remote_port", yaml:"remote-port"`
|
||||
RemoteHost string `json:"remote_addr" yaml:"remote-addr"`
|
||||
RemotePort int `json:"remote_port" yaml:"remote-port"`
|
||||
Shadowsocks ShadowsocksConfig `json,yaml:"shadowsocks"`
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ func (s *Server) AcceptConn(overlay tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
testConn := s.Cipher.StreamConn(rewindConn)
|
||||
if _, err := testConn.Read(buf[:]); err != nil {
|
||||
// we are under attack
|
||||
log.Error(common.NewError("shadowsocks failed to decrypt").Base(err))
|
||||
rewindConn.Rewind()
|
||||
rewindConn.StopBuffering()
|
||||
s.Redirect(&redirector.Redirection{
|
||||
@@ -63,6 +64,12 @@ func NewServer(ctx context.Context, underlay tunnel.Server) (*Server, error) {
|
||||
if err != nil {
|
||||
return nil, common.NewError("invalid shadowsocks cipher").Base(err)
|
||||
}
|
||||
if cfg.RemoteHost == "" {
|
||||
return nil, common.NewError("invalid shadowsocks redirection address")
|
||||
}
|
||||
if cfg.RemotePort == 0 {
|
||||
return nil, common.NewError("invalid shadowsocks redirection port")
|
||||
}
|
||||
log.Debug("shadowsocks client created")
|
||||
return &Server{
|
||||
underlay: underlay,
|
||||
|
||||
@@ -6,11 +6,12 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/tls/fingerprint"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/transport"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/tls/fingerprint"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/transport"
|
||||
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -139,6 +140,7 @@ func (s *Server) acceptLoop() {
|
||||
} else {
|
||||
if !s.nextHTTP {
|
||||
// there is no websocket layer waiting for connections, redirect it
|
||||
log.Error("incoming http request, but no websocket server is listening")
|
||||
s.redir.Redirect(&redirector.Redirection{
|
||||
InboundConn: rewindConn,
|
||||
RedirectTo: s.fallbackAddress,
|
||||
|
||||
@@ -66,6 +66,7 @@ func (s *Server) AcceptConn(tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
req, err := http.ReadRequest(rw.Reader)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("invalid http request")
|
||||
rewindConn.Rewind()
|
||||
rewindConn.StopBuffering()
|
||||
s.redir.Redirect(&redirector.Redirection{
|
||||
@@ -75,6 +76,7 @@ func (s *Server) AcceptConn(tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
return nil, common.NewError("not a valid http request: " + conn.RemoteAddr().String()).Base(err)
|
||||
}
|
||||
if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" || req.URL.Path != s.path {
|
||||
log.Debug("invalid http websocket handshake request")
|
||||
rewindConn.Rewind()
|
||||
rewindConn.StopBuffering()
|
||||
s.redir.Redirect(&redirector.Redirection{
|
||||
@@ -145,6 +147,14 @@ func NewServer(ctx context.Context, underlay tunnel.Server) (*Server, error) {
|
||||
return nil, common.NewError("websocket path must start with \"/\"")
|
||||
}
|
||||
}
|
||||
if cfg.RemoteHost == "" {
|
||||
log.Warn("empty websocket redirection hostname")
|
||||
cfg.RemoteHost = cfg.Websocket.Hostname
|
||||
}
|
||||
if cfg.RemotePort == 0 {
|
||||
log.Warn("empty websocket redirection port")
|
||||
cfg.RemotePort = 80
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
log.Debug("websocket server created")
|
||||
return &Server{
|
||||
|
||||
Reference in New Issue
Block a user