mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-19 00:10:06 +08:00
Some checks are pending
Test / test (1.20, macos-15-intel) (push) Waiting to run
Test / test (1.20, macos-latest) (push) Waiting to run
Test / test (1.20, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.20, ubuntu-latest) (push) Waiting to run
Test / test (1.20, windows-latest) (push) Waiting to run
Test / test (1.21, macos-15-intel) (push) Waiting to run
Test / test (1.21, macos-latest) (push) Waiting to run
Test / test (1.21, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.21, ubuntu-latest) (push) Waiting to run
Test / test (1.21, windows-latest) (push) Waiting to run
Test / test (1.22, macos-15-intel) (push) Waiting to run
Test / test (1.22, macos-latest) (push) Waiting to run
Test / test (1.22, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.22, ubuntu-latest) (push) Waiting to run
Test / test (1.22, windows-latest) (push) Waiting to run
Test / test (1.23, macos-15-intel) (push) Waiting to run
Test / test (1.23, macos-latest) (push) Waiting to run
Test / test (1.23, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.23, ubuntu-latest) (push) Waiting to run
Test / test (1.23, windows-latest) (push) Waiting to run
Test / test (1.24, macos-15-intel) (push) Waiting to run
Test / test (1.24, macos-latest) (push) Waiting to run
Test / test (1.24, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.24, ubuntu-latest) (push) Waiting to run
Test / test (1.24, windows-latest) (push) Waiting to run
Test / test (1.25, macos-15-intel) (push) Waiting to run
Test / test (1.25, macos-latest) (push) Waiting to run
Test / test (1.25, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.25, ubuntu-latest) (push) Waiting to run
Test / test (1.25, windows-latest) (push) Waiting to run
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
180 lines
4.7 KiB
Go
180 lines
4.7 KiB
Go
package sudoku
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io"
|
|
"math/rand"
|
|
"net"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/saba-futai/sudoku/pkg/obfs/httpmask"
|
|
)
|
|
|
|
var (
|
|
httpMaskUserAgents = []string{
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15",
|
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
}
|
|
httpMaskAccepts = []string{
|
|
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
|
"application/json, text/plain, */*",
|
|
"application/octet-stream",
|
|
"*/*",
|
|
}
|
|
httpMaskAcceptLanguages = []string{
|
|
"en-US,en;q=0.9",
|
|
"zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
|
}
|
|
httpMaskAcceptEncodings = []string{
|
|
"gzip, deflate, br",
|
|
"gzip, deflate",
|
|
}
|
|
httpMaskPaths = []string{
|
|
"/api/v1/upload",
|
|
"/data/sync",
|
|
"/v1/telemetry",
|
|
"/session",
|
|
"/ws",
|
|
}
|
|
httpMaskContentTypes = []string{
|
|
"application/octet-stream",
|
|
"application/json",
|
|
}
|
|
)
|
|
|
|
var (
|
|
httpMaskRngPool = sync.Pool{
|
|
New: func() any { return rand.New(rand.NewSource(time.Now().UnixNano())) },
|
|
}
|
|
httpMaskBufPool = sync.Pool{
|
|
New: func() any {
|
|
b := make([]byte, 0, 1024)
|
|
return &b
|
|
},
|
|
}
|
|
)
|
|
|
|
func trimPortForHost(host string) string {
|
|
if host == "" {
|
|
return host
|
|
}
|
|
h, _, err := net.SplitHostPort(host)
|
|
if err == nil && h != "" {
|
|
return h
|
|
}
|
|
return host
|
|
}
|
|
|
|
func appendCommonHeaders(buf []byte, host string, r *rand.Rand) []byte {
|
|
ua := httpMaskUserAgents[r.Intn(len(httpMaskUserAgents))]
|
|
accept := httpMaskAccepts[r.Intn(len(httpMaskAccepts))]
|
|
lang := httpMaskAcceptLanguages[r.Intn(len(httpMaskAcceptLanguages))]
|
|
enc := httpMaskAcceptEncodings[r.Intn(len(httpMaskAcceptEncodings))]
|
|
|
|
buf = append(buf, "Host: "...)
|
|
buf = append(buf, host...)
|
|
buf = append(buf, "\r\nUser-Agent: "...)
|
|
buf = append(buf, ua...)
|
|
buf = append(buf, "\r\nAccept: "...)
|
|
buf = append(buf, accept...)
|
|
buf = append(buf, "\r\nAccept-Language: "...)
|
|
buf = append(buf, lang...)
|
|
buf = append(buf, "\r\nAccept-Encoding: "...)
|
|
buf = append(buf, enc...)
|
|
buf = append(buf, "\r\nConnection: keep-alive\r\n"...)
|
|
buf = append(buf, "Cache-Control: no-cache\r\nPragma: no-cache\r\n"...)
|
|
return buf
|
|
}
|
|
|
|
// WriteHTTPMaskHeader writes an HTTP/1.x request header as a mask, according to strategy.
|
|
// Supported strategies: ""/"random", "post", "websocket".
|
|
func WriteHTTPMaskHeader(w io.Writer, host string, strategy string) error {
|
|
switch normalizeHTTPMaskStrategy(strategy) {
|
|
case "random":
|
|
return httpmask.WriteRandomRequestHeader(w, host)
|
|
case "post":
|
|
return writeHTTPMaskPOST(w, host)
|
|
case "websocket":
|
|
return writeHTTPMaskWebSocket(w, host)
|
|
default:
|
|
return fmt.Errorf("unsupported http-mask-strategy: %s", strategy)
|
|
}
|
|
}
|
|
|
|
func writeHTTPMaskPOST(w io.Writer, host string) error {
|
|
r := httpMaskRngPool.Get().(*rand.Rand)
|
|
defer httpMaskRngPool.Put(r)
|
|
|
|
path := httpMaskPaths[r.Intn(len(httpMaskPaths))]
|
|
ctype := httpMaskContentTypes[r.Intn(len(httpMaskContentTypes))]
|
|
|
|
bufPtr := httpMaskBufPool.Get().(*[]byte)
|
|
buf := *bufPtr
|
|
buf = buf[:0]
|
|
defer func() {
|
|
if cap(buf) <= 4096 {
|
|
*bufPtr = buf
|
|
httpMaskBufPool.Put(bufPtr)
|
|
}
|
|
}()
|
|
|
|
const minCL = int64(4 * 1024)
|
|
const maxCL = int64(10 * 1024 * 1024)
|
|
contentLength := minCL + r.Int63n(maxCL-minCL+1)
|
|
|
|
buf = append(buf, "POST "...)
|
|
buf = append(buf, path...)
|
|
buf = append(buf, " HTTP/1.1\r\n"...)
|
|
buf = appendCommonHeaders(buf, host, r)
|
|
buf = append(buf, "Content-Type: "...)
|
|
buf = append(buf, ctype...)
|
|
buf = append(buf, "\r\nContent-Length: "...)
|
|
buf = strconv.AppendInt(buf, contentLength, 10)
|
|
buf = append(buf, "\r\n\r\n"...)
|
|
|
|
_, err := w.Write(buf)
|
|
return err
|
|
}
|
|
|
|
func writeHTTPMaskWebSocket(w io.Writer, host string) error {
|
|
r := httpMaskRngPool.Get().(*rand.Rand)
|
|
defer httpMaskRngPool.Put(r)
|
|
|
|
path := httpMaskPaths[r.Intn(len(httpMaskPaths))]
|
|
|
|
bufPtr := httpMaskBufPool.Get().(*[]byte)
|
|
buf := *bufPtr
|
|
buf = buf[:0]
|
|
defer func() {
|
|
if cap(buf) <= 4096 {
|
|
*bufPtr = buf
|
|
httpMaskBufPool.Put(bufPtr)
|
|
}
|
|
}()
|
|
|
|
hostNoPort := trimPortForHost(host)
|
|
var keyBytes [16]byte
|
|
for i := 0; i < len(keyBytes); i++ {
|
|
keyBytes[i] = byte(r.Intn(256))
|
|
}
|
|
var wsKey [24]byte
|
|
base64.StdEncoding.Encode(wsKey[:], keyBytes[:])
|
|
|
|
buf = append(buf, "GET "...)
|
|
buf = append(buf, path...)
|
|
buf = append(buf, " HTTP/1.1\r\n"...)
|
|
buf = appendCommonHeaders(buf, host, r)
|
|
buf = append(buf, "Upgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: "...)
|
|
buf = append(buf, wsKey[:]...)
|
|
buf = append(buf, "\r\nOrigin: https://"...)
|
|
buf = append(buf, hostNoPort...)
|
|
buf = append(buf, "\r\n\r\n"...)
|
|
|
|
_, err := w.Write(buf)
|
|
return err
|
|
}
|