Files
x/handler/relay/metadata.go
T
ginuerzh d5fd62aa47 docs(handler/relay): convert all comments to English
Translate all Chinese comments in the relay handler package to English:
handler.go, connect.go, bind.go, forward.go, conn.go, entrypoint.go,
observe.go, metadata.go. All inline and doc comments are now in English.

Also set a persistent preference: all future code comments must be
written in English only.
2026-06-03 23:05:08 +08:00

151 lines
5.5 KiB
Go

package relay
import (
"crypto"
"crypto/tls"
"crypto/x509"
"time"
"github.com/go-gost/core/bypass"
mdata "github.com/go-gost/core/metadata"
"github.com/go-gost/x/internal/util/mux"
mdutil "github.com/go-gost/x/metadata/util"
"github.com/go-gost/x/registry"
)
// metadata holds the relay handler configuration parsed from the generic Metadata map.
type metadata struct {
// readTimeout is the deadline for reading the initial relay.Request handshake.
// Cleared immediately after the handshake, so it does not affect data transfer.
// Also passed to SnifferBuilder for upstream response header read timeout.
// Default: 15s (0 or negative falls back to 15s).
readTimeout time.Duration
// udpBufferSize is the buffer size (in bytes) for UDP datagram relay.
// Config keys: "udp.bufferSize", "udpBufferSize".
udpBufferSize int
// enableBind controls whether CmdBind is allowed.
// Disabled by default; set "bind: true" in config to enable.
enableBind bool
// noDelay controls whether the relay.Response header is sent immediately.
// When enabled, each write is an independent relay frame (low-latency).
// When disabled, the response header is buffered in wbuf and merged with
// the first data write.
noDelay bool
// hash specifies the consistent-hashing source. Currently supports "host",
// which uses the target address as the hash source for sticky sessions.
hash string
// muxCfg is the multiplexing session configuration, used only in BIND mode
// to upgrade the client connection to a mux session.
muxCfg *mux.Config
// observerPeriod is the stats event polling interval.
// Default: 5s, minimum: 1s.
// Config keys: "observePeriod", "observer.period", "observer.observePeriod".
observerPeriod time.Duration
// observerResetTraffic controls whether traffic counters are reset after
// each poll. When true, reported traffic is incremental; when false, cumulative.
observerResetTraffic bool
// sniffing enables protocol sniffing. When enabled, the handler detects
// the traffic protocol (HTTP/TLS) after connection establishment and
// selects the corresponding processing path (e.g. MITM decryption).
sniffing bool
// sniffingTimeout is the read deadline during sniffing.
sniffingTimeout time.Duration
// sniffingWebsocket enables WebSocket upgrade detection within sniffed HTTP.
sniffingWebsocket bool
// sniffingWebsocketSampleRate controls the sampling rate for WebSocket
// traffic recording (0.0 ~ 1.0).
sniffingWebsocketSampleRate float64
// certificate is the CA certificate used for MITM decryption.
certificate *x509.Certificate
// privateKey is the private key paired with the MITM certificate.
privateKey crypto.PrivateKey
// alpn is the TLS ALPN protocol list for MITM decryption.
alpn string
// mitmBypass is an allow/deny list of hostnames that skip MITM decryption.
mitmBypass bypass.Bypass
// limiterRefreshInterval is the traffic limiter cache refresh interval.
limiterRefreshInterval time.Duration
// limiterCleanupInterval is the traffic limiter cache cleanup interval.
limiterCleanupInterval time.Duration
}
// parseMetadata extracts typed configuration from the generic Metadata map.
//
// Rules:
// - Uses mdutil Get* helpers which support multiple fallback key names.
// - Numeric durations are treated as seconds; string durations use time.ParseDuration.
// - Unset or invalid values fall back to sensible defaults.
func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) {
h.md.readTimeout = mdutil.GetDuration(md, "readTimeout")
if h.md.readTimeout <= 0 {
h.md.readTimeout = 15 * time.Second
}
h.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize")
h.md.enableBind = mdutil.GetBool(md, "bind")
h.md.noDelay = mdutil.GetBool(md, "nodelay")
h.md.hash = mdutil.GetString(md, "hash")
h.md.muxCfg = &mux.Config{
Version: mdutil.GetInt(md, "mux.version"),
KeepAliveInterval: mdutil.GetDuration(md, "mux.keepaliveInterval"),
KeepAliveDisabled: mdutil.GetBool(md, "mux.keepaliveDisabled"),
KeepAliveTimeout: mdutil.GetDuration(md, "mux.keepaliveTimeout"),
MaxFrameSize: mdutil.GetInt(md, "mux.maxFrameSize"),
MaxReceiveBuffer: mdutil.GetInt(md, "mux.maxReceiveBuffer"),
MaxStreamBuffer: mdutil.GetInt(md, "mux.maxStreamBuffer"),
}
h.md.observerPeriod = mdutil.GetDuration(md, "observePeriod", "observer.period", "observer.observePeriod")
if h.md.observerPeriod == 0 {
h.md.observerPeriod = 5 * time.Second
}
if h.md.observerPeriod < time.Second {
h.md.observerPeriod = time.Second
}
h.md.observerResetTraffic = mdutil.GetBool(md, "observer.resetTraffic")
h.md.sniffing = mdutil.GetBool(md, "sniffing")
h.md.sniffingTimeout = mdutil.GetDuration(md, "sniffing.timeout")
h.md.sniffingWebsocket = mdutil.GetBool(md, "sniffing.websocket")
h.md.sniffingWebsocketSampleRate = mdutil.GetFloat(md, "sniffing.websocket.sampleRate")
certFile := mdutil.GetString(md, "mitm.certFile", "mitm.caCertFile")
keyFile := mdutil.GetString(md, "mitm.keyFile", "mitm.caKeyFile")
if certFile != "" && keyFile != "" {
tlsCert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return err
}
h.md.certificate, err = x509.ParseCertificate(tlsCert.Certificate[0])
if err != nil {
return err
}
h.md.privateKey = tlsCert.PrivateKey
}
h.md.alpn = mdutil.GetString(md, "mitm.alpn")
h.md.mitmBypass = registry.BypassRegistry().Get(mdutil.GetString(md, "mitm.bypass"))
h.md.limiterRefreshInterval = mdutil.GetDuration(md, "limiter.refreshInterval")
h.md.limiterCleanupInterval = mdutil.GetDuration(md, "limiter.cleanupInterval")
return
}