diff --git a/gost.go b/gost.go index 2bb2641..90c47f3 100644 --- a/gost.go +++ b/gost.go @@ -1,17 +1,17 @@ package main import ( - //"bufio" - //"bytes" + "bufio" + "bytes" //"crypto/tls" - //"errors" + "errors" "io" //"io/ioutil" "log" "net" - //"net/http" - //"strconv" - //"strings" + "net/http" + "strconv" + "strings" //"sync/atomic" "time" ) @@ -42,58 +42,158 @@ func (g *Gost) Run() error { log.Println("accept:", err) continue } - go g.serve(conn) + go g.handle(conn) } return ln.Close() } -func (g *Gost) serve(conn net.Conn) error { - var pconn net.Conn +func (g *Gost) handle(conn net.Conn) { defer conn.Close() + // as client + if len(g.Saddr) > 0 { + g.cli(conn) + return + } + + // as server + g.srv(conn) +} + +func (g *Gost) cli(conn net.Conn) { + sconn, err := g.connect(g.Saddr) + if err != nil { + return + } + defer sconn.Close() + + g.transport(conn, sconn) + return +} + +func (g *Gost) srv(conn net.Conn) { + b := make([]byte, 8192) + + n, err := conn.Read(b) + if err != nil { + log.Println(err) + return + } + + if bytes.Equal(b[:n], []byte{5, 1, 0}) { // socks5,NO AUTHENTICATION + log.Println("read cmd:", b[:n]) + if _, err := conn.Write([]byte{5, 0}); err != nil { + log.Println(err) + return + } + + cmd, err := ReadCmd(conn) + if err != nil { + return + } + host := cmd.Addr + ":" + strconv.Itoa(int(cmd.Port)) + log.Println("connect", host) + tconn, err := g.connect(host) + if err != nil { + log.Println(err) + NewCmd(ConnRefused, 0, "", 0).Write(conn) + return + } + defer tconn.Close() + + if err = NewCmd(Succeeded, AddrIPv4, "0.0.0.0", 0).Write(conn); err != nil { + log.Println(err) + return + } + + g.transport(conn, tconn) + return + } + + //log.Println(string(b[:n])) + req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(b[:n]))) + if err != nil { + log.Println(err) + return + } + + log.Println(req.Method, req.RequestURI) + host := req.Host + if !strings.Contains(host, ":") { + host = host + ":80" + } + tconn, err := g.connect(host) + if err != nil { + log.Println(err) + conn.Write([]byte("HTTP/1.1 503 Service unavailable\r\n" + + "Proxy-Agent: gost/1.0\r\n\r\n")) + return + } + defer tconn.Close() + + if req.Method == "CONNECT" { + if _, err = conn.Write( + []byte("HTTP/1.1 200 Connection established\r\n" + + "Proxy-Agent: gost/1.0\r\n\r\n")); err != nil { + return + } + } else { + if err := req.Write(tconn); err != nil { + return + } + } + + g.transport(conn, tconn) +} + +func (g *Gost) connect(addr string) (net.Conn, error) { + if len(g.Proxy) == 0 { + taddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return nil, err + } + return net.DialTCP("tcp", nil, taddr) + } + paddr, err := net.ResolveTCPAddr("tcp", g.Proxy) if err != nil { - log.Println(err) + return nil, err } - if paddr != nil { - pconn, err = net.DialTCP("tcp", nil, paddr) - if err != nil { - return err - } - return g.foward(conn, pconn) - } - - saddr, err := net.ResolveTCPAddr("tcp", g.Saddr) + pconn, err := net.DialTCP("tcp", nil, paddr) if err != nil { - log.Println(err) + return nil, err } - if saddr != nil { - sconn, err := net.DialTCP("tcp", nil, saddr) - if err != nil { - return err + + b := make([]byte, 1500) + buffer := bytes.NewBuffer(b) + buffer.WriteString("CONNECT " + addr + " HTTP/1.1\r\n") + buffer.WriteString("Host: " + addr + "\r\n") + buffer.WriteString("Proxy-Connection: keep-alive\r\n\r\n") + if _, err = pconn.Write(buffer.Bytes()); err != nil { + pconn.Close() + return nil, err + } + + r := "" + for !strings.HasSuffix(r, "\r\n\r\n") { + n := 0 + if n, err = pconn.Read(b); err != nil { + pconn.Close() + return nil, err } - defer sconn.Close() - - return g.transport(conn, sconn) + r += string(b[:n]) } - return nil -} - -func (g *Gost) foward(conn, pconn net.Conn) error { - defer pconn.Close() - - saddr, err := net.ResolveTCPAddr("tcp", g.Saddr) - if err != nil { - log.Println(err) + log.Println(r) + if !strings.Contains(r, "200") { + log.Println("connection failed:\n", r) + err = errors.New(r) + pconn.Close() + return nil, err } - if saddr != nil { - - } - - return nil + return pconn, nil } func (g *Gost) pipe(src io.Reader, dst io.Writer, c chan<- error) { @@ -101,7 +201,7 @@ func (g *Gost) pipe(src io.Reader, dst io.Writer, c chan<- error) { c <- err } -func (g *Gost) transport(conn net.Conn, conn2 net.Conn) (err error) { +func (g *Gost) transport(conn, conn2 net.Conn) (err error) { rChan := make(chan error, 1) wChan := make(chan error, 1) @@ -110,7 +210,9 @@ func (g *Gost) transport(conn net.Conn, conn2 net.Conn) (err error) { select { case err = <-wChan: + //log.Println("w exit", err) case err = <-rChan: + //log.Println("r exit", err) } return diff --git a/gost2 b/gost2 deleted file mode 100755 index 7b17d2d..0000000 Binary files a/gost2 and /dev/null differ diff --git a/socks5.go b/socks5.go index 646cea7..c8795b3 100644 --- a/socks5.go +++ b/socks5.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "errors" "io" + "log" "net" ) @@ -91,6 +92,7 @@ func ReadCmd(r io.Reader) (*Cmd, error) { if err != nil { return nil, err } + log.Println("read cmd:", b[:n]) if n < 10 { return nil, ErrBadFormat } @@ -128,7 +130,7 @@ func ReadCmd(r io.Reader) (*Cmd, error) { cmd.Addr = string(b[pos : pos+length]) pos += length default: - return nil, ErrBadAddrType + pos += 4 } cmd.Port = binary.BigEndian.Uint16(b[pos:]) @@ -157,6 +159,7 @@ func (cmd *Cmd) Write(w io.Writer) (err error) { binary.BigEndian.PutUint16(b[pos:], cmd.Port) pos += 2 + log.Println("write cmd:", b[:pos]) _, err = w.Write(b[:pos]) return