Jan 9, 2013

DKIM + SPF + Sendmail for multiple domains (Ubuntu)

First things first,

DKIM is DomainKeys Identified Mail and is used in mail servers, such as Postfix or Sendmail to sign e-mails and thus authenticating the sender so that a forgery can be detected. It also reduces the possibility of an e-mail being flagged as spam, but it's not a definite prevention.

A much simpler method is using SPF (Sender Policy Framework) which, in a nutshell, verifies the sender IP address.

According to the internet, using both should result to ????, PROFIT !!!.

SPF does not need a specific configuration. Whitelisted servers are listed in a DNS record, TXT or SPF, and an example record is:

example.com. IN TXT "v=spf1 a mx ~all"

And that's preety much it, for the simplest case there is. This record specifies the policy (v=spf1), whitelisted servers (a and mx records), and ~all states that every other IP address should be tagged as SOFTFAIL.
It can get much more complicated than this, so RTFM.

Okay, so, DKIM.

DKIM includes a cryptographic hash in the e-mail header which is calculated with the private key (on the server) and verified with the public key (in the DNS record).
DKIM-Signature: v=1; a=rsa-sha256; d=example.net; s=brisbane;
     c=relaxed/simple; q=dns/txt; l=1234; t=1117574938; x=1118006938;

First, install opendkim.
apt-get install opendkim

Edit the configuration file of opendkim.conf, located in /etc/opendkim.conf.
AutoRestart             Yes
UMask                   002
Syslog                  yes
AutoRestartRate         10/1h
Canonicalization        relaxed/simple
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/KeyTable
LogWhy                  Yes
Mode                    sv
PidFile                 /var/run/opendkim/opendkim.pid
SignatureAlgorithm      rsa-sha256
SigningTable            refile:/etc/opendkim/SigningTable
Socket                  inet:[email protected]
SyslogSuccess           Yes
TemporaryDirectory      /var/tmp
UserID                  opendkim:opendkim
As you can see, there are three more files to be added, TrustedHosts (whitelisted IPs that can sign e-mails), KeyTable (multiple domain configuration for public and private keys) and SigningTable (whitelisted users that can sign e-mail).

You get the idea.

[email protected] default._domainkey.example.com
All users from @example.com can sign. You can specifiy usernames and domains, instead of the wildcard, for additional security.

default._domainkey.example.com example.com:default:/etc/opendkim/keys/example.com.pvt
Location of the private key and name of the DNS record for each domain. The "default" before _domainkey.example.com and :default: is a selector. This can be changed to something else.

Next, we need to generate the public and private key for each domain.
Shouldn't be too difficult.
If some folders don't exist, just create them.
[email protected]:/etc/opendkim/keys# opendkim-genkey -D /etc/opendkim/keys/example.com -d example.com -s default
Again -s flag is for the selector. If you changed it, you need to enter it here.
The command generates a private key (default) and public key (default.txt). You will probably rename them, to match the configuration.
An important note here is that the files are owned by user opendkim, or you will get permission denied errors in /var/log/mail.err. Default permissions on those files are -rw------.

Move the private key to where you specified it should be in the KeyTable.
Insert the public key in your DNS as a TXT record.

Next up, telling sendmail to talk to opendkim.
Edit /etc/mail/sendmail.mc and add this line at the end. DO NOT EDIT sendmail.cf.
INPUT_MAIL_FILTER(`opendkim', `S=inet:[email protected]')

Rebuild sendmail configuration and restart, start opendkim if it's not running yet
[email protected]:~# sendmailconfig; service sendmail restart; service opendkim start
Test it out.

That's it, you're done!

Jan 8, 2013

PHP: shortest and easiest GeoIP (IP to Country)

Without using a database of IP addresses or an "external API" (not completely true), this is the shortest method of determining the country of an IP addresss.

The one-liner issues a shell_exec() to the whois command and parses the two letter country code from it.

if(preg_match('/^(\d+\.?){4}$/',$ip)) {
  $country = trim(shell_exec('whois '.$ip.' -H | grep country | awk \'{print $2}\''));

The preg_match() is of course optional, but for your own good, because as you may know, shell_exec() is VERY DANGEROUS.

Note: This does not work on all versions of WHOIS!

Also note that there is a daily query limit to the RIPE.NET database, so it's good to cache the results. It's not like that information gets changed often.

Jan 4, 2013

Sendmail :: X-Authentication-Warning: user set sender to email using -f

Solving the X-Authentication-Warning header in the emails you send requires quite a few steps.

An example of a typical warning:

X-Authentication-Warning: hostname: www-data set sender to [email protected] using -f

The -f flag in sendmail is used to set the envelope sender address. 
Usually the -f flag is passed in PHP's mail() function as an additional parameter argument. 

It comes in handy to set a valid bounce email address to catch undelivered mail. 

Even the PHP manual states that only the trusted users in the system (listed in /etc/mail/trusted-users) can set the -f flag. 
Each line in the file contains the trusted user name.

Trouble is, that's not enough

To tell sendmail to actually include the trusted-users file, you need to modify submit.mc, located in /etc/mail/submit.mc. Just add these two lines at the end of the file:



The last thing you need to do is rebuild the sendmail configuration files by executing the command sendmailconfig as root and restart sendmail.

Read more about SPF records and DKIM, to increase the chances of mail being delivered and not getting flagged as spam.