Add Snell protocol. Refactor MASQUE HTTP/2, Fair Queue. Update XHTTP, OpenVPN, Sudoku, Fallback. Fixes

This commit is contained in:
Shtorm
2026-06-26 01:25:57 +03:00
parent d174962a04
commit edf38d33d6
107 changed files with 5346 additions and 708 deletions

View File

@@ -0,0 +1,100 @@
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)
)

View File

@@ -0,0 +1,154 @@
package obfs
import (
"bytes"
"crypto/rand"
"encoding/binary"
"io"
"net"
"time"
B "github.com/sagernet/sing/common/buf"
)
// TLSObfsServer is the server side of the shadowsocks tls simple-obfs implementation.
type TLSObfsServer struct {
net.Conn
remain int
firstRequest bool
sessionTicketDone bool
firstResponse bool
}
func (tos *TLSObfsServer) read(b []byte, discardN int) (int, error) {
buf := B.Get(discardN)
_, err := io.ReadFull(tos.Conn, buf)
B.Put(buf)
if err != nil {
return 0, err
}
sizeBuf := make([]byte, 2)
_, err = io.ReadFull(tos.Conn, sizeBuf)
if err != nil {
return 0, nil
}
length := int(binary.BigEndian.Uint16(sizeBuf))
if length > len(b) {
n, err := tos.Conn.Read(b)
if err != nil {
return n, err
}
tos.remain = length - n
return n, nil
}
return io.ReadFull(tos.Conn, b[:length])
}
// skipOtherExts skips SNI & other TLS extensions.
func (tos *TLSObfsServer) skipOtherExts() error {
buf := make([]byte, 256)
_, err := tos.read(buf, 7)
if err != nil {
return err
}
_, err = io.ReadFull(tos.Conn, buf[:4*16+2])
return err
}
func (tos *TLSObfsServer) Read(b []byte) (int, error) {
if tos.remain > 0 {
length := tos.remain
if length > len(b) {
length = len(b)
}
n, err := io.ReadFull(tos.Conn, b[:length])
tos.remain -= n
return n, err
}
if tos.firstRequest {
tos.firstRequest = false
return tos.read(b, 9*16-4)
}
if !tos.sessionTicketDone {
tos.sessionTicketDone = true
err := tos.skipOtherExts()
if err != nil {
return 0, err
}
}
return tos.read(b, 3)
}
func (tos *TLSObfsServer) Write(b []byte) (int, error) {
length := len(b)
for i := 0; i < length; i += chunkSize {
end := i + chunkSize
if end > length {
end = length
}
n, err := tos.write(b[i:end])
if err != nil {
return n, err
}
}
return length, nil
}
func (tos *TLSObfsServer) write(b []byte) (int, error) {
if tos.firstResponse {
serverHello := makeServerHello(b)
_, err := tos.Conn.Write(serverHello)
tos.firstResponse = false
return len(b), err
}
buf := B.NewSize(5 + len(b))
defer buf.Release()
buf.Write([]byte{0x17, 0x03, 0x03})
binary.Write(buf, binary.BigEndian, uint16(len(b)))
buf.Write(b)
_, err := tos.Conn.Write(buf.Bytes())
if err != nil {
return 0, err
}
return len(b), nil
}
func (tos *TLSObfsServer) Upstream() any {
return tos.Conn
}
// NewTLSObfsServer returns a server-side TLS SimpleObfs.
func NewTLSObfsServer(conn net.Conn) net.Conn {
return &TLSObfsServer{
Conn: conn,
firstRequest: true,
firstResponse: true,
}
}
func makeServerHello(data []byte) []byte {
randBytes := make([]byte, 28)
sessionId := make([]byte, 32)
rand.Read(randBytes)
rand.Read(sessionId)
buf := &bytes.Buffer{}
buf.WriteByte(0x16)
binary.Write(buf, binary.BigEndian, uint16(0x0301))
binary.Write(buf, binary.BigEndian, uint16(91))
buf.Write([]byte{2, 0, 0, 87, 0x03, 0x03})
binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix()))
buf.Write(randBytes)
buf.WriteByte(32)
buf.Write(sessionId)
buf.Write([]byte{0xcc, 0xa8})
buf.WriteByte(0)
buf.Write([]byte{0x00, 0x00})
buf.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00})
buf.Write([]byte{0x00, 0x17, 0x00, 0x00})
buf.Write([]byte{0x00, 0x0b, 0x00, 0x02, 0x01, 0x00})
buf.Write([]byte{0x14, 0x03, 0x03, 0x00, 0x01, 0x01})
buf.Write([]byte{0x16, 0x03, 0x03})
binary.Write(buf, binary.BigEndian, uint16(len(data)))
buf.Write(data)
return buf.Bytes()
}