. mombe.org
home of the mad cow
  Not A Blog
 

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

Bloxsom Powered

© 2002-2005, webmaster@mombe.org
 
 
RSS Valid XHTML 1.0!

Creative Commons License