MAC OS X, Linux, Windows and other IT Tips and Tricks

16 May 17 Hardening the SSL security in Apache, Dovecot and Postfix


After having gotten a report from OpenVAS that my SSL security level of the mail server were medium, I looked for ways to improve this.
I found very good sites which helps me making these improvements:
Based on this site and extending to cover dovecot mail service here is the result:

Hardening Apache:

In /etc/apache2/mods-available/ssl.conf
Change the following parameters as follows:
SSLHonorCipherOrder on

Hardening Dovecot:

Note: you should have openssl >=1.0.0 dovecot >=2.1.x required, better dovecot >=2.2.x because of ECDHE support Dovecot tryies to use PFS by default, so besides the enabled SSL almost no actions are required change the log settings to see the cipher, grep for a login_log_format_elements in dovecot configs and add %k to it
login_log_format_elements = "user=< %u> method=%m rip=%r lip=%l mpid=%e %c %k"
Configure the allowed ciphers. Server side enforcement works only for dovecot >=2.2.6
In /etc/dovecot/conf.d/ssl.conf
Change some parameters as follows:
#only for dovecot >=2.2.6, enforce the server cipher preference
ssl_prefer_server_ciphers = yes
#disable SSLv2 and SSLv3
ssl_protocols = !SSLv2 !SSLv3

Add the following parameter:
ssl_dh_parameters_length = 2048
Delete the file /var/lib/dovecot/ssl-parameters.dat
and restart Dovecot service:
service dovecot restart
Dovecote seeing that the Diffie Hellman parameters are assigned to be 2048 bits long and that its file is just been deleted, will regenerate a new one in the background.

Hardening Postfix

In /etc/postfix/
Change or add the following configuration parameters:
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3

Generate a new Diffie Hellman parameters file as follows:
openssl dhparam -out /etc/ssl/dh2048.pem 2048

24 Feb 17 Whitelisting Hosts in Postfix/Amavis

I have an email server with very strong spam filtering and every now and then it does see the emails that I send from our own networks as SPAM.
In order to bypass the SPAM scanner for those networks without bypassing the virus scanning of Amavis I found these instructions in Internet at:

Allow clients on my internal network to bypass scanning by using the ‘MYNETS’ policy bank. You can use the built in ‘MYNETS’ policy bank to allow clients included in $mynetworks. Let’s assume you allow all (or most) clients on your internal network to send outbound mail through your spamfilter.
The IP addresses of these clients are included in Postfix’ $mynetworks in
mynetworks = !
In /etc/amavis/conf.d/50-user @mynetworks determines which clients will use the ‘MYNETS’ policy bank:
@mynetworks = qw( [::1] [FE80::]/10 [FEC0::]/10
! );

And you would configure the ‘MYNETS’ policy bank as desired:
Also added to /etc/amavis/conf.d/50-user
$policy_bank{'MYNETS'} = { # clients in @mynetworks
bypass_spam_checks_maps => [1], # don't spam-check internal mail
bypass_banned_checks_maps => [1], # don't banned-check internal mail
bypass_header_checks_maps => [1], # don't header-check internal mail

When using the “MYNETS’ policy bank, you must use *_send_xforward_command in which enables forwarding of the client’s IP address to amavisd-new.:
smtp-amavis unix - - n - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20

lmtp-amavis unix - - n - 2 lmtp
-o lmtp_data_done_timeout=1200
-o lmtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20

31 Mar 16 Fixing Spamassassin in Debian Jessie(8)

For a long time under Debian Wheezy Spamassassin was running quite well until I upgraded the system to Jessie. That is when Spamassassin(spamd) started to crash every now and then without giving much reasons why.

Cause of error message:
Looking in the system logs(/var/log/syslog) I found the following error:
spamd[7490]: util: refusing to untaint suspicious path: "/${SAHOME}"
I’m not sure if this is the cause of the crashes but it certainly doesn’t help. So I figured I should first try to solve this error first. According to this site since the Spamassassin is now started via ‘systemd’ the variables set in the init config file (/etc/default/spamassassin) are not expanded and they are passed on ‘as-is’ on the command line for starting spamd process. eg.
OPTIONS="--create-prefs --max-children 5 --username spamd --helper-home-dir ${SAHOME}"

Since this file will not be overwritten during updates the suggestion was to write the value of this variable directly in the OPTIONS line in (/etc/default/spamassassin) as follows:
OPTIONS="--create-prefs --max-children 5 --username spamd --helper-home-dir /var/lib/spamassassin/"
Now at least this error doesn’t occur any more and time will tell if the crashes of spamd are still happening.

09 Mar 16 Testing SSL Connections with SSLyze, Nmap or OpenSSL

OpenSSL is a great tool to check SSL connections to servers. The difficulty here is when one want a full scan of all possible SSL Cyphers and protocols used by a server. That is where SSLyze comes in handy. This tool is a Python script which will scan the target host/port for SSL handshake and report what works/support and what not. Unfortunately this lovely tool is not included in the Ubuntu/Debian distributions, and this is where this post comes handy.

IMPORTANT: Besides executing all the tests below one thing very important (as noted in the This link) is to upgrade OpenSSL to the latest version as follows:
OpenSSL 1.0.2 users should upgrade to 1.0.2g
OpenSSL 1.0.1 users should upgrade to 1.0.1s


Installing the dependencies and tool
cd /root/bin
tar fvxz 0.13.4.tar.gz
apt-get install python-pip python-dev
pip install nassl

Using SSLyze
python /root/bin/sslyze-0.13.4/ --regular


Scanning the full server for weaknesses including weak SSL Versions using NMAP.
Note: This operation can take a long time to execute.
apt-get install nmap
nmap -sV -sC

OR better(for checking the HTTPS,SMTPS,IMAPS,POP3S)
nmap --script ssl-cert,ssl-enum-ciphers -p 443,465,993,995


Checking the SSL connection with OpenSSL
echo 'q' | openssl s_client -host -port 443
Note: In this above case since the SSLv2 support is normally disabled for OpenSSL in Debian/Ubuntu distributions, you will not be able to see if the server is supporting it. To overcome this and enable SSLv2 support(for your testing Linux) then follow the instructions in this site:

For more information regarding protection against DROWN(SSLv2) or POODLE(SSLv3) attacks see:,_Insufficient_Transport_Layer_Protection_%28OTG-CRYPST-001%29

20 Jul 15 Relay emails for specific destinations

In the last couple of years many large email providers have started to refuse emails coming from certain IP addresses or according to certain other criteria. It is difficult to know for what reason certain emails are refused access with the server answer:
....refused to talk to me: 554....
The list of these emails destinations(which is growing by the day) is for example:

Therefore one temporary solution(till I can fix the cause) is to relay the problematic emails via a relay email server which is more accepted.
Here is the Postfix settings that allows me to do that:
Added the following entry in /etc/postfix/
transport_maps = hash:/etc/postfix/transport
And in the file /etc/postfix/transport relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25

Note: Here obviously you need to replace for your own relay server.
Hash the file for postfix:
postmap /etc/postfix/transport
And reload Postfix:
service postfix reload

19 May 15 Installing DMARC filtering in Debian Wheezy

Principle: DMARC is a bit of a strange animal. It serves as a filter against SPAM but only according to the rules given by the owner of the domain sending emails. So, for example, if I send emails as sender using a mail client program via my mail server , in order that my mails be seen as ‘good’ mail, I need to set-up the SPF and DKIM and DMARC TXT records in the DNS of the domain This way the receiving server will verify the validity of the SPF and DKIM of my domain and the using the DMARC record, decide what to do with the mails that fail the SPF or DKIM validation. In other words I instruct the receiving server what to do(and how) with emails that try to personify me sending emails. Of course the receiving server needs to have the DMARC vadidation mechanism installed to read my DNS DMARC record and act on the validation results.
This article provides instructions on how to install this mechanism only.
Installing DKIM(needed on the sending and receiving servers) is covered in this article:
I don’t cover the SPF here since there are a lot of info on the Internet which covers it.


Install the needed libraries:
apt-get install libmilter-dev
Check out the latest version of opendmarc in Source forge and use the link to download it:
eg. For version 1.3.1 you run the command:
tar xfvz opendmarc-1.3.1.tar.gz
cd opendmarc-1.3.1
./configure --prefix=/usr --with-spf --enable-live-tests
make && make install

Prepare the system user etc.
adduser --quiet --system --group --home /var/run/opendmarc opendmarc
chown opendmarc:opendmarc /var/run/opendmarc

Enter the sender host names that should be ignored by the filter
mkdir /etc/opendmarc/
echo -e "localshost\\\" > /etc/opendmarc/ignore.hosts

Edit the configuration file
vi /etc/opendmarc/opendmarc.conf
Set the parameters accordingly and issue the following command to get a short overview of the configuration:
grep -v '#' /etc/opendmarc.conf | egrep -v '^ *$'
For example content of my configuration file(/etc/opendmarc.conf):
AuthservIDWithJobID true
BaseDirectory /var/run/opendmarc
FailureReports true
FailureReportsOnNone true
HistoryFile /var/run/opendmarc/opendmarc.dat
IgnoreAuthenticatedClients true
IgnoreHosts /etc/opendmarc/ignore.hosts
PidFile /var/run/
RecordAllMessages false
ReportCommand /usr/sbin/sendmail -t
Socket inet:8893@localhost
SPFIgnoreResults true
SPFSelfValidate true
Syslog true
UserID opendmarc

The data files must be now created incl. access rights:
mkdir -p /var/run/opendmarc/
touch /var/run/opendmarc/opendmarc.dat
chown opendmarc.opendmarc /var/run/opendmarc/opendmarc.dat
chmod 600 /var/run/opendmarc/opendmarc.dat

Prepare the init start/stop script
cd /etc/init.d
cp skeleton opendmarc
chmod 755 opendmarc
vim opendmarc

Adapt the following parameters as appropriate to your settings:
# Provides: opendmarc
# Required-Start: $syslog
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: opendmarc milter init script
# Description: Start stop of opendmarc postfix milter
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the script
DESC="OpenDMARC milter"
DAEMON_ARGS="-c /etc/opendmarc/opendmarc.conf -u opendmarc"

And in the same file in function do_stop():
#start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
killall opendmarc
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
#start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
killall opendmarc
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"

Save the file.
Check the opendmarc configuration file:
opendmarc -c /etc/opendmarc/opendmarc.conf -u opendmarc -n && echo OK
If all OK then start the service:
service opendmarc start

Postfix configuration:
Edit /etc/postfix/ and add the following lines. If already existing because of openDKIM, then simply add the missing parameters as follows:
smtpd_milters = inet:, inet:localhost:8893
non_smtpd_milters = inet:, inet:localhost:8893

Restart postfix
service postfix restart

07 May 15 Anti-SPAM mail filtering using SPF on Debian Wheezy

Install the package:
apt-get install postfix-policyd-spf-perl
Add this line to /etc/postfix/
policy-spf_time_limit = 3600s
Add the following lines to /etc/postfix/
policy-spf unix - n n - - spawn
user=policyd-spf argv=/usr/sbin/postfix-policyd-spf-perl

In /etc/postfix/, find the smtpd_recipient_restrictions section, and, immediately after permit_mynetworks (and permit_sasl_authenticated, if you’re using that), add:
check_policy_service unix:private/policy-spf,
Restart Postfix and check your logs to see if everything is working properly.
tail -f /var/log/mail.log

07 May 15 TCP Load balancing email/web servers with NginX

I’ve got 2 synchronized email servers running and, in order to make sure I don’t have to change the servername settings of my mail client in case one server goes down, I was looking for a straight TCP layer load balancer. There are a few software packages on the market that can do that , eg. Lvs-kiss etc. I found the solution of using NginX quite interesting, since the load balancing seems to be better built especially regarding the return route which gave me some headaches with LVS-KISS. Here is an example of using NginX and TCP load balancing to 2 IMAPs/SMTPs/Webmail servers.

Note: Unfortunately my IMAPs/SMTPs servers are using a legitimate certificates but because the email clients do use the address of an extra server for Loadbalancing, the certificate is declared invalid by the email clients. This TCP load balancing operates at a lower layer(TCP) than application layer where SSL certificates can be used to authenticate. It is therefore not possible to add a certificate to this load balancer. For this reason it is recommended to use a wildcard certificate in both back-end Mail servers for production use of Mail services load-balancing. For HTTP and HTTPS there is no need for a wildcard certificate. Normal certificates installed in both web servers will do.

NginX shortcomings

NginX did have the TCP load-balancing feature compiled only in the Pro version with all the features of backend health check etc.
Since the version 1.9 they introduced a limited version of the TCP load-balancing feature into the community version.
Unfortunately if you need other pro features like backend health-checks you are out of luck.
Fortunately some 3rd parties have created a patch for earlier versions which implement the necessary features of a good low level TCP load balancer. In this tutorial I will show how to compile and patch an earlier version of Nginx to achieve the TCP Load-balancer.


Login as root and run the following commands:
apt-get remove nginx
apt-get install libssl-dev build-essential git
mkdir ~/build ; cd ~/build
wget -O - | tar xfvz -
git clone git://
cd nginx-1.6.2/
patch -p1 < ../nginx_tcp_proxy_module/tcp.patch ./configure --add-module=../nginx_tcp_proxy_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --without-http_rewrite_module --without-http_charset_module --without-http_gzip_module --without-http_ssi_module --without-http_userid_module --without-http_access_module --without-http_auth_basic_module --without-http_autoindex_module --without-http_geo_module --without-http_map_module --without-http_split_clients_module --without-http_referer_module --without-http_proxy_module --without-http_fastcgi_module --without-http_uwsgi_module --without-http_scgi_module --without-http_memcached_module --without-http_limit_conn_module --without-http_limit_req_module --without-http_empty_gif_module --without-http_browser_module --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/ --http-client-body-temp-path=/var/lib/nginx/body make && make install mkdir -p /usr/share/nginx/logs mkdir /var/log/nginx mkdir -p /var/lib/nginx/body touch /var/log/nginx/error.log /var/log/nginx/access.log touch /usr/share/nginx/logs/tcp_access.log chown -R www-data: /var/{lib,log}/nginx /usr/share/nginx/logs

Check it's version:
/usr/share/nginx/sbin/nginx -V
Create an init start/stop script
touch /etc/init.d/nginx
chmod 755 /etc/init.d/nginx
mcedit /etc/init.d/nginx

# Provides: nginx
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
# Include nginx defaults if available
if [ -f /etc/default/nginx ]; then
. /etc/default/nginx
test -x $DAEMON || exit 0
set -e
. /lib/lsb/init-functions
test_nginx_config() {
if $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1; then
return 0
return $?
case "$1" in
echo -n "Starting $DESC: "
# Check if the ULIMIT is set in /etc/default/nginx
if [ -n "$ULIMIT" ]; then
# Set the ulimits
ulimit $ULIMIT
start-stop-daemon --start --quiet --pidfile /var/run/$ \
--exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/$ \
--exec $DAEMON || true
echo "$NAME."
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/var/run/$ --exec $DAEMON || true
sleep 1
# Check if the ULIMIT is set in /etc/default/nginx
if [ -n "$ULIMIT" ]; then
# Set the ulimits
ulimit $ULIMIT
start-stop-daemon --start --quiet --pidfile \
/var/run/$ --exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
echo -n "Reloading $DESC configuration: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$ \
--exec $DAEMON || true
echo "$NAME."
echo -n "Testing $DESC configuration: "
if test_nginx_config; then
echo "$NAME."
exit $?
status_of_proc -p /var/run/$ "$DAEMON" nginx && exit 0 || exit $?
echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2
exit 1
exit 0

The NGinX configuration here TCP-load-balances the following ports: 143, 993, 587, 465, 80 & 443.

To use only the TCP load balancing feature of NginX we configure the strict minimum:
Rename the created configuration file
mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
Create the new configuration file with the following content:
mcedit /etc/nginx/nginx.conf
user www-data;
worker_processes 1;
events {
worker_connections 1024;
# ---------- TCP Load balancer for IMAPs, IMAP and SMTPS -----------------
tcp {
# ----------------- IMAPs ------------------
upstream cluster_imaps {
check interval=5000 rise=2 fall=5 timeout=2000 type=tcp;
server {
listen 993;
proxy_pass cluster_imaps;
# ----------------- IMAP -------------------
upstream cluster_imap {
check interval=5000 rise=2 fall=5 timeout=2000 type=imap;
server {
listen 143;
proxy_pass cluster_imap;
# ----------------- SMTP -------------------
upstream cluster_smtp {
check interval=5000 rise=2 fall=5 timeout=2000 type=smtp;
server {
listen 587;
proxy_pass cluster_smtp;
# ----------------- SMTP -------------------
upstream cluster_smtps {
check interval=5000 rise=2 fall=5 timeout=2000 type=smtp;
server {
listen 465;
proxy_pass cluster_smtps;
# ----------------- HTTP -------------------
upstream cluster_http {
check interval=5000 rise=2 fall=5 timeout=2000 type=tcp;
server {
listen 80;
proxy_pass cluster_http;
# ----------------- HTTPS -------------------
upstream cluster_https {
check interval=5000 rise=2 fall=5 timeout=2000 type=tcp;
server {
listen 443;
proxy_pass cluster_https;
#--------------- End of TCP Block --------------

Start NginX server:
service nginx start

Some explanations of this NginX configuration

interval=2000 # Alive-Check interval for the back-end mail servers, 2s
rise=2 # How many Alive-Checks must be successful in order to consider the server as ON-line
fall=5 # How many Alive-Checks must fail in order to consider the server as OFF-line
timeout=1000 # Timeout for responses of Alive-Checks Here: 1 sec.
type=imap; # Type of Alive-Check

STICKY Sessions
ip_hash; # Based on client IP

An overview of types from NGinX Git repositories:
1. tcp is a simple tcp socket connect and peek one byte.
2. ssl_hello sends a client ssl hello packet and receives the server ssl hello packet.
3. http sends a http request packet, receives and parses the http response to diagnose if the upstream server is alive.
4. smtp sends a smtp request packet, receives and parses the smtp response to diagnose if the upstream server is alive. The response begins with ‘2’ should be an OK response.
5. mysql connects to the mysql server, receives the greeting response to diagnose if the upstream server is alive.
6. pop3 receives and parses the pop3 response to diagnose if the upstream server is alive. The response begins with ‘+’ should be an OK response.
7. imap connects to the imap server, receives the greeting response to diagnose if the upstream server is alive.

19 Mar 14 Archiving all incoming/outgoing mails using Sieve

The following custom Sieve script can be used to make a copy of every email a user sends or receives.
In the example, the user is and the copy of the .MSG file is saved in the spyfolder directory.
if envelope :contains ["from","to"] "" { fileinto "c:\\spyfolder"; keep; }
Note: Be careful to monitor the size of the spyfolder as the message files could accumulate and fill the disk drive!

19 Mar 14 Blocking user to send sensitive information using Sieve

The following article uses examples to show how to block users from sending attachments containing sensitive information (e.g. financial information) to the outside world. The script blocks attachments with certain names by flagging particular words.

– Your domain is
– The administrator wants to block attachments with the word customer in the filename only if it is outbound (not to the local domain)
– The administrator also wants to block attachments with the word legal

Sieve Script:
Blocking ‘customer’ in attached filename:
if not envelope :contains "to" "" {
if attachment :matches "*customer*" { discard; stop; }

Blocking ‘customer’ and ‘legal’ in attached filename:
if not envelope :contains "to" "" {
if attachment :matches ["*customer*","*legal*"] { discard; stop; }