Commit 7dffd77c authored by rui.zheng's avatar rui.zheng

tunnel over http

parent 0ffb1daf
...@@ -111,7 +111,7 @@ func cliHandle(conn net.Conn) { ...@@ -111,7 +111,7 @@ func cliHandle(conn net.Conn) {
} }
defer c.Close() defer c.Close()
if Websocket { if UseWebsocket {
url := &url.URL{ url := &url.URL{
Host: Saddr, Host: Saddr,
} }
...@@ -123,6 +123,14 @@ func cliHandle(conn net.Conn) { ...@@ -123,6 +123,14 @@ func cliHandle(conn net.Conn) {
resp.Body.Close() resp.Body.Close()
c = NewWSConn(ws) c = NewWSConn(ws)
} else if UseHttp {
httpcli := NewHttpClientConn(c)
if err := httpcli.Handshake(); err != nil {
log.Println(err)
return
}
c = httpcli
defer httpcli.Close()
} }
sc := gosocks5.ClientConn(c, clientConfig) sc := gosocks5.ClientConn(c, clientConfig)
......
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 ( ...@@ -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() { ...@@ -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", "ginuerzh@gmail.com", "shadowsocks cipher password") flag.StringVar(&SPassword, "sp", "ginuerzh@gmail.com", "shadowsocks cipher password")
flag.BoolVar(&PrintVersion, "v", false, "print version") flag.BoolVar(&PrintVersion, "v", false, "print version")
...@@ -50,8 +51,10 @@ func main() { ...@@ -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}
} }
......
...@@ -5,7 +5,7 @@ import ( ...@@ -5,7 +5,7 @@ import (
) )
const ( const (
Version = "1.3" Version = "1.4"
) )
func printVersion() { func printVersion() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment