add otls
This commit is contained in:
parent
c7568170ac
commit
a99ff4aa15
@ -197,6 +197,7 @@ type ConnectOptions struct {
|
|||||||
Selector gosocks5.Selector
|
Selector gosocks5.Selector
|
||||||
UserAgent string
|
UserAgent string
|
||||||
NoTLS bool
|
NoTLS bool
|
||||||
|
NoDelay bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectOption allows a common way to set ConnectOptions.
|
// ConnectOption allows a common way to set ConnectOptions.
|
||||||
@ -243,3 +244,10 @@ func NoTLSConnectOption(b bool) ConnectOption {
|
|||||||
opts.NoTLS = b
|
opts.NoTLS = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NoDelayConnectOption specifies the NoDelay option for ss.Connect.
|
||||||
|
func NoDelayConnectOption(b bool) ConnectOption {
|
||||||
|
return func(opts *ConnectOptions) {
|
||||||
|
opts.NoDelay = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -137,8 +137,6 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
|||||||
|
|
||||||
timeout := node.GetDuration("timeout")
|
timeout := node.GetDuration("timeout")
|
||||||
|
|
||||||
var host string
|
|
||||||
|
|
||||||
var tr gost.Transporter
|
var tr gost.Transporter
|
||||||
switch node.Transport {
|
switch node.Transport {
|
||||||
case "tls":
|
case "tls":
|
||||||
@ -195,8 +193,9 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
|||||||
case "obfs4":
|
case "obfs4":
|
||||||
tr = gost.Obfs4Transporter()
|
tr = gost.Obfs4Transporter()
|
||||||
case "ohttp":
|
case "ohttp":
|
||||||
host = node.Get("host")
|
|
||||||
tr = gost.ObfsHTTPTransporter()
|
tr = gost.ObfsHTTPTransporter()
|
||||||
|
case "otls":
|
||||||
|
tr = gost.ObfsTLSTransporter()
|
||||||
case "ftcp":
|
case "ftcp":
|
||||||
tr = gost.FakeTCPTransporter()
|
tr = gost.FakeTCPTransporter()
|
||||||
case "udp":
|
case "udp":
|
||||||
@ -240,8 +239,10 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
|||||||
node.ConnectOptions = []gost.ConnectOption{
|
node.ConnectOptions = []gost.ConnectOption{
|
||||||
gost.UserAgentConnectOption(node.Get("agent")),
|
gost.UserAgentConnectOption(node.Get("agent")),
|
||||||
gost.NoTLSConnectOption(node.GetBool("notls")),
|
gost.NoTLSConnectOption(node.GetBool("notls")),
|
||||||
|
gost.NoDelayConnectOption(node.GetBool("nodelay")),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
host := node.Get("host")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = node.Host
|
host = node.Host
|
||||||
}
|
}
|
||||||
@ -441,6 +442,8 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
ln, err = gost.Obfs4Listener(node.Addr)
|
ln, err = gost.Obfs4Listener(node.Addr)
|
||||||
case "ohttp":
|
case "ohttp":
|
||||||
ln, err = gost.ObfsHTTPListener(node.Addr)
|
ln, err = gost.ObfsHTTPListener(node.Addr)
|
||||||
|
case "otls":
|
||||||
|
ln, err = gost.ObfsTLSListener(node.Addr)
|
||||||
case "tun":
|
case "tun":
|
||||||
cfg := gost.TunConfig{
|
cfg := gost.TunConfig{
|
||||||
Name: node.Get("name"),
|
Name: node.Get("name"),
|
||||||
|
2
go.mod
2
go.mod
@ -14,7 +14,7 @@ require (
|
|||||||
github.com/docker/libcontainer v2.2.1+incompatible
|
github.com/docker/libcontainer v2.2.1+incompatible
|
||||||
github.com/ginuerzh/gosocks4 v0.0.1
|
github.com/ginuerzh/gosocks4 v0.0.1
|
||||||
github.com/ginuerzh/gosocks5 v0.2.0
|
github.com/ginuerzh/gosocks5 v0.2.0
|
||||||
github.com/ginuerzh/tls-dissector v0.0.1
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796
|
||||||
github.com/go-log/log v0.1.0
|
github.com/go-log/log v0.1.0
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/golang/mock v1.2.0 // indirect
|
github.com/golang/mock v1.2.0 // indirect
|
||||||
|
10
go.sum
10
go.sum
@ -30,6 +30,16 @@ github.com/ginuerzh/gosocks5 v0.2.0 h1:K0Ua23U9LU3BZrf3XpGDcs0mP8DiEpa6PJE4TA/MU
|
|||||||
github.com/ginuerzh/gosocks5 v0.2.0/go.mod h1:qp22mr6tH/prEoaN0pFukq76LlScIE+F2rP2ZP5ZHno=
|
github.com/ginuerzh/gosocks5 v0.2.0/go.mod h1:qp22mr6tH/prEoaN0pFukq76LlScIE+F2rP2ZP5ZHno=
|
||||||
github.com/ginuerzh/tls-dissector v0.0.1 h1:yF6fIt78TO4CdjiLLn6R8r0XajQJE1Lbnuq6rP8mGW8=
|
github.com/ginuerzh/tls-dissector v0.0.1 h1:yF6fIt78TO4CdjiLLn6R8r0XajQJE1Lbnuq6rP8mGW8=
|
||||||
github.com/ginuerzh/tls-dissector v0.0.1/go.mod h1:u/kbBOqIOgJv39gywuUb3VwyzdZG5DKquOqfToKE6lk=
|
github.com/ginuerzh/tls-dissector v0.0.1/go.mod h1:u/kbBOqIOgJv39gywuUb3VwyzdZG5DKquOqfToKE6lk=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223041816-c0cb3da7ea91 h1:bFBTbZglO4xNVWSLwDEcVKBIurTXGL2sNKi9UuQima4=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223041816-c0cb3da7ea91/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223072427-83db9c3e4eb5 h1:pmGmno31njvF5xncoDcDuM8mE1984cxrQ0DeVD4lVfA=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223072427-83db9c3e4eb5/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223110639-e9c10af0eb19 h1:t/AZCq8FiVNN+Mx6UmIv7bXj3+OVThg070G8ajZ3wJw=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223110639-e9c10af0eb19/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223121713-a8bf02a99d69 h1:h9lREy0OWSTrjweGxduikppA2tCjGPoUj32SVHI3dr0=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223121713-a8bf02a99d69/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796 h1:VPXbYRvZUzTemsI7u0FzOnEuHeHwQuMTPXApAu8aeX4=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||||
github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U=
|
github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U=
|
||||||
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
|
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
|
2
gost.go
2
gost.go
@ -20,7 +20,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Version is the gost version.
|
// Version is the gost version.
|
||||||
const Version = "2.10.1"
|
const Version = "2.10.2-dev"
|
||||||
|
|
||||||
// Debug is a flag that enables the debug log.
|
// Debug is a flag that enables the debug log.
|
||||||
var Debug bool
|
var Debug bool
|
||||||
|
3
node.go
3
node.go
@ -83,10 +83,9 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
case "kcp", "ssh", "quic":
|
case "kcp", "ssh", "quic":
|
||||||
case "ssu":
|
case "ssu":
|
||||||
node.Transport = "udp"
|
node.Transport = "udp"
|
||||||
case "obfs4":
|
case "ohttp", "otls", "obfs4": // obfs
|
||||||
case "tcp", "udp":
|
case "tcp", "udp":
|
||||||
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
||||||
case "ohttp": // obfs-http
|
|
||||||
case "tun", "tap": // tun/tap device
|
case "tun", "tap": // tun/tap device
|
||||||
case "ftcp": // fake TCP
|
case "ftcp": // fake TCP
|
||||||
case "dns":
|
case "dns":
|
||||||
|
312
obfs.go
312
obfs.go
@ -5,6 +5,8 @@ package gost
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -20,6 +22,7 @@ import (
|
|||||||
pt "git.torproject.org/pluggable-transports/goptlib.git"
|
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/base"
|
||||||
"git.torproject.org/pluggable-transports/obfs4.git/transports/obfs4"
|
"git.torproject.org/pluggable-transports/obfs4.git/transports/obfs4"
|
||||||
|
dissector "github.com/ginuerzh/tls-dissector"
|
||||||
)
|
)
|
||||||
|
|
||||||
type obfsHTTPTransporter struct {
|
type obfsHTTPTransporter struct {
|
||||||
@ -249,6 +252,315 @@ func (c *obfsHTTPConn) Write(b []byte) (n int, err error) {
|
|||||||
return c.Conn.Write(b)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClientObfsTLSConn(conn net.Conn, host string) net.Conn {
|
||||||
|
return &obfsTLSConn{
|
||||||
|
Conn: conn,
|
||||||
|
host: host,
|
||||||
|
handshaked: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record := &dissector.Record{
|
||||||
|
Type: dissector.AppData,
|
||||||
|
Version: tls.VersionTLS12,
|
||||||
|
Opaque: b,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
type obfs4Context struct {
|
||||||
cf base.ClientFactory
|
cf base.ClientFactory
|
||||||
cargs interface{} // type obfs4ClientArgs
|
cargs interface{} // type obfs4ClientArgs
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
name: gost
|
name: gost
|
||||||
type: app
|
type: app
|
||||||
version: '2.10.1'
|
version: '2.10.2'
|
||||||
title: GO Simple Tunnel
|
title: GO Simple Tunnel
|
||||||
summary: A simple security tunnel written in golang
|
summary: A simple security tunnel written in golang
|
||||||
description: |
|
description: |
|
||||||
|
9
sni.go
9
sni.go
@ -270,7 +270,7 @@ func readClientHelloRecord(r io.Reader, host string, isClient bool) ([]byte, str
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
clientHello := &dissector.ClientHelloHandshake{}
|
clientHello := &dissector.ClientHelloMsg{}
|
||||||
if err := clientHello.Decode(record.Opaque); err != nil {
|
if err := clientHello.Decode(record.Opaque); err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
@ -280,7 +280,8 @@ func readClientHelloRecord(r io.Reader, host string, isClient bool) ([]byte, str
|
|||||||
|
|
||||||
for _, ext := range clientHello.Extensions {
|
for _, ext := range clientHello.Extensions {
|
||||||
if ext.Type() == 0xFFFE {
|
if ext.Type() == 0xFFFE {
|
||||||
if host, err = decodeServerName(string(ext.Bytes()[4:])); err == nil {
|
b, _ := ext.Encode()
|
||||||
|
if host, err = decodeServerName(string(b)); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,8 +297,8 @@ func readClientHelloRecord(r io.Reader, host string, isClient bool) ([]byte, str
|
|||||||
host = snExtension.Name
|
host = snExtension.Name
|
||||||
}
|
}
|
||||||
if isClient {
|
if isClient {
|
||||||
clientHello.Extensions = append(clientHello.Extensions,
|
e, _ := dissector.NewExtension(0xFFFE, []byte(encodeServerName(snExtension.Name)))
|
||||||
dissector.NewExtension(0xFFFE, []byte(encodeServerName(snExtension.Name))))
|
clientHello.Extensions = append(clientHello.Extensions, e)
|
||||||
}
|
}
|
||||||
if host != "" {
|
if host != "" {
|
||||||
snExtension.Name = host
|
snExtension.Name = host
|
||||||
|
47
ss.go
47
ss.go
@ -75,10 +75,21 @@ func (c *shadowConnector) ConnectContext(ctx context.Context, conn net.Conn, net
|
|||||||
if c.cipher != nil {
|
if c.cipher != nil {
|
||||||
conn = c.cipher.StreamConn(conn)
|
conn = c.cipher.StreamConn(conn)
|
||||||
}
|
}
|
||||||
if _, err := conn.Write(rawaddr[:n]); err != nil {
|
|
||||||
|
sc := &shadowConn{
|
||||||
|
Conn: conn,
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the addr at once.
|
||||||
|
if opts.NoDelay {
|
||||||
|
if _, err := sc.Write(rawaddr[:n]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return conn, nil
|
} else {
|
||||||
|
sc.wbuf.Write(rawaddr[:n]) // cache the header
|
||||||
|
}
|
||||||
|
|
||||||
|
return sc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type shadowHandler struct {
|
type shadowHandler struct {
|
||||||
@ -111,7 +122,9 @@ func (h *shadowHandler) Handle(conn net.Conn) {
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
if h.cipher != nil {
|
if h.cipher != nil {
|
||||||
conn = h.cipher.StreamConn(conn)
|
conn = &shadowConn{
|
||||||
|
Conn: h.cipher.StreamConn(conn),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.SetReadDeadline(time.Now().Add(ReadTimeout))
|
conn.SetReadDeadline(time.Now().Add(ReadTimeout))
|
||||||
@ -244,7 +257,9 @@ func (c *shadowUDPConnector) ConnectContext(ctx context.Context, conn net.Conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.cipher != nil {
|
if c.cipher != nil {
|
||||||
conn = c.cipher.StreamConn(conn)
|
conn = &shadowConn{
|
||||||
|
Conn: c.cipher.StreamConn(conn),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &socks5UDPTunnelConn{
|
return &socks5UDPTunnelConn{
|
||||||
@ -302,7 +317,9 @@ func (h *shadowUDPHandler) Handle(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if h.cipher != nil {
|
if h.cipher != nil {
|
||||||
conn = h.cipher.StreamConn(conn)
|
conn = &shadowConn{
|
||||||
|
Conn: h.cipher.StreamConn(conn),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Logf("[ssu] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr())
|
log.Logf("[ssu] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
@ -469,10 +486,17 @@ func (h *shadowUDPHandler) transportUDP(conn net.Conn, cc net.PacketConn) error
|
|||||||
// we wrap around it to make io.Copy happy.
|
// we wrap around it to make io.Copy happy.
|
||||||
type shadowConn struct {
|
type shadowConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
|
wbuf bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *shadowConn) Write(b []byte) (n int, err error) {
|
func (c *shadowConn) Write(b []byte) (n int, err error) {
|
||||||
n = len(b) // force byte length consistent
|
n = len(b) // force byte length consistent
|
||||||
|
if c.wbuf.Len() > 0 {
|
||||||
|
c.wbuf.Write(b) // append the data to the cached header
|
||||||
|
_, err = c.Conn.Write(c.wbuf.Bytes())
|
||||||
|
c.wbuf.Reset()
|
||||||
|
return
|
||||||
|
}
|
||||||
_, err = c.Conn.Write(b)
|
_, err = c.Conn.Write(b)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -546,9 +570,7 @@ type shadowCipher struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *shadowCipher) StreamConn(conn net.Conn) net.Conn {
|
func (c *shadowCipher) StreamConn(conn net.Conn) net.Conn {
|
||||||
return &shadowConn{
|
return ss.NewConn(conn, c.cipher.Copy())
|
||||||
Conn: ss.NewConn(conn, c.cipher.Copy()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *shadowCipher) PacketConn(conn net.PacketConn) net.PacketConn {
|
func (c *shadowCipher) PacketConn(conn net.PacketConn) net.PacketConn {
|
||||||
@ -566,14 +588,17 @@ func initShadowCipher(info *url.Userinfo) (cipher core.Cipher) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cipher, _ = core.PickCipher(method, nil, password)
|
cp, _ := ss.NewCipher(method, password)
|
||||||
|
if cp != nil {
|
||||||
|
cipher = &shadowCipher{cipher: cp}
|
||||||
|
}
|
||||||
if cipher == nil {
|
if cipher == nil {
|
||||||
cp, err := ss.NewCipher(method, password)
|
var err error
|
||||||
|
cipher, err = core.PickCipher(method, nil, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[ss] %s", err)
|
log.Logf("[ss] %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cipher = &shadowCipher{cipher: cp}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user