mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 15:54:03 +03:00
FILE / ScuroNeko/mtg
internal/config/config.go
Исходный файл и его история в репозитории.
The hardcoded noise range (2500-4700 bytes) in the FakeTLS ServerHello does not match the real certificate chain sizes of many popular fronting domains (e.g., dl.google.com ≈ 6480 bytes, microsoft.com ≈ 13004 bytes). This makes the proxy detectable by DPI systems that compare the ApplicationData size with the real cert chain size for the SNI domain. On startup, probe the fronting domain's actual TLS handshake size and use the measured value ± jitter instead of the static range. Falls back to the legacy 2500-4700 range if the probe fails. Also adds optional caching of probe results between restarts (noise-cache-path, noise-cache-ttl) and a configurable probe count (noise-probe-count) under [defense.doppelganger]. Closes #408
152 lines
4.3 KiB
Go
152 lines
4.3 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
|
|
"github.com/9seconds/mtg/v2/mtglib"
|
|
)
|
|
|
|
type Optional struct {
|
|
Enabled TypeBool `json:"enabled"`
|
|
}
|
|
|
|
type ListConfig struct {
|
|
Optional
|
|
|
|
DownloadConcurrency TypeConcurrency `json:"downloadConcurrency"`
|
|
URLs []TypeBlocklistURI `json:"urls"`
|
|
UpdateEach TypeDuration `json:"updateEach"`
|
|
}
|
|
|
|
type Config struct {
|
|
Debug TypeBool `json:"debug"`
|
|
AllowFallbackOnUnknownDC TypeBool `json:"allowFallbackOnUnknownDc"`
|
|
Secret mtglib.Secret `json:"secret"`
|
|
BindTo TypeHostPort `json:"bindTo"`
|
|
ProxyProtocolListener TypeBool `json:"proxyProtocolListener"`
|
|
PreferIP TypePreferIP `json:"preferIp"`
|
|
AutoUpdate TypeBool `json:"autoUpdate"`
|
|
DomainFrontingPort TypePort `json:"domainFrontingPort"`
|
|
DomainFrontingIP TypeIP `json:"domainFrontingIp"`
|
|
DomainFrontingProxyProtocol TypeBool `json:"domainFrontingProxyProtocol"`
|
|
TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"`
|
|
Concurrency TypeConcurrency `json:"concurrency"`
|
|
DomainFronting struct {
|
|
IP TypeIP `json:"ip"`
|
|
Port TypePort `json:"port"`
|
|
ProxyProtocol TypeBool `json:"proxyProtocol"`
|
|
} `json:"domainFronting"`
|
|
Defense struct {
|
|
AntiReplay struct {
|
|
Optional
|
|
|
|
MaxSize TypeBytes `json:"maxSize"`
|
|
ErrorRate TypeErrorRate `json:"errorRate"`
|
|
} `json:"antiReplay"`
|
|
Blocklist ListConfig `json:"blocklist"`
|
|
Allowlist ListConfig `json:"allowlist"`
|
|
Doppelganger struct {
|
|
URLs []TypeHttpsURL `json:"urls"`
|
|
Repeats TypeConcurrency `json:"repeats_per_raid"`
|
|
UpdateEach TypeDuration `json:"raid_each"`
|
|
DRS TypeBool `json:"drs"`
|
|
NoiseProbeCount TypeConcurrency `json:"noise_probe_count"`
|
|
NoiseCacheTTL TypeDuration `json:"noise_cache_ttl"`
|
|
NoiseCachePath string `json:"noise_cache_path"`
|
|
} `json:"doppelganger"`
|
|
} `json:"defense"`
|
|
Network struct {
|
|
Timeout struct {
|
|
TCP TypeDuration `json:"tcp"`
|
|
HTTP TypeDuration `json:"http"`
|
|
Idle TypeDuration `json:"idle"`
|
|
} `json:"timeout"`
|
|
DOHIP TypeIP `json:"dohIp"`
|
|
DNS TypeDNSURI `json:"dns"`
|
|
Proxies []TypeProxyURL `json:"proxies"`
|
|
} `json:"network"`
|
|
Stats struct {
|
|
StatsD struct {
|
|
Optional
|
|
|
|
Address TypeHostPort `json:"address"`
|
|
MetricPrefix TypeMetricPrefix `json:"metricPrefix"`
|
|
TagFormat TypeStatsdTagFormat `json:"tagFormat"`
|
|
} `json:"statsd"`
|
|
Prometheus struct {
|
|
Optional
|
|
|
|
BindTo TypeHostPort `json:"bindTo"`
|
|
HTTPPath TypeHTTPPath `json:"httpPath"`
|
|
MetricPrefix TypeMetricPrefix `json:"metricPrefix"`
|
|
} `json:"prometheus"`
|
|
} `json:"stats"`
|
|
}
|
|
|
|
func (c *Config) GetConcurrency(defaultValue uint) uint {
|
|
if concurrency := c.Concurrency.Get(0); concurrency != 0 {
|
|
return concurrency
|
|
}
|
|
return c.Concurrency.Get(defaultValue)
|
|
}
|
|
|
|
func (c *Config) GetDNS() *url.URL {
|
|
var dohURL *url.URL
|
|
|
|
if dohIP := c.Network.DOHIP.Get(nil); dohIP != nil {
|
|
dohURL, _ = url.Parse("https://" + dohIP.String())
|
|
}
|
|
|
|
return c.Network.DNS.Get(dohURL)
|
|
}
|
|
|
|
func (c *Config) GetDomainFrontingPort(defaultValue uint) uint {
|
|
if port := c.DomainFronting.Port.Get(0); port != 0 {
|
|
return port
|
|
}
|
|
return c.DomainFrontingPort.Get(defaultValue)
|
|
}
|
|
|
|
func (c *Config) GetDomainFrontingIP(defaultValue net.IP) string {
|
|
if ip := c.DomainFronting.IP.Get(nil); ip != nil {
|
|
return ip.String()
|
|
}
|
|
if ip := c.DomainFrontingIP.Get(defaultValue); ip != nil {
|
|
return ip.String()
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (c *Config) GetDomainFrontingProxyProtocol(defaultValue bool) bool {
|
|
return c.DomainFronting.ProxyProtocol.Get(false) || c.DomainFrontingProxyProtocol.Get(defaultValue)
|
|
}
|
|
|
|
func (c *Config) Validate() error {
|
|
if !c.Secret.Valid() {
|
|
return fmt.Errorf("invalid secret %s", c.Secret.String())
|
|
}
|
|
|
|
if c.BindTo.Get("") == "" {
|
|
return fmt.Errorf("incorrect bind-to parameter %s", c.BindTo.String())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Config) String() string {
|
|
buf := &bytes.Buffer{}
|
|
encoder := json.NewEncoder(buf)
|
|
|
|
encoder.SetEscapeHTML(false)
|
|
|
|
if err := encoder.Encode(c); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return buf.String()
|
|
}
|