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
}