initial commit

This commit is contained in:
ginuerzh
2022-03-14 20:27:14 +08:00
commit 9397cb5351
175 changed files with 16196 additions and 0 deletions

145
listener/obfs/http/conn.go Normal file
View File

@ -0,0 +1,145 @@
package http
import (
"bufio"
"bytes"
"crypto/sha1"
"encoding/base64"
"errors"
"io"
"net"
"net/http"
"net/http/httputil"
"sync"
"time"
"github.com/go-gost/gost/v3/pkg/logger"
)
type obfsHTTPConn struct {
net.Conn
rbuf bytes.Buffer
wbuf bytes.Buffer
handshaked bool
handshakeMutex sync.Mutex
header http.Header
logger logger.Logger
}
func (c *obfsHTTPConn) 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 *obfsHTTPConn) handshake() (err error) {
br := bufio.NewReader(c.Conn)
r, err := http.ReadRequest(br)
if err != nil {
return
}
if c.logger.IsLevelEnabled(logger.DebugLevel) {
dump, _ := httputil.DumpRequest(r, false)
c.logger.Debug(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 {
c.logger.Error(err)
return
}
resp := http.Response{
StatusCode: http.StatusOK,
ProtoMajor: 1,
ProtoMinor: 1,
Header: c.header,
}
if resp.Header == nil {
resp.Header = http.Header{}
}
resp.Header.Set("Date", time.Now().Format(time.RFC1123))
if r.Method != http.MethodGet || r.Header.Get("Upgrade") != "websocket" {
resp.StatusCode = http.StatusBadRequest
if c.logger.IsLevelEnabled(logger.DebugLevel) {
dump, _ := httputil.DumpResponse(&resp, false)
c.logger.Debug(string(dump))
}
resp.Write(c.Conn)
return errors.New("bad request")
}
resp.StatusCode = http.StatusSwitchingProtocols
resp.Header.Set("Connection", "Upgrade")
resp.Header.Set("Upgrade", "websocket")
resp.Header.Set("Sec-WebSocket-Accept", c.computeAcceptKey(r.Header.Get("Sec-WebSocket-Key")))
if c.logger.IsLevelEnabled(logger.DebugLevel) {
dump, _ := httputil.DumpResponse(&resp, false)
c.logger.Debug(string(dump))
}
if c.rbuf.Len() > 0 {
// cache the response header if there are extra data in the request body.
resp.Write(&c.wbuf)
return
}
err = resp.Write(c.Conn)
return
}
func (c *obfsHTTPConn) 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 *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)
}
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
func (c *obfsHTTPConn) computeAcceptKey(challengeKey string) string {
h := sha1.New()
h.Write([]byte(challengeKey))
h.Write(keyGUID)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

View File

@ -0,0 +1,63 @@
package http
import (
"net"
"github.com/go-gost/gost/v3/pkg/common/admission"
"github.com/go-gost/gost/v3/pkg/common/metrics"
"github.com/go-gost/gost/v3/pkg/listener"
"github.com/go-gost/gost/v3/pkg/logger"
md "github.com/go-gost/gost/v3/pkg/metadata"
"github.com/go-gost/gost/v3/pkg/registry"
)
func init() {
registry.ListenerRegistry().Register("ohttp", NewListener)
}
type obfsListener struct {
net.Listener
logger logger.Logger
md metadata
options listener.Options
}
func NewListener(opts ...listener.Option) listener.Listener {
options := listener.Options{}
for _, opt := range opts {
opt(&options)
}
return &obfsListener{
logger: options.Logger,
options: options,
}
}
func (l *obfsListener) Init(md md.Metadata) (err error) {
if err = l.parseMetadata(md); err != nil {
return
}
ln, err := net.Listen("tcp", l.options.Addr)
if err != nil {
return
}
ln = metrics.WrapListener(l.options.Service, ln)
ln = admission.WrapListener(l.options.Admission, ln)
l.Listener = ln
return
}
func (l *obfsListener) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &obfsHTTPConn{
Conn: c,
header: l.md.header,
logger: l.logger,
}, nil
}

View File

@ -0,0 +1,26 @@
package http
import (
"net/http"
mdata "github.com/go-gost/gost/v3/pkg/metadata"
)
type metadata struct {
header http.Header
}
func (l *obfsListener) parseMetadata(md mdata.Metadata) (err error) {
const (
header = "header"
)
if mm := mdata.GetStringMapString(md, header); len(mm) > 0 {
hd := http.Header{}
for k, v := range mm {
hd.Add(k, v)
}
l.md.header = hd
}
return
}

161
listener/obfs/tls/conn.go Normal file
View File

@ -0,0 +1,161 @@
package tls
import (
"bytes"
"crypto/rand"
"crypto/tls"
"net"
"sync"
"time"
dissector "github.com/go-gost/tls-dissector"
)
const (
maxTLSDataLen = 16384
)
type obfsTLSConn struct {
net.Conn
rbuf bytes.Buffer
wbuf bytes.Buffer
handshaked bool
handshakeMutex sync.Mutex
}
func (c *obfsTLSConn) Handshake() (err error) {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if c.handshaked {
return
}
if err = c.handshake(); err != nil {
return
}
c.handshaked = true
return nil
}
func (c *obfsTLSConn) 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 *obfsTLSConn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
}
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) {
if err = c.Handshake(); err != nil {
return
}
n = len(b)
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
}

View File

@ -0,0 +1,61 @@
package tls
import (
"net"
"github.com/go-gost/gost/v3/pkg/common/admission"
"github.com/go-gost/gost/v3/pkg/common/metrics"
"github.com/go-gost/gost/v3/pkg/listener"
"github.com/go-gost/gost/v3/pkg/logger"
md "github.com/go-gost/gost/v3/pkg/metadata"
"github.com/go-gost/gost/v3/pkg/registry"
)
func init() {
registry.ListenerRegistry().Register("otls", NewListener)
}
type obfsListener struct {
net.Listener
logger logger.Logger
md metadata
options listener.Options
}
func NewListener(opts ...listener.Option) listener.Listener {
options := listener.Options{}
for _, opt := range opts {
opt(&options)
}
return &obfsListener{
logger: options.Logger,
options: options,
}
}
func (l *obfsListener) Init(md md.Metadata) (err error) {
if err = l.parseMetadata(md); err != nil {
return
}
ln, err := net.Listen("tcp", l.options.Addr)
if err != nil {
return
}
ln = metrics.WrapListener(l.options.Service, ln)
ln = admission.WrapListener(l.options.Admission, ln)
l.Listener = ln
return
}
func (l *obfsListener) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &obfsTLSConn{
Conn: c,
}, nil
}

View File

@ -0,0 +1,12 @@
package tls
import (
md "github.com/go-gost/gost/v3/pkg/metadata"
)
type metadata struct {
}
func (l *obfsListener) parseMetadata(md md.Metadata) (err error) {
return
}