Skip to content

Commit

Permalink
mirate to trojan protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
wweir committed Jul 31, 2020
1 parent 13a6be4 commit dab1a78
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 5 deletions.
8 changes: 5 additions & 3 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,11 @@ func StartServer(relayTarget, password, cacheDir, certFile, keyFile, email strin
go func(conn net.Conn) {
defer conn.Close()

conn, target := transport.ParseProxyConn(conn, passwordData)
if target == "" {
target = relayTarget
target := relayTarget

conn, t := transport.ParseTrojanConn(conn, passwordData)
if t != nil {
target = t.Addr()
}

rc, err := net.Dial("tcp", target)
Expand Down
2 changes: 1 addition & 1 deletion router/http_ping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestPort_Ping(t *testing.T) {
if err != nil {
return nil, err
}
return transport.ToProxyConn(conn, host, uint16(p), password)
return transport.ToTrojanConn(conn, host, uint16(p), password)
}

type args struct {
Expand Down
122 changes: 122 additions & 0 deletions transport/trojan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package transport

import (
"crypto/sha256"
"encoding/hex"
"io"
"net"
"strconv"

"github.com/wweir/sower/util"
"golang.org/x/xerrors"
)

// +-----------------------+---------+----------------+---------+----------+
// | hex(SHA224(password)) | CRLF | Trojan Request | CRLF | Payload |
// +-----------------------+---------+----------------+---------+----------+
// | 56 | X'0D0A' | Variable | X'0D0A' | Variable |
// +-----------------------+---------+----------------+---------+----------+
// +-----+------+----------+----------+
// | CMD | ATYP | DST.ADDR | DST.PORT |
// +-----+------+----------+----------+
// | 1 | 1 | Variable | 2 |
// +-----+------+----------+----------+
// o CMD
// o CONNECT X'01'
// o UDP :X'03'
// o ATYP
// o IP V4 : X'01'
// o domain: X'03'
// o IP V6 : X'04'

type Trojan struct {
Password [56]byte
TrojanRequest
}
type TrojanRequest struct {
CMD uint8
ATYP uint8
DstAddr []byte
DstPort uint16
}

func (t *TrojanRequest) Addr() string {
switch t.ATYP {
case 0x01:
fallthrough
case 0x04:
return net.JoinHostPort(net.IP(t.DstAddr).String(), strconv.Itoa(int(t.DstPort)))
case 0x03:
return string(t.DstAddr) + ":" + strconv.Itoa(int(t.DstPort))
default:
panic("invalid ATYP")
}
}

func ParseTrojanConn(conn net.Conn, password []byte) (net.Conn, *Trojan) {
passData := sha256.Sum224(password)
passHead := hex.EncodeToString(passData[:])

teeConn := &util.TeeConn{Conn: conn}
defer teeConn.Stop()

buf := make([]byte, 56+2+1+1+1)
if _, err := io.ReadFull(teeConn, buf); err != nil {
return teeConn, nil
}
if string(buf[:56]) != passHead {
return teeConn, nil
}

t := Trojan{}
t.CMD, t.ATYP = buf[58], buf[59]
addrLen := buf[60]
switch t.ATYP {
case 0x01: //ipv4
buf = make([]byte, net.IPv4len+2+2)
buf[0] = addrLen
if _, err := io.ReadFull(teeConn, buf[1:]); err != nil {
return teeConn, nil
}

case 0x04: //ipv6
buf = make([]byte, net.IPv6len+2+2)
buf[0] = addrLen
if _, err := io.ReadFull(teeConn, buf[1:]); err != nil {
return teeConn, nil
}

case 0x03: // domain
buf = make([]byte, addrLen+2+2)
buf[0] = addrLen
if _, err := io.ReadFull(teeConn, buf); err != nil {
return teeConn, nil
}
default:
return teeConn, nil
}

t.DstAddr = buf[:len(buf)-4]
t.DstPort = uint16(buf[len(buf)-4])<<8 + uint16(buf[len(buf)-3])

teeConn.Reset()
return teeConn, &t
}

func ToTrojanConn(conn net.Conn, tgtHost string, tgtPort uint16, password []byte) (net.Conn, error) {
passData := sha256.Sum224(password)
passHead := hex.EncodeToString(passData[:])

buf := make([]byte, 0, 56+2+1+1+1+len(tgtHost)+2+2)
buf = append(buf, []byte(passHead)...)
buf = append(buf, '\r', '\n')
buf = append(buf, 1, 3, uint8(len(tgtHost)))
buf = append(buf, []byte(tgtHost)...)
buf = append(buf, byte(tgtPort>>8), byte(tgtPort))
buf = append(buf, '\r', '\n')

if n, err := conn.Write(buf); err != nil || n != len(buf) {
return conn, xerrors.Errorf("n: %d, msg: %s", n, err)
}
return conn, nil
}
2 changes: 1 addition & 1 deletion transport/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,5 @@ func Dial(targetAddr string, dialAddr func(domain string) (proxyAddr string, pas
if err != nil {
return nil, err
}
return ToProxyConn(conn, host, uint16(p), password)
return ToTrojanConn(conn, host, uint16(p), password)
}

0 comments on commit dab1a78

Please sign in to comment.