mirror of https://github.com/ginuerzh/gost
4 changed files with 252 additions and 11 deletions
@ -0,0 +1,230 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"bufio" |
||||
|
"bytes" |
||||
|
"code.google.com/p/go-uuid/uuid" |
||||
|
"github.com/ginuerzh/gosocks5" |
||||
|
"io" |
||||
|
"io/ioutil" |
||||
|
"log" |
||||
|
"net" |
||||
|
"net/http" |
||||
|
"net/url" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
s2cUri = "/s2c" |
||||
|
c2sUri = "/c2s" |
||||
|
) |
||||
|
|
||||
|
type HttpClientConn struct { |
||||
|
c net.Conn |
||||
|
url *url.URL |
||||
|
r io.ReadCloser |
||||
|
} |
||||
|
|
||||
|
func NewHttpClientConn(conn net.Conn) *HttpClientConn { |
||||
|
return &HttpClientConn{ |
||||
|
c: conn, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) Handshake() error { |
||||
|
log.Println("remote", conn.c.RemoteAddr().String()) |
||||
|
req := &http.Request{ |
||||
|
Method: "Get", |
||||
|
Host: conn.c.RemoteAddr().String(), |
||||
|
URL: &url.URL{ |
||||
|
Host: "ignored", |
||||
|
Scheme: "http", |
||||
|
Path: s2cUri, |
||||
|
}, |
||||
|
} |
||||
|
if err := req.Write(conn.c); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
resp, err := http.ReadResponse(bufio.NewReader(conn.c), req) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
b := make([]byte, 36) |
||||
|
if _, err = io.ReadFull(resp.Body, b); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
log.Println("token", string(b)) |
||||
|
q := url.Values{} |
||||
|
q.Set("token", string(b)) |
||||
|
conn.url = &url.URL{ |
||||
|
Scheme: "http", |
||||
|
Host: conn.c.RemoteAddr().String(), |
||||
|
Path: c2sUri, |
||||
|
RawQuery: q.Encode(), |
||||
|
} |
||||
|
conn.r = resp.Body |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) Read(b []byte) (n int, err error) { |
||||
|
return conn.r.Read(b) |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) Write(b []byte) (n int, err error) { |
||||
|
c, err := Connect(Saddr, Proxy) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
request, err := http.NewRequest("POST", conn.url.String(), bytes.NewReader(b)) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
err = request.Write(c) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
return len(b), nil |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) Close() error { |
||||
|
return conn.r.Close() |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) LocalAddr() net.Addr { |
||||
|
return conn.c.LocalAddr() |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) RemoteAddr() net.Addr { |
||||
|
return conn.c.RemoteAddr() |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) SetDeadline(t time.Time) error { |
||||
|
return conn.c.SetDeadline(t) |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) SetReadDeadline(t time.Time) error { |
||||
|
return conn.c.SetReadDeadline(t) |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpClientConn) SetWriteDeadline(t time.Time) error { |
||||
|
return conn.c.SetWriteDeadline(t) |
||||
|
} |
||||
|
|
||||
|
type HttpServerConn struct { |
||||
|
w http.ResponseWriter |
||||
|
c chan []byte |
||||
|
rb []byte |
||||
|
} |
||||
|
|
||||
|
func NewHttpServerConn(w http.ResponseWriter, c chan []byte) *HttpServerConn { |
||||
|
return &HttpServerConn{ |
||||
|
w: w, |
||||
|
c: c, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) Read(b []byte) (n int, err error) { |
||||
|
if len(conn.rb) == 0 { |
||||
|
var ok bool |
||||
|
if conn.rb, ok = <-conn.c; !ok { |
||||
|
return 0, io.EOF |
||||
|
} |
||||
|
} |
||||
|
n = copy(b, conn.rb) |
||||
|
conn.rb = conn.rb[n:] |
||||
|
|
||||
|
//log.Println("ws r:", n)
|
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) Write(b []byte) (n int, err error) { |
||||
|
n, err = conn.w.Write(b) |
||||
|
if f, ok := conn.w.(http.Flusher); ok { |
||||
|
f.Flush() |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) Close() error { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) LocalAddr() net.Addr { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) RemoteAddr() net.Addr { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) SetDeadline(t time.Time) error { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) SetReadDeadline(t time.Time) error { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (conn *HttpServerConn) SetWriteDeadline(t time.Time) error { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
type HttpServer struct { |
||||
|
Addr string |
||||
|
chans map[string]chan []byte |
||||
|
} |
||||
|
|
||||
|
func (s *HttpServer) s2c(w http.ResponseWriter, r *http.Request) { |
||||
|
token := uuid.New() |
||||
|
ch := make(chan []byte, 1) |
||||
|
|
||||
|
conn := NewHttpServerConn(w, ch) |
||||
|
if _, err := conn.Write([]byte(token)); err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
s.chans[token] = ch |
||||
|
defer delete(s.chans, token) |
||||
|
|
||||
|
c := gosocks5.ServerConn(conn, serverConfig) |
||||
|
socks5Handle(c) |
||||
|
} |
||||
|
|
||||
|
func (s *HttpServer) c2s(w http.ResponseWriter, r *http.Request) { |
||||
|
if r.Method != "POST" { |
||||
|
w.WriteHeader(http.StatusMethodNotAllowed) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
token := r.FormValue("token") |
||||
|
ch := s.chans[token] |
||||
|
if ch == nil { |
||||
|
w.WriteHeader(http.StatusBadRequest) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
b, err := ioutil.ReadAll(r.Body) |
||||
|
if err != nil || len(b) == 0 { |
||||
|
close(ch) |
||||
|
delete(s.chans, token) |
||||
|
return |
||||
|
} |
||||
|
ch <- b |
||||
|
} |
||||
|
|
||||
|
func (s *HttpServer) ListenAndServe() error { |
||||
|
s.chans = make(map[string]chan []byte) |
||||
|
http.HandleFunc(s2cUri, s.s2c) |
||||
|
http.HandleFunc(c2sUri, s.c2s) |
||||
|
return http.ListenAndServe(s.Addr, nil) |
||||
|
} |
||||
@ -9,13 +9,13 @@ import ( |
|||||
) |
) |
||||
|
|
||||
var ( |
var ( |
||||
Laddr, Saddr, Proxy string |
Laddr, Saddr, Proxy string |
||||
Websocket bool |
UseWebsocket, UseHttp bool |
||||
Shadows bool |
Shadows bool |
||||
SMethod, SPassword string |
SMethod, SPassword string |
||||
Method, Password string |
Method, Password string |
||||
CertFile, KeyFile string |
CertFile, KeyFile string |
||||
PrintVersion bool |
PrintVersion bool |
||||
) |
) |
||||
|
|
||||
func init() { |
func init() { |
||||
@ -27,7 +27,8 @@ func init() { |
|||||
flag.StringVar(&CertFile, "cert", "", "cert file for tls") |
flag.StringVar(&CertFile, "cert", "", "cert file for tls") |
||||
flag.StringVar(&KeyFile, "key", "", "key file for tls") |
flag.StringVar(&KeyFile, "key", "", "key file for tls") |
||||
flag.BoolVar(&Shadows, "ss", false, "run as shadowsocks server") |
flag.BoolVar(&Shadows, "ss", false, "run as shadowsocks server") |
||||
flag.BoolVar(&Websocket, "ws", false, "use websocket for tunnel") |
flag.BoolVar(&UseWebsocket, "ws", false, "use websocket for tunnel") |
||||
|
flag.BoolVar(&UseHttp, "http", false, "use http for tunnel") |
||||
flag.StringVar(&SMethod, "sm", "rc4-md5", "shadowsocks cipher method") |
flag.StringVar(&SMethod, "sm", "rc4-md5", "shadowsocks cipher method") |
||||
flag.StringVar(&SPassword, "sp", "[email protected]", "shadowsocks cipher password") |
flag.StringVar(&SPassword, "sp", "[email protected]", "shadowsocks cipher password") |
||||
flag.BoolVar(&PrintVersion, "v", false, "print version") |
flag.BoolVar(&PrintVersion, "v", false, "print version") |
||||
@ -50,8 +51,10 @@ func main() { |
|||||
|
|
||||
if len(Saddr) == 0 { |
if len(Saddr) == 0 { |
||||
var server Server |
var server Server |
||||
if Websocket { |
if UseWebsocket { |
||||
server = &WSServer{Addr: Laddr} |
server = &WSServer{Addr: Laddr} |
||||
|
} else if UseHttp { |
||||
|
server = &HttpServer{Addr: Laddr} |
||||
} else { |
} else { |
||||
server = &Socks5Server{Addr: Laddr} |
server = &Socks5Server{Addr: Laddr} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue