Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

  




 

 

Postfix Documentation
Previous Page Home Next Page

Simple content filter example

The first example is simple to set up. Postfix receives unfiltered mail from the network with the smtpd(8) server, and delivers unfiltered mail to a content filter with the Postfix pipe(8) delivery agent. The content filter injects filtered mail back into Postfix with the Postfix sendmail(1) command, so that Postfix can deliver it to the final destination.

This means that mail submitted via the Postfix sendmail(1) command cannot be content filtered.

In the figure below, names followed by a number represent Postfix commands or daemon programs. See the OVERVIEW document for an introduction to the Postfix architecture.

Unfiltered

->

smtpd(8)

pickup(8)
>- cleanup(8) -> qmgr(8)
Postfix
queue
-< local(8)
smtp(8)
pipe(8)
->
->
Filtered
Filtered
^
|
|
v
maildrop
queue
<- Postfix
postdrop(1)
<- Postfix
sendmail(1)
<- Content
filter

The content filter can be a simple shell script like this:

 1 #!/bin/sh
 2 
 3 # Simple shell-based filter. It is meant to be invoked as follows:
 4 #       /path/to/script -f sender recipients...
 5 
 6 # Localize these. The -G option does nothing before Postfix 2.3.
 7 INSPECT_DIR=/var/spool/filter
 8 SENDMAIL="/usr/sbin/sendmail -G -i" # NEVER NEVER NEVER use "-t" here.
 9 
10 # Exit codes from <sysexits.h>
11 EX_TEMPFAIL=75
12 EX_UNAVAILABLE=69
13 
14 # Clean up when done or when aborting.
15 trap "rm -f in.$$" 0 1 2 3 15
16 
17 # Start processing.
18 cd $INSPECT_DIR || {
19     echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; }
20 
21 cat >in.$$ || { 
22     echo Cannot save mail to file; exit $EX_TEMPFAIL; }
23 
24 # Specify your content filter here.
25 # filter <in.$$ || {
26 #   echo Message content rejected; exit $EX_UNAVAILABLE; }
27 
28 $SENDMAIL "$@" <in.$$
29 
30 exit $?

Notes:

  • Line 8: The -G option does nothing before Postfix 2.3, otherwise it disables address rewriting of message headers.

  • Line 8: The -i option says don't stop reading input when a line contains "." only.

  • Line 8: NEVER NEVER NEVER use the "-t" command-line option here. It will mis-deliver mail, like sending mailing list mail back to the mailing list.

  • Line 21: The idea is to first capture the message to file and then run the content through a third-party content filter program.

  • Line 22: If the mail cannot be captured to file, mail delivery is deferred by terminating with exit status 75 (EX_TEMPFAIL). Postfix places the message in the deferred mail queue and tries again later.

  • Line 25: You will need to specify a real content filter program here that receives the content on standard input.

  • Line 26: If the content filter program finds a problem, the mail is bounced by terminating with exit status 69 (EX_UNAVAILABLE). Postfix will return the message to the sender as undeliverable.

  • Note: in this time of mail worms and spam, it is a BAD IDEA to send known viruses or spam back to the sender, because that address is likely to be forged. It is safer to discard known to be bad content and to quarantine suspicious content so that it can be inspected by a human being.

  • Line 28: If the content is OK, it is given as input to the Postfix sendmail command, and the exit status of the filter command is whatever exit status the Postfix sendmail command produces. Postfix will deliver the message as usual.

  • Line 30: Postfix returns the exit status of the Postfix sendmail command.

I suggest that you first run this script by hand until you are satisfied with the results. Run it with a real message (headers+body) as input:

% /path/to/script -f sender recipient... <message-file

Once you're satisfied with the content filtering script:

  • Create a dedicated local user account called "filter". This user handles all potentially dangerous mail content - that is why it should be a separate account. Do not use "nobody", and most certainly do not use "root" or "postfix".

  • Create a directory /var/spool/filter that is accessible only to the "filter" user. This is where the content filtering script is supposed to store its temporary files.

  • Configure Postfix to deliver mail to the content filter with the pipe(8) delivery agent.

    /etc/postfix/
    master.cf:
      # =============================================================
      # service type  private unpriv  chroot  wakeup  maxproc command
      #               (yes)   (yes)   (yes)   (never) (100)
      # =============================================================
      filter    unix  -       n       n       -       10      pipe
        flags=Rq user=filter argv=/path/to/script -f ${sender} -- ${recipient}
    

    This runs up to 10 content filters in parallel. Instead of a limit of 10 concurrent processes, use whatever process limit is feasible for your machine. Content inspection software can gobble up a lot of system resources, so you don't want to have too much of it running at the same time.

  • To turn on content filtering for mail arriving via SMTP only, append "-o content_filter=filter:dummy" to the master.cf entry that defines the Postfix SMTP server:

    /etc/postfix/
    master.cf:
      # =============================================================
      # service type  private unpriv  chroot  wakeup  maxproc command
      #               (yes)   (yes)   (yes)   (never) (100)
      # =============================================================
      smtp      inet  ...other stuff here, do not change...   smtpd
            -o 
    content_filter=filter:dummy
    

    The " content_filter" line causes Postfix to add one content filter request record to each incoming mail message, with content "filter:dummy". This record overrides the normal mail routing and causes mail to be given to the content filter instead.

    The content_filter configuration parameter accepts the same syntax as the right-hand side in a Postfix transport table.

  • Execute "postfix reload" to complete the change.

Postfix Documentation
Previous Page Home Next Page