mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 17:35:40 +08:00
udptun: add udp tunnel support
This commit is contained in:
parent
1368cf7770
commit
824c9b3788
@ -14,6 +14,9 @@ type Dialer interface {
|
||||
// Dial connects to the given address via the proxy.
|
||||
Dial(network, addr string) (c net.Conn, err error)
|
||||
|
||||
// DialUDP returns a UDP PacketConn
|
||||
DialUDP(network, addr string) (c net.PacketConn, err error)
|
||||
|
||||
// Get the dialer by dstAddr
|
||||
NextDialer(dstAddr string) Dialer
|
||||
}
|
||||
|
13
direct.go
13
direct.go
@ -12,6 +12,9 @@ var Direct = &direct{}
|
||||
func (d *direct) Addr() string { return "DIRECT" }
|
||||
|
||||
func (d *direct) Dial(network, addr string) (net.Conn, error) {
|
||||
if network == "uot" {
|
||||
network = "udp"
|
||||
}
|
||||
c, err := net.Dial(network, addr)
|
||||
if c, ok := c.(*net.TCPConn); ok {
|
||||
c.SetKeepAlive(true)
|
||||
@ -19,4 +22,14 @@ func (d *direct) Dial(network, addr string) (net.Conn, error) {
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (d *direct) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||
uAddr, err := net.ResolveUDPAddr(network, addr)
|
||||
if err != nil {
|
||||
logf("ResolveUDPAddr error: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return net.DialUDP("udp", nil, uAddr)
|
||||
}
|
||||
|
||||
func (d *direct) NextDialer(dstAddr string) Dialer { return d }
|
||||
|
5
http.go
5
http.go
@ -214,6 +214,11 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) {
|
||||
return nil, errors.New("cound not connect remote address: " + addr + ". error code: " + code)
|
||||
}
|
||||
|
||||
// DialUDP .
|
||||
func (s *HTTP) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||
return nil, errors.New("udp not supported by http proxy now")
|
||||
}
|
||||
|
||||
// parseFirstLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts.
|
||||
func parseFirstLine(tp *textproto.Reader) (r1, r2, r3 string, ok bool) {
|
||||
line, err := tp.ReadLine()
|
||||
|
2
main.go
2
main.go
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// VERSION .
|
||||
const VERSION = "0.4.3"
|
||||
const VERSION = "0.5.0"
|
||||
|
||||
func dialerFromConf() Dialer {
|
||||
// global forwarders in xx.conf
|
||||
|
8
rule.go
8
rule.go
@ -56,7 +56,8 @@ func NewRuleDialer(rules []*RuleConf, gDialer Dialer) *RuleDialer {
|
||||
}
|
||||
|
||||
// Addr returns RuleDialer's address, always be "RULES"
|
||||
func (rd *RuleDialer) Addr() string { return "RULES" }
|
||||
// func (rd *RuleDialer) Addr() string { return "RULES" }
|
||||
func (rd *RuleDialer) Addr() string { return rd.gDialer.Addr() }
|
||||
|
||||
// NextDialer return next dialer according to rule
|
||||
func (rd *RuleDialer) NextDialer(dstAddr string) Dialer {
|
||||
@ -112,6 +113,11 @@ func (rd *RuleDialer) Dial(network, addr string) (net.Conn, error) {
|
||||
return rd.NextDialer(addr).Dial(network, addr)
|
||||
}
|
||||
|
||||
// DialUDP .
|
||||
func (rd *RuleDialer) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||
return rd.NextDialer(addr).DialUDP(network, addr)
|
||||
}
|
||||
|
||||
// AddDomainIP used to update ipMap rules according to domainMap rule
|
||||
func (rd *RuleDialer) AddDomainIP(domain, ip string) error {
|
||||
if ip != "" {
|
||||
|
@ -50,6 +50,9 @@ func ServerFromURL(s string, sDialer Dialer) (Server, error) {
|
||||
case "tcptun":
|
||||
d := strings.Split(addr, "=")
|
||||
return NewTCPTun(d[0], d[1], sDialer)
|
||||
case "udptun":
|
||||
d := strings.Split(addr, "=")
|
||||
return NewUDPTun(d[0], d[1], sDialer)
|
||||
case "dnstun":
|
||||
d := strings.Split(addr, "=")
|
||||
return NewDNSTun(d[0], d[1], sDialer)
|
||||
|
@ -156,6 +156,11 @@ func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// DialUDP .
|
||||
func (s *SOCKS5) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||
return nil, errors.New("udp not supported by socks5 proxy now")
|
||||
}
|
||||
|
||||
// connect takes an existing connection to a socks5 proxy server,
|
||||
// and commands the server to extend that connection to target,
|
||||
// which must be a canonical address with a host and port.
|
||||
|
28
ss.go
28
ss.go
@ -214,11 +214,22 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) {
|
||||
return nil, errors.New("Unable to parse address: " + addr)
|
||||
}
|
||||
|
||||
// udp over tcp tag
|
||||
if network == "udp" {
|
||||
switch network {
|
||||
case "tcp":
|
||||
return s.DialTCP(target)
|
||||
case "uot":
|
||||
target[0] = target[0] | 0x8
|
||||
return s.DialTCP(target)
|
||||
// case "udp":
|
||||
// return s.DialUDP(target)
|
||||
default:
|
||||
return nil, errors.New("Unknown schema: " + network)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DialTCP connects to the address addr via the proxy.
|
||||
func (s *SS) DialTCP(target Addr) (net.Conn, error) {
|
||||
c, err := s.cDialer.Dial("tcp", s.addr)
|
||||
if err != nil {
|
||||
logf("dial to %s error: %s", s.addr, err)
|
||||
@ -238,6 +249,19 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) {
|
||||
return c, err
|
||||
}
|
||||
|
||||
// DialUDP .
|
||||
func (s *SS) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||
target := ParseAddr(addr)
|
||||
if target == nil {
|
||||
return nil, errors.New("Unable to parse address: " + addr)
|
||||
}
|
||||
|
||||
c, _ := net.ListenPacket(network, "")
|
||||
c = s.PacketConn(c)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ListCipher .
|
||||
func ListCipher() string {
|
||||
return strings.Join(core.ListCipher(), " ")
|
||||
|
12
strategy.go
12
strategy.go
@ -5,8 +5,8 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewStrategyDialer returns a new Strategy Dialer
|
||||
@ -53,7 +53,7 @@ func newRRDialer(dialers []Dialer, website string, duration int) *rrDialer {
|
||||
rr.duration = duration
|
||||
|
||||
for k := range dialers {
|
||||
rr.status.Store(k,true)
|
||||
rr.status.Store(k, true)
|
||||
go rr.checkDialer(k)
|
||||
}
|
||||
|
||||
@ -65,6 +65,10 @@ func (rr *rrDialer) Dial(network, addr string) (net.Conn, error) {
|
||||
return rr.NextDialer(addr).Dial(network, addr)
|
||||
}
|
||||
|
||||
func (rr *rrDialer) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||
return rr.NextDialer(addr).DialUDP(network, addr)
|
||||
}
|
||||
|
||||
func (rr *rrDialer) NextDialer(dstAddr string) Dialer {
|
||||
n := len(rr.dialers)
|
||||
if n == 1 {
|
||||
@ -75,7 +79,7 @@ func (rr *rrDialer) NextDialer(dstAddr string) Dialer {
|
||||
for i := 0; i < n; i++ {
|
||||
rr.idx = (rr.idx + 1) % n
|
||||
result, ok := rr.status.Load(rr.idx)
|
||||
if (ok && result.(bool)) {
|
||||
if ok && result.(bool) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
@ -151,7 +155,7 @@ func (ha *haDialer) Dial(network, addr string) (net.Conn, error) {
|
||||
|
||||
result, ok := ha.status.Load(ha.idx)
|
||||
|
||||
if (ok && !result.(bool)) {
|
||||
if ok && !result.(bool) {
|
||||
d = ha.NextDialer(addr)
|
||||
}
|
||||
|
||||
|
74
udptun.go
Normal file
74
udptun.go
Normal file
@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UDPTun struct
|
||||
type UDPTun struct {
|
||||
*Forwarder
|
||||
sDialer Dialer
|
||||
|
||||
raddr string
|
||||
}
|
||||
|
||||
// NewUDPTun returns a UDPTun proxy.
|
||||
func NewUDPTun(addr, raddr string, sDialer Dialer) (*UDPTun, error) {
|
||||
s := &UDPTun{
|
||||
Forwarder: NewForwarder(addr, nil),
|
||||
sDialer: sDialer,
|
||||
raddr: raddr,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// ListenAndServe .
|
||||
func (s *UDPTun) ListenAndServe() {
|
||||
c, err := net.ListenPacket("udp", s.addr)
|
||||
if err != nil {
|
||||
logf("proxy-udptun failed to listen on %s: %v", s.addr, err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
logf("proxy-udptun listening UDP on %s", s.addr)
|
||||
|
||||
// var nm sync.Map
|
||||
buf := make([]byte, udpBufSize)
|
||||
tgt := ParseAddr(s.raddr)
|
||||
copy(buf, tgt)
|
||||
|
||||
for {
|
||||
n, clientAddr, err := c.ReadFrom(buf[len(tgt):])
|
||||
if err != nil {
|
||||
logf("proxy-udptun read error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
go func() {
|
||||
rc, err := s.sDialer.DialUDP("udp", s.raddr)
|
||||
if err != nil {
|
||||
logf("proxy-udptun failed to connect to server %v: %v", s.raddr, err)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: check here, get the correct sDialer's addr
|
||||
sUDPAddr, err := net.ResolveUDPAddr("udp", s.sDialer.Addr())
|
||||
if err != nil {
|
||||
logf("proxy-udptun failed to ResolveUDPAddr %", s.sDialer.Addr())
|
||||
return
|
||||
}
|
||||
|
||||
rc.WriteTo(buf[:len(tgt)+n], sUDPAddr)
|
||||
|
||||
go func() {
|
||||
timedCopy(c, clientAddr, rc, 5*time.Minute, false)
|
||||
rc.Close()
|
||||
}()
|
||||
|
||||
logf("proxy-udptun %s <-> %s", clientAddr, s.raddr)
|
||||
}()
|
||||
}
|
||||
}
|
@ -46,21 +46,22 @@ func (s *UoTTun) ListenAndServe() {
|
||||
}
|
||||
|
||||
go func() {
|
||||
// NOTE: acturally udp over tcp
|
||||
rc, err := s.sDialer.Dial("udp", s.raddr)
|
||||
rc, err := s.sDialer.Dial("uot", s.raddr)
|
||||
if err != nil {
|
||||
logf("failed to connect to server %v: %v", s.raddr, err)
|
||||
logf("proxy-uottun failed to connect to server %v: %v", s.raddr, err)
|
||||
return
|
||||
}
|
||||
|
||||
rc.Write(buf[:n])
|
||||
|
||||
// no remote forwarder
|
||||
// no remote forwarder, just a local udp forwarder
|
||||
if urc, ok := rc.(*net.UDPConn); ok {
|
||||
|
||||
go func() {
|
||||
timedCopy(c, clientAddr, urc, 5*time.Minute, false)
|
||||
urc.Close()
|
||||
}()
|
||||
|
||||
} else { // remote forwarder, udp over tcp
|
||||
resp, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user