diff --git a/conn.go b/conn.go index 7cc1bea..f1b46d6 100644 --- a/conn.go +++ b/conn.go @@ -58,6 +58,7 @@ func listenAndServe(arg Args) error { return listenAndServeUdpForward(arg) case "rtcp": // Remote TCP port forwarding return serveRTcpForward(arg) + case "rudp": // Remote UDP port forwarding default: ln, err = net.Listen("tcp", arg.Addr) } @@ -78,49 +79,6 @@ func listenAndServe(arg Args) error { } } -func serveRTcpForward(arg Args) error { - if arg.Forward == "" { - ln, err := net.Listen("tcp", arg.Addr) - if err != nil { - return err - } - defer ln.Close() - - for { - conn, err := ln.Accept() - if err != nil { - glog.V(LWARNING).Infoln(err) - continue - } - - tc := conn.(*net.TCPConn) - tc.SetKeepAlive(true) - tc.SetKeepAlivePeriod(time.Second * 60) - - go handleRTcpForwardConn(conn, arg) - } - } else { - retry := 0 - for { - conn, err := Connect(arg.Forward) - if err != nil { - glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", arg.Addr, arg.Forward, err) - time.Sleep((1 << uint(retry)) * time.Second) - if retry < 5 { - retry++ - } - continue - } - retry = 0 - - if err := connectRTcpForward(conn, arg); err != nil { - conn.Close() - time.Sleep(10 * time.Second) - } - } - } -} - func listenAndServeTcpForward(arg Args) error { ln, err := net.Listen("tcp", arg.Addr) if err != nil { @@ -165,6 +123,31 @@ func listenAndServeUdpForward(arg Args) error { } } +func serveRTcpForward(arg Args) error { + if len(forwardArgs) == 0 { + return errors.New("rtcp: at least one -F must be assigned") + } + + retry := 0 + for { + conn, _, err := forwardChain(forwardArgs...) + if err != nil { + glog.V(LWARNING).Infof("[rtcp] %s - %s : %s", arg.Addr, arg.Remote, err) + time.Sleep((1 << uint(retry)) * time.Second) + if retry < 5 { + retry++ + } + continue + } + retry = 0 + + if err := connectRTcpForward(conn, arg); err != nil { + conn.Close() + time.Sleep(10 * time.Second) + } + } +} + func handleConn(conn net.Conn, arg Args) { atomic.AddInt32(&connCounter, 1) glog.V(LDEBUG).Infof("%s connected, connections: %d", @@ -207,7 +190,7 @@ func handleConn(conn net.Conn, arg Args) { conn = gosocks5.ServerConn(conn, selector) req, err := gosocks5.ReadRequest(conn) if err != nil { - glog.V(LWARNING).Infoln("[socks5] request:", err) + glog.V(LWARNING).Infoln("[socks5]", err) return } handleSocks5Request(req, conn) @@ -298,9 +281,6 @@ func Connect(addr string) (conn net.Conn, err error) { var end Args conn, end, err = forwardChain(forwardArgs...) if err != nil { - if conn != nil { - conn.Close() - } return nil, err } if err := establish(conn, addr, end); err != nil { @@ -312,6 +292,13 @@ func Connect(addr string) (conn net.Conn, err error) { // establish connection throughout the forward chain func forwardChain(chain ...Args) (conn net.Conn, end Args, err error) { + defer func() { + if err != nil && conn != nil { + conn.Close() + conn = nil + } + }() + end = chain[0] if conn, err = net.DialTimeout("tcp", end.Addr, time.Second*90); err != nil { return diff --git a/forward.go b/forward.go index ade9655..deaed22 100644 --- a/forward.go +++ b/forward.go @@ -12,30 +12,30 @@ import ( func handleTcpForward(conn net.Conn, arg Args) { defer conn.Close() - if !strings.Contains(arg.Forward, ":") { - arg.Forward += ":22" // default is ssh service + if !strings.Contains(arg.Remote, ":") { + arg.Remote += ":22" // default is ssh service } - glog.V(LINFO).Infof("[tcp-forward] %s - %s", conn.RemoteAddr(), arg.Forward) - c, err := Connect(arg.Forward) + glog.V(LINFO).Infof("[tcp-forward] %s - %s", conn.RemoteAddr(), arg.Remote) + c, err := Connect(arg.Remote) if err != nil { - glog.V(LWARNING).Infof("[tcp-forward] %s -> %s : %s", conn.RemoteAddr(), arg.Forward, err) + glog.V(LWARNING).Infof("[tcp-forward] %s -> %s : %s", conn.RemoteAddr(), arg.Remote, err) return } defer c.Close() - glog.V(LINFO).Infof("[tcp-forward] %s <-> %s", conn.RemoteAddr(), arg.Forward) + glog.V(LINFO).Infof("[tcp-forward] %s <-> %s", conn.RemoteAddr(), arg.Remote) Transport(conn, c) - glog.V(LINFO).Infof("[tcp-forward] %s >-< %s", conn.RemoteAddr(), arg.Forward) + glog.V(LINFO).Infof("[tcp-forward] %s >-< %s", conn.RemoteAddr(), arg.Remote) } func handleUdpForward(conn *net.UDPConn, raddr *net.UDPAddr, data []byte, arg Args) { - if !strings.Contains(arg.Forward, ":") { - arg.Forward += ":53" // default is dns service + if !strings.Contains(arg.Remote, ":") { + arg.Remote += ":53" // default is dns service } - faddr, err := net.ResolveUDPAddr("udp", arg.Forward) + faddr, err := net.ResolveUDPAddr("udp", arg.Remote) if err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Forward, err) + glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Remote, err) return } @@ -44,235 +44,136 @@ func handleUdpForward(conn *net.UDPConn, raddr *net.UDPAddr, data []byte, arg Ar if len(forwardArgs) == 0 { lconn, err := net.ListenUDP("udp", nil) if err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Forward, err) + 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.Forward, err) + 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.Forward, len(data)) + 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.Forward, err) + 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.Forward, err) + glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Remote, err) } - glog.V(LINFO).Infof("[udp-forward] %s >-< %s", raddr, arg.Forward) + glog.V(LINFO).Infof("[udp-forward] %s >-< %s", raddr, arg.Remote) return } fconn, _, err := forwardChain(forwardArgs...) if err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Forward, err) - if fconn != nil { - fconn.Close() - } + glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Remote, err) return } defer fconn.Close() - glog.V(LINFO).Infof("[udp-forward] %s -> %s ASSOCIATE", raddr, arg.Forward) + glog.V(LINFO).Infof("[udp-forward] %s -> %s ASSOCIATE", raddr, arg.Remote) req := gosocks5.NewRequest(CmdUdpTun, nil) if err = req.Write(fconn); err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s -> %s ASSOCIATE : %s", raddr, arg.Forward, err) + glog.V(LWARNING).Infof("[udp-forward] %s -> %s ASSOCIATE : %s", raddr, arg.Remote, err) return } - glog.V(LDEBUG).Infof("[udp-forward] %s -> %s\n%s", raddr, arg.Forward, req) + glog.V(LDEBUG).Infof("[udp-forward] %s -> %s\n%s", raddr, arg.Remote, req) rep, err := gosocks5.ReadReply(fconn) if err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s <- %s ASSOCIATE : %s", raddr, arg.Forward, err) + glog.V(LWARNING).Infof("[udp-forward] %s <- %s ASSOCIATE : %s", raddr, arg.Remote, err) return } - glog.V(LDEBUG).Infof("[udp-forward] %s <- %s\n%s", raddr, arg.Forward, rep) + glog.V(LDEBUG).Infof("[udp-forward] %s <- %s\n%s", raddr, arg.Remote, rep) if rep.Rep != gosocks5.Succeeded { - glog.V(LWARNING).Infof("[udp-forward] %s <- %s ASSOCIATE failured", raddr, arg.Forward) + glog.V(LWARNING).Infof("[udp-forward] %s <- %s ASSOCIATE failured", raddr, arg.Remote) return } - glog.V(LINFO).Infof("[udp-forward] %s <-> %s ASSOCIATE ON %s", raddr, arg.Forward, rep.Addr) + glog.V(LINFO).Infof("[udp-forward] %s <-> %s ASSOCIATE ON %s", raddr, arg.Remote, rep.Addr) dgram := gosocks5.NewUDPDatagram( gosocks5.NewUDPHeader(uint16(len(data)), 0, ToSocksAddr(faddr)), data) fconn.SetWriteDeadline(time.Now().Add(time.Second * 90)) if err = dgram.Write(fconn); err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s -> %s : %s", raddr, arg.Forward, err) + 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.Forward, len(data)) + glog.V(LDEBUG).Infof("[udp-forward] %s >>> %s length %d", raddr, arg.Remote, len(data)) fconn.SetReadDeadline(time.Now().Add(time.Second * 90)) dgram, err = gosocks5.ReadUDPDatagram(fconn) if err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Forward, err) + 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, dgram.Header.Addr, len(dgram.Data)) if _, err = conn.WriteToUDP(dgram.Data, raddr); err != nil { - glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Forward, err) + glog.V(LWARNING).Infof("[udp-forward] %s <- %s : %s", raddr, arg.Remote, err) } - glog.V(LINFO).Infof("[udp-forward] %s >-< %s", raddr, arg.Forward) -} - -func handleRTcpForwardConn(conn net.Conn, arg Args) { - defer conn.Close() - - req, err := gosocks5.ReadRequest(conn) - if err != nil { - glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", conn.RemoteAddr(), arg.Addr, err) - return - } - bindAddr, _ := net.ResolveTCPAddr("tcp", req.Addr.String()) - ln, err := net.ListenTCP("tcp", bindAddr) - if err != nil { - glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) - rep := gosocks5.NewReply(gosocks5.Failure, nil) - if err := rep.Write(conn); err != nil { - glog.V(LWARNING).Infof("[rtcp] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) - } - return - } - - addr := ToSocksAddr(ln.Addr()) - addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - - rep := gosocks5.NewReply(gosocks5.Succeeded, addr) - if err := rep.Write(conn); err != nil { - glog.V(LWARNING).Infof("[rtcp] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) - ln.Close() - return - } - glog.V(LINFO).Infof("[rtcp] %s - %s BIND ON %s OK", conn.RemoteAddr(), req.Addr, addr) - - lnChan := make(chan net.Conn, 1) - go func() { - defer close(lnChan) - c, err := ln.AcceptTCP() - if err != nil { - // glog.V(LWARNING).Infof("[rtcp] %s <- %s ACCEPT : %s", conn.RemoteAddr(), addr, err) - return - } - lnChan <- c - }() - - peerChan := make(chan *gosocks5.Reply, 1) - go func() { - defer close(peerChan) - reply, err := gosocks5.ReadReply(conn) - if err != nil { - return - } - peerChan <- reply - }() - - var pconn net.Conn - - for { - select { - case c := <-lnChan: - ln.Close() // only accept one peer - if c == nil { - if err := gosocks5.NewReply(gosocks5.Failure, nil).Write(conn); err != nil { - glog.V(LWARNING).Infoln("[rtcp] %s <- %s : %s", conn.RemoteAddr(), addr, err) - } - glog.V(LWARNING).Infof("[rtcp] %s >-< %s : %s", conn.RemoteAddr(), addr) - return - } - glog.V(LINFO).Infof("[rtcp] %s <- %s PEER %s ACCEPTED", conn.RemoteAddr(), addr, c.RemoteAddr()) - gosocks5.NewReply(gosocks5.Succeeded, ToSocksAddr(c.RemoteAddr())).Write(conn) - pconn = c - lnChan = nil - ln = nil - case reply := <-peerChan: - if reply == nil { - if ln != nil { - ln.Close() - } - if pconn != nil { - pconn.Close() - } - glog.V(LWARNING).Infof("[rtcp] %s >-< %s", conn.RemoteAddr(), addr) - return - } - goto out - } - } - -out: - defer pconn.Close() - - glog.V(LINFO).Infof("[rtcp] %s <-> %s", conn.RemoteAddr(), pconn.RemoteAddr()) - Transport(conn, pconn) - glog.V(LINFO).Infof("[rtcp] %s >-< %s", conn.RemoteAddr(), pconn.RemoteAddr()) + glog.V(LINFO).Infof("[udp-forward] %s >-< %s", raddr, arg.Remote) } func connectRTcpForward(conn net.Conn, arg Args) error { - glog.V(LINFO).Infof("[rtcp] %s - %s", arg.Addr, arg.Forward) + glog.V(LINFO).Infof("[rtcp] %s - %s", arg.Addr, arg.Remote) - addr, _ := net.ResolveTCPAddr("tcp", arg.Bind) + addr, _ := net.ResolveTCPAddr("tcp", arg.Addr) req := gosocks5.NewRequest(gosocks5.CmdBind, ToSocksAddr(addr)) + bindAddr := req.Addr if err := req.Write(conn); err != nil { - glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", arg.Addr, arg.Forward, err) + glog.V(LWARNING).Infof("[rtcp] %s <- %s : %s", bindAddr, arg.Remote, err) return err } // first reply, bind status rep, err := gosocks5.ReadReply(conn) if err != nil { - glog.V(LWARNING).Infof("[rtcp] %s <- %s : %s", arg.Addr, arg.Forward, err) + glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", bindAddr, arg.Remote, err) return err } if rep.Rep != gosocks5.Succeeded { - glog.V(LWARNING).Infof("[rtcp] %s <- %s : bind on %s failure", arg.Addr, arg.Forward, arg.Bind) - return errors.New("Bind on " + arg.Bind + " failure") + glog.V(LWARNING).Infof("[rtcp] %s -> %s : bind on %s failure", bindAddr, arg.Remote, arg.Addr) + return errors.New("Bind on " + arg.Addr + " failure") } - glog.V(LINFO).Infof("[rtcp] %s - %s BIND ON %s OK", arg.Addr, arg.Forward, arg.Bind) + glog.V(LINFO).Infof("[rtcp] %s - %s BIND ON %s OK", bindAddr, arg.Remote, rep.Addr) // second reply, peer connection rep, err = gosocks5.ReadReply(conn) if err != nil { - glog.V(LWARNING).Infof("[rtcp] %s <- %s : %s", arg.Addr, arg.Forward, err) + glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", bindAddr, arg.Remote, err) return err } if rep.Rep != gosocks5.Succeeded { - glog.V(LWARNING).Infof("[rtcp] %s <- %s : peer connect failure", arg.Addr, arg.Forward) + glog.V(LWARNING).Infof("[rtcp] %s -> %s : peer connect failure", bindAddr, arg.Remote) return errors.New("peer connect failure") } - glog.V(LINFO).Infof("[rtcp] %s <- %s PEER %s CONNECTED", conn.RemoteAddr(), req.Addr, rep.Addr) + glog.V(LINFO).Infof("[rtcp] %s -> %s PEER %s CONNECTED", bindAddr, arg.Remote, rep.Addr) go func() { defer conn.Close() - lconn, err := net.Dial("tcp", arg.Addr) + lconn, err := net.Dial("tcp", arg.Remote) if err != nil { - glog.V(LWARNING).Infof("[rtcp] %s <- %s : %s", arg.Addr, arg.Forward, err) + glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", rep.Addr, lconn.RemoteAddr(), err) return } defer lconn.Close() - if err := gosocks5.NewReply(gosocks5.Succeeded, nil).Write(conn); err != nil { - glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", arg.Addr, arg.Forward, err) - return - } - - glog.V(LINFO).Infof("[rtcp] %s <-> %s", arg.Addr, arg.Forward) + glog.V(LINFO).Infof("[rtcp] %s <-> %s", rep.Addr, lconn.RemoteAddr()) Transport(lconn, conn) - glog.V(LINFO).Infof("[rtcp] %s >-< %s", arg.Addr, arg.Forward) + glog.V(LINFO).Infof("[rtcp] %s >-< %s", rep.Addr, lconn.RemoteAddr()) }() return nil diff --git a/main.go b/main.go index a92fc70..df628b7 100644 --- a/main.go +++ b/main.go @@ -45,8 +45,7 @@ func main() { return } if pv { - fmt.Fprintln(os.Stderr, "gost", Version) - fmt.Fprintln(os.Stderr, runtime.Version()) + fmt.Fprintf(os.Stderr, "gost %s (%s)\n", Version, runtime.Version()) return } diff --git a/socks.go b/socks.go index 7c10511..00ba34d 100644 --- a/socks.go +++ b/socks.go @@ -192,18 +192,67 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { glog.V(LINFO).Infof("[socks5-connect] %s <-> %s", conn.RemoteAddr(), req.Addr) Transport(conn, tconn) glog.V(LINFO).Infof("[socks5-connect] %s >-< %s", conn.RemoteAddr(), req.Addr) + case gosocks5.CmdBind: glog.V(LINFO).Infof("[socks5-bind] %s - %s", conn.RemoteAddr(), req.Addr) - if len(forwardArgs) > 0 { - forwardBind(req, conn) - } else { - tc := conn.(*net.TCPConn) - tc.SetKeepAlive(true) - tc.SetKeepAlivePeriod(time.Second * 60) - - serveBind(req, conn) + reply, fconn, err := socks5Bind(req, conn) + if reply != nil { + if err := reply.Write(conn); err != nil { + glog.V(LWARNING).Infof("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) + if fconn != nil { + fconn.Close() + } + return + } + glog.V(LDEBUG).Infof("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, reply) } + + if err != nil { + glog.V(LWARNING).Infof("[socks5-bind] %s - %s : %s", conn.RemoteAddr(), req.Addr, err) + return + } + defer fconn.Close() + + glog.V(LINFO).Infof("[socks5-bind] %s <-> %s", conn.RemoteAddr(), fconn.RemoteAddr()) + Transport(conn, fconn) + glog.V(LINFO).Infof("[socks5-bind] %s >-< %s", conn.RemoteAddr(), fconn.RemoteAddr()) + + /* + case gosocks5.CmdUdp: + case CmdUdpTun: + glog.V(LINFO).Infof("[socks5-udp] %s - %s ASSOCIATE", conn.RemoteAddr(), req.Addr) + if len(forwardArgs) > 0 { // direct forward + fconn, _, err := forwardChain(forwardArgs...) + if err != nil { + glog.V(LWARNING).Infof("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) + rep := gosocks5.NewReply(gosocks5.Failure, nil) + if err := rep.Write(conn); err != nil { + glog.V(LWARNING).Infof("[socks5-udp] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) + } else { + glog.V(LDEBUG).Infof("[socks5-udp] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) + } + return + } + defer fconn.Close() + if err := req.Write(fconn); err != nil { + glog.V(LWARNING).Infof("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) + rep := gosocks5.NewReply(gosocks5.Failure, nil) + if err := rep.Write(conn); err != nil { + glog.V(LWARNING).Infof("[socks5-udp] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) + } else { + glog.V(LDEBUG).Infof("[socks5-udp] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) + } + return + } + + glog.V(LINFO).Infof("[socks5-udp] %s <-> %s", conn.RemoteAddr(), req.Addr) + Transport(conn, fconn) + glog.V(LINFO).Infof("[socks5-udp] %s >-< %s", conn.RemoteAddr(), req.Addr) + } else { + + } + */ case gosocks5.CmdUdp, CmdUdpTun: // TODO: udp tunnel <-> forward chain glog.V(LINFO).Infof("[socks5-udp] %s - %s ASSOCIATE", conn.RemoteAddr(), req.Addr) @@ -296,35 +345,35 @@ func handleSocks5Request(req *gosocks5.Request, conn net.Conn) { } } -func serveBind(req *gosocks5.Request, conn net.Conn) error { +func socks5Bind(req *gosocks5.Request, conn net.Conn) (*gosocks5.Reply, net.Conn, error) { + if len(forwardArgs) > 0 { + fconn, _, err := forwardChain(forwardArgs...) + if err != nil { + return gosocks5.NewReply(gosocks5.Failure, nil), nil, err + } + + if err := req.Write(fconn); err != nil { + fconn.Close() + return gosocks5.NewReply(gosocks5.Failure, nil), nil, err + } + + return nil, fconn, nil + } + bindAddr, _ := net.ResolveTCPAddr("tcp", req.Addr.String()) ln, err := net.ListenTCP("tcp", bindAddr) if err != nil { - glog.V(LWARNING).Infof("[socks5-bind] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) - if bindAddr != nil { - ln, err = net.ListenTCP("tcp", nil) - } - if err != nil { - glog.V(LWARNING).Infof("[socks5-bind] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) - rep := gosocks5.NewReply(gosocks5.Failure, nil) - if err := rep.Write(conn); err != nil { - glog.V(LWARNING).Infof("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) - } else { - glog.V(LDEBUG).Infof("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) - } - return err - } + return gosocks5.NewReply(gosocks5.Failure, nil), nil, err } addr := ToSocksAddr(ln.Addr()) // Issue: may not reachable when host has two interfaces addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - rep := gosocks5.NewReply(gosocks5.Succeeded, addr) if err := rep.Write(conn); err != nil { glog.V(LWARNING).Infof("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) ln.Close() - return err + return nil, nil, err } glog.V(LDEBUG).Infof("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) glog.V(LINFO).Infof("[socks5-bind] %s - %s BIND ON %s OK", conn.RemoteAddr(), req.Addr, addr) @@ -342,7 +391,9 @@ func serveBind(req *gosocks5.Request, conn net.Conn) error { peerChan := make(chan error, 1) go func() { defer close(peerChan) - _, err := ioutil.ReadAll(conn) + b := tcpPool.Get().([]byte) + defer tcpPool.Put(b) + _, err := conn.Read(b) if err != nil { if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { return @@ -358,14 +409,8 @@ func serveBind(req *gosocks5.Request, conn net.Conn) error { case c := <-lnChan: ln.Close() // only accept one peer if c == nil { - if err := gosocks5.NewReply(gosocks5.Failure, nil).Write(conn); err != nil { - glog.V(LWARNING).Infoln("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), addr, err) - } - glog.V(LWARNING).Infof("[socks5-bind] %s >-< %s", conn.RemoteAddr(), addr) - return errors.New("accept error") + return gosocks5.NewReply(gosocks5.Failure, nil), nil, errors.New("[socks5-bind] accept error") } - // glog.V(LINFO).Infof("[socks5-bind] %s <- %s PEER %s ACCEPTED", conn.RemoteAddr(), req.Addr, c.RemoteAddr()) - // gosocks5.NewReply(gosocks5.Succeeded, ToSocksAddr(c.RemoteAddr())).Write(conn) pconn = c lnChan = nil ln = nil @@ -378,98 +423,23 @@ func serveBind(req *gosocks5.Request, conn net.Conn) error { if pconn != nil { pconn.Close() } - glog.V(LWARNING).Infof("[socks5-bind] %s >-< %s", conn.RemoteAddr(), addr) - return err + if err == nil { + err = errors.New("Oops, some mysterious error!") + } + return nil, nil, err } goto out } } out: - defer pconn.Close() conn.SetReadDeadline(time.Time{}) - paddr := ToSocksAddr(pconn.RemoteAddr()) - glog.V(LINFO).Infof("[socks5-bind] %s <- %s PEER %s ACCEPTED", conn.RemoteAddr(), addr, paddr) - - rep = gosocks5.NewReply(gosocks5.Succeeded, paddr) - if err := rep.Write(conn); err != nil { - glog.V(LWARNING).Infof("[socks5 bind] %s <- %s : %s", conn.RemoteAddr(), addr, err) - return err - } - glog.V(LDEBUG).Infof("[socks5 bind] %s <- %s\n%s", conn.RemoteAddr(), addr, rep) - - glog.V(LINFO).Infof("[socks5-bind] %s <-> %s", conn.RemoteAddr(), paddr) - defer glog.V(LINFO).Infof("[socks5-bind] %s >-< %s", conn.RemoteAddr(), paddr) - return Transport(conn, pconn) + glog.V(LINFO).Infof("[socks5-bind] %s <- %s PEER %s ACCEPTED", conn.RemoteAddr(), addr, pconn.RemoteAddr()) + rep = gosocks5.NewReply(gosocks5.Succeeded, ToSocksAddr(pconn.RemoteAddr())) + return rep, pconn, nil } -func forwardBind(req *gosocks5.Request, conn net.Conn) error { - fconn, _, err := forwardChain(forwardArgs...) - if err != nil { - glog.V(LWARNING).Infof("[socks5-bind] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) - if fconn != nil { - fconn.Close() - } - rep := gosocks5.NewReply(gosocks5.Failure, nil) - if err := rep.Write(conn); err != nil { - glog.V(LWARNING).Infof("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err) - } else { - glog.V(LDEBUG).Infof("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) - } - return err - } - defer fconn.Close() - - if err := req.Write(fconn); err != nil { - glog.V(LWARNING).Infoln("[socks5-bind] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) - gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) - return err - } - glog.V(LDEBUG).Infof("[socks5-bind] %s -> %s\n%s", conn.RemoteAddr(), req.Addr, req) - - /* - // first reply - rep, err := peekReply(conn, fconn) - if err != nil { - glog.V(LWARNING).Infoln("[socks5] BIND forward", err) - return err - } - glog.V(LINFO).Infoln("[socks5] BIND forward on", rep.Addr, "OK") - - // second reply - rep, err = peekReply(conn, fconn) - if err != nil { - glog.V(LWARNING).Infoln("[socks5] BIND forward accept", err) - return err - } - glog.V(LINFO).Infoln("[socks5] BIND forward accept", rep.Addr) - */ - glog.V(LINFO).Infof("[socks5-bind] %s <-> %s", conn.RemoteAddr(), req.Addr) - defer glog.V(LINFO).Infof("[socks5-bind] %s >-< %s", conn.RemoteAddr(), req.Addr) - return Transport(conn, fconn) -} - -/* -func peekReply(dst, src net.Conn) (rep *gosocks5.Reply, err error) { - rep, err = gosocks5.ReadReply(src) - if err != nil { - glog.V(LWARNING).Infof("[socks5-bind] FORWARD %s <- : %s", dst.RemoteAddr(), err) - rep = gosocks5.NewReply(gosocks5.Failure, nil) - } - if err = rep.Write(dst); err != nil { - return - } - glog.V(LDEBUG).Infof("[socks5-bind] FORWARD %s <-\n%s", dst.RemoteAddr(), rep) - - if rep.Rep != gosocks5.Succeeded { - err = errors.New("Failure") - } - - return -} -*/ - func createServerConn(uconn *net.UDPConn) (c *UDPConn, err error) { if len(forwardArgs) == 0 { c = Server(uconn) @@ -478,9 +448,6 @@ func createServerConn(uconn *net.UDPConn) (c *UDPConn, err error) { fconn, _, err := forwardChain(forwardArgs...) if err != nil { - if fconn != nil { - fconn.Close() - } return } glog.V(LINFO).Infoln("[udp] forward associate") @@ -509,7 +476,7 @@ func createServerConn(uconn *net.UDPConn) (c *UDPConn, err error) { } func ToSocksAddr(addr net.Addr) *gosocks5.Addr { - host := "" + host := "0.0.0.0" port := 0 if addr != nil { h, p, _ := net.SplitHostPort(addr.String()) diff --git a/util.go b/util.go index a24d68a..2369392 100644 --- a/util.go +++ b/util.go @@ -25,8 +25,7 @@ type Args struct { Addr string // host:port Protocol string // protocol: http/socks(5)/ss Transport string // transport: ws(s)/tls/tcp/udp/rtcp/rudp - Forward string // forward address, used by local tcp/udp port forwarding - Bind string // remote binding port, used by remote tcp/udp port forwarding + Remote string // remote address, used by tcp/udp port forwarding User *url.Userinfo // authentication for proxy Cert tls.Certificate // tls certificate } @@ -37,8 +36,8 @@ func (args Args) String() string { authUser = args.User.Username() authPass, _ = args.User.Password() } - return fmt.Sprintf("host: %s, protocol: %s, transport: %s, forward: %s, auth: %s/%s", - args.Addr, args.Protocol, args.Transport, args.Forward, authUser, authPass) + return fmt.Sprintf("host: %s, protocol: %s, transport: %s, remote: %s, auth: %s/%s", + args.Addr, args.Protocol, args.Transport, args.Remote, authUser, authPass) } func parseArgs(ss []string) (args []Args) { @@ -77,13 +76,9 @@ func parseArgs(ss []string) (args []Args) { switch arg.Transport { case "ws", "wss", "tls": case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding - arg.Forward = strings.Trim(u.EscapedPath(), "/") - case "rtcp", "rudp": // started from v2.1, rtcp and rudp are for remote port forwarding\ - if a := strings.Split(strings.Trim(u.EscapedPath(), "/"), ":"); len(a) == 3 { - arg.Forward = a[0] + ":" + a[1] - arg.Bind = ":" + a[2] - glog.V(LINFO).Infoln(arg.Forward, arg.Bind) - } + arg.Remote = strings.Trim(u.EscapedPath(), "/") + case "rtcp", "rudp": // started from v2.1, rtcp and rudp are for remote port forwarding + arg.Remote = strings.Trim(u.EscapedPath(), "/") default: arg.Transport = "" } diff --git a/ws.go b/ws.go index c5fc21d..4a90106 100644 --- a/ws.go +++ b/ws.go @@ -112,12 +112,13 @@ func NewWs(arg Args) *ws { } func (s *ws) handle(w http.ResponseWriter, r *http.Request) { + glog.V(LINFO).Infoln("[ws] %s - %s", r.RemoteAddr, s.arg.Addr) if glog.V(LDEBUG) { dump, err := httputil.DumpRequest(r, false) if err != nil { - glog.Infoln(err) + glog.V(LWARNING).Infoln("[ws] %s - %s : %s", r.RemoteAddr, s.arg.Addr, err) } else { - glog.Infoln(string(dump)) + glog.V(LDEBUG).Infoln("[ws] %s - %s\n%s", r.RemoteAddr, s.arg.Addr, string(dump)) } } conn, err := s.upgrader.Upgrade(w, r, nil)