xref: /openbsd/usr.sbin/smtpd/smtpd-filters.7 (revision 4cfece93)
1.\"	$OpenBSD: smtpd-filters.7,v 1.6 2020/04/25 09:44:02 eric Exp $
2.\"
3.\" Copyright (c) 2008 Janne Johansson <jj@openbsd.org>
4.\" Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
5.\" Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
6.\"
7.\" Permission to use, copy, modify, and distribute this software for any
8.\" purpose with or without fee is hereby granted, provided that the above
9.\" copyright notice and this permission notice appear in all copies.
10.\"
11.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18.\"
19.\"
20.Dd $Mdocdate: April 25 2020 $
21.Dt FILTERS 7
22.Os
23.Sh NAME
24.Nm filters
25.Nd filtering API for the
26.Xr smtpd 8
27daemon
28.Sh DESCRIPTION
29The
30.Xr smtpd 8
31daemon provides a Simple Mail Transfer Protocol (SMTP) implementation
32that allows an ordinary machine to become Mail eXchangers (MX).
33Many features that are commonly used by MX,
34such as delivery reporting or Spam filtering,
35are outside the scope of SMTP and too complex to fit in
36.Xr smtpd 8 .
37.Pp
38Because an MX needs to provide these features,
39.Xr smtpd 8
40provides an API to extend its behavior through pluggable
41.Nm .
42.Pp
43At runtime,
44.Xr smtpd 8
45can report events to
46.Nm
47and query what it should answer to these events.
48This allows the decision logic to rely on third-party programs.
49.Sh DESIGN
50The
51.Nm
52are programs that run as unique standalone processes,
53they do not share
54.Xr smtpd 8
55memory space.
56They are executed by
57.Xr smtpd 8
58at startup and expected to run in an infinite loop,
59reading events and filtering requests from
60.Xr stdin 4 ,
61writing responses to
62.Xr stdout 4
63and logging to
64.Xr stderr 4 .
65They are not allowed to terminate.
66.Pp
67Because
68.Nm
69are standalone programs that communicate with
70.Xr smtpd 8
71through
72.Xr fd 4 ,
73they may run as different users than
74.Xr smtpd 8
75and may be written in any language.
76The
77.Nm
78must not use blocking I/O,
79they must support answering asynchronously to
80.Xr smtpd 8 .
81.Sh REPORT AND FILTER
82The API relies on two streams,
83report and filter.
84.Pp
85The report stream is a one-way stream which allows
86.Xr smtpd 8
87to inform
88.Nm
89in real-time about events that are occurring in the daemon.
90The report events do not expect an answer from
91.Nm ,
92it is just meant to provide them with informations.
93A filter should be able to replicate the
94.Xr smtpd 8
95state for a session by gathering informations coming from report events.
96No decision is ever taken by the report stream.
97.Pp
98The filter stream is a two-way stream which allows
99.Xr smtpd 8
100to query
101.Nm
102about what it should do with a session at a given phase.
103The filter requests expects an answer from
104.Nm ,
105.Xr smtpd 8
106will not let the session move forward until then.
107A decision must always be taken by the filter stream.
108.Pp
109It is sometimes possible to rely on filter requests to gather information,
110but because a reponse is expected by
111.Xr smtpd 8 ,
112this is more costly than using report events.
113The correct pattern for writing filters is to use the report events to
114create a local state for a session,
115then use filter requests to take decisions based on this state.
116The only case when using filter request instead of report events is correct,
117is when a decision is required for the filter request and there is no need for
118more information than that of the event.
119.Sh PROTOCOL
120The protocol is straightforward,
121it consists of a human-readable line exchanges between
122.Nm
123and
124.Xr smtpd 8
125through
126.Xr fd 4 .
127.Pp
128The protocol begins with a handshake.
129First,
130.Xr smtpd 8
131provides
132.Nm
133with general configuration information in the form of key-value lines:
134.Bd -literal -offset indent
135config|smtpd-version|6.6.1
136config|smtp-session-timeout|300
137config|subsystem|smtp-in
138config|ready
139.Ed
140.Pp
141Then,
142.Nm
143register the stream,
144subsystem and event they want to handle:
145.Bd -literal -offset indent
146register|report|smtp-in|link-connect
147register|ready
148.Ed
149.Pp
150Finally,
151.Xr smtpd 8
152will emit report events and filter requests,
153expecting
154.Nm
155to react accordingly either by responding or not depending on the stream:
156.Bd -literal -offset indent
157report|0.5|1576146008.006099|smtp-in|link-connect|7641df9771b4ed00|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25
158report|0.5|1576147242.200225|smtp-in|link-connect|7641dfb3798eb5bf|mail.openbsd.org|pass|199.185.178.25:31205|45.77.67.80:25
159report|0.5|1576148447.982572|smtp-in|link-connect|7641dfc063102cbd|mail.openbsd.org|pass|199.185.178.25:24786|45.77.67.80:25
160.Ed
161.Pp
162The char
163.Dq |
164may only appear in the last field of a payload,
165in which case it should be considered a regular char and not a separator.
166Other fields have strict formatting excluding the possibility of having a
167.Dq | .
168.Pp
169The list of subsystems and events,
170as well as the format of requests and reponses,
171will be documented in the sections below.
172.Sh CONFIGURATION
173During the initial handshake,
174.Xr smtpd 8
175will emit a serie of configuration keys and values.
176The list is meant to be ignored by
177.Nm
178that do not require it and consumed gracefully by filters that do.
179.Pp
180There are currently three keys:
181.Bd -literal -offset indent
182config|smtpd-version|6.6.1
183config|smtp-session-timeout|300
184config|subsystem|smtp-in
185.Ed
186.Pp
187When
188.Xr smtpd 8
189has sent all configuration keys it emits the following line:
190.Bd -literal -offset indent
191config|ready
192.Ed
193.Sh REPORT EVENTS
194There is currently only one subsystem supported in the API:
195smtp-in.
196.Pp
197Each report event is generated by
198.Xr smtpd 8
199as a single line similar to the one below:
200.Bd -literal -offset indent
201report|0.5|1576146008.006099|smtp-in|link-connect|7641df9771b4ed00|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25
202.Ed
203.Pp
204The format consists of a protocol prefix containing the stream,
205the protocol version,
206the timestamp,
207the subsystem,
208the event and the unique session identifier separated by
209.Dq | :
210.Bd -literal -offset indent
211report|0.5|1576146008.006099|smtp-in|link-connect|7641df9771b4ed00
212.Ed
213.Pp
214It is followed by a suffix containing the event-specific parameters,
215also separated by
216.Dq | :
217.Bd -literal -offset indent
218mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25
219.Ed
220.Pp
221The list of events and event-specific parameters are provided here for smtp-in:
222.Bl -tag -width Ds
223.It Ic link-connect : Ar rdns fcrdns src dest
224This event is generated upon connection.
225.Pp
226.Ar rdns
227contains the reverse DNS hostname for the remote end or an empty string if none.
228.Pp
229.Ar fcrdns
230contains the string
231.Dq pass
232or
233.Dq fail
234depending on if the remote end validates FCrDNS.
235.Pp
236.Ar src
237holds either the IP address and port from source address,
238in the format
239.Dq address:port
240or the path to a UNIX socket in the format
241.Dq unix:/path .
242.Pp
243.Ar dest
244holds either the IP address and port from destination address,
245in the format
246.Dq address:port
247or the path to a UNIX socket in the format
248.Dq unix:/path .
249.It Ic link-greeting : Ar hostname
250This event is generated upon display of the server banner.
251.Pp
252.Ar hostname
253contains the hostname displayed in the banner.
254.It Ic link-identify : Ar method identity
255This event is generated upon
256.Dq HELO
257or
258.Dq EHLO
259command from the client.
260.Pp
261.Ar method
262contains the string
263.Dq HELO
264or
265.Dq EHLO
266indicating the method used by the client.
267.Pp
268.Ar identity
269contains the identity provided by the client.
270.It Ic link-tls : Ar tls-string
271This event is generated upon successful negotiation of TLS.
272.Pp
273.Ar tls-string
274contains a colon-separated list of TLS properties including the TLS version,
275the cipher suite used by the session and the cipher strenght in bits.
276.It Ic link-disconnect
277This event is generated upon disconnection of the client.
278.It Ic link-auth : Ar username result
279This event is generated upon authentication attempt of the client.
280.Pp
281.Ar username
282contains the username used for the authentication attempt.
283.Pp
284.Ar result
285contains the string
286.Dq pass ,
287.Dq fail
288or
289.Dq error
290depending on the result of the authentication attempt.
291.It Ic tx-reset : Op message-id
292This event is generated when a transaction is reset.
293.Pp
294If reset happend while in a transaction,
295.Ar message-id
296contains the identifier of the transaction being reset.
297.It Ic tx-begin : Ar message-id
298This event is generated when a transaction is initiated.
299.Pp
300.Ar message-id
301contains the identifier for the transaction.
302.It Ic tx-mail : Ar message-id Ar result address
303This event is generated when client emits
304.Dq MAIL FROM .
305.Pp
306.Ar message-id
307contains the identifier for the transaction.
308.Pp
309.Ar result
310contains
311.Dq ok
312if the sender was accepted,
313.Dq permfail
314if it was rejected
315or
316.Dq tempfail
317if it was rejected for a transient error.
318.Pp
319.Ar address
320contains the e-mail address of the sender.
321The address is normalized and sanitized,
322the protocol
323.Dq <
324and
325.Dq >
326are removed and so are parameters to
327.Dq MAIL FROM .
328.It Ic tx-rcpt : Ar message-id Ar result address
329This event is generated when client emits
330.Dq RCPT TO .
331.Pp
332.Ar message-id
333contains the identifier for the transaction.
334.Pp
335.Ar result
336contains
337.Dq ok
338if the recipient was accepted,
339.Dq permfail
340if it was rejected
341or
342.Dq tempfail
343if it was rejected for a transient error.
344.Pp
345.Ar address
346contains the e-mail address of the recipient.
347The address is normalized and sanitized,
348the protocol
349.Dq <
350and
351.Dq >
352are removed and so are parameters to
353.Dq RCPT TO .
354.It Ic tx-envelope : Ar message-id Ar envelope-id
355This event is generated when an envelope is accepted.
356.Pp
357.Ar envelope-id
358contains the unique identifier for the envelope.
359.It Ic tx-data : Ar message-id Ar result
360This event is generated when client has emitted
361.Dq DATA .
362.Pp
363.Ar message-id
364contains the unique identifier for the transaction.
365.Pp
366.Ar result
367contains
368.Dq ok
369if server accepted to process the message,
370.Dq permfail
371if it has not accepted and
372.Dq tempfail
373if a transient error is preventing the processing of message.
374.It Ic tx-commit : Ar message-id Ar message-size
375This event is generated when a transaction has been accepted by the server.
376.Pp
377.Ar message-id
378contains the unique identifier for the SMTP transaction.
379.Pp
380.Ar message-size
381contains the size of the message submitted in the
382.Dq DATA
383phase of the SMTP transaction.
384.It Ic tx-rollback : Ar message-id
385This event is generated when a transaction has been rejected by the server.
386.Pp
387.Ar message-id
388contains the unique identifier for the SMTP transaction.
389.It Ic protocol-client : Ar command
390This event is generated for every command submitted by the client.
391It contains the raw command as received by the server.
392.Pp
393.Ar command
394contains the command emitted by the client to the server.
395.It Ic protocol-server : Ar response
396This event is generated for every response emitted by the server.
397It contains the raw response as emitted by the server.
398.Pp
399.Ar response
400contains the response emitted by the server to the client.
401.It Ic filter-report : Ar filter-kind Ar name message
402This event is generated when a filter emits a report.
403.Pp
404.Ar filter-kind may be either
405.Dq builtin
406or
407.Dq proc
408depending on if the filter is an
409.Xr smtpd 8
410builtin filter or a proc filter implementing the API.
411.Pp
412.Ar name
413is the name of the filter that generated the report.
414.Pp
415.Ar message
416is a filter-specific message.
417.It Ic filter-response : Ar phase response Op param
418This event is generated when a filter responds to a filtering request.
419.Pp
420.Ar phase
421contains the phase name for the request.
422The phases are documented in the next section.
423.Pp
424.Ar response
425contains the response of the filter to the request,
426it is either one of
427.Dq proceed ,
428.Dq report ,
429.Dq reject ,
430.Dq disconnect ,
431.Dq junk or
432.Dq rewrite .
433.Pp
434If specified,
435.Ar param
436is the parameter to the response.
437.It Ic timeout
438This event is generated when a timeout happens for a session.
439.El
440.Sh FILTER REQUESTS
441There is currently only one subsystem supported in the API:
442smtp-in.
443.Pp
444The filter requests allow
445.Xr smtpd 8
446to query
447.Nm
448about what to do with a session at a particular phase.
449In addition,
450they allow
451.Nm
452to alter the content of a message by adding,
453modifying,
454or suppressing lines of input in a way that is similar to what program like
455.Xr sed 1
456or
457.Xr grep 1
458would do.
459.Pp
460Each filter request is generated by
461.Xr smtpd 8
462as a single line similar to the one below:
463.Bd -literal -offset indent
464filter|0.5|1576146008.006099|smtp-in|connect|7641df9771b4ed00|1ef1c203cc576e5d|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25
465.Ed
466.Pp
467The format consists of a protocol prefix containing the stream,
468the protocol version,
469the timestamp,
470the subsystem,
471the filtering phase,
472the unique session identifier and an opaque token separated by
473.Dq |
474that the filter should provide in its response:
475.Bd -literal -offset indent
476filter|0.5|1576146008.006099|smtp-in|connect|7641df9771b4ed00|1ef1c203cc576e5d
477.Ed
478.Pp
479It is followed by a suffix containing the phase-specific parameters to the
480filter request,
481also separated by
482.Dq | :
483.Bd -literal -offset indent
484mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25
485.Ed
486.Pp
487Unlike with report events,
488.Xr smtpd 8
489expects answers from filter requests and will not allow a session to move
490forward before the filter has instructed
491.Xr smtpd 8
492what to do with it.
493.Pp
494For all phases,
495excepted
496.Dq data-line ,
497the responses must follow the same construct,
498a message type
499.Dq filter-result ,
500followed by the unique session id,
501the opaque token,
502a decision and optional decision-specific parameters:
503.Bd -literal -offset indent
504filter-result|7641df9771b4ed00|1ef1c203cc576e5d|proceed
505filter-result|7641df9771b4ed00|1ef1c203cc576e5d|reject|550 nope
506.Ed
507.Pp
508The possible decisions to a
509.Dq filter-result
510message will be described below.
511.Pp
512For the
513.Dq data-line
514phase,
515.Nm
516are fed with a stream of lines corresponding to the message to filter,
517and terminated by a single dot:
518.Bd -literal -offset indent
519filter|0.5|1576146008.006099|smtp-in|data-line|7641df9771b4ed00|1ef1c203cc576e5d|line 1
520filter|0.5|1576146008.006103|smtp-in|data-line|7641df9771b4ed00|1ef1c203cc576e5d|line 2
521filter|0.5|1576146008.006105|smtp-in|data-line|7641df9771b4ed00|1ef1c203cc576e5d|.
522.Ed
523.Pp
524They are expected to produce an output stream similarly terminate by a single
525dot.
526A filter may inject,
527suppress,
528modify or echo back the lines it receives.
529Ultimately,
530.Xr smtpd 8
531will assume that the message consists of the output from
532.Nm .
533.Pp
534Note that filters may be chained and the lines that are input into a filter
535are the lines that are output from previous filter.
536.Pp
537The response to
538.Dq data-line
539requests use their own construct.
540A
541.Dq filter-dataline
542prefix,
543followed by the unique session identifier,
544the opaque token and the output line as follows:
545.Bd -literal -offset indent
546filter-dataline|7641df9771b4ed00|1ef1c203cc576e5d|line 1
547filter-dataline|7641df9771b4ed00|1ef1c203cc576e5d|line 2
548filter-dataline|7641df9771b4ed00|1ef1c203cc576e5d|.
549.Ed
550.Pp
551The list of events and event-specific parameters are provided here for smtp-in:
552.Bl -tag -width Ds
553.It Ic connect : Ar rdns fcrdns src dest
554This request is emitted after connection,
555before the banner is displayed.
556.It Ic helo : Ar identity
557This request is emitted after the client has emitted
558.Dq HELO .
559.It Ic ehlo : Ar identity
560This request is emitted after the client has emitted
561.Dq EHLO .
562.It Ic starttls : Ar tls-string
563This request is emitted after the client has requested
564.Dq STARTTLS .
565.It Ic auth : Ar auth
566This request is emitted after the client has requested
567.Dq AUTH .
568.It Ic mail-from : Ar address
569This request is emitted after the client has requested
570.Dq MAIL FROM .
571.It Ic rcpt-to : Ar address
572This request is emitted after the client has requested
573.Dq RCPT TO .
574.It Ic data
575This request is emitted after the client has requested
576.Dq DATA .
577.It Ic data-line : Ar line
578This request is emitted for each line of input in the
579.Dq DATA
580phase.
581The lines are raw dot-escaped SMTP DATA input,
582terminated with a single dot.
583.It Ic commit
584This request is emitted after the final single dot is received.
585.El
586.Pp
587For every filtering phase,
588excepted
589.Dq data-line ,
590the following decisions may be taken by a filter:
591.Bl -tag -width Ds
592.It Ic proceed
593No action is taken,
594session or transaction may be passed to the next filter.
595.It Ic junk
596The session or transaction is marked as Spam.
597.Xr smtpd 8
598will prepend a
599.Dq X-Spam
600header to the message.
601.It Ic reject Ar error
602The command is rejected with the message
603.Ar error .
604The message must be a valid SMTP message including status code,
6055xx or 4xx.
606.Pp
607Messages starting with a 5xx status result in a permanent failure,
608those starting with a 4xx status result in a temporary failure.
609.Pp
610Messages starting with a 421 status will result in a client disconnect.
611.It Ic disconnect Ar error
612The client is disconnected with the message
613.Ar error .
614The message must be a valid SMTP message including status code,
6155xx or 4xx.
616.Pp
617Messages starting with a 5xx status result in a permanent failure,
618those starting with a 4xx status result in a temporary failure.
619.It Ic rewrite Ar parameter
620The command parameter is rewritten.
621.Pp
622This decision allows a filter to perform a rewrite of client-submitted
623commands before they are processed by the SMTP engine.
624.Ar parameter
625is expected to be a valid SMTP parameter for the command.
626.It Ic report Ar parameter
627Generates a report with
628.Ar parameter
629for this filter.
630.El
631.\".Sh EXAMPLES
632.\"This example filter written in
633.\".Xr sh 1
634.\"will echo back...
635.\".Bd -literal -offset indent
636.\"XXX
637.\".Ed
638.\".Pp
639.\"This example filter will filter...
640.\".Bd -literal -offset indent
641.\"XXX
642.\".Ed
643.\".Pp
644.\"Note that libraries may provide a simpler interface to
645.\".Nm
646.\"that does not require implementing the protocol itself.
647.\".Ed
648.Sh SEE ALSO
649.Xr smtpd 8
650.Sh HISTORY
651.Nm
652first appeared in
653.Ox 6.6 .
654