Skip to content

Commit

Permalink
fix ss fallback, redirector nil interface
Browse files Browse the repository at this point in the history
  • Loading branch information
p4gefau1t committed Jun 21, 2020
1 parent 3e196db commit f906f21
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 12 deletions.
22 changes: 20 additions & 2 deletions proxy/custom/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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),
Expand Down
3 changes: 2 additions & 1 deletion redirector/redirector.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"io"
"net"
"reflect"

"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/log"
Expand Down Expand Up @@ -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
}
Expand Down
178 changes: 175 additions & 3 deletions test/scenario/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(`
Expand Down Expand Up @@ -48,7 +48,7 @@ outbound:
tag: trojan
config:
password:
- 12345678
- "12345678"
path:
-
Expand Down Expand Up @@ -83,7 +83,7 @@ inbound:
config:
disable-http-check: true
password:
- 12345678
- "12345678"
- protocol: mux
tag: mux
Expand Down Expand Up @@ -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()
}
}
4 changes: 2 additions & 2 deletions test/scenario/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
4 changes: 2 additions & 2 deletions tunnel/shadowsocks/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}

Expand Down
7 changes: 7 additions & 0 deletions tunnel/shadowsocks/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions tunnel/tls/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions tunnel/websocket/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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{
Expand Down Expand Up @@ -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{
Expand Down

0 comments on commit f906f21

Please sign in to comment.