|
|
|
@ -3,9 +3,15 @@ |
|
|
|
package gost |
|
|
|
|
|
|
|
import ( |
|
|
|
"bufio" |
|
|
|
"bytes" |
|
|
|
"errors" |
|
|
|
"fmt" |
|
|
|
"net" |
|
|
|
"net/http" |
|
|
|
"net/http/httputil" |
|
|
|
"net/url" |
|
|
|
"sync" |
|
|
|
|
|
|
|
"github.com/go-log/log" |
|
|
|
|
|
|
|
@ -14,6 +20,129 @@ import ( |
|
|
|
"git.torproject.org/pluggable-transports/obfs4.git/transports/obfs4" |
|
|
|
) |
|
|
|
|
|
|
|
type obfsHTTPTransporter struct { |
|
|
|
tcpTransporter |
|
|
|
} |
|
|
|
|
|
|
|
// ObfsHTTPTransporter creates a Transporter that is used by HTTP obfuscating tunnel client.
|
|
|
|
func ObfsHTTPTransporter() Transporter { |
|
|
|
return &obfsHTTPTransporter{} |
|
|
|
} |
|
|
|
|
|
|
|
func (tr *obfsHTTPTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) { |
|
|
|
opts := &HandshakeOptions{} |
|
|
|
for _, option := range options { |
|
|
|
option(opts) |
|
|
|
} |
|
|
|
return &obfsHTTPConn{Conn: conn}, nil |
|
|
|
} |
|
|
|
|
|
|
|
type obfsHTTPListener struct { |
|
|
|
net.Listener |
|
|
|
} |
|
|
|
|
|
|
|
// ObfsHTTPListener creates a Listener for HTTP obfuscating tunnel server.
|
|
|
|
func ObfsHTTPListener(addr string) (Listener, error) { |
|
|
|
laddr, err := net.ResolveTCPAddr("tcp", addr) |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
ln, err := net.ListenTCP("tcp", laddr) |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
return &obfsHTTPListener{Listener: tcpKeepAliveListener{ln}}, nil |
|
|
|
} |
|
|
|
|
|
|
|
func (l *obfsHTTPListener) Accept() (net.Conn, error) { |
|
|
|
conn, err := l.Listener.Accept() |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
|
|
|
|
return &obfsHTTPConn{Conn: conn, isServer: true}, nil |
|
|
|
} |
|
|
|
|
|
|
|
type obfsHTTPConn struct { |
|
|
|
net.Conn |
|
|
|
r *http.Request |
|
|
|
isServer bool |
|
|
|
handshaked bool |
|
|
|
handshakeMutex sync.Mutex |
|
|
|
} |
|
|
|
|
|
|
|
func (c *obfsHTTPConn) Handshake() (err error) { |
|
|
|
c.handshakeMutex.Lock() |
|
|
|
defer c.handshakeMutex.Unlock() |
|
|
|
|
|
|
|
if c.handshaked { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
if c.isServer { |
|
|
|
c.r, err = http.ReadRequest(bufio.NewReader(c.Conn)) |
|
|
|
if err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
if Debug { |
|
|
|
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 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.Header.Set("User-Agent", DefaultUserAgent) |
|
|
|
} |
|
|
|
if err = r.Write(c.Conn); err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
if Debug { |
|
|
|
dump, _ := httputil.DumpRequest(r, false) |
|
|
|
log.Logf("[ohttp] %s -> %s\n%s", c.Conn.LocalAddr(), c.Conn.RemoteAddr(), string(dump)) |
|
|
|
} |
|
|
|
var resp *http.Response |
|
|
|
resp, err = http.ReadResponse(bufio.NewReader(c.Conn), r) |
|
|
|
if err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
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 |
|
|
|
} |
|
|
|
|
|
|
|
func (c *obfsHTTPConn) Read(b []byte) (n int, err error) { |
|
|
|
if err = c.Handshake(); err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
return c.Conn.Read(b) |
|
|
|
} |
|
|
|
|
|
|
|
func (c *obfsHTTPConn) Write(b []byte) (n int, err error) { |
|
|
|
if err = c.Handshake(); err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
return c.Conn.Write(b) |
|
|
|
} |
|
|
|
|
|
|
|
type obfs4Context struct { |
|
|
|
cf base.ClientFactory |
|
|
|
cargs interface{} // type obfs4ClientArgs
|