Sovite.Core.Screen (sovite v0.6.0)

Copy Markdown View Source

Anti-abuse checks of SMTP clients, run by Sovite.Core.SMTPHandler before its own checks of each stage. Clients in smtp.trusted_networks skip all of them.

The screen

On listeners with screen (by default those in smtp mode), each client gets a score, as with Postfix's postscreen:

  • The client address is looked up in the [[screen.dnsbl]] lists (Sovite.Abuse.DNSBL), in the background. Each list it is on adds its weight; allow lists such as DNSWL have negative weights.
  • With screen.greet_delay, the greeting waits that long. A client that talks first adds screen.early_talker_weight.
  • At EHLO and MAIL, the [[screen.rhsbl]] lists are checked for the EHLO name and the sender's domain.

A client that reaches screen.threshold is refused: before the greeting with 554 5.7.1, then the connection is closed; at EHLO or MAIL, that command gets 554 5.7.1. A client at or below screen.allow_threshold is allow-listed: the domain lists and greylisting are skipped. A client that passed the greeting, without talking first or a failed lookup, is remembered for screen.cache_time and not delayed or looked up again meanwhile.

Rate limits

The [rate_limit] limits count, per client address (per /64 for IPv6), new connections (421 4.7.0 and closed), messages (MAIL, 450 4.7.1), and recipients (450 4.7.1); and per authenticated user, messages and recipients. Authenticated clients only count against the user limits.

Greylisting

With greylist.enabled, a valid recipient from an unknown client network and sender is deferred with 450 4.7.1 until the client tries again after greylist.delay, see Sovite.Core.Greylist. Authenticated and allow-listed clients, and listeners without screen, skip it.

Outbound

Authenticated users whose mail fails too often are suspended, see Sovite.Core.Outbound; their MAIL gets 550 5.7.1.

Telemetry

  • [:sovite, :screen, :rejected] - %{score}, %{session_id, remote_ip, stage, reasons}, when a client reaches the threshold.

Summary

Functions

Starts screening the client: looks it up in the DNS lists, and asks for the greeting delay.

Scores the client before the greeting, see the moduledoc.

Checks the EHLO name in the RHSBL lists.

Counts the connection against rate_limit.client_connections.

Checks a MAIL command: suspension and sending limits of the user, message limits of the client, and the sender's domain in the RHSBL lists.

The screen state of a new session.

The options for a listener. runtime has :screen (the listener screens clients), :screen_cache (a Sovite.Abuse.Cache), :rate_limit (a Sovite.Abuse.RateLimit), :repo, and :outbound (Sovite.Core.Outbound options).

Checks an accepted recipient: greylisting, and the recipient limits of the user or the client.

Functions

connect(state)

@spec connect(map()) :: {:ok, map()} | {:pause, pos_integer(), map()}

Starts screening the client: looks it up in the DNS lists, and asks for the greeting delay.

greet(early, state)

@spec greet(binary(), map()) :: {:ok, map()} | {:close, Sovite.SMTP.Reply.t(), map()}

Scores the client before the greeting, see the moduledoc.

helo(state)

@spec helo(map()) :: {:ok, map()} | {:reply, Sovite.SMTP.Reply.t(), map()}

Checks the EHLO name in the RHSBL lists.

limit_connection(state)

@spec limit_connection(map()) :: {:ok, map()} | {:close, Sovite.SMTP.Reply.t(), map()}

Counts the connection against rate_limit.client_connections.

mail(sender, state)

@spec mail(String.t(), map()) :: {:ok, map()} | {:reply, Sovite.SMTP.Reply.t(), map()}

Checks a MAIL command: suspension and sending limits of the user, message limits of the client, and the sender's domain in the RHSBL lists.

new()

@spec new() :: map()

The screen state of a new session.

opts(config, runtime)

@spec opts(Sovite.Core.Config.t(), keyword()) :: map()

The options for a listener. runtime has :screen (the listener screens clients), :screen_cache (a Sovite.Abuse.Cache), :rate_limit (a Sovite.Abuse.RateLimit), :repo, and :outbound (Sovite.Core.Outbound options).

rcpt(recipient, state)

@spec rcpt(String.t(), map()) :: {:ok, map()} | {:reply, Sovite.SMTP.Reply.t(), map()}

Checks an accepted recipient: greylisting, and the recipient limits of the user or the client.