diff --git a/conn.go b/conn.go index 94908f3..f3edf3a 100644 --- a/conn.go +++ b/conn.go @@ -46,28 +46,22 @@ func listenAndServe(arg Args) error { switch arg.Transport { case "ws": // websocket connection - err = NewWs(arg).ListenAndServe() - if err != nil { - glog.Infoln(err) - } - return err + return NewWs(arg).ListenAndServe() case "wss": // websocket security connection - err = NewWs(arg).listenAndServeTLS() - if err != nil { - glog.Infoln(err) - } - return err + return NewWs(arg).listenAndServeTLS() case "tls": // tls connection ln, err = tls.Listen("tcp", arg.Addr, &tls.Config{Certificates: []tls.Certificate{arg.Cert}}) - case "tcp": - fallthrough + case "tcp": // TCP port forwarding + return listenAndServeTcpForward(arg) + case "udp": // UDP port forwarding + //return listenAndServeUdpForward(arg) + return nil default: ln, err = net.Listen("tcp", arg.Addr) } if err != nil { - glog.Infoln(err) return err } @@ -81,10 +75,47 @@ func listenAndServe(arg Args) error { } go handleConn(conn, arg) } +} +func listenAndServeTcpForward(arg Args) error { + ln, err := net.Listen("tcp", arg.Addr) + if err != nil { + return err + } + for { + conn, err := ln.Accept() + if err != nil { + glog.V(LWARNING).Infoln(err) + continue + } + go handleTcpForward(conn, arg) + } return nil } +/* +func listenAndServeUdpForward(arg Args) error { + addr, err := net.ResolveUDPAddr("udp", arg.Addr) + if err != nil { + return err + } + ln, err := net.ListenUDP("udp", addr) + if err != nil { + return err + } + for { + b := udpPool.Get().([]byte) + defer udpPool.Put(b) + + _, c, err := ln.ReadFromUDP(b) + if err != nil { + glog.V(LWARNING).Infoln(err) + continue + } + handleUdpForward(c, arg) + } +} +*/ func handleConn(conn net.Conn, arg Args) { atomic.AddInt32(&connCounter, 1) glog.V(LINFO).Infof("%s connected, connections: %d", @@ -99,7 +130,7 @@ func handleConn(conn net.Conn, arg Args) { defer atomic.AddInt32(&connCounter, -1) defer conn.Close() - // server supported methods + // socks5 server supported methods selector := &serverSelector{ methods: []uint8{ gosocks5.MethodNoAuth, @@ -134,7 +165,7 @@ func handleConn(conn net.Conn, arg Args) { return } - // http + socks5 + // http or socks5 //b := make([]byte, 16*1024) b := tcpPool.Get().([]byte) @@ -212,7 +243,7 @@ func Connect(addr string) (conn net.Conn, err error) { addr += ":80" } if len(forwardArgs) == 0 { - return net.DialTimeout("tcp", addr, time.Second*30) + return net.DialTimeout("tcp", addr, time.Second*60) } var end Args diff --git a/forward.go b/forward.go new file mode 100644 index 0000000..590eeb3 --- /dev/null +++ b/forward.go @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/golang/glog" + "net" +) + +func handleTcpForward(conn net.Conn, arg Args) { + glog.V(LINFO).Infoln("[tcp-forward] CONNECT", arg.Forward) + c, err := Connect(arg.Forward) + if err != nil { + glog.V(LWARNING).Infoln("[tcp-forward] CONNECT", arg.Forward, err) + return + } + defer c.Close() + + glog.V(LINFO).Infoln("[tcp-forward] CONNECT", arg.Forward, "OK") + Transport(conn, c) +} + +func handleUdpForward(conn *net.UDPConn, arg Args) { + +} diff --git a/main.go b/main.go index bc17936..a92fc70 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/golang/glog" "os" + "runtime" "sync" ) @@ -18,7 +19,7 @@ const ( ) const ( - Version = "2.0" + Version = "2.1-dev" ) var ( @@ -45,6 +46,7 @@ func main() { } if pv { fmt.Fprintln(os.Stderr, "gost", Version) + fmt.Fprintln(os.Stderr, runtime.Version()) return } @@ -60,7 +62,7 @@ func main() { wg.Add(1) go func(arg Args) { defer wg.Done() - listenAndServe(arg) + glog.V(LERROR).Infoln(listenAndServe(arg)) }(args) } wg.Wait() diff --git a/tls.go b/tls.go index 9c7ffc2..2ce8f5d 100644 --- a/tls.go +++ b/tls.go @@ -6,6 +6,8 @@ import ( ) const ( + + // This is the default cert file for convenience, providing your own cert is recommended. rawCert = `-----BEGIN CERTIFICATE----- MIIC5jCCAdCgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD bzAeFw0xNDAzMTcwNjIwNTFaFw0xNTAzMTcwNjIwNTFaMBIxEDAOBgNVBAoTB0Fj diff --git a/util.go b/util.go index 63dc78e..f2d8279 100644 --- a/util.go +++ b/util.go @@ -23,8 +23,9 @@ func (ss *strSlice) Set(value string) error { // admin:123456@localhost:8080 type Args struct { Addr string // host:port - Protocol string // protocol: http&socks5/http/socks/socks5/ss, default is http&socks5 - Transport string // transport: tcp/ws/tls, default is tcp(raw tcp) + Protocol string // protocol: http/socks(5)/ss + Transport string // transport: ws(s)/tls/tcp/udp + Forward string // forward address, used by tcp/udp port forwarding User *url.Userinfo Cert tls.Certificate // tls certificate } @@ -35,14 +36,14 @@ func (args Args) String() string { authUser = args.User.Username() authPass, _ = args.User.Password() } - return fmt.Sprintf("host: %s, protocol: %s, transport: %s, auth: %s:%s", - args.Addr, args.Protocol, args.Transport, authUser, authPass) + return fmt.Sprintf("host: %s, protocol: %s, transport: %s, forward: %s, auth: %s/%s", + args.Addr, args.Protocol, args.Transport, args.Forward, authUser, authPass) } func parseArgs(ss []string) (args []Args) { for _, s := range ss { if !strings.Contains(s, "://") { - s = "tcp://" + s + s = "auto://" + s } u, err := url.Parse(s) if err != nil { @@ -51,9 +52,10 @@ func parseArgs(ss []string) (args []Args) { } arg := Args{ - Addr: u.Host, - User: u.User, - Cert: tlsCert, + Addr: u.Host, + User: u.User, + Cert: tlsCert, + Forward: strings.Trim(u.EscapedPath(), "/"), } schemes := strings.Split(u.Scheme, "+") @@ -69,12 +71,15 @@ func parseArgs(ss []string) (args []Args) { switch arg.Protocol { case "http", "socks", "socks5", "ss": default: - arg.Protocol = "default" + arg.Protocol = "" } + switch arg.Transport { - case "ws", "wss", "tls", "tcp": + case "ws", "wss", "tls": + case "tcp", "udp": // started from v2.1, tcp and udp are for port forwarding + arg.Protocol = "" default: - arg.Transport = "tcp" + arg.Transport = "" } args = append(args, arg) @@ -83,7 +88,7 @@ func parseArgs(ss []string) (args []Args) { return } -// based on io.Copy +// Based on io.Copy, but the io.ErrShortWrite is ignored (mainly for websocket) func Copy(dst io.Writer, src io.Reader) (written int64, err error) { buf := make([]byte, 32*1024)