Skip to content

Shield events

The Shield raises three events. Unlike the other event handlers, they are not tied to a client session: they describe an address, and they fire from the engine that protects the virtual site, whether or not the address ever got a session. They exist so you can be told, in a script, what the Shield is doing: send a message, write to your own log, feed a firewall.

EventWhen it fires
OnShieldStrikeThe Shield recorded a strike against an address: a failed sign in, an unknown username, a dropped connection, handshake garbage.
OnShieldBanThe Shield banned an address or a network, automatically or because an operator or a script asked for it.
OnShieldBanHitA banned address tried to connect again and was refused at accept. Raised at most once per address per minute, however often it knocks.

Notification only

These events are notifications. The handler runs on its own queue, off the enforcement path, after the strike or the ban has already happened. A script on them cannot veto anything: the strike stays recorded and the ban stays in force whatever the script does. The engine never waits for a script either. If handlers cannot keep up with a flood of strikes, events are dropped rather than slowing authentication down, and the Shield page's Activity tab counts them as script events dropped.

Only the handlers configured on the virtual site run for these events. Users' own event handlers never do, because there is no user: the address has not signed in as anyone.

The default timeout

These events can be driven by a stranger, as often as they like, simply by failing to sign in. A handler on them therefore gets the short default timeout of 30 seconds when its own timeout is left at zero, like every other event that can fire before authentication. Keep these handlers quick.

What the script can read

EventCtx() carries the address and the ban. VirtualSite is filled as always; the other fields of the context are empty, since there is no file and no user.

FieldMeaning
ClientIPThe address the event is about.
TargetThe banned address or network. The same as ClientIP for a strike.
IsCIDRtrue when Target is a network.
RuleWhich rule fired: auth_failures, slow_burn, enumeration, connect_abandon, subnet_pool, protocol_probe, operator or script.
ProtocolThe protocol the address was using: ssh, ftp, ftps, ftpes, https, share or r2fs.
DetailWhat the rule observed, in plain words.
ExpiresOnWhen the ban lifts, as an RFC 3339 UTC timestamp. Empty for a permanent ban, and for a strike.
Permanenttrue for a permanent ban.
UsernameFor OnShieldStrike, the username that was tried, when the strike was a failed sign in. Empty otherwise.

The Session object is a detached one: Session.GetRemoteAddress() returns the address, and Terminate() does nothing, because there is no connection to end.

Example: a Slack message for every ban

ts
{
  var ctx = EventCtx();
  var when = ctx.Permanent ? "permanently" : "until " + ctx.ExpiresOn;
  var what = ctx.IsCIDR ? "network " + ctx.Target : "address " + ctx.Target;
  var text = "Shield banned " + what + " on " + ctx.VirtualSite + " " + when +
    " (" + ctx.Rule + ", " + ctx.Protocol + "): " + ctx.Detail;
  var resp = HttpClient.Post("https://hooks.slack.com/services/T000/B000/XXXX",
    JSON.stringify({ text: text }), { "Content-Type": "application/json" });
  if (resp.StatusCode != 200) {
    Log.Warn("Slack refused the ban notice: " + resp.StatusCode);
  }
}

Bind the script to OnShieldBan in the virtual site's event handlers. Mark it as running asynchronously if the webhook is slow; the engine does not wait either way.