Using DKIM in Exim
Since Exim 4.70, DKIM (DomainKeys Indentified Mail - RFC4871) has been supported by default.
The current implementation supports signing outgoing mail, as well as verifying signatures in incoming messages, using the acl_smtp_dkim ACL. By default, DKIM signatures are verified as new messages come in, though no action is taken unless you've implicitly configured rules in the DKIM ACL.
After installing Exim (>= 4.70), you should see debug logs for incoming mail from servers that have DKIM signatures setup- they look like:
DKIM: d=gmail.com s=gamma c=relaxed/relaxed a=rsa-sha256 [verification succeeded]
Verifying Incoming Mail
By default, Exim does not filter any mail based on the validity of the DKIM signature- it's up to you to add ACL rules to control what happens when you receive messages with "bad" signatures.
First add an ACL section for the DKIM processing; this should be included with your other ACL statements:
acl_smtp_dkim = acl_check_dkim
Next, after the "begin acl", section, add your DKIM ACL section, and by default, accept all messages in this ACL:
acl_check_dkim: accept
Now you need to decide what kind of rules you want to setup- you probably don't want to put a rule that applies to all domains- though, if the company went to the trouble of adding DKIM signatures to their e-mail, you'd hope they'd get it right, and not publish invalid public keys.
For now, let's add a simple rule for gmail; google knows what they're doing, so their systems should be setup correctly:
acl_check_dkim: # # check the DKIM signature for gmail # deny message = Common guys, what's going on? sender_domains = gmail.com dkim_signers = gmail.com dkim_status = none:invalid:fail accept
You can add as many rules, for whatever domains you want in this ACL.
Signing Outgoing Mail
Now that you're checking incoming mail, you probably want to sign mail coming out of your system. This is a relatively easy process, that I've broken down into three steps:
Step1- Generate a private and public key to sign your messages; you can do this easily with openssl:
#openssl genrsa -out dkim.private.key 768
Then extract the public key from the private key:
#openssl rsa -in dkim.private.key -out dkim.public.key -pubout -outform PEM
Step2- Configure the Exim remote-smtp transport to sign outgoing messages, using your new private key. You'll need to pick a domain and a selector for this process.
When remote SMTP servers validate your DKIM signatures, they simply do a DNS look up, based on the selector and your domain- the domain needs to (obviously) be a valid domain you own, that you can add DNS entries to, and the selector can be any string you want. So, for example, using the domain "example.com", and the selector "x", you would add to the remote_smtp transport in Exim:
remote_smtp:
driver = smtp
dkim_domain = example.com
dkim_selector = x
dkim_private_key = dkim.private.key
dkim_canon = relaxed
This tells Exim to sign any outbound e-mail, using the domain example.com, the selector "x", and the private key we just generated. The dkim_canon = relaxed, sets the canonicalization method to use when signing messages. DKIM supports "simple" and "relaxed" algorithms- to understand the difference, see section 3.4 of the DKIM RFC.
Step3- add your DKIM public key to your DNS.
The DKIM public key generated above is advertised to other SMTP servers, using a DNS TXT record. In DNS for the domain example.com, add a new TXT record:
x._domainkey.example.com. TXT v=DKIM1; t=y; k=rsa; p=<public key>
Where "x" is the selector you used above, and <public key> is the public key data (minus the key header/footer text).
When setup correctly, your DKIM text record should look something like this:
# host -t txt x._domainkey.example.com x._domainkey.example.com descriptive text "v=DKIM1\; t=y\; k=rsa\; p=MIGfMA0GCS qGSIb3DQEBAQUAA4GNADCBiQKBgQC5k8yUyuyu9UAVHHU7Al4ppTDtxFWsZ6Pqd9NWZnomtewBdz8I 2LJkqmA/3Cyb5Eiaqk4NulPFfDbfA0Lkw7SNyOS9BRN02KGtKIWjFqDwjB99haaWYw9H4IZcuJp0Y q0kySCdBp/sPP+iTotdBiE85Jakw3tzgYkdvaS05ZUdBwIDAQAB"
(lines breaks were added for readability- your entry should be one continuous line)
This DNS record is referred to as the "selector" record; you need to also setup a "policy" record. The policy record is your domains policy for domain keys- you should start with something like:
_domainkey.example.com. t=y; o=~;
The t=y specifies that you are in test mode and this should be removed when you are certain that your domain key setup is functioning properly. The "~" in the o=~ specifies that some of the mail from your domain is signed, but not all. You could also specify o=- if all of the mail coming from your domain will be signed.
Once you have all of that in-place, restart Exim, and send out a message using the remote-smtp transport. You should now see a DKIM-Signature: header listed in the message headers, which lists your domain (as d=), and selector (as s=), as well as a signature for this e-mail, which can be validated against your public DKIM key, that you've published in DNS.
For more information, see the Exim DKIM page, or the DKIM RFC.
UPDATE:
Once you've set everything up, you can test your DKIM (and SPF and SenderID, etc) install, by using the port25.com validation service.
Just send an e-mail to check-auth@verifier.port25.com, and it will auto-respond with a validation report
All new Fonolo interface launched!
I'm very excited to announce the release of the new Fonolo consumer web interface. This new web interface not only has a new look and feel, but has improved usability, and many new features and enhancements.
Some of the enhancements to the web portal include:
Anonymous Deep Dialing
Anonymous, in the sense that you do NOT have to sign-up for an account with Fonolo, to try the service out. Search for the company you want from the list of over 500 companies in our database, right from the main page of our website, and click to start your call- no sign-up required. no special software. no special phone- all for FREE.


QuickTones
Ever been on a phone call, and they ask you for your account number? or if you have a Frequent Flyer number, but you can't remember it, and the piece of paper you have it written down on is long since gone?
Store frequently used account numbers, frequent flyer numbers, PINs, etc, in the Fonolo system, for one-click access while on a call. Simply select the tones from your list, and Fonolo will send the tones on your call, as if you had pressed the buttons yourself.
Heads-Up Display for your calls
While a call is active, you'll have full control over adding notes or recordings, with our new "Heads-Up Display" at the top of your screen. This control panel remains active during the life of your call, even if you navigate to other sections of the site.

Improved Call Recordings and Notes
When you make recordings during a call, Fonolo will organize them on a master timeline for that call, along with any notes that you added. Now you can flag the important parts and easily find them later.

Try the new Fonolo website today! it's completely free, and easy to use.
Handling SIP URI Dialing in Asterisk
Asterisk, by design, is very "extension" orientated- that is, if you want to dial an end-point, it requires an extension to route the call to. These extensions (defined in the asterisk extensions.conf file), can be extensions registered to phones, DIDs (XXXYYYZZZZ), or simply usernames assigned to users by the network administrator. Extensions are used for both incoming, and outgoing phone calls.
For example, if I place a call through my SIP phone to 1-444-555-1212, then asterisk will look up the "extension" 14445551212 in the extensions.conf file, to determine how to route the call.
Similarly to how e-mail works, an artifact of these extensions is a direct SIP address, which is basically your SIP extension @ your SIP server- so, if my phone was extension 555, and my SIP server had the IP address 192.168.1.1, then my SIP address would be: sip:555@192.168.1.1, and (if it's not implictely blocked), I can be dialed directly using that SIP address.
But, because Asterisk is so extension orientated, it doesn't easily allow for outbound dialing, using remote SIP addresses; If I try to dial the address sip:444@somedomain.com, Asterisk will immediately strip off the host portion (@somedomain.com), and try to route the call based simply on the extension "444"- which, since it's an extension on a remote server (@somedomain.com), it won't be able to route it locally, and will fail.
The solution? Well, it's not ideal, but Asterisk provides the ability to use wild cards in the extensions.conf file (it refers to them as "patterns") when doing extension look ups; this is handy when you have blocks of extension or DID's- you can use the wildcard to map like extensions to the same config, keeping your config file small.
The issue, is that the wild card only compares against the local part of the SIP URI, which can look like almost anything, including other phone numbers.
First, define some general config
[general] ; ; Your termination provider (defined in sip.conf) ; TERM_PROVIDER = SIP/company_peer ; ; The IP address of this asterisk server ; ASTERISK_IP = 192.168.1.1
The "ASTERISK_IP" address is important later, as we'll use it to validate outgoing SIP addresses.
Then in your default config, you should have something like this configured already- handling NANPA style dialing, and international dialing
[default]
;
; Dial NANPA style phone numbers directly
;
exten => _1NXXNXXXXXX,n,Dial(${TERM_PROVIDER}/${EXTEN},60)
exten => _1NXXNXXXXXX,n,HangUp()
;
; Dial international numbers directly
;
exten => _011.,n,Dial(${TERM_PROVIDER}/${EXTEN}, 60)
exten => _011.,n,HangUp()
After all the specific matches are done, then add:
;
; very last, assume anything else is a SIP URI
;
exten => _.,n,GotoIf($[${SIPDOMAIN} = ${ASTERISK_IP}]?unhandled)
exten => _.,n,GotoIf($[${SIPDOMAIN} = ${ASTERISK_IP}:5060]?unhandled)
exten => _.,n,Macro(uri-dial,${EXTEN}@${SIPDOMAIN})
exten => _.,n,HangUp()
;
; if the call doesn't match anything
;
[unhandled]
exten => s,n,Congestion()
The reason this has to be last, is because matching the extension "_." will match *anything*- basically it's a catch-all. You're saying that if it doesn't match anything else before this, then assume it must be a SIP URI.
This section also compares the ${SIPDOMAIN} variable to your ASTERISK_IP address; this ensures that only SIP URI's with remote hosts are processed as SIP URI's. If the host matches our ASTERISK_IP address value (ie- it's a local extension), then it should have already matched something above this catch-all config.
Pass any SIP URI dials to the uri-dial MACRO, merging back together the extension and the SIP domain value.
;
; handle dialing SIP uri's directly
;
[macro-uri-dial]
exten => s,n,NoOp(Calling as SIP address: ${ARG1})
exten => s,n,Dial(SIP/${ARG1},60)
This solution works, but isn't ideal, as it will match anything that didn't already match; a better solution would be for it to NOT strip off the SIP domain, and allow for using a regular expression of some kind to check the extension, but there is currently no better way of handling this in Asterisk.
Memcache Access From PostgreSQL
A big part of my job is to spend time figuring out how new technologies work, build on it, and then figure out new and inventive ways of merging it into new and existing systems- so I spent a lot of time "playing" around with stuff.
One thing I recently threw together, was some simple stored procedures for PostgreSQL, to give us built-in access to our memcached cluster, using the PL/PERL procedural language, and the Cache::Memcached module. None of this is rocket science, but might be useful for somebody out there that is looking to implement something similar.
First off, you need to build PostgreSQL with PERL support, and create the plperlu (un-trusted) language in our database; you need to use the "un-trusted" language, as we need to "use" the Cache::Memcached module;
postgres=# create language plperlu ; CREATE LANGUAGE
Then you need to install the Cache::Memcached PERL module; I'll assume you know how to do that; you can either install it through CPAN, or get it from the cpan.org site.
You also need at least one instance of memcached running somewhere; it doesn't have to be on your local network, it just needs to be accessible by your database.
Then create the following procedures; I've only listed the "set" and "get" procedures, but you could easily follow the Cache::Memcached module man page, and create a "replace" and "delete" (and any other) procedures you needed.
So first the "set" procedure:
create or replace function memcache_set(_key text, _value bytea) returns int as $$
use Cache::Memcached;
my ($_key, $_value) = @_;
$m = new Cache::Memcached {
'debug' => 0
};
my @list = ("127.0.0.1:9996", "127.0.0.1:9997");
my $servers = \@list;
$m->set_servers($servers);
$m->enable_compress(0);
if ($m->set($_key, $_value))
{
return 0;
} else
{
return 1;
}
$$ language plperlu;
And then a "get" procedure:
create or replace function memcache_get(_key text) returns bytea as $$
use Cache::Memcached;
my ($_key) = @_;
$m = new Cache::Memcached {
'debug' => 0
};
my @list = ("127.0.0.1:9996", "127.0.0.1:9997");
my $servers = \@list;
$m->set_servers($servers);
$m->enable_compress(0);
my $val = $m->get($_key);
if (defined($val))
{
return $val;
} else
{
return undef;
}
$$ language plperlu;
Now, in this case, I used a list of two different servers, both running on localhost, one on port 9996 and the other on port 9997; these servers could be anywhere, and you could only list one- but a really important thing to remember: if you do list more than one server, make sure you always list it in the same order, between all your procedures and all applications that may use this same data.
memcached calculates which server to store the data on, based on the order of this list; so you'll get un-expected results if you list these servers differently between your applications.
A Simple Test
Now that you have the functions defined, you can use them to do some really interesting caching, directly from your database. Starting off with a simple test:
postgres=# select memcache_set('foo', 'bar');
memcache_set
---------------
0
(1 row)
Then do a "get" to retrieve the data
postgres=# select memcache_get('foo');
memcache_get
---------------
bar
(1 row)
Database Session Handler
Now, lets say you had a database-backed session handler for your website; say maybe a PHP site, using something like this, which simply uses the PHP session_set_save_handler() method. Assume a simple session table like this:
create table sessions ( session_id char(32) not null, data bytea not null default '' );
"session_id" is the PHP session id (an MD5 string in this case), and "data" is the serialized contents of the PHP session.
Then add two rules- one for insert and one for update; this triggers the new memcache_set() procedure, so that new session data is always pushed out to your memcached servers
create rule session_insert_rule as on insert to sessions do also select memcache_set(NEW.session_id::text, NEW.data); create rule session_update_rule as on update to sessions do also select memcache_set(NEW.session_id::text, NEW.data);
Testing this is simple:
postgres=# insert into sessions values ('5cc27b0285c9d2e6dc4125456d308548',
'This would be the session data');
INSERT 0 1
postgres=# select memcache_get('5cc27b0285c9d2e6dc4125456d308548');
memcache_get
--------------------------------
This would be the session data
(1 row)
And then subsequent updates
postgres=# update sessions set data = 'This is the new data' where
session_id = '5cc27b0285c9d2e6dc4125456d308548';
UPDATE 1
postgres=# select memcache_get('5cc27b0285c9d2e6dc4125456d308548');
memcache_get
-------------------
This is the new data
(1 row)
Now just make your PHP session handler (or whatever) checks memcached first, before selecting from the sessions table; if you build it right, and set your expiration times correctly, you should be able to build a system that (almost) *never* reads this data from the database, as the data is always available from memcached.