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