glider/proxy/trojan/trojan.go

138 lines
2.9 KiB
Go
Raw Normal View History

2020-04-08 01:09:51 +08:00
// protocol spec:
// https://trojan-gfw.github.io/trojan/protocol
package trojan
import (
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"net"
"net/url"
2020-10-08 18:48:23 +08:00
"strings"
2020-04-08 01:09:51 +08:00
"github.com/nadoo/glider/log"
"github.com/nadoo/glider/pool"
2020-04-08 01:09:51 +08:00
"github.com/nadoo/glider/proxy"
"github.com/nadoo/glider/proxy/socks"
2020-04-08 01:09:51 +08:00
)
2020-10-03 20:51:27 +08:00
// Trojan is a base trojan struct.
2020-04-08 01:09:51 +08:00
type Trojan struct {
dialer proxy.Dialer
proxy proxy.Proxy
addr string
pass [56]byte
serverName string
skipVerify bool
tlsConfig *tls.Config
}
func init() {
proxy.RegisterDialer("trojan", NewTrojanDialer)
// proxy.RegisterServer("trojan", NewTrojanServer)
}
// NewTrojan returns a trojan proxy.
func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
u, err := url.Parse(s)
if err != nil {
log.F("[trojan] parse url err: %s", err)
2020-04-08 01:09:51 +08:00
return nil, err
}
query := u.Query()
2020-04-08 01:09:51 +08:00
t := &Trojan{
dialer: d,
proxy: p,
addr: u.Host,
skipVerify: query.Get("skipVerify") == "true",
serverName: query.Get("serverName"),
}
if t.serverName == "" {
2020-10-08 18:48:23 +08:00
idx := strings.LastIndex(t.addr, ":")
if idx == -1 {
idx = len(t.addr)
t.addr = net.JoinHostPort(t.addr, "443")
}
2020-10-08 18:48:23 +08:00
t.serverName = t.addr[:idx]
2020-04-08 01:09:51 +08:00
}
// pass
hash := sha256.New224()
hash.Write([]byte(u.User.Username()))
hex.Encode(t.pass[:], hash.Sum(nil))
t.tlsConfig = &tls.Config{
ServerName: t.serverName,
InsecureSkipVerify: t.skipVerify,
2020-10-03 20:51:27 +08:00
NextProtos: []string{"http/1.1"},
2020-04-08 01:09:51 +08:00
ClientSessionCache: tls.NewLRUClientSessionCache(64),
MinVersion: tls.VersionTLS12,
2020-04-08 01:09:51 +08:00
}
return t, nil
}
// NewTrojanDialer returns a trojan proxy dialer.
func NewTrojanDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
return NewTrojan(s, d, nil)
}
// Addr returns forwarder's address.
func (s *Trojan) Addr() string {
if s.addr == "" {
return s.dialer.Addr()
}
return s.addr
}
// Dial connects to the address addr on the network net via the proxy.
func (s *Trojan) Dial(network, addr string) (net.Conn, error) {
2020-04-12 15:27:20 +08:00
return s.dial(network, addr)
}
func (s *Trojan) dial(network, addr string) (net.Conn, error) {
2020-04-08 01:09:51 +08:00
rc, err := s.dialer.Dial("tcp", s.addr)
if err != nil {
2020-04-12 15:27:20 +08:00
log.F("[trojan]: dial to %s error: %s", s.addr, err)
2020-04-08 01:09:51 +08:00
return nil, err
}
tlsConn := tls.Client(rc, s.tlsConfig)
if err := tlsConn.Handshake(); err != nil {
return nil, err
}
2020-04-19 23:20:15 +08:00
buf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(buf)
2020-04-08 01:09:51 +08:00
buf.Write(s.pass[:])
buf.WriteString("\r\n")
2020-04-12 15:27:20 +08:00
cmd := socks.CmdConnect
if network == "udp" {
cmd = socks.CmdUDPAssociate
}
buf.WriteByte(cmd)
2020-04-08 01:09:51 +08:00
buf.Write(socks.ParseAddr(addr))
buf.WriteString("\r\n")
_, err = tlsConn.Write(buf.Bytes())
2020-04-12 15:27:20 +08:00
2020-04-08 01:09:51 +08:00
return tlsConn, err
}
// DialUDP connects to the given address via the proxy.
func (s *Trojan) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
2020-04-12 15:27:20 +08:00
c, err := s.dial("udp", addr)
if err != nil {
return nil, nil, err
}
pkc := NewPktConn(c, socks.ParseAddr(addr))
2020-04-12 17:48:04 +08:00
// TODO: check the addr in return value
2020-04-12 15:27:20 +08:00
return pkc, nil, nil
2020-04-08 01:09:51 +08:00
}