1 Star 0 Fork 0

Ragus/gost

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
obfs.go 15.32 KB
一键复制 编辑 原始数据 按行查看 历史
ginuerzh 提交于 2020-03-03 18:58 . fix typo
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
// obfs4 connection wrappers
package gost
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
"sync"
"time"
"github.com/go-log/log"
pt "git.torproject.org/pluggable-transports/goptlib.git"
"git.torproject.org/pluggable-transports/obfs4.git/transports/base"
"git.torproject.org/pluggable-transports/obfs4.git/transports/obfs4"
dissector "github.com/ginuerzh/tls-dissector"
)
const (
maxTLSDataLen = 16384
)
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, host: opts.Host}, 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
host string
rbuf bytes.Buffer
wbuf bytes.Buffer
isServer bool
headerDrained 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 {
err = c.serverHandshake()
} else {
err = c.clientHandshake()
}
if err != nil {
return
}
c.handshaked = true
return nil
}
func (c *obfsHTTPConn) serverHandshake() (err error) {
br := bufio.NewReader(c.Conn)
r, err := http.ReadRequest(br)
if err != nil {
return
}
if Debug {
dump, _ := httputil.DumpRequest(r, false)
log.Logf("[ohttp] %s -> %s\n%s", c.RemoteAddr(), c.LocalAddr(), string(dump))
}
if r.ContentLength > 0 {
_, err = io.Copy(&c.rbuf, r.Body)
} else {
var b []byte
b, err = br.Peek(br.Buffered())
if len(b) > 0 {
_, err = c.rbuf.Write(b)
}
}
if err != nil {
log.Logf("[ohttp] %s -> %s : %v", c.Conn.RemoteAddr(), c.Conn.LocalAddr(), err)
return
}
b := bytes.Buffer{}
if r.Method != http.MethodGet || r.Header.Get("Upgrade") != "websocket" {
b.WriteString("HTTP/1.1 503 Service Unavailable\r\n")
b.WriteString("Content-Length: 0\r\n")
b.WriteString("Date: " + time.Now().Format(time.RFC1123) + "\r\n")
b.WriteString("\r\n")
if Debug {
log.Logf("[ohttp] %s <- %s\n%s", c.RemoteAddr(), c.LocalAddr(), b.String())
}
b.WriteTo(c.Conn)
return errors.New("bad request")
}
b.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
b.WriteString("Server: nginx/1.10.0\r\n")
b.WriteString("Date: " + time.Now().Format(time.RFC1123) + "\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(r.Header.Get("Sec-WebSocket-Key"))))
b.WriteString("\r\n")
if Debug {
log.Logf("[ohttp] %s <- %s\n%s", c.RemoteAddr(), c.LocalAddr(), b.String())
}
if c.rbuf.Len() > 0 {
c.wbuf = b // cache the response header if there are extra data in the request body.
return
}
_, err = b.WriteTo(c.Conn)
return
}
func (c *obfsHTTPConn) clientHandshake() (err error) {
r := &http.Request{
Method: http.MethodGet,
ProtoMajor: 1,
ProtoMinor: 1,
URL: &url.URL{Scheme: "http", Host: c.host},
Header: make(http.Header),
}
r.Header.Set("User-Agent", DefaultUserAgent)
r.Header.Set("Connection", "Upgrade")
r.Header.Set("Upgrade", "websocket")
key, _ := generateChallengeKey()
r.Header.Set("Sec-WebSocket-Key", key)
// cache the request header
if err = r.Write(&c.wbuf); err != nil {
return
}
if Debug {
dump, _ := httputil.DumpRequest(r, false)
log.Logf("[ohttp] %s -> %s\n%s", c.LocalAddr(), c.RemoteAddr(), string(dump))
}
return nil
}
func (c *obfsHTTPConn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
}
if !c.isServer {
if err = c.drainHeader(); err != nil {
return
}
}
if c.rbuf.Len() > 0 {
return c.rbuf.Read(b)
}
return c.Conn.Read(b)
}
func (c *obfsHTTPConn) drainHeader() (err error) {
if c.headerDrained {
return
}
c.headerDrained = true
br := bufio.NewReader(c.Conn)
// drain and discard the response header
var line string
var buf bytes.Buffer
for {
line, err = br.ReadString('\n')
if err != nil {
return
}
buf.WriteString(line)
if line == "\r\n" {
break
}
}
if Debug {
log.Logf("[ohttp] %s <- %s\n%s", c.LocalAddr(), c.RemoteAddr(), buf.String())
}
// cache the extra data for next read.
var b []byte
b, err = br.Peek(br.Buffered())
if len(b) > 0 {
_, err = c.rbuf.Write(b)
}
return
}
func (c *obfsHTTPConn) Write(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
}
if c.wbuf.Len() > 0 {
c.wbuf.Write(b) // append the data to the cached header
_, err = c.wbuf.WriteTo(c.Conn)
n = len(b) // exclude the header length
return
}
return c.Conn.Write(b)
}
type obfsTLSTransporter struct {
tcpTransporter
}
// ObfsTLSTransporter creates a Transporter that is used by TLS obfuscating.
func ObfsTLSTransporter() Transporter {
return &obfsTLSTransporter{}
}
func (tr *obfsTLSTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) {
opts := &HandshakeOptions{}
for _, option := range options {
option(opts)
}
return ClientObfsTLSConn(conn, opts.Host), nil
}
type obfsTLSListener struct {
net.Listener
}
// ObfsTLSListener creates a Listener for TLS obfuscating server.
func ObfsTLSListener(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 &obfsTLSListener{Listener: tcpKeepAliveListener{ln}}, nil
}
func (l *obfsTLSListener) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return ServerObfsTLSConn(conn, ""), nil
}
var (
cipherSuites = []uint16{
0xc02c, 0xc030, 0x009f, 0xcca9, 0xcca8, 0xccaa, 0xc02b, 0xc02f,
0x009e, 0xc024, 0xc028, 0x006b, 0xc023, 0xc027, 0x0067, 0xc00a,
0xc014, 0x0039, 0xc009, 0xc013, 0x0033, 0x009d, 0x009c, 0x003d,
0x003c, 0x0035, 0x002f, 0x00ff,
}
compressionMethods = []uint8{0x00}
algorithms = []uint16{
0x0601, 0x0602, 0x0603, 0x0501, 0x0502, 0x0503, 0x0401, 0x0402,
0x0403, 0x0301, 0x0302, 0x0303, 0x0201, 0x0202, 0x0203,
}
)
type obfsTLSConn struct {
net.Conn
rbuf bytes.Buffer
wbuf bytes.Buffer
host string
isServer bool
handshaked chan struct{}
handshakeMutex sync.Mutex
}
// ClientObfsTLSConn creates a connection for obfs-tls client.
func ClientObfsTLSConn(conn net.Conn, host string) net.Conn {
return &obfsTLSConn{
Conn: conn,
host: host,
handshaked: make(chan struct{}),
}
}
// ServerObfsTLSConn creates a connection for obfs-tls server.
func ServerObfsTLSConn(conn net.Conn, host string) net.Conn {
return &obfsTLSConn{
Conn: conn,
host: host,
isServer: true,
handshaked: make(chan struct{}),
}
}
func (c *obfsTLSConn) Handshaked() bool {
select {
case <-c.handshaked:
return true
default:
return false
}
}
func (c *obfsTLSConn) Handshake(payload []byte) (err error) {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if c.Handshaked() {
return
}
if c.isServer {
err = c.serverHandshake()
} else {
err = c.clientHandshake(payload)
}
if err != nil {
return
}
close(c.handshaked)
return nil
}
func (c *obfsTLSConn) clientHandshake(payload []byte) error {
clientMsg := &dissector.ClientHelloMsg{
Version: tls.VersionTLS12,
SessionID: make([]byte, 32),
CipherSuites: cipherSuites,
CompressionMethods: compressionMethods,
Extensions: []dissector.Extension{
&dissector.SessionTicketExtension{
Data: payload,
},
&dissector.ServerNameExtension{
Name: c.host,
},
&dissector.ECPointFormatsExtension{
Formats: []uint8{0x01, 0x00, 0x02},
},
&dissector.SupportedGroupsExtension{
Groups: []uint16{0x001d, 0x0017, 0x0019, 0x0018},
},
&dissector.SignatureAlgorithmsExtension{
Algorithms: algorithms,
},
&dissector.EncryptThenMacExtension{},
&dissector.ExtendedMasterSecretExtension{},
},
}
clientMsg.Random.Time = uint32(time.Now().Unix())
rand.Read(clientMsg.Random.Opaque[:])
rand.Read(clientMsg.SessionID)
b, err := clientMsg.Encode()
if err != nil {
return err
}
record := &dissector.Record{
Type: dissector.Handshake,
Version: tls.VersionTLS10,
Opaque: b,
}
if _, err := record.WriteTo(c.Conn); err != nil {
return err
}
// server hello handshake message
if _, err := record.ReadFrom(c.Conn); err != nil {
return err
}
if record.Type != dissector.Handshake {
return dissector.ErrBadType
}
// change cipher spec message
if _, err := record.ReadFrom(c.Conn); err != nil {
return err
}
if record.Type != dissector.ChangeCipherSpec {
return dissector.ErrBadType
}
// encrypted handshake message
if _, err := record.ReadFrom(c.Conn); err != nil {
return err
}
if record.Type != dissector.Handshake {
return dissector.ErrBadType
}
_, err = c.rbuf.Write(record.Opaque)
return err
}
func (c *obfsTLSConn) serverHandshake() error {
record := &dissector.Record{}
if _, err := record.ReadFrom(c.Conn); err != nil {
log.Log(err)
return err
}
if record.Type != dissector.Handshake {
return dissector.ErrBadType
}
clientMsg := &dissector.ClientHelloMsg{}
if err := clientMsg.Decode(record.Opaque); err != nil {
log.Log(err)
return err
}
for _, ext := range clientMsg.Extensions {
if ext.Type() == dissector.ExtSessionTicket {
b, err := ext.Encode()
if err != nil {
log.Log(err)
return err
}
c.rbuf.Write(b)
break
}
}
serverMsg := &dissector.ServerHelloMsg{
Version: tls.VersionTLS12,
SessionID: clientMsg.SessionID,
CipherSuite: 0xcca8,
CompressionMethod: 0x00,
Extensions: []dissector.Extension{
&dissector.RenegotiationInfoExtension{},
&dissector.ExtendedMasterSecretExtension{},
&dissector.ECPointFormatsExtension{
Formats: []uint8{0x00},
},
},
}
serverMsg.Random.Time = uint32(time.Now().Unix())
rand.Read(serverMsg.Random.Opaque[:])
b, err := serverMsg.Encode()
if err != nil {
return err
}
record = &dissector.Record{
Type: dissector.Handshake,
Version: tls.VersionTLS10,
Opaque: b,
}
if _, err := record.WriteTo(&c.wbuf); err != nil {
return err
}
record = &dissector.Record{
Type: dissector.ChangeCipherSpec,
Version: tls.VersionTLS12,
Opaque: []byte{0x01},
}
if _, err := record.WriteTo(&c.wbuf); err != nil {
return err
}
return nil
}
func (c *obfsTLSConn) Read(b []byte) (n int, err error) {
if c.isServer { // NOTE: only Write performs the handshake operation on client side.
if err = c.Handshake(nil); err != nil {
return
}
}
select {
case <-c.handshaked:
}
if c.rbuf.Len() > 0 {
return c.rbuf.Read(b)
}
record := &dissector.Record{}
if _, err = record.ReadFrom(c.Conn); err != nil {
return
}
n = copy(b, record.Opaque)
_, err = c.rbuf.Write(record.Opaque[n:])
return
}
func (c *obfsTLSConn) Write(b []byte) (n int, err error) {
n = len(b)
if !c.Handshaked() {
if err = c.Handshake(b); err != nil {
return
}
if !c.isServer { // the data b has been sended during handshake phase.
return
}
}
for len(b) > 0 {
data := b
if len(b) > maxTLSDataLen {
data = b[:maxTLSDataLen]
b = b[maxTLSDataLen:]
} else {
b = b[:0]
}
record := &dissector.Record{
Type: dissector.AppData,
Version: tls.VersionTLS12,
Opaque: data,
}
if c.wbuf.Len() > 0 {
record.Type = dissector.Handshake
record.WriteTo(&c.wbuf)
_, err = c.wbuf.WriteTo(c.Conn)
return
}
if _, err = record.WriteTo(c.Conn); err != nil {
return
}
}
return
}
type obfs4Context struct {
cf base.ClientFactory
cargs interface{} // type obfs4ClientArgs
sf base.ServerFactory
sargs *pt.Args
}
var obfs4Map = make(map[string]obfs4Context)
// Obfs4Init initializes the obfs client or server based on isServeNode
func Obfs4Init(node Node, isServeNode bool) error {
if _, ok := obfs4Map[node.Addr]; ok {
return fmt.Errorf("obfs4 context already inited")
}
t := new(obfs4.Transport)
stateDir := node.Values.Get("state-dir")
if stateDir == "" {
stateDir = "."
}
ptArgs := pt.Args(node.Values)
if !isServeNode {
cf, err := t.ClientFactory(stateDir)
if err != nil {
return err
}
cargs, err := cf.ParseArgs(&ptArgs)
if err != nil {
return err
}
obfs4Map[node.Addr] = obfs4Context{cf: cf, cargs: cargs}
} else {
sf, err := t.ServerFactory(stateDir, &ptArgs)
if err != nil {
return err
}
sargs := sf.Args()
obfs4Map[node.Addr] = obfs4Context{sf: sf, sargs: sargs}
log.Log("[obfs4] server inited:", obfs4ServerURL(node))
}
return nil
}
func obfs4GetContext(addr string) (obfs4Context, error) {
ctx, ok := obfs4Map[addr]
if !ok {
return obfs4Context{}, fmt.Errorf("obfs4 context not inited")
}
return ctx, nil
}
func obfs4ServerURL(node Node) string {
ctx, err := obfs4GetContext(node.Addr)
if err != nil {
return ""
}
values := (*url.Values)(ctx.sargs)
query := values.Encode()
return fmt.Sprintf(
"%s+%s://%s/?%s", //obfs4-cert=%s&iat-mode=%s",
node.Protocol,
node.Transport,
node.Addr,
query,
)
}
func obfs4ClientConn(addr string, conn net.Conn) (net.Conn, error) {
ctx, err := obfs4GetContext(addr)
if err != nil {
return nil, err
}
pseudoDial := func(a, b string) (net.Conn, error) { return conn, nil }
return ctx.cf.Dial("tcp", "", pseudoDial, ctx.cargs)
}
func obfs4ServerConn(addr string, conn net.Conn) (net.Conn, error) {
ctx, err := obfs4GetContext(addr)
if err != nil {
return nil, err
}
return ctx.sf.WrapConn(conn)
}
type obfs4Transporter struct {
tcpTransporter
}
// Obfs4Transporter creates a Transporter that is used by obfs4 client.
func Obfs4Transporter() Transporter {
return &obfs4Transporter{}
}
func (tr *obfs4Transporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) {
opts := &HandshakeOptions{}
for _, option := range options {
option(opts)
}
timeout := opts.Timeout
if timeout <= 0 {
timeout = HandshakeTimeout
}
conn.SetDeadline(time.Now().Add(timeout))
defer conn.SetDeadline(time.Time{})
return obfs4ClientConn(opts.Addr, conn)
}
type obfs4Listener struct {
addr string
net.Listener
}
// Obfs4Listener creates a Listener for obfs4 server.
func Obfs4Listener(addr string) (Listener, error) {
ln, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
l := &obfs4Listener{
addr: addr,
Listener: tcpKeepAliveListener{ln.(*net.TCPListener)},
}
return l, nil
}
func (l *obfs4Listener) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
cc, err := obfs4ServerConn(l.addr, conn)
if err != nil {
conn.Close()
return nil, err
}
return cc, nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/ragus/gost.git
git@gitee.com:ragus/gost.git
ragus
gost
gost
master

搜索帮助