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

add bind forward

parent 706e22e7
...@@ -111,7 +111,7 @@ func handleConn(conn net.Conn, arg Args) { ...@@ -111,7 +111,7 @@ func handleConn(conn net.Conn, arg Args) {
} }
return return
} }
handleSocks5Request(req, conn, arg) handleSocks5Request(req, conn)
return return
} }
...@@ -162,7 +162,7 @@ func handleConn(conn net.Conn, arg Args) { ...@@ -162,7 +162,7 @@ func handleConn(conn net.Conn, arg Args) {
} }
return return
} }
handleSocks5Request(req, conn, arg) handleSocks5Request(req, conn)
return return
} }
...@@ -198,41 +198,43 @@ func (r *reqReader) Read(p []byte) (n int, err error) { ...@@ -198,41 +198,43 @@ func (r *reqReader) Read(p []byte) (n int, err error) {
return return
} }
func connect(addr string) (conn net.Conn, err error) { func Connect(addr string) (conn net.Conn, err error) {
if !strings.Contains(addr, ":") { if !strings.Contains(addr, ":") {
addr += ":80" addr += ":80"
} }
if len(forwardArgs) == 0 { if len(forwardArgs) == 0 {
return net.Dial("tcp", addr) return net.Dial("tcp", addr)
} }
return forwardChain(addr, forwardArgs[0], forwardArgs[1:]...)
}
func forwardChain(addr string, level1 Args, chain ...Args) (conn net.Conn, err error) { var end Args
if glog.V(LINFO) { conn, end, err = forwardChain(forwardArgs...)
glog.Infof("forward: %s/%s %s", level1.Protocol, level1.Transport, level1.Addr)
}
if conn, err = net.Dial("tcp", level1.Addr); err != nil {
return
}
c, err := forward(conn, level1)
if err != nil { if err != nil {
if conn != nil {
conn.Close()
}
return nil, err
}
if err := establish(conn, addr, end); err != nil {
conn.Close() conn.Close()
return nil, err return nil, err
} }
conn = c return conn, nil
}
if len(chain) == 0 { func forwardChain(chain ...Args) (conn net.Conn, end Args, err error) {
if err := establish(conn, addr, level1); err != nil { end = chain[0]
conn.Close() if conn, err = net.Dial("tcp", end.Addr); err != nil {
return nil, err
}
return return
} }
c, err := forward(conn, end)
if err != nil {
return
}
conn = c
cur := level1 chain = chain[1:]
for _, arg := range chain { for _, arg := range chain {
if err = establish(conn, arg.Addr, cur); err != nil { if err = establish(conn, arg.Addr, end); err != nil {
goto exit goto exit
} }
...@@ -241,26 +243,18 @@ func forwardChain(addr string, level1 Args, chain ...Args) (conn net.Conn, err e ...@@ -241,26 +243,18 @@ func forwardChain(addr string, level1 Args, chain ...Args) (conn net.Conn, err e
goto exit goto exit
} }
conn = c conn = c
cur = arg end = arg
} }
exit: exit:
if err != nil {
conn.Close()
return nil, err
}
if err := establish(conn, addr, cur); err != nil {
conn.Close()
return nil, err
}
return return
} }
func forward(conn net.Conn, arg Args) (net.Conn, error) { func forward(conn net.Conn, arg Args) (net.Conn, error) {
var err error var err error
if glog.V(LINFO) {
glog.Infof("forward: %s/%s %s", arg.Protocol, arg.Transport, arg.Addr)
}
switch arg.Transport { switch arg.Transport {
case "ws": // websocket connection case "ws": // websocket connection
conn, err = wsClient(conn, arg.Addr) conn, err = wsClient(conn, arg.Addr)
...@@ -312,10 +306,19 @@ func establish(conn net.Conn, addr string, arg Args) error { ...@@ -312,10 +306,19 @@ func establish(conn net.Conn, addr string, arg Args) error {
Host: host, Host: host,
Port: uint16(p), Port: uint16(p),
}) })
rep, err := requestSocks5(conn, req) if err := req.Write(conn); err != nil {
return err
}
if glog.V(LDEBUG) {
glog.Infoln(req)
}
rep, err := gosocks5.ReadReply(conn)
if err != nil { if err != nil {
return err return err
} }
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
if rep.Rep != gosocks5.Succeeded { if rep.Rep != gosocks5.Succeeded {
return errors.New("Service unavailable") return errors.New("Service unavailable")
} }
......
...@@ -47,7 +47,7 @@ func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) { ...@@ -47,7 +47,7 @@ func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) {
return return
} }
c, err := connect(req.Host) c, err := Connect(req.Host)
if err != nil { if err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln(err) glog.Warningln(err)
......
...@@ -2,6 +2,7 @@ package main ...@@ -2,6 +2,7 @@ package main
import ( import (
"crypto/tls" "crypto/tls"
"errors"
"github.com/ginuerzh/gosocks5" "github.com/ginuerzh/gosocks5"
"github.com/golang/glog" "github.com/golang/glog"
"net" "net"
...@@ -175,24 +176,7 @@ func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Con ...@@ -175,24 +176,7 @@ func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Con
return conn, nil return conn, nil
} }
func requestSocks5(conn net.Conn, req *gosocks5.Request) (*gosocks5.Reply, error) { func handleSocks5Request(req *gosocks5.Request, conn net.Conn) {
if err := req.Write(conn); err != nil {
return nil, err
}
if glog.V(LDEBUG) {
glog.Infoln(req.String())
}
rep, err := gosocks5.ReadReply(conn)
if err != nil {
return nil, err
}
if glog.V(LDEBUG) {
glog.Infoln(rep.String())
}
return rep, nil
}
func handleSocks5Request(req *gosocks5.Request, conn net.Conn, arg Args) {
if glog.V(LDEBUG) { if glog.V(LDEBUG) {
glog.Infoln(req) glog.Infoln(req)
} }
...@@ -202,7 +186,7 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn, arg Args) { ...@@ -202,7 +186,7 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn, arg Args) {
if glog.V(LINFO) { if glog.V(LINFO) {
glog.Infoln("socks5 connect:", req.Addr.String()) glog.Infoln("socks5 connect:", req.Addr.String())
} }
tconn, err := connect(req.Addr.String()) tconn, err := Connect(req.Addr.String())
if err != nil { if err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 connect:", err) glog.Warningln("socks5 connect:", err)
...@@ -234,15 +218,21 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn, arg Args) { ...@@ -234,15 +218,21 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn, arg Args) {
Transport(conn, tconn) Transport(conn, tconn)
case gosocks5.CmdBind: case gosocks5.CmdBind:
l, err := net.ListenTCP("tcp", nil) if len(forwardArgs) > 0 {
forwardBind(req, conn)
} else {
serveBind(conn)
}
case gosocks5.CmdUdp:
uconn, err := net.ListenUDP("udp", nil)
if err != nil { if err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 bind listen:", err) glog.Warningln("socks5 udp listen:", err)
} }
rep := gosocks5.NewReply(gosocks5.Failure, nil) rep := gosocks5.NewReply(gosocks5.Failure, nil)
if err := rep.Write(conn); err != nil { if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 bind listen:", err) glog.Warningln("socks5 udp listen:", err)
} }
} else { } else {
if glog.V(LDEBUG) { if glog.V(LDEBUG) {
...@@ -251,102 +241,193 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn, arg Args) { ...@@ -251,102 +241,193 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn, arg Args) {
} }
return return
} }
defer uconn.Close()
addr := ToSocksAddr(l.Addr()) addr := ToSocksAddr(uconn.LocalAddr())
addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
if glog.V(LINFO) { if glog.V(LINFO) {
glog.Infoln("socks5 bind:", addr) glog.Infoln("socks5 udp:", addr)
} }
rep := gosocks5.NewReply(gosocks5.Succeeded, addr) rep := gosocks5.NewReply(gosocks5.Succeeded, addr)
if err := rep.Write(conn); err != nil { if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 bind:", err) glog.Warningln("socks5 udp:", err)
} }
l.Close()
return return
} else {
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
} }
if glog.V(LDEBUG) { srvTunnelUDP(conn, uconn)
glog.Infoln(rep) }
} }
tconn, err := l.AcceptTCP() func serveBind(conn net.Conn) error {
l.Close() // only accept one peer l, err := net.ListenTCP("tcp", nil)
if err != nil { if err != nil {
if glog.V(LWARNING) {
glog.Warningln("socks5 bind listen:", err)
}
rep := gosocks5.NewReply(gosocks5.Failure, nil)
if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 bind accept:", err) glog.Warningln("socks5 bind listen:", err)
} }
rep = gosocks5.NewReply(gosocks5.Failure, nil) } else {
if err := rep.Write(conn); err != nil { if glog.V(LDEBUG) {
if glog.V(LWARNING) { glog.Infoln(rep)
glog.Warningln("socks5 bind accept:", err)
}
} else {
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
} }
return
} }
defer tconn.Close() return err
}
addr = ToSocksAddr(tconn.RemoteAddr()) addr := ToSocksAddr(l.Addr())
if glog.V(LINFO) { // Issue: may not reachable when host has two interfaces
glog.Infoln("socks5 bind accept:", addr.String()) addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
if glog.V(LINFO) {
glog.Infoln("socks5 bind:", addr)
}
rep := gosocks5.NewReply(gosocks5.Succeeded, addr)
if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) {
glog.Warningln("socks5 bind:", err)
}
l.Close()
return err
}
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
tconn, err := l.AcceptTCP()
l.Close() // only accept one peer
if err != nil {
if glog.V(LWARNING) {
glog.Warningln("socks5 bind accept:", err)
} }
rep = gosocks5.NewReply(gosocks5.Succeeded, addr) rep = gosocks5.NewReply(gosocks5.Failure, nil)
if err := rep.Write(conn); err != nil { if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 bind accept:", err) glog.Warningln("socks5 bind accept:", err)
} }
return } else {
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
} }
if glog.V(LDEBUG) { return err
glog.Infoln(rep) }
defer tconn.Close()
addr = ToSocksAddr(tconn.RemoteAddr())
if glog.V(LINFO) {
glog.Infoln("socks5 bind accept:", addr.String())
}
rep = gosocks5.NewReply(gosocks5.Succeeded, addr)
if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) {
glog.Warningln("socks5 bind accept:", err)
} }
return err
}
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
return Transport(conn, tconn)
}
if err := Transport(conn, tconn); err != nil { func forwardBind(req *gosocks5.Request, conn net.Conn) error {
//log.Println(err) fc, _, err := forwardChain(forwardArgs...)
if err != nil {
if fc != nil {
fc.Close()
} }
case gosocks5.CmdUdp: rep := gosocks5.NewReply(gosocks5.Failure, nil)
uconn, err := net.ListenUDP("udp", nil) if err := rep.Write(conn); err != nil {
if err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 udp listen:", err) glog.Warningln("socks5 bind:", err)
} }
rep := gosocks5.NewReply(gosocks5.Failure, nil) } else {
if err := rep.Write(conn); err != nil { if glog.V(LDEBUG) {
if glog.V(LWARNING) { glog.Infoln(rep)
glog.Warningln("socks5 udp listen:", err)
}
} else {
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
} }
return
} }
defer uconn.Close() return err
}
defer fc.Close()
addr := ToSocksAddr(uconn.LocalAddr()) if err := req.Write(fc); err != nil {
addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) if glog.V(LWARNING) {
if glog.V(LINFO) { glog.Warningln("socks5 bind:", err)
glog.Infoln("socks5 udp:", addr)
} }
rep := gosocks5.NewReply(gosocks5.Succeeded, addr) gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
return err
}
if glog.V(LDEBUG) {
glog.Infoln(req)
}
// first reply
if err := peekBindReply(conn, fc); err != nil {
return err
}
// second reply
if err := peekBindReply(conn, fc); err != nil {
return err
}
return Transport(conn, fc)
}
func peekBindReply(conn, fc net.Conn) error {
rep, err := gosocks5.ReadReply(fc)
if err != nil {
if glog.V(LWARNING) {
glog.Warningln("socks5 bind:", err)
}
rep = gosocks5.NewReply(gosocks5.Failure, nil)
}
if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) {
glog.Warningln("socks5 bind:", err)
}
return err
}
if glog.V(LDEBUG) {
glog.Infoln(rep)
}
if rep.Rep != gosocks5.Succeeded {
return errors.New("Bind failure")
}
return nil
}
/*
func forwardUDP() error {
fc, _, err := forwardChain(forwardArgs...)
if err != nil {
if fc != nil {
fc.Close()
}
rep := gosocks5.NewReply(gosocks5.Failure, nil)
if err := rep.Write(conn); err != nil { if err := rep.Write(conn); err != nil {
if glog.V(LWARNING) { if glog.V(LWARNING) {
glog.Warningln("socks5 udp:", err) glog.Warningln("socks5 bind:", err)
} }
return
} else { } else {
if glog.V(LDEBUG) { if glog.V(LDEBUG) {
glog.Infoln(rep) glog.Infoln(rep)
} }
} }
srvTunnelUDP(conn, uconn) return err
} }
} defer fc.Close()
}
*/
func srvTunnelUDP(conn net.Conn, uconn *net.UDPConn) { func srvTunnelUDP(conn net.Conn, uconn *net.UDPConn) {
go func() { go func() {
b := make([]byte, 16*1024) b := make([]byte, 16*1024)
......
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