Skip to content

Bans at connection

When a player connects, Bastrel checks the bans in force before letting them in. The check reads memory only (the bans are loaded at startup and reloaded every 5 minutes), so it adds no database query to a connection.

Bastrel collects the player’s identifiers (license, license2, discord, fivem, steam when present, and the IP) and hardware tokens, then compares them with every ban in force. Values are compared whole, never as part of a string.

  • Strong match: a license, discord, fivem or steam identifier of a ban. The connection is refused, in every mode.
  • Weak match only: a hardware token or a license2 of a ban, with no strong identifier. This often means a second account on the same machine. Bastrel lets the player in (a shared machine is not proof), then raises BAS-CN-001 once they are in game, with their server id, and alerts the staff (in enforce).
  • The IP is never compared. Players behind the same connection (family, shared network) would be banned together. It is kept in the identifier tables only.

Which identifier types are strong or weak is set in config/modules.lua (bans.strongIdentifiers, bans.weakIdentifiers); the IP is refused in both.

Bastrel can compare a player’s license with the bans of other servers that agreed to share them. This feature is built but switched off: it does nothing unless the setting modules.netban.enabled is true, your plan includes it, your account opted in and the Bastrel API has enabled it; no plan includes it today.

When it is on, only a keyed hash of the license leaves your server (never the identifier itself, an IP or a hardware token), and the lookup starts once the player is in game, so a slow or unreachable API never delays a join. A match raises BAS-CN-002 and alerts the staff (in enforce); it adds nothing to the player’s score (weight 0), never refuses a connection and never bans. The decision stays with a human.

Read this before you opt in. Once your account has opted in and the feature is on for your plan, each ban your server records sends the network, for the player’s license only: a keyed hash of it (not the license itself), the ban code (for example BAS-MV-001) and the day of the ban. Never the reason, your server, your account, an IP, a hardware token or any other identifier. Other opted-in servers can learn that “a ban with this code exists since this day” for a license they ask about; they cannot read your ban or who issued it. In return, your server asks about each player who joins and receives, if there is a match, a count, the oldest day and opaque references with the code of each ban.

Settings in modules.netban: timeoutMs (200 to 3000 ms, default 1500), evidenceMax (references kept from an answer, 1 to 100, default 20; the API cuts at its own limit), queueReserve (places of the shared API queue always left free for the licence, the config and the uplink, 1 to 7, default 4). Players already online when Bastrel restarts are not asked about.

A refused player sees the ban id, the reason, and when the ban ends (or that it is permanent), in the language of config/main.lua (locale). To add a link to your appeal form or Discord, set it in config/main.lua:

appealUrl = 'https://discord.gg/your-server',

A ban id is not a secret and is not proof of identity: when a player appeals, check who they are by other means.

A ban in force refuses the connection in every mode, observe included: a ban is a decision already taken, not an automatic detection, and observe only covers automatic detections. This applies to every ban, manual ones included. The BAS-CN-001 staff alert (weak match) is only sent in enforce; in observe it is logged.

If the check fails for any reason, the player is let in and the error is logged (connect.failed). Bastrel never makes your server unreachable.

config/modules.lua, connection.onWeakMatch: what a weak match does. Only 'alert' exists: a weak match never refuses a connection and never bans.

connection.pendingMs (default 600000, 10 minutes): a weak match is kept from the connection until the player is in game. If the player takes longer than this to get in (a long queue in front of Bastrel, for example), the match is dropped with a connect.weakMatchExpired line and BAS-CN-001 is not raised: raise the value if your queue is longer.

With two Rockstar accounts on the same machine: ban account A, then connect with account B. B is accepted and, once in game, BAS-CN-001 is logged with the id of A’s ban and the types that matched (never their values).