Skip to content

Commit

Permalink
socks5 to http
Browse files Browse the repository at this point in the history
  • Loading branch information
txthinking committed Sep 5, 2017
1 parent 7629704 commit faff6bd
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 10 deletions.
51 changes: 44 additions & 7 deletions cli/brook/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func main() {
app.Commands = []cli.Command{
cli.Command{
Name: "server",
Usage: "Run as brook protocol server mode",
Usage: "Run as server mode",
Flags: []cli.Flag{
cli.StringFlag{
Name: "listen, l",
Expand Down Expand Up @@ -77,7 +77,7 @@ func main() {
},
cli.Command{
Name: "servers",
Usage: "Run as brook protocol multiple servers mode",
Usage: "Run as multiple servers mode",
Flags: []cli.Flag{
cli.IntFlag{
Name: "timeout, t",
Expand Down Expand Up @@ -124,7 +124,7 @@ func main() {
},
cli.Command{
Name: "client",
Usage: "Run as brook protocol client mode",
Usage: "Run as client mode",
Flags: []cli.Flag{
cli.StringFlag{
Name: "listen, l",
Expand Down Expand Up @@ -173,7 +173,7 @@ func main() {
},
cli.Command{
Name: "ssserver",
Usage: "Run as shadowsocks protocol server mode, fixed method is aes-256-cfb",
Usage: "Run as shadowsocks server mode, fixed method is aes-256-cfb",
Flags: []cli.Flag{
cli.StringFlag{
Name: "listen, l",
Expand Down Expand Up @@ -207,7 +207,7 @@ func main() {
},
cli.Command{
Name: "ssservers",
Usage: "Run as shadowsocks protocol multiple servers mode, fixed method is aes-256-cfb",
Usage: "Run as shadowsocks multiple servers mode, fixed method is aes-256-cfb",
Flags: []cli.Flag{
cli.IntFlag{
Name: "timeout, t",
Expand Down Expand Up @@ -250,7 +250,7 @@ func main() {
},
cli.Command{
Name: "ssclient",
Usage: "Run as shadowsocks protocol client mode, fixed method is aes-256-cfb",
Usage: "Run as shadowsocks client mode, fixed method is aes-256-cfb",
Flags: []cli.Flag{
cli.StringFlag{
Name: "listen, l",
Expand Down Expand Up @@ -398,7 +398,7 @@ func main() {
},
cli.Command{
Name: "socks5",
Usage: "Run as raw socks5 protocol server",
Usage: "Run as raw socks5 server",
Flags: []cli.Flag{
cli.StringFlag{
Name: "listen, l",
Expand Down Expand Up @@ -434,6 +434,43 @@ func main() {
return brook.RunSocks5Server(c.String("listen"), c.String("username"), c.String("password"), c.Int("timeout"), c.Int("deadline"))
},
},
cli.Command{
Name: "socks5tohttp",
Usage: "Convert socks5 to http proxy",
Flags: []cli.Flag{
cli.StringFlag{
Name: "listen, l",
Usage: "Client listen address: like: 127.0.0.1:8080",
},
cli.StringFlag{
Name: "socks5, s",
Usage: "Socks5 address",
},
cli.IntFlag{
Name: "timeout, t",
Value: 0,
Usage: "connection tcp keepalive timeout (s)",
},
cli.IntFlag{
Name: "deadline, d",
Value: 0,
Usage: "connection deadline time (s)",
},
},
Action: func(c *cli.Context) error {
if c.String("listen") == "" || c.String("socks5") == "" {
cli.ShowCommandHelp(c, "socks5tohttp")
return nil
}
if debug {
enableDebug()
}
return brook.RunSocks5ToHTTP(c.String("listen"), c.String("socks5"), c.Int("timeout"), c.Int("deadline"))
},
},
}
if len(os.Args) > 1 {
os.Args[1] = strings.Replace(os.Args[1], "bk", "", -1)
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
Expand Down
12 changes: 10 additions & 2 deletions run.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ func RunSocks5Server(address, username, password string, timeout, deadline int)
if err != nil {
return err
}
//return s.ListenAndServe(nil)
return s.ListenAndForward(nil, "127.0.0.1:1080")
return s.ListenAndServe(nil)
}

// RunSocks5ToHTTP used to make a new Socks5ToHTTP and start a http proxy to listen
func RunSocks5ToHTTP(address, socks5 string, timeout, deadline int) error {
s, err := NewSocks5ToHTTP(address, socks5, timeout, deadline)
if err != nil {
return err
}
return s.ListenAndServe(nil)
}
4 changes: 3 additions & 1 deletion socks5.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ func (c *Socks5Server) ListenAndServe(sm Socks5Middleman) error {
}
}

// ListenAndForward will let client start to listen and forward to another socks5, sm can be nil
// ListenAndForward will let client start a no auth socks5 proxy to listen and forward to another socks5,
// c.UserName, c.Password will effect the forwarded socks5,
// sm can be nil
func (c *Socks5Server) ListenAndForward(sm Socks5Middleman, addr string) error {
ta, err := net.ResolveTCPAddr("tcp", c.Address)
if err != nil {
Expand Down
151 changes: 151 additions & 0 deletions socks5tohttp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package brook

import (
"bytes"
"errors"
"io"
"log"
"net"
"time"

"golang.org/x/net/proxy"
)

type Socks5ToHTTP struct {
Address string
Socks5Address string
Dial proxy.Dialer
Timeout int
Deadline int
Listen net.Listener
HTTPMiddleman HTTPMiddleman
}

func NewSocks5ToHTTP(addr, socks5addr string, timeout, deadline int) (*Socks5ToHTTP, error) {
dial, err := proxy.SOCKS5("tcp", socks5addr, nil, proxy.Direct)
if err != nil {
return nil, err
}
return &Socks5ToHTTP{
Address: addr,
Socks5Address: socks5addr,
Dial: dial,
Timeout: timeout,
Deadline: deadline,
}, nil
}

func (s *Socks5ToHTTP) ListenAndServe(h HTTPMiddleman) error {
ta, err := net.ResolveTCPAddr("tcp", s.Address)
if err != nil {
return err
}
l, err := net.ListenTCP("tcp", ta)
if err != nil {
return err
}
defer l.Close()
s.Listen = l
s.HTTPMiddleman = h
for {
conn, err := l.AcceptTCP()
if err != nil {
return err
}
go func(conn *net.TCPConn) {
if err := s.handle(conn); err != nil {
log.Println(err)
}
}(conn)
}
}

func (s *Socks5ToHTTP) Shutdown() error {
if s.Listen == nil {
return nil
}
return s.Listen.Close()
}

func (s *Socks5ToHTTP) handle(conn *net.TCPConn) error {
defer conn.Close()
if s.Timeout != 0 {
if err := conn.SetKeepAlivePeriod(time.Duration(s.Timeout) * time.Second); err != nil {
return err
}
}
if s.Deadline != 0 {
if err := conn.SetDeadline(time.Now().Add(time.Duration(s.Deadline) * time.Second)); err != nil {
return err
}
}

b := make([]byte, 0, 1024)
for {
var b1 [1024]byte
n, err := conn.Read(b1[:])
if err != nil {
return err
}
b = append(b, b1[:n]...)
if bytes.Contains(b, []byte{0x0d, 0x0a, 0x0d, 0x0a}) {
break
}
}

bb := bytes.SplitN(b, []byte(" "), 3)
if len(bb) != 3 {
return errors.New("Invalid Request")
}
method, address := string(bb[0]), string(bb[1])
var addr string
if method == "CONNECT" {
addr = address
} else {
var err error
addr, err = GetAddressFromURL(address)
if err != nil {
return err
}
}

if s.HTTPMiddleman != nil {
if handled, err := s.HTTPMiddleman.HandleHTTPProxy(method, addr, b, conn); err != nil || handled {
return err
}
}

rc, err := s.Dial.Dial("tcp", addr)
if err != nil {
return err
}
defer rc.Close()
if s.Timeout != 0 {
if rtc, ok := rc.(*net.TCPConn); ok {
if err := rtc.SetKeepAlivePeriod(time.Duration(s.Timeout) * time.Second); err != nil {
return err
}
}
}
if s.Deadline != 0 {
if err := rc.SetDeadline(time.Now().Add(time.Duration(s.Deadline) * time.Second)); err != nil {
return err
}
}
if method == "CONNECT" {
_, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
if err != nil {
return err
}
}
if method != "CONNECT" {
if _, err := rc.Write(b); err != nil {
return err
}
}
go func() {
_, _ = io.Copy(rc, conn)
}()
_, _ = io.Copy(conn, rc)
return nil
}

0 comments on commit faff6bd

Please sign in to comment.