Commit e12336fc authored by rui.zheng's avatar rui.zheng

update udp local port forwarding policy

parent d492b8b5
...@@ -35,7 +35,7 @@ var ( ...@@ -35,7 +35,7 @@ var (
// udp buffer pool // udp buffer pool
udpPool = sync.Pool{ udpPool = sync.Pool{
New: func() interface{} { New: func() interface{} {
return make([]byte, 64*1024+262) return make([]byte, 32*1024)
}, },
} }
) )
...@@ -108,35 +108,6 @@ func listenAndServeTcpForward(arg Args) error { ...@@ -108,35 +108,6 @@ func listenAndServeTcpForward(arg Args) error {
} }
} }
func prepareUdpConnectTunnel(addr net.Addr) (net.Conn, error) {
conn, _, err := forwardChain(forwardArgs...)
if err != nil {
return nil, err
}
conn.SetWriteDeadline(time.Now().Add(time.Second * 90))
if err = gosocks5.NewRequest(CmdUdpConnect, ToSocksAddr(addr)).Write(conn); err != nil {
conn.Close()
return nil, err
}
conn.SetWriteDeadline(time.Time{})
conn.SetReadDeadline(time.Now().Add(90 * time.Second))
reply, err := gosocks5.ReadReply(conn)
if err != nil {
conn.Close()
return nil, err
}
conn.SetReadDeadline(time.Time{})
if reply.Rep != gosocks5.Succeeded {
conn.Close()
return nil, errors.New("udp connect failure")
}
return conn, nil
}
func listenAndServeUdpForward(arg Args) error { func listenAndServeUdpForward(arg Args) error {
laddr, err := net.ResolveUDPAddr("udp", arg.Addr) laddr, err := net.ResolveUDPAddr("udp", arg.Addr)
if err != nil { if err != nil {
...@@ -148,55 +119,65 @@ func listenAndServeUdpForward(arg Args) error { ...@@ -148,55 +119,65 @@ func listenAndServeUdpForward(arg Args) error {
return err return err
} }
for { conn, err := net.ListenUDP("udp", laddr)
var conn *net.UDPConn if err != nil {
glog.V(LWARNING).Infof("[udp-connect] %s -> %s : %s", laddr, raddr, err)
return err
}
defer conn.Close()
if len(forwardArgs) == 0 {
for { for {
conn, err = net.ListenUDP("udp", laddr) b := udpPool.Get().([]byte)
n, addr, err := conn.ReadFromUDP(b)
if err != nil { if err != nil {
glog.V(LWARNING).Infof("[udp-connect] %s -> %s : %s", laddr, raddr, err) glog.V(LWARNING).Infof("[udp-connect] %s -> %s : %s", laddr, raddr, err)
time.Sleep((1) * time.Second)
continue continue
} }
break go func() {
handleUdpForwardLocal(conn, addr, raddr, b[:n])
udpPool.Put(b)
}()
} }
}
if len(forwardArgs) == 0 { rChan, wChan := make(chan *gosocks5.UDPDatagram, 32), make(chan *gosocks5.UDPDatagram, 32)
defer conn.Close()
for { go func() {
b := udpPool.Get().([]byte) for {
b := make([]byte, 32*1024)
n, addr, err := conn.ReadFromUDP(b)
if err != nil {
glog.V(LWARNING).Infof("[udp-connect] %s -> %s : %s", laddr, raddr, err)
return
}
n, addr, err := conn.ReadFromUDP(b) select {
if err != nil { case rChan <- gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(n), 0, ToSocksAddr(addr)), b[:n]):
glog.V(LWARNING).Infoln(err) default:
continue // glog.V(LWARNING).Infof("[udp-connect] %s -> %s : rbuf is full", laddr, raddr)
}
go func() {
handleUdpForwardLocal(conn, addr, raddr, b[:n])
udpPool.Put(b)
}()
} }
} }
}()
var tun net.Conn go func() {
retry := 0
for { for {
tun, err = prepareUdpConnectTunnel(raddr) dgram := <-wChan
addr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String())
if err != nil { if err != nil {
glog.V(LWARNING).Infof("[udp-connect] %s -> %s : %s", laddr, raddr, err) glog.V(LWARNING).Infof("[udp-connect] %s <- %s : %s", laddr, raddr, err)
time.Sleep((1 << uint(retry)) * time.Second) continue // drop silently
if retry < 5 { }
retry++ if _, err = conn.WriteToUDP(dgram.Data, addr); err != nil {
} glog.V(LWARNING).Infof("[udp-connect] %s <- %s : %s", laddr, raddr, err)
continue return
} }
break
} }
glog.V(LWARNING).Infof("[udp-connect] %s <-> %s", laddr, raddr) }()
tunnelUDP(conn, tun, false)
glog.V(LWARNING).Infof("[udp-connect] %s >-< %s", laddr, raddr) for {
conn.Close() handleUdpForwardTunnel(laddr, raddr, rChan, wChan)
} }
} }
......
...@@ -6,7 +6,6 @@ import ( ...@@ -6,7 +6,6 @@ import (
"github.com/ginuerzh/gosocks5" "github.com/ginuerzh/gosocks5"
"github.com/golang/glog" "github.com/golang/glog"
"net" "net"
"strings"
"time" "time"
) )
...@@ -56,109 +55,98 @@ func handleUdpForwardLocal(conn *net.UDPConn, laddr, raddr *net.UDPAddr, data [] ...@@ -56,109 +55,98 @@ func handleUdpForwardLocal(conn *net.UDPConn, laddr, raddr *net.UDPAddr, data []
return return
} }
func handleUdpForward(conn *net.UDPConn, raddr *net.UDPAddr, data []byte, arg Args) { func prepareUdpConnectTunnel(addr net.Addr) (net.Conn, error) {
if !strings.Contains(arg.Remote, ":") { conn, _, err := forwardChain(forwardArgs...)
arg.Remote += ":53" // default is dns service
}
faddr, err := net.ResolveUDPAddr("udp", arg.Remote)
if err != nil { if err != nil {
glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Remote, err) return nil, err
return
} }
glog.V(LINFO).Infof("[udp-forward] %s - %s", raddr, faddr) conn.SetWriteDeadline(time.Now().Add(time.Second * 90))
if err = gosocks5.NewRequest(CmdUdpConnect, ToSocksAddr(addr)).Write(conn); err != nil {
if len(forwardArgs) == 0 { conn.Close()
lconn, err := net.ListenUDP("udp", nil) return nil, err
if err != nil {
glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Remote, err)
return
}
defer lconn.Close()
if _, err := lconn.WriteToUDP(data, faddr); err != nil {
glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Remote, err)
return
}
glog.V(LDEBUG).Infof("[udp-forward] %s >>> %s length %d", raddr, arg.Remote, len(data))
b := udpPool.Get().([]byte)
defer udpPool.Put(b)
lconn.SetReadDeadline(time.Now().Add(time.Second * 60))
n, addr, err := lconn.ReadFromUDP(b)
if err != nil {
glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Remote, err)
return
}
glog.V(LDEBUG).Infof("[udp-forward] %s <<< %s length %d", raddr, addr, n)
if _, err := conn.WriteToUDP(b[:n], raddr); err != nil {
glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Remote, err)
}
glog.V(LINFO).Infof("[udp-forward] %s >-< %s", raddr, arg.Remote)
return
} }
conn.SetWriteDeadline(time.Time{})
tun, _, err := forwardChain(forwardArgs...) conn.SetReadDeadline(time.Now().Add(90 * time.Second))
reply, err := gosocks5.ReadReply(conn)
if err != nil { if err != nil {
glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Remote, err) conn.Close()
return return nil, err
} }
defer tun.Close() conn.SetReadDeadline(time.Time{})
glog.V(LINFO).Infof("[udp-forward] %s -> %s ASSOCIATE", raddr, arg.Remote)
req := gosocks5.NewRequest(CmdUdpTun, nil) if reply.Rep != gosocks5.Succeeded {
tun.SetWriteDeadline(time.Now().Add(time.Second * 90)) conn.Close()
if err = req.Write(tun); err != nil { return nil, errors.New("failure")
glog.V(LWARNING).Infof("[udp-forward] %s -> %s ASSOCIATE : %s", raddr, arg.Remote, err)
return
} }
tun.SetWriteDeadline(time.Time{})
glog.V(LDEBUG).Infof("[udp-forward] %s -> %s\n%s", raddr, arg.Remote, req)
tun.SetReadDeadline(time.Now().Add(90 * time.Second)) return conn, nil
rep, err := gosocks5.ReadReply(tun) }
if err != nil {
glog.V(LWARNING).Infof("[udp-forward] %s <- %s ASSOCIATE : %s", raddr, arg.Remote, err)
return
}
tun.SetReadDeadline(time.Time{})
glog.V(LDEBUG).Infof("[udp-forward] %s <- %s\n%s", raddr, arg.Remote, rep) func handleUdpForwardTunnel(laddr, raddr *net.UDPAddr, rChan, wChan chan *gosocks5.UDPDatagram) {
if rep.Rep != gosocks5.Succeeded { var tun net.Conn
glog.V(LWARNING).Infof("[udp-forward] %s <- %s ASSOCIATE failured", raddr, arg.Remote) var err error
return retry := 0
for {
tun, err = prepareUdpConnectTunnel(raddr)
if err != nil {
glog.V(LWARNING).Infof("[udp-connect] %s -> %s : %s", laddr, raddr, err)
time.Sleep((1 << uint(retry)) * time.Second)
if retry < 5 {
retry++
}
continue
}
break
} }
glog.V(LINFO).Infof("[udp-forward] %s <-> %s ASSOCIATE ON %s", raddr, arg.Remote, rep.Addr)
dgram := gosocks5.NewUDPDatagram( glog.V(LINFO).Infof("[udp-connect] %s <-> %s", laddr, raddr)
gosocks5.NewUDPHeader(uint16(len(data)), 0, ToSocksAddr(faddr)), data)
tun.SetWriteDeadline(time.Now().Add(time.Second * 90)) rExit := make(chan interface{})
if err = dgram.Write(tun); err != nil { rErr, wErr := make(chan error, 1), make(chan error, 1)
glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Remote, err)
return
}
tun.SetWriteDeadline(time.Time{})
glog.V(LDEBUG).Infof("[udp-forward] %s >>> %s length %d", raddr, arg.Remote, len(data))
tun.SetReadDeadline(time.Now().Add(time.Second * 90)) go func() {
dgram, err = gosocks5.ReadUDPDatagram(tun) for {
if err != nil { select {
glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Remote, err) case dgram := <-rChan:
return if err := dgram.Write(tun); err != nil {
} glog.V(LWARNING).Infof("[udp-connect] %s -> %s : %s", laddr, raddr, err)
tun.SetReadDeadline(time.Time{}) rErr <- err
glog.V(LDEBUG).Infof("[udp-forward] %s <<< %s length %d", raddr, dgram.Header.Addr, len(dgram.Data)) return
}
glog.V(LDEBUG).Infof("[udp-tun] %s >>> %s length: %d", laddr, raddr, len(dgram.Data))
case <-rExit:
// glog.V(LDEBUG).Infof("[udp-connect] %s -> %s : exited", laddr, raddr)
return
}
}
}()
go func() {
for {
dgram, err := gosocks5.ReadUDPDatagram(tun)
if err != nil {
glog.V(LWARNING).Infof("[udp-connect] %s <- %s : %s", laddr, raddr, err)
close(rExit)
wErr <- err
return
}
if _, err = conn.WriteToUDP(dgram.Data, raddr); err != nil { select {
glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Remote, err) case wChan <- dgram:
} glog.V(LDEBUG).Infof("[udp-tun] %s <<< %s length: %d", laddr, raddr, len(dgram.Data))
default:
}
}
}()
// NOTE: for now we only get one response from peer select {
glog.V(LINFO).Infof("[udp-forward] %s >-< %s", raddr, arg.Remote) case <-rErr:
//log.Println("w exit", err)
case <-wErr:
//log.Println("r exit", err)
}
glog.V(LINFO).Infof("[udp-connect] %s >-< %s", laddr, raddr)
} }
func connectRTcpForward(conn net.Conn, arg Args) error { func connectRTcpForward(conn net.Conn, arg Args) error {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment