≡ Menu

Postfix

Postfix provides Mime header check for all incoming messages. You can put restrictions on .exe / .bat / .vbs files and block all attachments.

mime_header_checks directive allows you to define file, you will place a restriction for any file extensions that you do not want to have passing through your mail sever system.

On most mail server the first thing that needs to be done is to enable header checks and block dangerous files.

Define mine header checks

Open main.cf file:
# vi /etc/postfix/main.cf
Append / set mime_header_checks directive as follows:
mime_header_checks = regexp:/etc/postfix/mime_header_checks

Save and close the file.

Block attachments

Now open /etc/postfix/mime_header_checks file:
# vi /etc/postfix/mime_header_checks
Append following line:
/name=[^>]*\.(bat|com|exe|dll|vbs)/ REJECT
Save and close the file.

Restart postfix

First create postfix lookup table for mime_header_checks file:
# /etc/init.d/postfix restart

Watch log file

You should see rejected mail log in /var/log/maillog file:
# tail -f /var/log/maillog
Output:

Jun 20 14:28:06 server postfix/smtpd[5442]: connect from web31601.mail.mud.yahoo.com[68.142.198.147]
Jun 20 14:28:07 server postfix/smtpd[5442]: 245F913906EE: client=web31601.mail.mud.yahoo.com[68.142.198.147]
Jun 20 14:28:07 server postfix/cleanup[5492]: 245F913906EE: message-id=<274995.40473.qm@web31601.mail.mud.yahoo.com>
Jun 20 14:28:07 server postfix/cleanup[5492]: 245F913906EE: reject: header Content-Type: application/x-msdos-program; name="updatebankdetails.bat" from web31601.mail.mud.yahoo.com[68.142.198.147]; from= to= proto=SMTP helo=: Message content rejected

For more information please read postfix and header_checks man page.

Librenix has a posted small and sweet article that explains basic steps to configure and install a mail server with antivirus / antispam in minutes.

From the article:
This article illustrates a situation where you need to set up your own mail server (be it your home mail server, or a small office one). It actually shows that, if using an integrated service mail server, anyone can do the job, all in a matter of minutes.
AXIGEN Mail Server, the solution chosen for this example, can send and receive e-mails securely via "mydomain.com" and is able to retrieve them in a WebMail interface - this means that it includes all mail services needed for a fully functional mail server (SMTP, IMAP, POP3, WebMail, WebAdmin).

To get an idea of the amount of time you can spare by installing such a solution, just think of all the different open source applications you would need to install instead (i.e. an MTA, Squirrelmail for Webmail, QmailAdmin for web configuration, Courier for IMAP and POP3 and many others.)

=> Install a Mail Server with Antivirus and Antispam in minutes

Postfix configure anti spam with blacklist

Postfix is free and powerful MTA. You can easily configure Postfix to block spam. You need to add
following directives to /etc/postfix/main.cf file:

=> disable_vrfy_command = yes : Disable the SMTP VRFY command. This stops some techniques used to harvest email addresses.

=> smtpd_delay_reject = yes : It allows Postfix to log recipient address information when rejecting a client name/address or sender address, so that it is possible to find out whose mail is being rejected.

=> smtpd_helo_requi
red = yes
: Require that a remote SMTP client introduces itself at the beginning of an SMTP session with the HELO or EHLO command. Many spam bot ignores HELO/EHLO command and you save yourself from spam. Following lines further restrictions on HELO command:
smtpd_helo_restrictions = permit_mynetworks,
reject_non_fqdn_hostname, Reject email if remote hostname is not in fully-qualified domain form. Usually bots sending email don't have FQDN names.
reject_invalid_hostname, Reject all bots sending email from computers connected via DSL/ADSL computers. They don't have valid internet hostname.
permit

You can put the following access restrictions that the Postfix SMTP server applies in the context of the RCPT TO command.
=> smtpd_recipient_restrictions =
reject_invalid_hostname, - Reject email if it not valid hostname
reject_non_fqdn_hostname, - Reject email if it not valid FQDN
reject_non_fqdn_sender, - Reject the request when the MAIL FROM address is not in fully-qualified domain form. For example email send from xyz or abc is rejected.
reject_non_fqdn_recipient, - Reject the request when the RCPT TO address is not in fully-qualified domain form
reject_unknown_sender_domain, - Reject email, if sender domain does not exists
reject_unknown_recipient_domain, Reject email, if recipient domain does not exists
permit_mynetworks,
reject_rbl_client list.dsbl.org, Configure spam black lists
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client dul.dnsbl.sorbs.net,
permit

Open /etc/postfix/main.cf file :
# vi /etc/postfix/main.cf
Set/modify configuration as follows

disable_vrfy_command = yes
smtpd_delay_reject = yes
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks,
     reject_non_fqdn_hostname,
     reject_invalid_hostname,
     permit
smtpd_recipient_restrictions =
   permit_sasl_authenticated,
   reject_invalid_hostname,
   reject_non_fqdn_hostname,
   reject_non_fqdn_sender,
   reject_non_fqdn_recipient,
   reject_unknown_sender_domain,
   reject_unknown_recipient_domain,
   permit_mynetworks,
   reject_rbl_client list.dsbl.org,
   reject_rbl_client sbl.spamhaus.org,
   reject_rbl_client cbl.abuseat.org,
   reject_rbl_client dul.dnsbl.sorbs.net,
   permit
smtpd_error_sleep_time = 1s
smtpd_soft_error_limit = 10
smtpd_hard_error_limit = 20

Also force (highlighted using red color) Postfix to limit incoming or receiving email rate to avoid spam.

Save and close the file. Restart postfix:
# /etc/init.d/postfix restart

Watch out maillog file. Now you should see lots of spam email blocked by above configuration directive:
# tail -f /var/log/maillog
Output:

Jan  9 06:07:22 server postfix/smtpd[10308]: NOQUEUE: reject: RCPT from 183-12-81.ip.adsl.hu[81.183.12.81]: 554 Service unavailable; Client host [81.183.12.81] blocked using dul.dnsbl.sorbs.net; Dynamic IP Addresses See: http://www.sorbs.net/lookup.shtml?81.183.12.81; from= to= proto=ESMTP helo=<183-12-230.ip.adsl.hu>
Jan  9 06:07:23 server postfix/smtpd[10308]: lost connection after RCPT from 183-12-81.ip.adsl.hu[81.183.12.81]
Jan  9 06:07:23 server postfix/smtpd[10308]: disconnect from 183-12-81.ip.adsl.hu[81.183.12.81]
Jan  9 06:10:43 server postfix/anvil[10310]: statistics: max connection rate 1/60s for (smtp:81.183.12.81) at Jan  9 06:07:17
Jan  9 06:10:43 server postfix/anvil[10310]: statistics: max connection count 1 for (smtp:81.183.12.81) at Jan  9 06:07:17
Jan  9 06:10:43 server postfix/anvil[10310]: statistics: max cache size 1 at Jan  9 06:07:17
Jan  9 06:16:58 server postfix/smtpd[10358]: warning: 81.92.197.249: address not listed for hostname unassigned.or.unconfigured.reverse.nfsi-telecom.net
Jan  9 06:16:58 server postfix/smtpd[10358]: connect from unknown[81.92.197.249]
Jan  9 06:17:00 server postfix/smtpd[10358]: NOQUEUE: reject: RCPT from unknown[81.92.197.249]: 550 : Recipient address rejected: User unknown in virtual alias table; from=<> to= proto=ESMTP helo=
Jan  9 06:17:00 server postfix/smtpd[10358]: disconnect from unknown[81.92.197.249]

Next time I will write about simple procmail and spamassassin combination to filter out spam :)

Address rewriting allows changing outgoing email ID or domain name itself. This is good for hiding internal user names. For example:
SMTP user: tom-01
EMAIL ID: tom@domain.com
Server name: server01.hosting.com

However when tom-01 send an email from shell prompt or using php it looks like it was send from tom-01@server01.hosting.com

In some cases internal hosts have no valid Internet domain name, and instead use a name such as localdomain.local or something else. This can be a problem when you want to send mail over the Internet, because many mail servers reject mail addresses with invalid domain names to avoid spam.

Postfix MTA offers smtp_generic_maps parameter. You can specify lookup tables that replace local mail addresses by valid Internet addresses when mail leaves the machine via SMTP.

Open your main.cf file
# vi /etc/postfix/main.cf

Append following parameter
smtp_generic_maps = hash:/etc/postfix/generic

Save and close the file. Open /etc/postfix/generic file:
# vi /etc/postfix/generic

Make sure tom-01@server01.hosting.com change to tom@domain.com
tom-01@server01.hosting.com tom@domain.com

Save and close the file. Create or update generic postfix table:
# postmap /etc/postfix/generic

Restart postfix:
# /etc/init.d/postfix restart

When mail is sent to a remote host via SMTP this replaces tom-01@server01.hosting.com by tom@domain.com mail address. You can use this trick to replace address with your ISP address if you are connected via local SMTP.

ORDB.org RBL Anti Spam service going offline

Email filtering is an essential task. There are many methods like:
=> Bayesian spam filtering
=> SpamAssassin/DSPAM programs
=> Check open relay using RBL etc

Now ORDB.org is shutting down its operation. ORDB is quite effective and I use this list against all of email servers. Spammers still use 3rd party servers and desktop computers so that they could minimize or avoid detection by re-routing their e-mail through these third party e-mail servers.

According to their home page:
We encourage system owners to remove ORDB checks from their mailers immediately and start investigating alternative methods of spam filtering. We recommend a combination involving greylisting and content-based analysis (such as the dspam project, bmf or Spam Assassin). DNS and the mailing lists will vanish today, December 18, 2006.

Generally, I use following sequence while configuring anti-spam
reject_rbl_client relays.ordb.org,
reject_rbl_client list.dsbl.org,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client dul.dnsbl.sorbs.net

These services blocks thousands of spam everyday before hitting email server and Spam Assassin. Indeed a bad news for mail server admins!

PHP has mail() function to send an email to users. However this mail() will not work:

=> If sendmail (or compatible binary) is not installed

=> If Apache Web server / Lighttpd running in chrooted jail

=> And your smtp server needs an authentication before sending an email

=> Or you just need to send email using PHP PEAR

In all these cases you need to use PHP PEAR's Mail:: interface. It defines the interface for implementing mailers under the PEAR hierarchy, and provides supporting functions which are useful in multiple mailer backends. In this tip you will learn about how to send an e-mail directly to client smtp server in real time.

PHP Pear's Mail.php is located in /usr/share/pear/ directory. Following is sample code to send an email via authenticated smtp server.

PHP send email using PHP SMTP mail Pear functions - Sample source code

Following code is well commented, you need to make necessary changes as per your setup.

<?php
include("Mail.php");
/* mail setup recipients, subject etc */
$recipients = "feedback@yourdot.com";
$headers["From"] = "user@somewhere.com";
$headers["To"] = "feedback@yourdot.com";
$headers["Subject"] = "User feedback";
$mailmsg = "Hello, This is a test.";
/* SMTP server name, port, user/passwd */
$smtpinfo["host"] = "smtp.mycorp.com";
$smtpinfo["port"] = "25";
$smtpinfo["auth"] = true;
$smtpinfo["username"] = "smtpusername";
$smtpinfo["password"] = "smtpPassword";
/* Create the mail object using the Mail::factory method */
$mail_object =& Mail::factory("smtp", $smtpinfo);
/* Ok send mail */
$mail_object->send($recipients, $headers, $mailmsg);
?>

Sending smtp email from chrooted Apache or Lighttpd webserver

Read following section, if you are running a secure chrooted Apache or Lighttpd web server. I have already written about setting php mail() function in chrooted jail. If you are using chrooted jail server setup, copy all files from /usr/share/pear directory to /chroot-directory/usr/share/pear directory. For example if lighttpd chrooted jail located in /webroot directory, you need to type following commands to install PHP pear support:
# mkdir -p /webroot/usr/share/pear
# cd /webroot/usr/share/pear
# cp -avr /usr/share/pear .

If PHP SAFE MODE is on, you must set /webroot/usr/share/pear directory permission to webserver username to allow access. Otherwise you will see error as follows:

1-Nov-2006 09:43:19] PHP Warning:  main(): SAFE MODE Restriction in effect.  The script whose uid is 506 is not allowed to access /usr/share/pear/PEAR.php owned by uid 0 in /usr/share/pear/Mail.php on line 636.

So if webserver username is lighttpd or apache use following command to setup correct ownership:
# chown lighttpd:lighttpd /webroot/usr/share/pear -ROR# chown apache:apache /webroot/usr/share/pear -R

You may also find modified wordpress WP-ContactForm plugin useful. It is a drop in form for users to contact you. It can be implemented on a page or a post. Original authored by Ryan Duff, which use php mail() function to send email. I have modified the same to send email via my ISP authenticated gateway using PHP PEAR's Mail:: interface :D

When you cannot monitor your server for service availability, it is better to take help of automated monitor and restart utility. Last 4 days I was away from my server as I was enjoying my vacation. During this time due to load my lighttpd webserver died but it was restarted automatically within 2 minutes. I had utility configured for monitoring services on a Linux system called monit. It offers all features you ever needed for system monitoring and perform error recovery for UNIX like system.

Before monit I had my own shell and perl script for monitoring service. If service failed script will try to restart service and send an automated email to me. However monit is a superior solution.

monit is a utility for managing and monitoring processes, files, directories and devices on a Unix system. Monit conducts automatic maintenance and repair and can execute meaningful causal actions in error situations. For example, monit can start a process if it does not run, restart a process if it does not respond and stop a process if it uses to much resources. You may use monit to monitor files, directories and devices for changes, such as timestamps changes, checksum changes or size changes.

Monit logo

You may also use monit to monitor files, directories and devices on localhost. Monit can monitor these items for changes, such as timestamps changes, checksum changes or size changes. This is also useful for security reasons you can monitor the md5 checksum of files that should not change.

Personally, I always install and configure monit on all boxes which are under my control.

Install monit under Debian or Ubuntu Linux

Use apt-get command to install monit
# apt-get install monitOR$ sudo apt-get install monit

Install monit under Red Hat enterprise Linux / CentOS Linux (source code installation)

Many distributions include monit. However monit is not included in official Red hat enterprise Linux. Just download monit source code from official web site using wget command:
# cd /opt
# wget http://www.tildeslash.com/monit/dist/monit-4.8.2.tar.gz
Untar monit
# tar -zxvf monit-4.8.2.tar.gz
# cd monit-4.8.2

Configure and compile monit:

# ./configure
# make

Install monit

# make install

Copy monit configuration file:

# cp monitrc /etc/monitrc

By default monit is located at /usr/local/bin/monit

How do I Configure monit?

monitrc is name of monit configuration file and it is by default located at /etc/monitrc location. However each distribution places file in different location: .
=> Source code installation : /etc/monitrc
=> Debian / Unentu Linux installation : /etc/monit/monitrc

Open monit configuration file and setup values as follows:
# vi /etc/monitrc

a) Run it as daemon and check the services (such as web, mysql, sshd) at 2-minute
intervals.
set daemon 120

b) Set syslog logging with the 'daemon' facility:
set logfile syslog facility log_daemon

c) Set mail server name to send email alert
set mailserver mail.cyberciti.biz
Set email format such as from email
set mail-format { from: alert@nixcraft.in
subject: $SERVICE $EVENT at $DATE
message: Monit $ACTION $SERVICE at $DATE on $HOST: $DESCRIPTION.
}

d) Now most important part, restart lighttpd or apache web server if failed or killed by Linux kernel due to any causes:
check process lighttpd with pidfile /var/run/lighttpd.pid
group lighttpd
start program = "/etc/init.d/lighttpd start"
stop program = "/etc/init.d/lighttpd stop"
if failed host 75.126.43.232 port 80
protocol http then restart
if 5 restarts within 5 cycles then timeout

Where,

  • check process lighttpd with pidfile /var/run/lighttpd.pid : You are specifying lighttpd pid file and daemon name
  • group lighttpd: Specify group name, which is allowed or used to start/restart lighttpd
  • start program = "/etc/init.d/lighttpd start" : Command to start lighttpd server
  • stop program = "/etc/init.d/lighttpd stop" : Command to stop lighttpd server
  • if failed host 127.0.0.1 port 80 : Server IP address and port number (80)
  • protocol http then restart : If above IP and port failed restart the webserver
  • if 5 restarts within 5 cycles then timeout : Try to restart 5 times; if monit cannot restart webserver 5 times; just time out to avoid race condition.

Here is my mysql server restart configuration directives:
check process mysqld with pidfile /var/run/mysqld/mysqld.pid
group database
start program = "/etc/init.d/mysqld start"
stop program = "/etc/init.d/mysqld stop"
if failed host 127.0.0.1 port 3306 then restart
if 5 restarts within 5 cycles then timeout

Here is my sshd server configuration directives:
check process sshd with pidfile /var/run/sshd.pid
start program "/etc/init.d/sshd start"
stop program "/etc/init.d/sshd stop"
if failed host 127.0.0.1 port 22 protocol ssh then restart
if 5 restarts within 5 cycles then timeout

Here is my Apache serverrestart configuration directives:
check process httpd with pidfile /var/run/httpd.pid
group apache
start program = "/etc/init.d/httpd start"
stop program = "/etc/init.d/httpd stop"
if failed host 127.0.0.1 port 80
protocol http then restart
if 5 restarts within 5 cycles then timeout

Replace IP address 127.0.0.1 with your actual IP address. If you are using Debian just start monit:
# /etc/init.d/monit start

If you are using Red Hat Enterprise Linux, start monit from /etc/inittab file:
Open /etc/inittab file:
# vi /etc/inittab
Append following line:
mo:2345:respawn:/usr/local/bin/monit -Ic /etc/monitrc

Now start monit:
# init -qOR
# telinit -q

You can verify that monit is started from /var/log/messages log file:
# tail -f /var/log/messagesOutput:

Nov 21 04:39:21 server monit[8759]: Starting monit daemon
Nov 21 04:39:21 server monit[8759]: Monit started

If lighttpd died, you will see something as follows in log file:

Nov 21 04:45:13 server monit[8759]: 'lighttpd' process is not running
Nov 21 04:45:13 server monit[8759]: 'lighttpd' trying to restart
Nov 21 04:45:13 server monit[8759]: 'lighttpd' start: /etc/init.d/lighttpd

You may use monit to monitor daemon processes or similar programs running on localhost or started from /etc/init.d/ location such as
=> Apache Web Server
=> SSH Server
=> Postfix/Sendmail MTA
=> MySQL etc

Further readings