glider/proxy/anytls/padding.go

128 lines
2.2 KiB
Go

package anytls
import (
"crypto/md5"
"crypto/rand"
"fmt"
"math/big"
"strconv"
"strings"
"sync/atomic"
)
const (
checkMark = -1
)
var defaultPaddingScheme = []byte(`stop=8
0=30-30
1=100-400
2=400-500,c,500-1000,c,500-1000,c,500-1000,c,500-1000
3=9-9,500-1000
4=500-1000
5=500-1000
6=500-1000
7=500-1000`)
type PaddingFactory struct {
scheme map[string]string
RawScheme []byte
Stop uint32
Md5 string
}
var defaultPaddingFactory atomic.Pointer[PaddingFactory]
func init() {
UpdatePaddingScheme(defaultPaddingScheme)
}
func UpdatePaddingScheme(rawScheme []byte) bool {
padding := NewPaddingFactory(rawScheme)
if padding == nil {
return false
}
defaultPaddingFactory.Store(padding)
return true
}
func NewPaddingFactory(rawScheme []byte) *PaddingFactory {
scheme := stringMapFromBytes(rawScheme)
if len(scheme) == 0 {
return nil
}
stop, err := strconv.Atoi(scheme["stop"])
if err != nil || stop <= 0 {
return nil
}
rawCopy := append([]byte(nil), rawScheme...)
return &PaddingFactory{
scheme: scheme,
RawScheme: rawCopy,
Stop: uint32(stop),
Md5: fmt.Sprintf("%x", md5.Sum(rawCopy)),
}
}
func loadPaddingFactory() *PaddingFactory {
return defaultPaddingFactory.Load()
}
func (p *PaddingFactory) GenerateRecordPayloadSizes(pkt uint32) []int {
if p == nil {
return nil
}
raw, ok := p.scheme[strconv.Itoa(int(pkt))]
if !ok {
return nil
}
parts := strings.Split(raw, ",")
sizes := make([]int, 0, len(parts))
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "c" {
sizes = append(sizes, checkMark)
continue
}
bounds := strings.SplitN(part, "-", 2)
if len(bounds) != 2 {
continue
}
minSize, err := strconv.ParseInt(bounds[0], 10, 64)
if err != nil {
continue
}
maxSize, err := strconv.ParseInt(bounds[1], 10, 64)
if err != nil {
continue
}
if minSize > maxSize {
minSize, maxSize = maxSize, minSize
}
if minSize <= 0 || maxSize <= 0 {
continue
}
if minSize == maxSize {
sizes = append(sizes, int(minSize))
continue
}
delta, err := rand.Int(rand.Reader, big.NewInt(maxSize-minSize+1))
if err != nil {
sizes = append(sizes, int(minSize))
continue
}
sizes = append(sizes, int(minSize+delta.Int64()))
}
return sizes
}