#60: add http obfuscating tunnel support

This commit is contained in:
rui.zheng
2017-09-11 17:55:55 +08:00
parent 18982205ff
commit 6a65b32b71
4 changed files with 85 additions and 14 deletions
+59 -10
View File
@@ -5,8 +5,8 @@ package gost
import (
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/httputil"
@@ -66,6 +66,8 @@ func (l *obfsHTTPListener) Accept() (net.Conn, error) {
type obfsHTTPConn struct {
net.Conn
r *http.Request
rbuf []byte
wbuf []byte
isServer bool
handshaked bool
handshakeMutex sync.Mutex
@@ -80,7 +82,8 @@ func (c *obfsHTTPConn) Handshake() (err error) {
}
if c.isServer {
c.r, err = http.ReadRequest(bufio.NewReader(c.Conn))
br := bufio.NewReader(c.Conn)
c.r, err = http.ReadRequest(br)
if err != nil {
return
}
@@ -88,22 +91,58 @@ func (c *obfsHTTPConn) Handshake() (err error) {
dump, _ := httputil.DumpRequest(c.r, false)
log.Logf("[ohttp] %s -> %s\n%s", c.Conn.RemoteAddr(), c.Conn.LocalAddr(), string(dump))
}
b := bytes.NewBufferString("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
if br.Buffered() > 0 {
c.rbuf, err = br.Peek(br.Buffered())
} else {
c.rbuf, err = ioutil.ReadAll(c.r.Body)
}
if err != nil {
log.Logf("[ohttp] %s -> %s : %v", c.Conn.RemoteAddr(), c.Conn.LocalAddr(), err)
return
}
b := bytes.Buffer{}
if c.r.Header.Get("Connection") == "Upgrade" &&
c.r.Header.Get("Upgrade") == "websocket" {
b.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
b.WriteString("Server: nginx/1.10.0\r\n")
b.WriteString("Connection: Upgrade\r\n")
b.WriteString("Upgrade: websocket\r\n")
b.WriteString(fmt.Sprintf("Sec-WebSocket-Accept: %s\r\n", computeAcceptKey(c.r.Header.Get("Sec-WebSocket-Key"))))
b.WriteString("\r\n")
} else {
b.WriteString("HTTP/1.1 200 OK\r\n")
b.WriteString("Server: nginx/1.10.0\r\n")
b.WriteString("Content-Type: application/octet-stream\r\n")
b.WriteString("Connection: keep-alive\r\n")
b.WriteString("Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform\r\n")
b.WriteString("Pragma: no-cache\r\n")
b.WriteString("\r\n")
}
if Debug {
log.Logf("[ohttp] %s <- %s\n%s", c.Conn.RemoteAddr(), c.Conn.LocalAddr(), b.String())
}
if _, err = b.WriteTo(c.Conn); err != nil {
return
}
} else {
r := c.r
if r == nil {
r, err = http.NewRequest(http.MethodPost, "http://www.baidu.com/", nil)
if err != nil {
return
r = &http.Request{
Method: http.MethodPost,
ProtoMajor: 1,
ProtoMinor: 1,
URL: &url.URL{Scheme: "http", Host: "www.baidu.com"},
Header: make(http.Header),
}
r.Header.Set("Connection", "keep-alive")
r.Header.Set("User-Agent", DefaultUserAgent)
if len(c.wbuf) > 0 {
r.Body = ioutil.NopCloser(bytes.NewReader(c.wbuf))
r.ContentLength = int64(len(c.wbuf))
}
}
if err = r.Write(c.Conn); err != nil {
return
@@ -117,13 +156,12 @@ func (c *obfsHTTPConn) Handshake() (err error) {
if err != nil {
return
}
defer resp.Body.Close()
if Debug {
dump, _ := httputil.DumpResponse(resp, false)
log.Logf("[ohttp] %s <- %s\n%s", c.Conn.LocalAddr(), c.Conn.RemoteAddr(), string(dump))
}
if resp.StatusCode != http.StatusOK {
return errors.New(resp.Status)
}
}
c.handshaked = true
return nil
@@ -133,13 +171,24 @@ func (c *obfsHTTPConn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
}
if len(c.rbuf) > 0 {
n = copy(b, c.rbuf)
c.rbuf = c.rbuf[n:]
return
}
return c.Conn.Read(b)
}
func (c *obfsHTTPConn) Write(b []byte) (n int, err error) {
handshaked := c.handshaked
c.wbuf = b
if err = c.Handshake(); err != nil {
return
}
if !handshaked {
n = len(c.wbuf)
return
}
return c.Conn.Write(b)
}