trojan: added udp support

This commit is contained in:
nadoo 2020-04-12 15:27:20 +08:00
parent 2520a1c8b4
commit bfcf9272dc
6 changed files with 138 additions and 66 deletions

View File

@ -15,58 +15,26 @@ we can set up local listeners as proxy servers, and forward requests to internet
```
## Features
Listen (local proxy server):
- Socks5 proxy(tcp&udp)
- Http proxy(tcp)
- SS proxy(tcp&udp)
- Linux transparent proxy(iptables redirect)
- TCP tunnel
- UDP tunnel
- UDP over TCP tunnel
- TLS, use it together with above proxy protocols(tcp)
- Unix domain socket, use it together with above proxy protocols(tcp)
- KCP protocol, use it together with above proxy protocols(tcp)
Forward (local proxy client/upstream proxy server):
- Socks5 proxy(tcp&udp)
- Http proxy(tcp)
- SS proxy(tcp&udp&uot)
- SSR proxy(tcp)
- VMess proxy(tcp)
- Trojan proxy(tcp)
- TLS, use it together with above proxy protocols(tcp)
- Websocket, use it together with above proxy protocols(tcp)
- Unix domain socket, use it together with above proxy protocols(tcp)
- KCP protocol, use it together with above proxy protocols(tcp)
- Simple-Obfs, use it together with above proxy protocols(tcp)
DNS Forwarding Server (udp2tcp):
- DNS Over Proxy
- Listen on UDP and forward dns requests to remote dns server in TCP via forwarders
- Specify different upstream dns server based on destinations(in rule file)
- Tunnel mode: forward to a fixed upstream dns server
- Add resolved IPs to proxy rules
- Add resolved IPs to ipset
- DNS cache
- Custom dns record
IPSet Management (Linux kernel version >= 2.6.32):
- Add ip/cidrs from rule files on startup
- Add resolved ips for domains from rule files by dns forwarding server
General:
- Proxy Server( -listen )
- Proxy Client( -forward )
- Http and socks5 on the same port
- Forwarder chain
- RR/HA/LHA/DH strategy for multiple forwarders
- Periodical proxy checking
- Rule proxy based on destinations: [Config Examples](config/examples)
- Send requests from specific ip/interface
- DNS Forwarding Server:
- DNS Over Proxy
- Listen on UDP and forward dns requests to remote dns server in TCP via forwarders
- Specify different upstream dns server based on destinations(in rule file)
- Tunnel mode: forward to a fixed upstream dns server
- Add resolved IPs to proxy rules
- Add resolved IPs to ipset
- DNS cache
- Custom dns record
- IPSet Management (Linux kernel version >= 2.6.32):
- Add ip/cidrs from rule files on startup
- Add resolved ips for domains from rule files by dns forwarding server
TODO:
@ -76,6 +44,25 @@ TODO:
- [ ] TUN/TAP device support
- [ ] SSH tunnel support (maybe)
### Protocols
Protocol | Listen/TCP | Listen/UDP | Forward/TCP | Forward/UDP
-|-|-|-|-
Socks5 | √ | √ | √ | √
Http | √ | | √ |
SS | √ | √ | √ | √
Redir | √ | | |
Tcptun | √ | | |
Udptun | | √ | |
UoTtun | | √ | |
TLS | √ | | √ |
Unix | √ | | √ |
KCP | | √ | √ |
SSR | | | √ |
VMess | | | √ |
Trojan | | | √ | √
WebSocket | | | √ |
Simple-Obfs | | | √ |
## Install
Binary:

View File

@ -13,26 +13,22 @@ const (
AuthPassword = 2
)
// SOCKS request commands as defined in RFC 1928 section 4.
// SOCKS request commands as defined in RFC 1928 section 4
const (
CmdConnect = 1
CmdBind = 2
CmdUDPAssociate = 3
CmdConnect byte = 1
CmdBind byte = 2
CmdUDPAssociate byte = 3
)
// SOCKS address types as defined in RFC 1928 section 5.
// SOCKS address types as defined in RFC 1928 section 5
const (
ATypIP4 = 1
ATypDomain = 3
ATypIP6 = 4
)
const (
// maximum size of SOCKS address in bytes.
MaxAddrLen = 1 + 1 + 255 + 2
// minimum size of SOCKS address in bytes.
MinAddrLen = 5
)
// MaxAddrLen is the maximum size of SOCKS address in bytes
const MaxAddrLen = 1 + 1 + 255 + 2
// Errors are socks5 errors
var Errors = []error{

View File

@ -58,7 +58,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
return n, raddr, err
}
if n < socks.MinAddrLen {
if n < 3 {
return n, raddr, errors.New("not enough size to get addr")
}

View File

@ -39,10 +39,6 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
return n, raddr, err
}
if n < socks.MinAddrLen {
return n, raddr, errors.New("not enough size to get addr")
}
tgtAddr := socks.SplitAddr(buf)
if tgtAddr == nil {
return n, raddr, errors.New("can not get addr")

75
proxy/trojan/packet.go Normal file
View File

@ -0,0 +1,75 @@
// https://trojan-gfw.github.io/trojan/protocol
// If the connection is a UDP ASSOCIATE, then each UDP packet has the following format:
// +------+----------+----------+--------+---------+----------+
// | ATYP | DST.ADDR | DST.PORT | Length | CRLF | Payload |
// +------+----------+----------+--------+---------+----------+
// | 1 | Variable | 2 | 2 | X'0D0A' | Variable |
// +------+----------+----------+--------+---------+----------+
package trojan
import (
"bytes"
"encoding/binary"
"errors"
"io"
"net"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/socks"
)
// PktConn .
type PktConn struct {
net.Conn
tgtAddr socks.Addr
}
func NewPktConn(c net.Conn, tgtAddr socks.Addr) *PktConn {
pc := &PktConn{
Conn: c,
tgtAddr: tgtAddr,
}
return pc
}
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
// ATYP, DST.ADDR, DST.PORT
_, err := socks.ReadAddr(pc.Conn)
if err != nil {
return 0, nil, err
}
// Length
if _, err = io.ReadFull(pc.Conn, b[:2]); err != nil {
return 0, nil, err
}
length := int(binary.BigEndian.Uint16(b[:2]))
if length > conn.UDPBufSize {
return 0, nil, errors.New("packet invalid")
}
// CRLF
if _, err = io.ReadFull(pc.Conn, b[:2]); err != nil {
return 0, nil, err
}
// Payload
n, err := io.ReadFull(pc.Conn, b[:length])
if err != nil {
return 0, nil, err
}
// TODO: check the addr in return value, it's a fake packetConn so the addr is not valid
return n, nil, err
}
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
var buf bytes.Buffer
buf.Write(pc.tgtAddr)
binary.Write(&buf, binary.BigEndian, uint16(len(b)))
buf.WriteString("\r\n")
buf.Write(b)
return pc.Write(buf.Bytes())
}

View File

@ -32,7 +32,6 @@ import (
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"errors"
"net"
"net/url"
"strings"
@ -42,7 +41,7 @@ import (
"github.com/nadoo/glider/proxy"
)
// Trojan is a base trojan struct.
// Trojan is a base trojan struct
type Trojan struct {
dialer proxy.Dialer
proxy proxy.Proxy
@ -115,8 +114,13 @@ func (s *Trojan) Addr() string {
// 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
}
@ -128,14 +132,28 @@ func (s *Trojan) Dial(network, addr string) (net.Conn, error) {
var buf bytes.Buffer
buf.Write(s.pass[:])
buf.WriteString("\r\n")
buf.WriteByte(socks.CmdConnect)
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) {
return nil, nil, errors.New("trojan client does not support udp now")
c, err := s.dial("udp", addr)
if err != nil {
return nil, nil, err
}
pkc := NewPktConn(c, socks.ParseAddr(addr))
return pkc, nil, nil
}