Skip to content

Hardening

Tsu edited this page Jun 6, 2026 · 3 revisions

This page covers Stratum controls that protect the server from bad or abusive client behavior.

Source of Truth

  • Config model: sources/VintagestoryLib/Vintagestory.Server/StratumConfig.cs (hardening-related sections)
  • Runtime guards: sources/VintagestoryLib/Vintagestory.Server/StratumPacketLimiter.cs, sources/VintagestoryLib/Vintagestory.Server/StratumPacketBackPressure.cs, sources/VintagestoryLib/Vintagestory.Server/StratumBlockBreakGuard.cs, sources/VintagestoryLib/Vintagestory.Server/StratumLoginProtection.cs, sources/VintagestoryLib/Vintagestory.Server/StratumPlayerPrivacy.cs
  • Hook/wiring: sources/VintagestoryLib/Vintagestory.Server/StratumRuntime.cs, sources/VintagestoryLib/Vintagestory.Server/ServerSystemStratum.cs, related patches/ entries

The canonical config model is StratumConfig and runtime wiring starts in StratumRuntime and ServerSystemStratum.

Packet Limits

PacketLimits is handled by StratumRuntime.PacketLimiter (StratumPacketLimiter).

These settings cap packet traffic per client and per packet type, with optional violation-based disconnects.

stratum.default.json:

"PacketLimits": {
  "Enabled": true,
  "DropViolations": true,
  "LogViolations": false,
  "KickViolations": true,
  "KickInvalidPackets": true,
  "KickOversizedCustomPackets": true,
  "KickAfterViolations": 8,
  "KickMessage": "Disconnected by Stratum packet protection",
  "WindowSeconds": 5,
  "DefaultMaxPackets": 300,
  "MovementMaxPackets": 420,
  "InventoryMaxPackets": 90,
  "BlockInteractionMaxPackets": 140,
  "EntityInteractionMaxPackets": 140,
  "HandInteractionMaxPackets": 90,
  "CustomPacketMaxPackets": 120,
  "CustomPacketMaxBytes": 262144
}

/stratum packets returns the limiter report through:

return TextCommandResult.Success(StratumRuntime.PacketLimiter.BuildReport() + "\n" + StratumRuntime.BlockBreakGuard.BuildReport());

Packet Back-Pressure

PacketBackPressure is handled by StratumRuntime.PacketBackPressure (StratumPacketBackPressure).

Back-pressure is separate from packet limits:

  • limits classify/rate-limit abusive input
  • back-pressure caps main-thread packet drain work per tick
public bool Enabled { get; set; } = true;
public int MaxMillisecondsPerTick { get; set; } = 25;
public int MaxPacketsPerClientPerTick { get; set; } = 32;
public int MaxQueueDepthPerClient { get; set; } = 2000;
public bool KickOnQueueOverflow { get; set; } = true;

See deep dive: Feature: Packet Back-Pressure.

Block Break Guards

BlockBreakGuards is handled by StratumRuntime.BlockBreakGuard (StratumBlockBreakGuard) and called from block break handling in ServerSystemBlockSimulation.

Config shape:

public bool Enabled { get; set; } = true;
public bool RequireServerSelection { get; set; } = false;
public bool DropViolations { get; set; } = true;
public bool LogViolations { get; set; } = false;
public bool KickViolations { get; set; } = false;
public int KickAfterViolations { get; set; } = 12;
public int ViolationWindowSeconds { get; set; } = 20;
public float RequiredProgressRatio { get; set; } = 0.5f;
public float GraceSeconds { get; set; } = 0.5f;
public float MinimumTrackedBreakSeconds { get; set; } = 0.5f;
public float PartialProgressRetentionSeconds { get; set; } = 8f;
public float MaxRememberedProgressRatio { get; set; } = 0.95f;
public int MaxRememberedPartialBreaksPerClient { get; set; } = 24;

Fast or trivial breaks can be accepted without tracked-progress checks:

if (resistance <= 0f || expectedBreakSeconds <= Math.Max(0f, config.MinimumTrackedBreakSeconds))
{
    return true;
}

Partial progress is remembered for a short window after the player stops mining or changes target. This covers normal vanilla partial block damage without accepting stale progress forever.

Violation window and kick threshold are enforced by per-client rolling state:

state.RegisterViolation(now, Math.Max(1, config.ViolationWindowSeconds));
shouldKick = config.KickViolations && config.KickAfterViolations > 0 && state.ViolationsInWindow >= config.KickAfterViolations;

See deep dive: Feature: Block Break Guard.

Client Mod Policy

ClientModPolicy is implemented in StratumRuntime.BuildClientModWhitelist(...).

When both Enabled and StrictWhitelist are true, Stratum builds a whitelist from:

  • server universal mods (optional)
  • server config whitelist entries
  • explicit AllowModIds
"ClientModPolicy": {
  "Enabled": true,
  "StrictWhitelist": true,
  "IncludeServerUniversalMods": true,
  "AllowModIds": [],
  "LogPolicyOnStartup": true
}

Login Protection

LoginProtection is implemented in StratumLoginProtection.

On join, Stratum starts the engine invulnerability activity timer and tracks per-player protection state:

player.Entity.SetActivityRunning("invulnerable", (int)durationMs);

Protection ends on timeout or configured cancel conditions (movement and/or fire/lava).

"LoginProtection": {
  "Enabled": true,
  "ProtectionSeconds": 5,
  "CancelOnHorizontalMove": true,
  "MoveThresholdBlocks": 0.5,
  "CancelInFireOrLava": true,
  "AnnounceOnStart": true,
  "AnnounceOnEnd": true
}

Player Privacy

PlayerPrivacy is implemented in StratumPlayerPrivacy and connected through PlayerMapDisclosureHook.

At startup it can also push world config overrides such as render distance:

server.api.World.Config.SetFloat("mapPlayerRenderDistance", cfg.MaxBroadcastDistanceBlocks);

And disclosure decisions are made in AllowMapPinDisclosure(...) and CoordinateSnap(...).

"PlayerPrivacy": {
  "Enabled": false,
  "HideMapPins": true,
  "AllowGroupMapVisibility": true,
  "CoordinateSnapBlocks": 0,
  "MaxBroadcastDistanceBlocks": -1
}

ServerSystemStratum.OnBeginRunGame calls StratumPlayerPrivacy.Initialize(server).

Related References

For commands/chat/theme/nametags/identity, see Commands and Identity.

For runtime tuning that affects load rather than hardening policy, see Performance.

Clone this wiki locally