Provided by: opensmtpd_7.5.0p0-1_amd64 bug

NAME

       smtpd-filters — filtering API for the smtpd daemon

DESCRIPTION

       The smtpd(8) daemon provides a Simple Mail Transfer Protocol (SMTP) implementation, which allows ordinary
       machines  to  become  Mail eXchangers (MX).  Some features that are commonly used by MX, such as delivery
       reporting or spam filtering, are outside the scope of SMTP and too complex to fit in smtpd(8).

       Because an MX may need to provide these features, smtpd(8) provides an API to extend its behavior through
       smtpd-filters.

       At runtime, smtpd(8) can report events to smtpd-filters, querying what it should answer to these  events.
       This allows the decision logic to rely on third-party programs.

DESIGN

       smtpd-filters  are  programs  that  run as unique standalone processes, they do not share smtpd(8) memory
       space.  They are executed by smtpd(8) at startup and expected to run in an infinite loop, reading  events
       and  filtering requests from stdin(4), writing responses to stdout(4) and logging to stderr(4).  They are
       not allowed to terminate.

       Because smtpd-filters are standalone programs that communicate with smtpd(8) through fd(4), they may  run
       as different users than smtpd(8) and may be written in any language.  smtpd-filters must not use blocking
       I/O, they must support answering asynchronously to smtpd(8).

REPORT AND FILTER

       The API relies on two streams, report and filter.

       The  report  stream  is a one-way stream which allows smtpd(8) to inform smtpd-filters in real-time about
       events.  Report events do not expect an answer  from  smtpd-filters;  they  are  just  meant  to  provide
       information.   A  filter  should  be  able  to  replicate  the  smtpd(8) state for a session by gathering
       information coming from report events.  No decision is ever taken by the report stream.

       The filter stream is a two-way stream which allows smtpd(8) to query smtpd-filters about what  it  should
       do  with  a session at a given phase.  Filter requests expect an answer from smtpd-filters; smtpd(8) will
       not let the session move forward until then.  A decision must always be taken by the filter stream.

       It is sometimes possible to rely on filter requests to gather information,  but  because  a  response  is
       expected  by  smtpd(8),  this  is  more costly than using report events.  The correct pattern for writing
       filters is to use report events to create a local state for a session, then use filter requests  to  take
       decisions  based  on  this  state.   The only case when using filter requests instead of report events is
       correct is when a decision is required for the filter request and there is no need for  more  information
       than that of the event itself.

PROTOCOL

       The  protocol  consists  of  human-readable  lines  exchanged between smtpd-filters and smtpd(8), through
       fd(4).

       The protocol begins with a handshake.  First, smtpd(8) provides smtpd-filters with general  configuration
       information in the form of key-value lines:

             config|smtpd-version|6.6.1
             config|smtp-session-timeout|300
             config|subsystem|smtp-in
             config|ready

       Then, smtpd-filters register the stream, subsystem and event they want to handle:

             register|report|smtp-in|link-connect
             register|ready

       Finally,  smtpd(8)  emits  report  events  and filter requests, expecting smtpd-filters to respond or not
       depending on the stream:

             report|0.5|1576146008.006099|smtp-in|link-connect|7641df9771b4ed00|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25
             report|0.5|1576147242.200225|smtp-in|link-connect|7641dfb3798eb5bf|mail.openbsd.org|pass|199.185.178.25:31205|45.77.67.80:25
             report|0.5|1576148447.982572|smtp-in|link-connect|7641dfc063102cbd|mail.openbsd.org|pass|199.185.178.25:24786|45.77.67.80:25

       The character “|” may only appear in the last field of a payload, in which case it should be considered a
       regular character and not a separator.  No other field may contain a “|”.

       The list of subsystems and events, as well as the format of requests and responses, are documented in the
       sections below.

CONFIGURATION

       During the initial handshake, smtpd(8) emits a series of configuration keys  and  values.   The  list  is
       meant to be ignored by smtpd-filters that do not require it and consumed gracefully by filters that do.

       There are currently three keys:

             config|smtpd-version|6.6.1
             config|smtp-session-timeout|300
             config|subsystem|smtp-in

       When smtpd(8) has sent all configuration keys, it emits the following line:

             config|ready

REPORT EVENTS

       There is currently only one subsystem supported in the API: smtp-in.

       Each report event is generated by smtpd(8) as a single line similar to the one below:

             report|0.5|1576146008.006099|smtp-in|link-connect|7641df9771b4ed00|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25

       The  format consists of a protocol prefix containing the stream, the protocol version, the timestamp, the
       subsystem, the event and the unique session identifier, separated by “|”:

             report|0.5|1576146008.006099|smtp-in|link-connect|7641df9771b4ed00

       It is followed by a suffix containing the event-specific parameters, also separated by “|”:

             mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25

       The list of events and event-specific parameters for smtp-in are as follows:

       link-connect: rdns fcrdns src dest
               This event is generated upon connection.

               rdns contains the reverse DNS hostname for the remote end or an empty string if none.

               fcrdns contains the string “pass” or “fail” depending on if the remote end validates FCrDNS.

               src contains either the IP address and port of the source address, in the format  “address:port”,
               or the path to a UNIX socket in the format “unix:/path”.

               dest  holds  either  the  IP  address  and  port  of  the  destination  address,  in  the  format
               “address:port”, or the path to a UNIX socket in the format “unix:/path”.

       link-greeting: hostname
               This event is generated upon display of the server banner.

               hostname contains the hostname displayed in the banner.

       link-identify: method identity
               This event is generated upon “HELO” or “EHLO” command from the client.

               method contains the string “HELO” or “EHLO” indicating the method used by the client.

               identity contains the identity provided by the client.

       link-tls: tls-string
               This event is generated upon successful negotiation of TLS.

               tls-string contains a colon-separated list of TLS  properties  including  the  TLS  version,  the
               cipher suite used by the session and the cipher strength in bits.

       link-disconnect
               This event is generated upon disconnection of the client.

       link-auth: result username
               This event is generated upon an authentication attempt by the client.

               result   contains  the  string  “pass”,  “fail”  or  “error”  depending  on  the  result  of  the
               authentication attempt.

               username contains the username used for the authentication attempt.

       tx-reset: [message-id]
               This event is generated when a transaction is reset.

               If reset took place during a transaction, message-id contains the identifier of  the  transaction
               being reset.

       tx-begin: message-id
               This event is generated when a transaction is initiated.

               message-id contains the identifier for the transaction.

       tx-mail: message-id result address
               This event is generated when client emits “MAIL FROM”.

               message-id contains the identifier for the transaction.

               result  contains  “ok” if the sender was accepted, “permfail” if it was rejected or “tempfail” if
               it was rejected for a transient error.

               address contains the e-mail address of the sender.  The address is normalized and sanitized,  the
               characters “<” and “>” are removed, along with any parameters to “MAIL FROM”.

       tx-rcpt: message-id result address
               This event is generated when client emits “RCPT TO”.

               message-id contains the identifier for the transaction.

               result  contains  “ok” if the recipient was accepted, “permfail” if it was rejected or “tempfail”
               if it was rejected for a transient error.

               address contains the e-mail address of the recipient.  The address is normalized  and  sanitized,
               the characters “<” and “>” are removed, along with any parameters to “RCPT TO”.

       tx-envelope: message-id envelope-id
               This event is generated when an envelope is accepted.

               envelope-id contains the unique identifier for the envelope.

       tx-data: message-id result
               This event is generated when client has emitted “DATA”.

               message-id contains the unique identifier for the transaction.

               result contains “ok” if server accepted the message for processing, “permfail” if it has not been
               accepted and “tempfail” if a transient error prevented message processing.

       tx-commit: message-id message-size
               This event is generated when a transaction has been accepted by the server.

               message-id contains the unique identifier for the SMTP transaction.

               message-size  contains  the  size  of  the  message  submitted  in  the  “DATA” phase of the SMTP
               transaction.

       tx-rollback: message-id
               This event is generated when a transaction has been rejected by the server.

               message-id contains the unique identifier for the SMTP transaction.

       protocol-client: command
               This event is generated for every command submitted by the client.  It contains the  raw  command
               as received by the server.

               command contains the command emitted by the client to the server.

       protocol-server: response
               This  event  is generated for every response emitted by the server.  It contains the raw response
               as emitted by the server.

               response contains the response emitted by the server to the client.

       filter-report: filter-kind name message
               This event is generated when a filter emits a report.

               filter-kind may be either “builtin” or “proc” depending on if the filter is an  smtpd(8)  builtin
               filter or a proc filter implementing the API.

               name is the name of the filter that generated the report.

               message is a filter-specific message.

       filter-response: phase response [param]
               This event is generated when a filter responds to a filtering request.

               phase contains the phase name for the request.  The phases are documented in the next section.

               response  contains  the  response  of  the  filter to the request, it is either one of “proceed”,
               “report”, “reject”, “disconnect”, “junk or” “rewrite”.

               If specified, param is the parameter to the response.

       timeout
               This event is generated when a timeout happens for a session.

FILTER REQUESTS

       There is currently only one subsystem supported in the API: smtp-in.

       Filter requests allow smtpd(8) to query smtpd-filters about what to do with a  session  at  a  particular
       phase.   In addition, they allow smtpd-filters to alter the content of a message by adding, modifying, or
       suppressing lines of input in a way that is similar to what program like sed(1) or grep(1) would do.

       Each filter request is generated by smtpd(8) as a single line similar  to  the  one  below.   Fields  are
       separated by the “|” character.

             filter|0.5|1576146008.006099|smtp-in|connect|7641df9771b4ed00|1ef1c203cc576e5d|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25

       The  format consists of a protocol prefix containing the stream, the protocol version, the timestamp, the
       subsystem, the filtering phase, the unique session identifier and an opaque token that the filter  should
       provide in its response:

             filter|0.5|1576146008.006099|smtp-in|connect|7641df9771b4ed00|1ef1c203cc576e5d

       It is followed by a suffix containing the phase-specific parameters of the filter request, also separated
       by “|”:

             mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25

       Unlike  with report events, smtpd(8) expects answers from filter requests and will not allow a session to
       move forward until the filter has instructed smtpd(8) how to treat it.

       For all phases except  “data-line”,  responses  must  follow  the  same  construct:  a  message  of  type
       “filter-result”,  followed  by the unique session id, the opaque token, a decision and optional decision-
       specific parameters:

             filter-result|7641df9771b4ed00|1ef1c203cc576e5d|proceed
             filter-result|7641df9771b4ed00|1ef1c203cc576e5d|reject|550 nope

       The possible decisions for a “filter-result” message are documented below.

       For the “data-line” phase, smtpd-filters are fed a stream  of  lines  corresponding  to  the  message  to
       filter, terminated by a single dot:

             filter|0.5|1576146008.006099|smtp-in|data-line|7641df9771b4ed00|1ef1c203cc576e5d|line 1
             filter|0.5|1576146008.006103|smtp-in|data-line|7641df9771b4ed00|1ef1c203cc576e5d|line 2
             filter|0.5|1576146008.006105|smtp-in|data-line|7641df9771b4ed00|1ef1c203cc576e5d|.

       They  are expected to return an output stream similarly terminated by a single dot.  A filter may add to,
       suppress, modify or echo back the lines it receives.   Ultimately,  smtpd(8)  assumes  that  the  message
       consists of the output from smtpd-filters.

       Note  that  filters  may  be chained, and the lines that are input into a subsequent filter are the lines
       that are output from a previous filter.

       The response to “data-line” requests use their own construct.  A “filter-dataline”  prefix,  followed  by
       the unique session identifier, the opaque token and the output line as follows:

             filter-dataline|7641df9771b4ed00|1ef1c203cc576e5d|line 1
             filter-dataline|7641df9771b4ed00|1ef1c203cc576e5d|line 2
             filter-dataline|7641df9771b4ed00|1ef1c203cc576e5d|.

       The list of events and event-specific parameters for smtp-in are as follows:

       connect: rdns fcrdns src dest
               This request is emitted after connection, before the banner is displayed.

       helo: identity
               This request is emitted after the client has emitted “HELO”.

       ehlo: identity
               This request is emitted after the client has emitted “EHLO”.

       starttls: tls-string
               This request is emitted after the client has requested “STARTTLS”.

       auth: auth
               This request is emitted after the client has requested “AUTH”.

       mail-from: address
               This request is emitted after the client has requested “MAIL FROM”.

       rcpt-to: address
               This request is emitted after the client has requested “RCPT TO”.

       data    This request is emitted after the client has requested “DATA”.

       data-line: line
               This  request  is  emitted  for  each  line of input in the “DATA” phase.  The lines are raw dot-
               escaped SMTP DATA input, terminated with a single dot.

       commit  This request is emitted after the final single dot is received.

       For every filtering phase, excepted “data-line”, the following decisions may be taken by a filter:

       proceed
               No action is taken, session or transaction may be passed to the next filter.

       junk    The session or transaction is marked as spam.  smtpd(8) will prepend an “X-Spam”  header  to  the
               message.

       reject error
               The  command  is  rejected  with  the  message  error.   The message must be a valid SMTP message
               including status code, 5xx or 4xx.

               Messages starting with a 5xx status result in a permanent failure,  those  starting  with  a  4xx
               status result in a temporary failure.

               Messages starting with a 421 status will result in a client disconnect.

       disconnect error
               The  client  is  disconnected  with  the message error.  The message must be a valid SMTP message
               including status code, 5xx or 4xx.

               Messages starting with a 5xx status result in a permanent failure,  those  starting  with  a  4xx
               status result in a temporary failure.

       rewrite parameter
               The command parameter is rewritten.

               This  decision  allows a filter to perform a rewrite of client-submitted commands before they are
               processed by the SMTP engine.  parameter is expected  to  be  a  valid  SMTP  parameter  for  the
               command.

       report parameter
               Generates a report with parameter for this filter.

SEE ALSO

       smtpd(8)

HISTORY

       smtpd-filters first appeared in OpenBSD 6.6.

Debian                                            July 7, 2023                                  SMTPD-FILTERS(7)