Documentation
¶
Index ¶
- Constants
- Variables
- func DefaultProxyProtocolTrustedProxies() []string
- func ResolveProxyProtocolTrustedProxies(configured []string) []string
- type Auth
- type Compression
- type Config
- type ForcedHosts
- type Forwarding
- type ForwardingMode
- type OfflineModeUsernameBlacklistScope
- type PacketLimiter
- type PermissionSet
- type Permissions
- type Query
- type Quota
- type QuotaSettings
- type Status
- type Via
Constants ¶
const ( MinPrivateKeyBits = 1024 MaxPrivateKeyBits = 8192 )
Bounds for the operator-configurable login RSA key size. The lower bound is crypto/rsa's own minimum (rsa.GenerateKey rejects anything smaller); the upper bound keeps a typo from stalling startup with an enormous key generation. auth.DefaultPrivateKeyBits stays the default.
Variables ¶
var DefaultConfig = Config{ Bind: "0.0.0.0:25565", OnlineMode: true, Auth: Auth{}, OnlineModeKickExistingPlayers: false, OfflineModeUsernameBlacklistScope: OfflineModeUsernameBlacklistScopeAll, OfflineModeUsernameBlacklistReason: text("§cThis username is reserved for its authenticated owner."), Forwarding: Forwarding{ Mode: LegacyForwardingMode, VelocitySecret: "", }, Status: Status{ ShowMaxPlayers: 1000, Motd: defaultMotd(), Favicon: "data:image/png;base64,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", LogPingRequests: false, }, Query: Query{ Enabled: false, Port: 25577, ShowPlugins: false, }, AnnounceForge: false, Servers: map[string]string{}, Try: []string{}, ForcedHosts: map[string][]string{}, FailoverOnUnexpectedServerDisconnect: true, ConnectionTimeout: configutil.Duration(5000 * time.Millisecond), ReadTimeout: configutil.Duration(30000 * time.Millisecond), Quota: Quota{ Connections: QuotaSettings{ Enabled: true, OPS: 5, Burst: 10, MaxEntries: 1000, }, Logins: QuotaSettings{ Enabled: true, OPS: 0.4, Burst: 3, MaxEntries: 1000, }, }, PacketLimiter: PacketLimiter{ Interval: configutil.Duration(7 * time.Second), PacketsPerSecond: 500, BytesPerSecond: -1, }, Compression: Compression{ Threshold: 256, Level: -1, }, ProxyProtocol: false, ProxyProtocolBackend: false, ShouldPreventClientProxyConnections: false, BungeePluginChannelEnabled: true, BuiltinCommands: true, RequireBuiltinCommandPermissions: false, AnnounceProxyCommands: true, Debug: false, ShutdownReason: defaultShutdownReason(), ForceKeyAuthentication: true, Lite: liteconfig.DefaultConfig, Bedrock: bconfig.DefaultBedrockConfig, }
DefaultConfig is a default Config.
Functions ¶
func DefaultProxyProtocolTrustedProxies ¶ added in v0.68.31
func DefaultProxyProtocolTrustedProxies() []string
DefaultProxyProtocolTrustedProxies returns the upstreams whose PROXY protocol header is trusted when Config.ProxyProtocolTrustedProxies is empty.
It covers the loopback, private and link-local networks a PROXY protocol sender is normally deployed in (a load balancer sidecar, a Kubernetes ingress, a cloud platform's internal network), but never the public internet: anybody able to open a TCP connection to the proxy from a public address must not be able to assert an arbitrary client IP. Operators fronting Gate with a proxy that has a public address must list it explicitly.
A new slice is returned on every call so callers cannot mutate the defaults.
func ResolveProxyProtocolTrustedProxies ¶ added in v0.68.31
ResolveProxyProtocolTrustedProxies returns the configured trusted upstreams, falling back to DefaultProxyProtocolTrustedProxies when none are configured.
Types ¶
type Auth ¶ added in v0.34.0
type Auth struct {
// SessionServerURL is the base URL for the Mojang session server to authenticate online mode players.
// Defaults to https://sessionserver.mojang.com/session/minecraft/hasJoined
SessionServerURL *configutil.URL `yaml:"sessionServerUrl"` // TODO support multiple urls configutil.SingleOrMulti[URL]
// PrivateKeyBits is the bit size of the RSA key Gate generates at startup to
// encrypt the login handshake of online mode players.
// Defaults to 1024 bits, the size vanilla Minecraft servers use.
// Raise it to 2048 or 3072 if your clients and tools accept a larger key;
// note the key is generated once at startup, so changing this requires a restart.
PrivateKeyBits int `yaml:"privateKeyBits" json:"privateKeyBits,omitempty"`
}
Auth is the config for authentication.
type Compression ¶
type Config ¶
type Config struct {
Bind string `yaml:"bind"` // The address to listen for connections.
OnlineMode bool `yaml:"onlineMode,omitempty" json:"onlineMode,omitempty"` // Whether to enable online mode.
Auth Auth `yaml:"auth,omitempty" json:"auth,omitempty"` // Authentication settings.
OnlineModeKickExistingPlayers bool `yaml:"onlineModeKickExistingPlayers,omitempty" json:"onlineModeKickExistingPlayers,omitempty"` // Kicks existing players when a premium player with the same name joins.
// OfflineModeUsernameBlacklist reserves names only on login paths that are effectively
// offline mode. Authenticated joins remain allowed to use the same names.
// A login is effectively offline mode when the proxy runs offline mode or when the
// session's identity is an unauthenticated offline identity (e.g. an offline/cracked
// player arriving through Connect with the offline UUID of the requested name), so
// the reservation also applies on an online-mode proxy for names claimed without
// Mojang authentication.
OfflineModeUsernameBlacklist []string `yaml:"offlineModeUsernameBlacklist,omitempty" json:"offlineModeUsernameBlacklist,omitempty"`
OfflineModeUsernameBlacklistScope OfflineModeUsernameBlacklistScope `yaml:"offlineModeUsernameBlacklistScope,omitempty" json:"offlineModeUsernameBlacklistScope,omitempty"`
OfflineModeUsernameBlacklistReason *configutil.TextComponent `yaml:"offlineModeUsernameBlacklistReason,omitempty" json:"offlineModeUsernameBlacklistReason,omitempty"`
Forwarding Forwarding `yaml:"forwarding,omitempty" json:"forwarding,omitempty"` // Player info forwarding settings.
Status Status `yaml:"status,omitempty" json:"status,omitempty"` // Status response settings.
Query Query `yaml:"query,omitempty" json:"query,omitempty"` // Query settings.
// Whether the proxy should present itself as a
// Forge/FML-compatible server. By default, this is disabled.
AnnounceForge bool `yaml:"announceForge,omitempty" json:"announceForge,omitempty"`
Servers map[string]string `yaml:"servers,omitempty" json:"servers,omitempty"` // name:address
Try []string `yaml:"try,omitempty" json:"try,omitempty"` // Try server names order
ForcedHosts ForcedHosts `yaml:"forcedHosts,omitempty" json:"forcedHosts,omitempty"`
FailoverOnUnexpectedServerDisconnect bool `yaml:"failoverOnUnexpectedServerDisconnect,omitempty" json:"failoverOnUnexpectedServerDisconnect,omitempty"`
ConnectionTimeout configutil.Duration `yaml:"connectionTimeout,omitempty" json:"connectionTimeout,omitempty"` // Write timeout
ReadTimeout configutil.Duration `yaml:"readTimeout,omitempty" json:"readTimeout,omitempty"` // Read timeout
Quota Quota `yaml:"quota,omitempty" json:"quota,omitempty"` // Rate limiting settings
PacketLimiter PacketLimiter `yaml:"packetLimiter,omitempty" json:"packetLimiter,omitempty"` // Per-connection serverbound packet rate limiting
Compression Compression `yaml:"compression,omitempty" json:"compression,omitempty"`
ProxyProtocol bool `yaml:"proxyProtocol,omitempty" json:"proxyProtocol,omitempty"` // Enable HA-Proxy protocol mode
ProxyProtocolBackend bool `yaml:"proxyProtocolBackend" json:"proxyProtocolBackend,omitempty"` // Enable HA-Proxy protocol mode for backend servers
// ProxyProtocolTrustedProxies lists the upstreams (IP addresses or CIDR
// blocks) whose PROXY protocol header is trusted to carry the real client
// address. A header sent by any other peer is rejected, so a client that can
// reach the proxy directly cannot claim to connect from somebody else's IP.
// When empty, DefaultProxyProtocolTrustedProxies is used.
// Used for client connections when ProxyProtocol is enabled; entries are still
// validated while it is disabled.
ProxyProtocolTrustedProxies []string `yaml:"proxyProtocolTrustedProxies,omitempty" json:"proxyProtocolTrustedProxies,omitempty"`
ShouldPreventClientProxyConnections bool `yaml:"shouldPreventClientProxyConnections" json:"shouldPreventClientProxyConnections,omitempty"` // Sends player IP to Mojang on login
AcceptTransfers bool `yaml:"acceptTransfers,omitempty" json:"acceptTransfers,omitempty"` // Whether to accept transfers from other hosts via transfer packet
BungeePluginChannelEnabled bool `yaml:"bungeePluginChannelEnabled,omitempty" json:"bungeePluginChannelEnabled,omitempty"` // Whether to enable BungeeCord plugin messaging
BuiltinCommands bool `yaml:"builtinCommands,omitempty" json:"builtinCommands,omitempty"` // Whether to enable builtin commands
RequireBuiltinCommandPermissions bool `yaml:"requireBuiltinCommandPermissions,omitempty" json:"requireBuiltinCommandPermissions,omitempty"` // Whether builtin commands require player permissions
AnnounceProxyCommands bool `yaml:"announceProxyCommands,omitempty" json:"announceProxyCommands,omitempty"` // Whether to announce proxy commands to players
ForceKeyAuthentication bool `yaml:"forceKeyAuthentication,omitempty" json:"forceKeyAuthentication,omitempty"` // Added in 1.19
// Permissions configures Gate's built-in, file-backed permission provider:
// it answers a player's PermissionsSetupEvent at login, so builtin commands
// can be granted per player without a Go extension (see Permissions).
Permissions Permissions `yaml:"permissions,omitempty" json:"permissions,omitempty"`
Debug bool `yaml:"debug,omitempty" json:"debug,omitempty"` // Enable debug mode
ShutdownReason *configutil.TextComponent `yaml:"shutdownReason,omitempty" json:"shutdownReason,omitempty"`
Lite liteconfig.Config `yaml:"lite,omitempty" json:"lite,omitempty"` // Lite mode settings
Via Via `yaml:"via,omitempty" json:"via,omitempty"` // Via backend compatibility settings
// Bedrock edition configuration
Bedrock bconfig.BedrockConfig `yaml:"bedrock,omitempty" json:"bedrock,omitempty"`
}
Config is the configuration of the proxy.
type ForcedHosts ¶
type Forwarding ¶
type Forwarding struct {
Mode ForwardingMode `yaml:"mode"`
VelocitySecret string `yaml:"velocitySecret"` // Used with "velocity" mode
BungeeGuardSecret string `yaml:"bungeeGuardSecret"` // Used with "bungeeguard" mode
}
type ForwardingMode ¶
type ForwardingMode string
ForwardingMode is a player info forwarding mode.
const ( NoneForwardingMode ForwardingMode = "none" LegacyForwardingMode ForwardingMode = "legacy" // VelocityForwardingMode is a forwarding mode specified by the Velocity java proxy and // supported by PaperSpigot for versions starting at 1.13. VelocityForwardingMode ForwardingMode = "velocity" // BungeeGuardForwardingMode is a forwarding mode used by versions lower than 1.13 BungeeGuardForwardingMode ForwardingMode = "bungeeguard" )
type OfflineModeUsernameBlacklistScope ¶ added in v0.73.0
type OfflineModeUsernameBlacklistScope string
OfflineModeUsernameBlacklistScope selects which offline-mode login paths apply OfflineModeUsernameBlacklist.
const ( // OfflineModeUsernameBlacklistScopeAll is deliberately the default for // compatibility with configurations created before this setting existed. OfflineModeUsernameBlacklistScopeAll OfflineModeUsernameBlacklistScope = "all" // OfflineModeUsernameBlacklistScopeConnect applies the reservation only to // connections created by Gate's authenticated Connect tunnel adapter. OfflineModeUsernameBlacklistScopeConnect OfflineModeUsernameBlacklistScope = "connect" )
type PacketLimiter ¶ added in v0.65.0
type PacketLimiter struct {
Interval configutil.Duration `yaml:"interval"` // Sliding window the rates are measured over.
PacketsPerSecond int `yaml:"packetsPerSecond"` // Max serverbound packets/s per connection (<=0 disables).
BytesPerSecond int `yaml:"bytesPerSecond"` // Max serverbound bytes/s per connection (<=0 disables).
}
PacketLimiter limits how many serverbound packets/bytes a single connection may send over a sliding window, mitigating packet floods from already connected clients (the Quota limits only apply at connect/login time). A limit <= 0 disables that dimension; if both are <= 0 the limiter is off.
type PermissionSet ¶ added in v0.76.0
type PermissionSet struct {
// contains filtered or unexported fields
}
PermissionSet is a validated and normalized Permissions block.
Entries are keyed by the player identity they select, so a lookup does not have to compare keys case-insensitively: "uuid:<canonical>" or "name:<lowercase>".
func (*PermissionSet) ValueFor ¶ added in v0.76.0
func (s *PermissionSet) ValueFor(id uuid.UUID, username, node string) permission.TriState
ValueFor returns the tri-state of node for the player identified by id and username: True on a matching grant, False on a matching deny and Undefined otherwise, leaving nodes this block does not know to other providers.
type Permissions ¶ added in v0.76.0
type Permissions struct {
// Default is granted to every player without an entry in Players.
Default []string `yaml:"default,omitempty" json:"default,omitempty"`
// Players maps a player UUID or username to the nodes granted to it.
// A listed player replaces Default.
Players map[string][]string `yaml:"players,omitempty" json:"players,omitempty"`
// Deny maps a player UUID or username to explicitly denied nodes.
Deny map[string][]string `yaml:"deny,omitempty" json:"deny,omitempty"`
}
Permissions configures Gate's built-in, file-backed permission provider.
It is the config-only answer to "how do I let players use /server but not /send" without writing a Go extension: the provider answers proxy.PermissionsSetupEvent for every player at login and leaves any node it does not know undefined, so other providers (extensions, plugins) still decide those. See https://github.com/minekube/gate/issues/1293.
Semantics:
- default: granted to every player that has no entry under players.
- players: a listed player REPLACES default, so an entry grants exactly the nodes it lists.
- deny: explicit denials always win, over default and over players.
Keys are player UUIDs or, as a convenience only, usernames matched case-insensitively (an offline-mode name is not an identity, so prefer UUIDs). Values are permission nodes, a trailing-wildcard prefix such as gate.command.*, or * for everything.
func (Permissions) Build ¶ added in v0.76.0
func (p Permissions) Build() (*PermissionSet, error)
Build validates and normalizes the block.
A nil set with a nil error means the block is empty: no provider must be registered and behaviour stays exactly as before this feature existed.
func (Permissions) Empty ¶ added in v0.76.0
func (p Permissions) Empty() bool
Empty reports whether no permission is configured at all.
func (Permissions) Validate ¶ added in v0.76.0
func (p Permissions) Validate() []error
Validate reports every problem in the block, so a typo fails config validation at startup instead of silently not matching at runtime.
type Quota ¶
type Quota struct {
Connections QuotaSettings `yaml:"connections"` // Limits new connections per second, per IP block.
Logins QuotaSettings `yaml:"logins"` // Limits logins per second, per IP block.
}
Quota is the config for rate limiting.
type QuotaSettings ¶
type QuotaSettings struct {
Enabled bool `yaml:"enabled"` // If false, there is no such limiting.
OPS float32 `yaml:"ops"` // Allowed operations/events per second, per IP block
Burst int `yaml:"burst"` // The maximum events per second, per block; the size of the token bucket
MaxEntries int `yaml:"maxEntries"` // Maximum number of IP blocks to keep track of in cache
}
type Via ¶ added in v0.66.36
type Via struct {
// Enabled starts the managed ViaLite runtime for backend connections.
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
// Mode is "subprocess" (portable default) or "embedded" (in-process
// shared library). Empty means subprocess.
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
// Bind is the runtime's internal loopback bind address. Empty picks a
// free port on 127.0.0.1.
Bind string `yaml:"bind,omitempty" json:"bind,omitempty"`
// LibraryPath uses that shared library instead of resolving one.
LibraryPath string `yaml:"libraryPath,omitempty" json:"libraryPath,omitempty"`
// BinaryPath uses that vialite binary for subprocess mode.
BinaryPath string `yaml:"binaryPath,omitempty" json:"binaryPath,omitempty"`
// Version selects the runtime release. Empty, "auto" and "latest" all
// mean the newest stable ViaLite release, resolved once at startup, so a
// newly published runtime applies on the next Gate restart (there is no
// hot swap). This is independent of the Go module version Gate links.
// With Mirror set, the mirror's own latest release is used; a mirror that
// cannot report one falls back to a compiled-in release and logs a
// warning. Set an exact tag such as "v0.3.1" to pin a rollout.
Version string `yaml:"version,omitempty" json:"version,omitempty"`
// Mirror overrides the release download base (GitHub release URL layout,
// optionally serving <mirror>/latest for version resolution).
Mirror string `yaml:"mirror,omitempty" json:"mirror,omitempty"`
// Offline disables runtime downloads entirely: BinaryPath/LibraryPath, an
// embedded artifact, or one on $PATH must be present.
Offline bool `yaml:"offline,omitempty" json:"offline,omitempty"`
}
Via configures managed ViaLite support: Via-powered Java protocol translation for backend connections, Gate classic only. Gate accepts the player and picks a backend; ViaLite translates the backend-facing protocol when client and backend versions differ.