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

tunnel over http

parent 0ffb1daf
......@@ -111,7 +111,7 @@ func cliHandle(conn net.Conn) {
}
defer c.Close()
if Websocket {
if UseWebsocket {
url := &url.URL{
Host: Saddr,
}
......@@ -123,6 +123,14 @@ func cliHandle(conn net.Conn) {
resp.Body.Close()
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)
......
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 (
Laddr, Saddr, Proxy string
Websocket bool
Shadows bool
SMethod, SPassword string
Method, Password string
CertFile, KeyFile string
PrintVersion bool
Laddr, Saddr, Proxy string
UseWebsocket, UseHttp bool
Shadows bool
SMethod, SPassword string
Method, Password string
CertFile, KeyFile string
PrintVersion bool
)
func init() {
......@@ -27,7 +27,8 @@ func init() {
flag.StringVar(&CertFile, "cert", "", "cert file for tls")
flag.StringVar(&KeyFile, "key", "", "key file for tls")
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(&SPassword, "sp", "ginuerzh@gmail.com", "shadowsocks cipher password")
flag.BoolVar(&PrintVersion, "v", false, "print version")
......@@ -50,8 +51,10 @@ func main() {
if len(Saddr) == 0 {
var server Server
if Websocket {
if UseWebsocket {
server = &WSServer{Addr: Laddr}
} else if UseHttp {
server = &HttpServer{Addr: Laddr}
} else {
server = &Socks5Server{Addr: Laddr}
}
......
......@@ -5,7 +5,7 @@ import (
)
const (
Version = "1.3"
Version = "1.4"
)
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