mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-26 20:29:03 +03:00
101 lines
2.0 KiB
Go
101 lines
2.0 KiB
Go
package obfs
|
|
|
|
import (
|
|
"bufio"
|
|
cryptorand "crypto/rand"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io"
|
|
"math/rand/v2"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// HTTPObfsServer is the server side of the shadowsocks http simple-obfs implementation.
|
|
type HTTPObfsServer struct {
|
|
net.Conn
|
|
buf []byte
|
|
bio *bufio.Reader
|
|
offset int
|
|
firstRequest bool
|
|
firstResponse bool
|
|
}
|
|
|
|
func (hos *HTTPObfsServer) Read(b []byte) (int, error) {
|
|
if hos.buf != nil {
|
|
n := copy(b, hos.buf[hos.offset:])
|
|
hos.offset += n
|
|
if hos.offset == len(hos.buf) {
|
|
hos.offset = 0
|
|
hos.buf = nil
|
|
}
|
|
return n, nil
|
|
}
|
|
if hos.firstRequest {
|
|
bio := bufio.NewReader(hos.Conn)
|
|
req, err := http.ReadRequest(bio)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if req.Method != "GET" || req.Header.Get("Connection") != "Upgrade" {
|
|
return 0, io.EOF
|
|
}
|
|
buf, err := io.ReadAll(req.Body)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
n := copy(b, buf)
|
|
if n < len(buf) {
|
|
hos.buf = buf
|
|
hos.offset = n
|
|
}
|
|
req.Body.Close()
|
|
hos.bio = bio
|
|
hos.firstRequest = false
|
|
return n, nil
|
|
}
|
|
return hos.bio.Read(b)
|
|
}
|
|
|
|
func (hos *HTTPObfsServer) Write(b []byte) (int, error) {
|
|
if hos.firstResponse {
|
|
randBytes := make([]byte, 16)
|
|
cryptorand.Read(randBytes)
|
|
date := time.Now().Format(time.RFC1123)
|
|
resp := fmt.Sprintf(httpResponseTemplate, vMajor, vMinor, date, base64.URLEncoding.EncodeToString(randBytes))
|
|
_, err := hos.Conn.Write([]byte(resp))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
hos.firstResponse = false
|
|
}
|
|
return hos.Conn.Write(b)
|
|
}
|
|
|
|
func (hos *HTTPObfsServer) Upstream() any {
|
|
return hos.Conn
|
|
}
|
|
|
|
// NewHTTPObfsServer returns a server-side HTTPObfs.
|
|
func NewHTTPObfsServer(conn net.Conn) net.Conn {
|
|
return &HTTPObfsServer{
|
|
Conn: conn,
|
|
firstRequest: true,
|
|
firstResponse: true,
|
|
}
|
|
}
|
|
|
|
const httpResponseTemplate = "HTTP/1.1 101 Switching Protocols\r\n" +
|
|
"Server: nginx/1.%d.%d\r\n" +
|
|
"Date: %s\r\n" +
|
|
"Upgrade: websocket\r\n" +
|
|
"Connection: Upgrade\r\n" +
|
|
"Sec-WebSocket-Accept: %s\r\n" +
|
|
"\r\n"
|
|
|
|
var (
|
|
vMajor = rand.IntN(11)
|
|
vMinor = rand.IntN(12)
|
|
)
|