mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 17:35:40 +08:00
trojan: added udp support
This commit is contained in:
parent
2520a1c8b4
commit
bfcf9272dc
71
README.md
71
README.md
@ -15,36 +15,15 @@ we can set up local listeners as proxy servers, and forward requests to internet
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
- Proxy Server( -listen )
|
||||||
Listen (local proxy server):
|
- Proxy Client( -forward )
|
||||||
|
- Http and socks5 on the same port
|
||||||
- Socks5 proxy(tcp&udp)
|
- Forwarder chain
|
||||||
- Http proxy(tcp)
|
- RR/HA/LHA/DH strategy for multiple forwarders
|
||||||
- SS proxy(tcp&udp)
|
- Periodical proxy checking
|
||||||
- Linux transparent proxy(iptables redirect)
|
- Rule proxy based on destinations: [Config Examples](config/examples)
|
||||||
- TCP tunnel
|
- Send requests from specific ip/interface
|
||||||
- UDP tunnel
|
- DNS Forwarding Server:
|
||||||
- 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
|
- DNS Over Proxy
|
||||||
- Listen on UDP and forward dns requests to remote dns server in TCP via forwarders
|
- 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)
|
- Specify different upstream dns server based on destinations(in rule file)
|
||||||
@ -53,21 +32,10 @@ DNS Forwarding Server (udp2tcp):
|
|||||||
- Add resolved IPs to ipset
|
- Add resolved IPs to ipset
|
||||||
- DNS cache
|
- DNS cache
|
||||||
- Custom dns record
|
- Custom dns record
|
||||||
|
- IPSet Management (Linux kernel version >= 2.6.32):
|
||||||
IPSet Management (Linux kernel version >= 2.6.32):
|
|
||||||
|
|
||||||
- Add ip/cidrs from rule files on startup
|
- Add ip/cidrs from rule files on startup
|
||||||
- Add resolved ips for domains from rule files by dns forwarding server
|
- Add resolved ips for domains from rule files by dns forwarding server
|
||||||
|
|
||||||
General:
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
- [ ] IPv6 support in ipset manager
|
- [ ] IPv6 support in ipset manager
|
||||||
@ -76,6 +44,25 @@ TODO:
|
|||||||
- [ ] TUN/TAP device support
|
- [ ] TUN/TAP device support
|
||||||
- [ ] SSH tunnel support (maybe)
|
- [ ] 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
|
## Install
|
||||||
|
|
||||||
Binary:
|
Binary:
|
||||||
|
@ -13,26 +13,22 @@ const (
|
|||||||
AuthPassword = 2
|
AuthPassword = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// SOCKS request commands as defined in RFC 1928 section 4.
|
// SOCKS request commands as defined in RFC 1928 section 4
|
||||||
const (
|
const (
|
||||||
CmdConnect = 1
|
CmdConnect byte = 1
|
||||||
CmdBind = 2
|
CmdBind byte = 2
|
||||||
CmdUDPAssociate = 3
|
CmdUDPAssociate byte = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
// SOCKS address types as defined in RFC 1928 section 5.
|
// SOCKS address types as defined in RFC 1928 section 5
|
||||||
const (
|
const (
|
||||||
ATypIP4 = 1
|
ATypIP4 = 1
|
||||||
ATypDomain = 3
|
ATypDomain = 3
|
||||||
ATypIP6 = 4
|
ATypIP6 = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// MaxAddrLen is the maximum size of SOCKS address in bytes
|
||||||
// maximum size of SOCKS address in bytes.
|
const MaxAddrLen = 1 + 1 + 255 + 2
|
||||||
MaxAddrLen = 1 + 1 + 255 + 2
|
|
||||||
// minimum size of SOCKS address in bytes.
|
|
||||||
MinAddrLen = 5
|
|
||||||
)
|
|
||||||
|
|
||||||
// Errors are socks5 errors
|
// Errors are socks5 errors
|
||||||
var Errors = []error{
|
var Errors = []error{
|
||||||
|
@ -58,7 +58,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||||||
return n, raddr, err
|
return n, raddr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if n < socks.MinAddrLen {
|
if n < 3 {
|
||||||
return n, raddr, errors.New("not enough size to get addr")
|
return n, raddr, errors.New("not enough size to get addr")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +39,6 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||||||
return n, raddr, err
|
return n, raddr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if n < socks.MinAddrLen {
|
|
||||||
return n, raddr, errors.New("not enough size to get addr")
|
|
||||||
}
|
|
||||||
|
|
||||||
tgtAddr := socks.SplitAddr(buf)
|
tgtAddr := socks.SplitAddr(buf)
|
||||||
if tgtAddr == nil {
|
if tgtAddr == nil {
|
||||||
return n, raddr, errors.New("can not get addr")
|
return n, raddr, errors.New("can not get addr")
|
||||||
|
75
proxy/trojan/packet.go
Normal file
75
proxy/trojan/packet.go
Normal 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())
|
||||||
|
}
|
@ -32,7 +32,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@ -42,7 +41,7 @@ import (
|
|||||||
"github.com/nadoo/glider/proxy"
|
"github.com/nadoo/glider/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Trojan is a base trojan struct.
|
// Trojan is a base trojan struct
|
||||||
type Trojan struct {
|
type Trojan struct {
|
||||||
dialer proxy.Dialer
|
dialer proxy.Dialer
|
||||||
proxy proxy.Proxy
|
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.
|
// Dial connects to the address addr on the network net via the proxy.
|
||||||
func (s *Trojan) Dial(network, addr string) (net.Conn, error) {
|
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)
|
rc, err := s.dialer.Dial("tcp", s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.F("[trojan]: dial to %s error: %s", s.addr, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,14 +132,28 @@ func (s *Trojan) Dial(network, addr string) (net.Conn, error) {
|
|||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.Write(s.pass[:])
|
buf.Write(s.pass[:])
|
||||||
buf.WriteString("\r\n")
|
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.Write(socks.ParseAddr(addr))
|
||||||
buf.WriteString("\r\n")
|
buf.WriteString("\r\n")
|
||||||
_, err = tlsConn.Write(buf.Bytes())
|
_, err = tlsConn.Write(buf.Bytes())
|
||||||
|
|
||||||
return tlsConn, err
|
return tlsConn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *Trojan) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user