d5fd62aa47
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.
151 lines
5.5 KiB
Go
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
|
|
} |