trojan: support listen as trojan server

This commit is contained in:
nadoo 2020-10-10 19:04:33 +08:00
parent 6eda2b79c8
commit 175ef16a5c
17 changed files with 357 additions and 115 deletions

View File

@ -52,7 +52,7 @@ we can set up local listeners as proxy servers, and forward requests to internet
|ss |√|√|√|√|client & server
|ssr | | |√| |client only
|ssh | | |√| |client only
|trojan | | |√|√|client only
|trojan |√|√|√|√|client & server
|vless |√|√|√|√|client & server
|vmess | | |√| |client only
|redir |√| | | |linux only
@ -88,7 +88,7 @@ glider -h
<summary>click to see details</summary>
```bash
./glider 0.11.2 usage:
./glider 0.12.0 usage:
-checkdisabledonly
check disabled fowarders only
-checkinterval int
@ -106,7 +106,7 @@ glider -h
-dnsalwaystcp
always use tcp to query upstream dns servers no matter there is a forwarder or not
-dnscachesize int
size of CACHE (default 1024)
size of CACHE (default 4096)
-dnsmaxttl int
maximum TTL value for entries in the CACHE(seconds) (default 1800)
-dnsminttl int
@ -141,7 +141,7 @@ glider -h
verbose mode
Available schemes:
listen: mixed ss socks5 http vless redir redir6 tcptun udptun uottun tls unix kcp
listen: mixed ss socks5 http vless trojan redir redir6 tcptun udptun uottun tls unix kcp
forward: reject ss socks4 socks5 http ssr ssh vless vmess trojan tls ws unix kcp simple-obfs
Socks5 scheme:
@ -171,9 +171,12 @@ VMess scheme:
VLESS scheme:
vless://uuid@host:port[?fallback=127.0.0.1:80]
Trojan scheme:
Trojan client scheme:
trojan://pass@host:port[?serverName=SERVERNAME][&skipVerify=true]
Trojan server scheme:
trojan://pass@host:port?cert=PATH&key=PATH
Available securities for vmess:
none, aes-128-gcm, chacha20-poly1305

View File

@ -130,7 +130,7 @@ func usage() {
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Available schemes:\n")
fmt.Fprintf(w, " listen: mixed ss socks5 http vless redir redir6 tcptun udptun uottun tls unix kcp\n")
fmt.Fprintf(w, " listen: mixed ss socks5 http vless trojan redir redir6 tcptun udptun uottun tls unix kcp\n")
fmt.Fprintf(w, " forward: reject ss socks4 socks5 http ssr ssh vless vmess trojan tls ws unix kcp simple-obfs\n")
fmt.Fprintf(w, "\n")
@ -168,10 +168,14 @@ func usage() {
fmt.Fprintf(w, " vless://uuid@host:port[?fallback=127.0.0.1:80]\n")
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Trojan scheme:\n")
fmt.Fprintf(w, "Trojan client scheme:\n")
fmt.Fprintf(w, " trojan://pass@host:port[?serverName=SERVERNAME][&skipVerify=true]\n")
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Trojan server scheme:\n")
fmt.Fprintf(w, " trojan://pass@host:port?cert=PATH&key=PATH\n")
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Available securities for vmess:\n")
fmt.Fprintf(w, " none, aes-128-gcm, chacha20-poly1305\n")
fmt.Fprintf(w, "\n")

View File

@ -72,6 +72,15 @@ listen=socks5://:1080
# socks5 over kcp
# listen=kcp://aes:key@127.0.0.1:8444?dataShards=10&parityShards=3,socks5://
# vless server
# listen=vless://UUID@:1234
# vless over tls server
# listen=tls://:1234?cert=/path/to/cert&key=/path/to/key,vless://UUID@?fallback=127.0.0.1:80
# trojan server
#listen=trojan://PASSWORD:1234?cert=/path/to/cert&key=/path/to/key
# FORWARDERS
# ----------
# Forwarders, we can setup multiple forwarders.
@ -216,6 +225,9 @@ dnsmaxttl=1800
# minimum TTL value for entries in the CACHE(seconds)
dnsminttl=0
# size of CACHE
dnscachesize=4096
# custom records
dnsrecord=www.example.com/1.2.3.4
dnsrecord=www.example.com/2606:2800:220:1:248:1893:25c8:1946

View File

@ -83,7 +83,7 @@ func (c *LruCache) Set(k string, v []byte, ttl int) {
c.putToHead(k, v, exp)
// NOTE: the cache size will always be c.size + 2,
// NOTE: the cache size will always >= 2,
// but it doesn't matter in our environment.
if len(c.cache) > c.size {
c.removeTail()

View File

@ -76,7 +76,7 @@ func (c *Client) Exchange(reqBytes []byte, clientAddr string, preferTCP bool) ([
go func(qname string, reqBytes []byte, preferTCP bool) {
defer pool.PutBuffer(reqBytes)
if dnsServer, network, dialerAddr, respBytes, err := c.exchange(qname, reqBytes, preferTCP); err == nil {
c.handleAnswer(respBytes, clientAddr, dnsServer, network, dialerAddr)
c.handleAnswer(respBytes, "cache", dnsServer, network, dialerAddr)
}
}(req.Question.QNAME, valCopy(reqBytes), preferTCP)
}
@ -209,12 +209,13 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) (
// exchangeTCP exchange with server over tcp.
func (c *Client) exchangeTCP(rc net.Conn, reqBytes []byte) ([]byte, error) {
reqLen := pool.GetBuffer(2)
defer pool.PutBuffer(reqLen)
buf := pool.GetBuffer(2 + len(reqBytes))
defer pool.PutBuffer(buf)
binary.BigEndian.PutUint16(reqLen, uint16(len(reqBytes)))
binary.BigEndian.PutUint16(buf[:2], uint16(len(reqBytes)))
copy(buf[2:], reqBytes)
if _, err := (&net.Buffers{reqLen, reqBytes}).WriteTo(rc); err != nil {
if _, err := rc.Write(buf); err != nil {
return nil, err
}

View File

@ -143,12 +143,15 @@ func (s *Server) ServeTCP(c net.Conn) {
return
}
respLen := pool.GetBuffer(2)
defer pool.PutBuffer(respLen)
binary.BigEndian.PutUint16(respLen, uint16(len(respBytes)))
buf := pool.GetBuffer(2 + len(respBytes))
defer pool.PutBuffer(buf)
if _, err := (&net.Buffers{respLen, respBytes}).WriteTo(c); err != nil {
binary.BigEndian.PutUint16(buf[:2], uint16(len(respBytes)))
copy(buf[2:], respBytes)
if _, err := c.Write(buf); err != nil {
log.F("[dns-tcp] error in write respBytes: %s", err)
return
}
}

4
go.mod
View File

@ -9,11 +9,11 @@ require (
github.com/nadoo/go-shadowsocks2 v0.1.2
github.com/nadoo/ipset v0.3.0
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/xtaci/kcp-go/v5 v5.5.17
github.com/xtaci/kcp-go/v5 v5.6.1
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0
golang.org/x/net v0.0.0-20201009032441-dbdefad45b89 // indirect
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect
golang.org/x/tools v0.0.0-20201009032223-96877f285f7e // indirect
golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
)

8
go.sum
View File

@ -97,8 +97,8 @@ github.com/xtaci/kcp-go v5.4.11+incompatible h1:tJbtarpmOoOD74cZ41uvvF5Hyt1nvctH
github.com/xtaci/kcp-go v5.4.11+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go/v5 v5.5.12 h1:iALGyvti/oBbl1TbVoUpHEUHCorDEb3tEKl1CPY3KXM=
github.com/xtaci/kcp-go/v5 v5.5.12/go.mod h1:H0T/EJ+lPNytnFYsKLH0JHUtiwZjG3KXlTM6c+Q4YUo=
github.com/xtaci/kcp-go/v5 v5.5.17 h1:bkdaqtER0PMlP05BBHfu6W+71kt/NwbAk93KH7F78Ck=
github.com/xtaci/kcp-go/v5 v5.5.17/go.mod h1:pVx3jb4LT5edTmPayc77tIU9nRsjGck8wep5ZV/RBO0=
github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI=
github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -177,8 +177,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU=
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201009032223-96877f285f7e h1:G1acLyqfyttmexrW7XPhzsaS8m6s+P9XsW9djwh10s4=
golang.org/x/tools v0.0.0-20201009032223-96877f285f7e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91 h1:UNUk0ao5UA0V4v2wikQWc4U+yG5UGoWku8MHs27mMqs=
golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

View File

@ -15,6 +15,7 @@ const (
// SOCKS request commands as defined in RFC 1928 section 4
const (
CmdError byte = 0
CmdConnect byte = 1
CmdBind byte = 2
CmdUDPAssociate byte = 3

View File

@ -73,11 +73,12 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
// +----+------+------+----------+----------+----------+
// | 2 | 1 | 1 | Variable | 2 | Variable |
// +----+------+------+----------+----------+----------+
tgtAddr := socks.SplitAddr(buf[3:])
tgtAddr := socks.SplitAddr(buf[3:n])
if tgtAddr == nil {
return n, raddr, errors.New("can not get addr")
}
copy(b, buf[3+len(tgtAddr):])
n = copy(b, buf[3+len(tgtAddr):n])
//test
if pc.writeAddr == nil {
@ -88,7 +89,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
pc.tgtAddr = tgtAddr
}
return n - len(tgtAddr) - 3, raddr, err
return n, raddr, err
}
// WriteTo overrides the original function from net.PacketConn.

View File

@ -42,11 +42,12 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
return n, raddr, err
}
tgtAddr := socks.SplitAddr(buf)
tgtAddr := socks.SplitAddr(buf[:n])
if tgtAddr == nil {
return n, raddr, errors.New("can not get addr")
}
copy(b, buf[len(tgtAddr):])
n = copy(b, buf[len(tgtAddr):n])
//test
if pc.writeAddr == nil {
@ -57,7 +58,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
pc.tgtAddr = tgtAddr
}
return n - len(tgtAddr), raddr, err
return n, raddr, err
}
// WriteTo overrides the original function from net.PacketConn

View File

@ -24,7 +24,6 @@ type TLS struct {
certFile string
keyFile string
cert stdtls.Certificate
server proxy.Server
}
@ -76,7 +75,7 @@ func NewTLSDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
ServerName: p.serverName,
InsecureSkipVerify: p.skipVerify,
ClientSessionCache: stdtls.NewLRUClientSessionCache(64),
MinVersion: stdtls.VersionTLS10,
MinVersion: stdtls.VersionTLS12,
}
return p, err

86
proxy/trojan/client.go Normal file
View File

@ -0,0 +1,86 @@
package trojan
import (
"crypto/tls"
"net"
"github.com/nadoo/glider/log"
"github.com/nadoo/glider/pool"
"github.com/nadoo/glider/proxy"
"github.com/nadoo/glider/proxy/socks"
)
// NewTrojanDialer returns a trojan proxy dialer.
func NewTrojanDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
t, err := NewTrojan(s, d, nil)
if err != nil {
log.F("[trojan] create instance error: %s", err)
return nil, err
}
t.tlsConfig = &tls.Config{
ServerName: t.serverName,
InsecureSkipVerify: t.skipVerify,
NextProtos: []string{"http/1.1"},
ClientSessionCache: tls.NewLRUClientSessionCache(64),
MinVersion: tls.VersionTLS12,
}
return t, err
}
// 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) {
return s.dial(network, addr)
}
func (s *Trojan) dial(network, addr string) (net.Conn, error) {
rc, err := s.dialer.Dial("tcp", s.addr)
if err != nil {
log.F("[trojan]: dial to %s error: %s", s.addr, err)
return nil, err
}
tlsConn := tls.Client(rc, s.tlsConfig)
if err := tlsConn.Handshake(); err != nil {
return nil, err
}
buf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(buf)
buf.Write(s.pass[:])
buf.WriteString("\r\n")
cmd := socks.CmdConnect
if network == "udp" {
cmd = socks.CmdUDPAssociate
}
buf.WriteByte(cmd)
buf.Write(socks.ParseAddr(addr))
buf.WriteString("\r\n")
_, err = tlsConn.Write(buf.Bytes())
return tlsConn, err
}
// DialUDP connects to the given address via the proxy.
func (s *Trojan) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
c, err := s.dial("udp", addr)
if err != nil {
return nil, nil, err
}
pkc := NewPktConn(c, socks.ParseAddr(addr))
// TODO: check the addr in return value
return pkc, nil, nil
}

197
proxy/trojan/server.go Normal file
View File

@ -0,0 +1,197 @@
package trojan
import (
"bytes"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"strings"
"github.com/nadoo/glider/log"
"github.com/nadoo/glider/pool"
"github.com/nadoo/glider/proxy"
"github.com/nadoo/glider/proxy/socks"
)
// NewTrojanServer returns a trojan proxy server.
func NewTrojanServer(s string, p proxy.Proxy) (proxy.Server, error) {
t, err := NewTrojan(s, nil, p)
if err != nil {
log.F("[trojan] create instance error: %s", err)
return nil, err
}
cert, err := tls.LoadX509KeyPair(t.certFile, t.keyFile)
if err != nil {
log.F("[trojan] unable to load cert: %s, key %s", t.certFile, t.keyFile)
return nil, err
}
t.tlsConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
}
return t, err
}
// ListenAndServe listen and serves connections.
func (s *Trojan) ListenAndServe() {
l, err := net.Listen("tcp", s.addr)
if err != nil {
log.F("[trojan] failed to listen on %s: %v", s.addr, err)
return
}
defer l.Close()
log.F("[trojan] listening TCP on %s with TLS", s.addr)
for {
c, err := l.Accept()
if err != nil {
log.F("[trojan] failed to accept: %v", err)
continue
}
go s.Serve(c)
}
}
// Serve serves a connection.
func (s *Trojan) Serve(cc net.Conn) {
defer cc.Close()
if cc, ok := cc.(*net.TCPConn); ok {
cc.SetKeepAlive(true)
}
c := tls.Server(cc, s.tlsConfig)
err := c.Handshake()
if err != nil {
log.F("[trojan] error in tls handshake: %s", err)
return
}
cmd, target, err := s.readHeader(c)
if err != nil {
log.F("[trojan] error in server handshake: %s", err)
return
}
network := "tcp"
dialer := s.proxy.NextDialer(target.String())
if cmd == socks.CmdUDPAssociate {
// there is no upstream proxy, just serve it
if dialer.Addr() == "DIRECT" {
s.ServeUoT(c, target)
return
}
network = "udp"
}
rc, err := dialer.Dial(network, target.String())
if err != nil {
log.F("[trojan] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), target, dialer.Addr(), err)
return
}
defer rc.Close()
log.F("[trojan] %s <-> %s via %s", c.RemoteAddr(), target, dialer.Addr())
if err = proxy.Relay(c, rc); err != nil {
log.F("[trojan] %s <-> %s via %s, relay error: %v", c.RemoteAddr(), target, dialer.Addr(), err)
// record remote conn failure only
if !strings.Contains(err.Error(), s.addr) {
s.proxy.Record(dialer, false)
}
}
}
func (s *Trojan) readHeader(c net.Conn) (byte, socks.Addr, error) {
// pass: 56, "\r\n": 2, cmd: 1
buf := pool.GetBuffer(59)
defer pool.PutBuffer(buf)
if _, err := io.ReadFull(c, buf); err != nil {
return socks.CmdError, nil, err
}
// pass, 56bytes
if !bytes.Equal(buf[:56], s.pass[:]) {
return socks.CmdError, nil, errors.New("wrong password")
}
// cmd, 1byte
cmd := byte(buf[58])
// target
tgt, err := socks.ReadAddr(c)
if err != nil {
return cmd, nil, fmt.Errorf("read target address error: %v", err)
}
// "\r\n", 2bytes
if _, err := io.ReadFull(c, buf[:2]); err != nil {
return socks.CmdError, tgt, err
}
return cmd, tgt, nil
}
// ServeUoT serves udp over tcp requests.
func (s *Trojan) ServeUoT(c net.Conn, tgt socks.Addr) {
rc, err := net.ListenPacket("udp", "")
if err != nil {
log.F("[trojan] UDP remote listen error: %v", err)
return
}
defer rc.Close()
tgtAddr, err := net.ResolveUDPAddr("udp", tgt.String())
if err != nil {
log.F("[vless] error in ResolveUDPAddr: %v", err)
return
}
pc := NewPktConn(c, tgt)
go func() {
buf := pool.GetBuffer(proxy.UDPBufSize)
defer pool.PutBuffer(buf)
for {
n, _, err := pc.ReadFrom(buf)
if err != nil {
log.F("[trojan] read error: %s\n", err)
return
}
_, err = rc.WriteTo(buf[:n], tgtAddr)
if err != nil {
log.F("[trojan] write rc error: %s\n", err)
return
}
}
}()
log.F("[trojan] %s <-tcp-> %s - %s <-udp-> %s", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt)
buf := pool.GetBuffer(proxy.UDPBufSize)
defer pool.PutBuffer(buf)
for {
n, _, err := rc.ReadFrom(buf)
if err != nil {
log.F("[trojan] read rc error: %v", err)
break
}
_, err = pc.WriteTo(buf[:n], nil)
if err != nil {
log.F("[trojan] write pc error: %v", err)
break
}
}
}

View File

@ -7,14 +7,13 @@ import (
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"errors"
"fmt"
"net"
"net/url"
"strings"
"github.com/nadoo/glider/log"
"github.com/nadoo/glider/pool"
"github.com/nadoo/glider/proxy"
"github.com/nadoo/glider/proxy/socks"
)
// Trojan is a base trojan struct.
@ -26,19 +25,20 @@ type Trojan struct {
serverName string
skipVerify bool
tlsConfig *tls.Config
certFile string
keyFile string
}
func init() {
proxy.RegisterDialer("trojan", NewTrojanDialer)
// proxy.RegisterServer("trojan", NewTrojanServer)
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)
return nil, err
return nil, fmt.Errorf("parse url err: %s", err)
}
query := u.Query()
@ -48,6 +48,8 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
addr: u.Host,
skipVerify: query.Get("skipVerify") == "true",
serverName: query.Get("serverName"),
certFile: query.Get("cert"),
keyFile: query.Get("key"),
}
if t.serverName == "" {
@ -60,78 +62,14 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
}
// 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,
NextProtos: []string{"http/1.1"},
ClientSessionCache: tls.NewLRUClientSessionCache(64),
MinVersion: tls.VersionTLS12,
pass := u.User.Username()
if pass == "" {
return nil, errors.New("[trojan] password must be specified")
}
hash := sha256.New224()
hash.Write([]byte(pass))
hex.Encode(t.pass[:], hash.Sum(nil))
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) {
return s.dial(network, addr)
}
func (s *Trojan) dial(network, addr string) (net.Conn, error) {
rc, err := s.dialer.Dial("tcp", s.addr)
if err != nil {
log.F("[trojan]: dial to %s error: %s", s.addr, err)
return nil, err
}
tlsConn := tls.Client(rc, s.tlsConfig)
if err := tlsConn.Handshake(); err != nil {
return nil, err
}
buf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(buf)
buf.Write(s.pass[:])
buf.WriteString("\r\n")
cmd := socks.CmdConnect
if network == "udp" {
cmd = socks.CmdUDPAssociate
}
buf.WriteByte(cmd)
buf.Write(socks.ParseAddr(addr))
buf.WriteString("\r\n")
_, err = tlsConn.Write(buf.Bytes())
return tlsConn, err
}
// DialUDP connects to the given address via the proxy.
func (s *Trojan) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
c, err := s.dial("udp", addr)
if err != nil {
return nil, nil, err
}
pkc := NewPktConn(c, socks.ParseAddr(addr))
// TODO: check the addr in return value
return pkc, nil, nil
}

View File

@ -30,11 +30,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
// Payload
n, err := io.ReadFull(pc.Conn, b[:length])
if err != nil {
return n, nil, err
}
return n, nil, nil
return n, nil, err
}
// WriteTo implements the necessary function of net.PacketConn.

View File

@ -50,7 +50,6 @@ func (s *VLess) Serve(c net.Conn) {
}
var fallback bool
var dialer proxy.Dialer
target := s.fallback
wbuf := pool.GetWriteBuffer()
@ -67,7 +66,7 @@ func (s *VLess) Serve(c net.Conn) {
}
network := "tcp"
dialer = s.proxy.NextDialer(target)
dialer := s.proxy.NextDialer(target)
if !fallback {
c = NewServerConn(c)
target, err = ReadAddrString(c)
@ -75,6 +74,7 @@ func (s *VLess) Serve(c net.Conn) {
log.F("[vless] get target error: %v", err)
return
}
dialer = s.proxy.NextDialer(target)
if cmd == CmdUDP {
// there is no upstream proxy, just serve it