Friday, March 24, 2006
Exim, FreeBSD & Greylisting
I was trying to find neat greylisting solutions for exim and came to the conclusion that there
weren't really any. The biggest stumbling block seemed to be my
requirements: that it use something like the Berkeley DB (rather than a full
fledged SQL database), and that it was in FreeBSD's ports system. There are
plenty of SQL-based solutions, and no exim solutions in ports.
What I did find was postgrey, a Postfix policy
server that supported greylisting. The question then became one of
whether I could convince exim to speak Postfix ...
This initially looked quite easy. Postgrey listens on a unix domain socket,
and exim has a readsocket expansion variable that reads from one. All I had
to do was emulate enough of Postfix's protocol on the socket. What I came
up with was:
defer log_message = greylisted host $sender_host_address
set acl_m0 = request=smtpd_access_policy\nprotocol_state=RCPT\n \
protocol_name=${uc:$received_protocol}\n \
helo_name=$sender_helo_name\n \
client_address=$sender_host_address\n \
client_name=$sender_host_name\n \
sender=$sender_address\n \
recipient=$local_part@$domain\n\n
set acl_m0 = ${sg{${readsocket{/var/run/postgrey}{$acl_m0} \
{5s}{}{action=DUNNO}}}{action=}{}}
message = ${sg{$acl_m0}{^\\w+\\s*}{}}
condition = ${if eq{${uc:${substr{0}{5}{$acl_m0}}}}{DEFER}{true}{false}}
(the lines with a \ right off to the right hand side aren't
supposed to break — remove the whitespace and \ and put them
on one line. You'll need to change /var/run/postgrey to whereever
your policy engine's socket is.)
What this does is set acl_m0 to contain a Postfix-ish query for the policy
server, and then pass that to postgrey. It then resets acl_m0 to postgrey's
response, and interprets that response as an ACL condition. Note that it
isn't a full implementation of Postfix's protocol. All it cares about is a
"DEFER" response when it needs to defer mail. (note "DEFER" and
"DEFER_IF_PERMIT" are handled the same.)
Note that the hardcoded action=DUNNO occurs when a socket read
times out, and allows this to fail safe (i.e. mail will be delivered) in the
event of a problem with postgrey.
Postfix's protocol allows for a policy server to prepend a header on
delivered e-mail, and postgrey uses this to notify users of how long mail
was delayed for. If you want to make use of this feature, you need the
following ACL somewhere under your defer one.
warn message = ${sg{$acl_m0}{^\\w+\\s*}{}}
condition = ${if eq{${uc:${substr{0}{7}{$acl_m0}}}}{PREPEND}{true}{false}}
This sets the headers to whatever comes after the "PREPEND" line.
There's a small problem with all of this, however. Postfix's protocol
allows policy server re-use; exim expects a readsocket to send an EOF.
postgrey implements the former and, as a result, exim never gets a response.
Since postgrey's written in Perl, it's
easy to change this behaviour. It's easily solved with a patch to postgrey. The
patch adds a --no-reuse option ot postgrey which causes an EOF to be sent
when a particular policy run is complete.
With this done, exim will happily greylist using postgrey. I suspect the
same approach can be taken for many other Postfix policy servers ... YMMV
and all that.
posted by guy at: 09:19 SAST |
path: /systems |
permanent link
Sunday, March 05, 2006
Of Fibre Terminations & Inter-Switch Trunks
It's been a long, long weekend of work. It all started yesterday with our
relocating about 48 pairs of fibre optics from one building to another
building next door. Boring, but very time consuming stuff. After many
hiccups we got it all up and running at about 10AM this morning. But that's
not the interesting bit, and I'm well over it, so I'm not going to mention
it again ;-)
What is cool is what we did this afternoon. We set up our first
inter-switch trunk (IST). We have two Nortel ERS8600 routing switches
situated about a kilometre appart (one in each of our data centres). As of
about 4PM this afternoon, they're one logical switch.
The way this works is essentially VRRP, but with a few subtle differences.
For each VLAN that we set up a VRRP gateway IP address, the two switches
load balance by being the VRRP "master" for any traffic entering the IST
through them. This is best explained with the following traceroutes:
kimbly# netstat -rn | grep default
default 146.231.160.1 UGS 0 15904 tx0
kimbly# traceroute hippo.ru.ac.za
traceroute to hippo.ru.ac.za (146.231.128.1), 64 hops max, 40 byte packets
1 catering-amm.gw.ru.ac.za (146.231.160.3) 0.601 ms 0.424 ms 0.412 ms
2 struben.core.ru.ac.za (146.231.0.17) 0.623 ms 0.524 ms 0.476 ms
3 hippo.ru.ac.za (146.231.128.1) 0.381 ms 0.307 ms 0.324 ms
kimbly# traceroute nat.amm.ru.ac.za
traceroute to nat.amm.ru.ac.za (146.231.48.34), 64 hops max, 40 byte packets
1 catering-amm.gw.ru.ac.za (146.231.160.3) 0.601 ms 0.424 ms 0.412 ms
2 nat.amm.ru.ac.za (146.231.48.34) 0.404 ms 0.357 ms 0.417 ms
drostdy# netstat -rn | grep default
default 146.231.160.1 UGS 0 11895 rl0
drostdy# traceroute nat.amm.ru.ac.za
traceroute to nat.amm.ru.ac.za (146.231.48.34), 64 hops max, 40 byte packets
1 catering-struben.gw.ru.ac.za (146.231.160.2) 0.779 ms 0.584 ms 0.556 ms
2 amm.core.ru.ac.za (146.231.0.18) 0.716 ms 0.557 ms 0.528 ms
3 nat.amm.ru.ac.za (146.231.48.34) 0.404 ms 0.357 ms 0.417 ms
drostdy# traceroute hippo.ru.ac.za
traceroute to hippo.ru.ac.za (146.231.128.1), 64 hops max, 40 byte packets
1 catering-struben.gw.ru.ac.za (146.231.160.2) 0.779 ms 0.584 ms 0.556 ms
2 hippo.ru.ac.za (146.231.128.1) 0.381 ms 0.307 ms 0.324 ms
For those who don't get it, both machines have a common default gateway
(146.231.160.1). kimbly and nat.amm are connected to amm.core.ru.ac.za,
drostdy and hippo are connected to struben.core. The first hop on each
traceroute shows the non-VRRP IP address of the switch doing the routing
— in other words, the two traceroutes are routed by two different
switches, even though they have the same IP as next-hop.
That's just cool. And I'm tired. :)
posted by guy at: 20:17 SAST |
path: /systems |
permanent link
