add obfs http/tls listener
This commit is contained in:
2
go.mod
2
go.mod
@ -5,6 +5,7 @@ go 1.16
|
|||||||
require (
|
require (
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||||
github.com/coreos/go-iptables v0.5.0 // indirect
|
github.com/coreos/go-iptables v0.5.0 // indirect
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20201202075250-98fa925912da
|
||||||
github.com/go-gost/gosocks5 v0.3.0
|
github.com/go-gost/gosocks5 v0.3.0
|
||||||
github.com/golang/snappy v0.0.3
|
github.com/golang/snappy v0.0.3
|
||||||
github.com/google/gopacket v1.1.19 // indirect
|
github.com/google/gopacket v1.1.19 // indirect
|
||||||
@ -17,4 +18,5 @@ require (
|
|||||||
github.com/xtaci/smux v1.5.15
|
github.com/xtaci/smux v1.5.15
|
||||||
github.com/xtaci/tcpraw v1.2.25
|
github.com/xtaci/tcpraw v1.2.25
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||||
)
|
)
|
||||||
|
4
go.sum
4
go.sum
@ -30,6 +30,10 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
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.2-0.20201202075250-98fa925912da h1:CPNdzkS5TMPghHVTYJp08SUdSneNVSwJSePAPGDuYgY=
|
||||||
|
github.com/ginuerzh/tls-dissector v0.0.2-0.20201202075250-98fa925912da/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-gost/gosocks5 v0.3.0 h1:Hkmp9YDRBSCJd7xywW6dBPT6B9aQTkuWd+3WCheJiJA=
|
github.com/go-gost/gosocks5 v0.3.0 h1:Hkmp9YDRBSCJd7xywW6dBPT6B9aQTkuWd+3WCheJiJA=
|
||||||
|
140
server/listener/obfs/http/conn.go
Normal file
140
server/listener/obfs/http/conn.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type conn struct {
|
||||||
|
net.Conn
|
||||||
|
rbuf bytes.Buffer
|
||||||
|
wbuf bytes.Buffer
|
||||||
|
handshaked bool
|
||||||
|
handshakeMutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) Handshake() (err error) {
|
||||||
|
c.handshakeMutex.Lock()
|
||||||
|
defer c.handshakeMutex.Unlock()
|
||||||
|
|
||||||
|
if c.handshaked {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.handshake(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.handshaked = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) handshake() (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 *conn) Read(b []byte) (n int, err error) {
|
||||||
|
if err = c.Handshake(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.rbuf.Len() > 0 {
|
||||||
|
return c.rbuf.Read(b)
|
||||||
|
}
|
||||||
|
return c.Conn.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
|
||||||
|
|
||||||
|
func computeAcceptKey(challengeKey string) string {
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(challengeKey))
|
||||||
|
h.Write(keyGUID)
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
88
server/listener/obfs/http/listener.go
Normal file
88
server/listener/obfs/http/listener.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/logger"
|
||||||
|
"github.com/go-gost/gost/server/listener"
|
||||||
|
"github.com/go-gost/gost/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ listener.Listener = (*Listener)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Listener struct {
|
||||||
|
md metadata
|
||||||
|
net.Listener
|
||||||
|
logger logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListener(opts ...listener.Option) *Listener {
|
||||||
|
options := &listener.Options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
return &Listener{
|
||||||
|
logger: options.Logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Init(md listener.Metadata) (err error) {
|
||||||
|
l.md, err = l.parseMetadata(md)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
laddr, err := net.ResolveTCPAddr("tcp", l.md.addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ln, err := net.ListenTCP("tcp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.md.keepAlive {
|
||||||
|
l.Listener = &utils.TCPKeepAliveListener{
|
||||||
|
TCPListener: ln,
|
||||||
|
KeepAlivePeriod: l.md.keepAlivePeriod,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Listener = ln
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Accept() (net.Conn, error) {
|
||||||
|
c, err := l.Listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &conn{Conn: c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) parseMetadata(md listener.Metadata) (m metadata, err error) {
|
||||||
|
if val, ok := md[addr]; ok {
|
||||||
|
m.addr = val
|
||||||
|
} else {
|
||||||
|
err = errors.New("missing address")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.keepAlive = true
|
||||||
|
if val, ok := md[keepAlive]; ok {
|
||||||
|
m.keepAlive, _ = strconv.ParseBool(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := md[keepAlivePeriod]; ok {
|
||||||
|
m.keepAlivePeriod, _ = time.ParseDuration(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
19
server/listener/obfs/http/metadata.go
Normal file
19
server/listener/obfs/http/metadata.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
addr = "addr"
|
||||||
|
keepAlive = "keepAlive"
|
||||||
|
keepAlivePeriod = "keepAlivePeriod"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultKeepAlivePeriod = 180 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type metadata struct {
|
||||||
|
addr string
|
||||||
|
keepAlive bool
|
||||||
|
keepAlivePeriod time.Duration
|
||||||
|
}
|
306
server/listener/obfs/tls/conn.go
Normal file
306
server/listener/obfs/tls/conn.go
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dissector "github.com/ginuerzh/tls-dissector"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxTLSDataLen = 16384
|
||||||
|
)
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsRecordTypes = []uint8{0x16, 0x14, 0x16, 0x17}
|
||||||
|
tlsVersionMinors = []uint8{0x01, 0x03, 0x03, 0x03}
|
||||||
|
|
||||||
|
ErrBadType = errors.New("bad type")
|
||||||
|
ErrBadMajorVersion = errors.New("bad major version")
|
||||||
|
ErrBadMinorVersion = errors.New("bad minor version")
|
||||||
|
ErrMaxDataLen = errors.New("bad tls data len")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tlsRecordStateType = iota
|
||||||
|
tlsRecordStateVersion0
|
||||||
|
tlsRecordStateVersion1
|
||||||
|
tlsRecordStateLength0
|
||||||
|
tlsRecordStateLength1
|
||||||
|
tlsRecordStateData
|
||||||
|
)
|
||||||
|
|
||||||
|
type obfsTLSParser struct {
|
||||||
|
step uint8
|
||||||
|
state uint8
|
||||||
|
length uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *obfsTLSParser) Parse(b []byte) (int, error) {
|
||||||
|
i := 0
|
||||||
|
last := 0
|
||||||
|
length := len(b)
|
||||||
|
|
||||||
|
for i < length {
|
||||||
|
ch := b[i]
|
||||||
|
switch r.state {
|
||||||
|
case tlsRecordStateType:
|
||||||
|
if tlsRecordTypes[r.step] != ch {
|
||||||
|
return 0, ErrBadType
|
||||||
|
}
|
||||||
|
r.state = tlsRecordStateVersion0
|
||||||
|
i++
|
||||||
|
case tlsRecordStateVersion0:
|
||||||
|
if ch != 0x03 {
|
||||||
|
return 0, ErrBadMajorVersion
|
||||||
|
}
|
||||||
|
r.state = tlsRecordStateVersion1
|
||||||
|
i++
|
||||||
|
case tlsRecordStateVersion1:
|
||||||
|
if ch != tlsVersionMinors[r.step] {
|
||||||
|
return 0, ErrBadMinorVersion
|
||||||
|
}
|
||||||
|
r.state = tlsRecordStateLength0
|
||||||
|
i++
|
||||||
|
case tlsRecordStateLength0:
|
||||||
|
r.length = uint16(ch) << 8
|
||||||
|
r.state = tlsRecordStateLength1
|
||||||
|
i++
|
||||||
|
case tlsRecordStateLength1:
|
||||||
|
r.length |= uint16(ch)
|
||||||
|
if r.step == 0 {
|
||||||
|
r.length = 91
|
||||||
|
} else if r.step == 1 {
|
||||||
|
r.length = 1
|
||||||
|
} else if r.length > maxTLSDataLen {
|
||||||
|
return 0, ErrMaxDataLen
|
||||||
|
}
|
||||||
|
if r.length > 0 {
|
||||||
|
r.state = tlsRecordStateData
|
||||||
|
} else {
|
||||||
|
r.state = tlsRecordStateType
|
||||||
|
r.step++
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
case tlsRecordStateData:
|
||||||
|
left := uint16(length - i)
|
||||||
|
if left > r.length {
|
||||||
|
left = r.length
|
||||||
|
}
|
||||||
|
if r.step >= 2 {
|
||||||
|
skip := i - last
|
||||||
|
copy(b[last:], b[i:length])
|
||||||
|
length -= int(skip)
|
||||||
|
last += int(left)
|
||||||
|
i = last
|
||||||
|
} else {
|
||||||
|
i += int(left)
|
||||||
|
}
|
||||||
|
r.length -= left
|
||||||
|
if r.length == 0 {
|
||||||
|
if r.step < 3 {
|
||||||
|
r.step++
|
||||||
|
}
|
||||||
|
r.state = tlsRecordStateType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if last == 0 {
|
||||||
|
return 0, nil
|
||||||
|
} else if last < length {
|
||||||
|
length -= last
|
||||||
|
}
|
||||||
|
|
||||||
|
return length, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type conn struct {
|
||||||
|
net.Conn
|
||||||
|
rbuf bytes.Buffer
|
||||||
|
wbuf bytes.Buffer
|
||||||
|
host string
|
||||||
|
handshaked chan struct{}
|
||||||
|
parser *obfsTLSParser
|
||||||
|
handshakeMutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// newConn creates a connection for obfs-tls server.
|
||||||
|
func newConn(c net.Conn, host string) net.Conn {
|
||||||
|
return &conn{
|
||||||
|
Conn: c,
|
||||||
|
host: host,
|
||||||
|
handshaked: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) Handshaked() bool {
|
||||||
|
select {
|
||||||
|
case <-c.handshaked:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) Handshake(payload []byte) (err error) {
|
||||||
|
c.handshakeMutex.Lock()
|
||||||
|
defer c.handshakeMutex.Unlock()
|
||||||
|
|
||||||
|
if c.Handshaked() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.handshake(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
close(c.handshaked)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) handshake() 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 *conn) Read(b []byte) (n int, err error) {
|
||||||
|
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 *conn) Write(b []byte) (n int, err error) {
|
||||||
|
n = len(b)
|
||||||
|
if !c.Handshaked() {
|
||||||
|
if err = c.Handshake(b); err != nil {
|
||||||
|
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
|
||||||
|
}
|
88
server/listener/obfs/tls/listener.go
Normal file
88
server/listener/obfs/tls/listener.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/logger"
|
||||||
|
"github.com/go-gost/gost/server/listener"
|
||||||
|
"github.com/go-gost/gost/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ listener.Listener = (*Listener)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Listener struct {
|
||||||
|
md metadata
|
||||||
|
net.Listener
|
||||||
|
logger logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListener(opts ...listener.Option) *Listener {
|
||||||
|
options := &listener.Options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
return &Listener{
|
||||||
|
logger: options.Logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Init(md listener.Metadata) (err error) {
|
||||||
|
l.md, err = l.parseMetadata(md)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
laddr, err := net.ResolveTCPAddr("tcp", l.md.addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ln, err := net.ListenTCP("tcp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.md.keepAlive {
|
||||||
|
l.Listener = &utils.TCPKeepAliveListener{
|
||||||
|
TCPListener: ln,
|
||||||
|
KeepAlivePeriod: l.md.keepAlivePeriod,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Listener = ln
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Accept() (net.Conn, error) {
|
||||||
|
c, err := l.Listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &conn{Conn: c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) parseMetadata(md listener.Metadata) (m metadata, err error) {
|
||||||
|
if val, ok := md[addr]; ok {
|
||||||
|
m.addr = val
|
||||||
|
} else {
|
||||||
|
err = errors.New("missing address")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.keepAlive = true
|
||||||
|
if val, ok := md[keepAlive]; ok {
|
||||||
|
m.keepAlive, _ = strconv.ParseBool(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := md[keepAlivePeriod]; ok {
|
||||||
|
m.keepAlivePeriod, _ = time.ParseDuration(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
19
server/listener/obfs/tls/metadata.go
Normal file
19
server/listener/obfs/tls/metadata.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
addr = "addr"
|
||||||
|
keepAlive = "keepAlive"
|
||||||
|
keepAlivePeriod = "keepAlivePeriod"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultKeepAlivePeriod = 180 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type metadata struct {
|
||||||
|
addr string
|
||||||
|
keepAlive bool
|
||||||
|
keepAlivePeriod time.Duration
|
||||||
|
}
|
Reference in New Issue
Block a user