[exim] TCP Header Rewrite

Brian Candler B.Candler at pobox.com
Thu May 5 12:26:39 PDT 2005


On Thu, May 05, 2005 at 01:39:00PM +0200, John Oxley wrote:
>                          local
>                            ^
>                            I
>                            I
> client --> smarthost --> router --> shaper --> international
> 
> The smarthost is a FreeBSD-5.3-STABLE system running exim 4.50 built from the
> exim-mysql port.  The router is transparent.
> 
> This setup works well as is, but the problem is that the shaper thinks that the
> traffic has come from the smarthost itself, and not the client, and thus the
> client isn't being bandwidth limited for international mail.

Yep. That's the thing about having a smarthost; your mail is aggregated with
everyone else's.

The first solution I can see, which does not scale, is to give everyone
their own smarthost (or virtual smarthost), with its own IP address.

You can do this with exim:

1. The trivial way is to set up N exim daemons, all bound to N different
interfaces, and with slightly different configs (ACLs which permit only
client X to relay through virtual smarthost X)

2. Being a bit cleverer, you can have a single exim configuration which
listens on multiple IP addresses (which will happen anyway if your box has
multiple interfaces), and then chooses which interface to bind to for
outgoing connections based on which IP address the message arrived on.

It sounds like (2) is closest to what you propose. You might even get away
with something as simple as this:

[under 'begin transports']

remote_smtp:
  driver = smtp
  interface = $interface_address

Now, if you set up an Exim box with (say) 10 different IP aliases, try
connecting to each in turn and relaying a message through it. If my guess is
right, the relayed message will originate from the same interface as it came
in on. If so, all you need to do is to modify your ACL so that each client
can only relay via their own virtual smarthost, e.g. by making
relay_from_hosts a lookup based on $interface_address (if each client comes
from a different IP range). Alternatively, you could make them all use SMTP
AUTH, and then lookup their authenticated identity to find the interface
address for outgoing SMTP connections.

Things may break down if Exim has multiple messages queued to the same
remote host, and you don't want messages sent by one client to be relayed
down a TCP/IP connection belonging to another client (at their expense). So
you may need to set connection_max_messages = 1 to prevent that.

Now, you're still stuck with needing N IP addresses for N customers. In
theory you might be able to improve on that by using different ranges of
source ports for different customers; e.g. customer 1's mail can originate
from ports 1024-1039; customer 2's mail can originate from posts 1040-1055;
customer 3 is ports 1056-1081; and so on.

That would be really messy to implement, since Exim (sensibly) doesn't allow
you to choose which port to bind to for an outgoing connection, and it still
doesn't scale (allowing 16 ports per customer you'd be limited to about 4000
customers)

The fundamental problem is how your shaper can associate a particular
traffic stream with a particular customer. If the shaper had the ability to
act as a SOCKS proxy, then perhaps Exim could use it to open outbound
connections, and the shaper could use the proxy authenticated ID to
associate the stream with the customer. I don't know of any such shaper, but
maybe they do exist. You'd still need to modify Exim to be able to use a
SOCKS proxy for outbound SMTP connections (which is perhaps a useful feature
to have in the SMTP driver, although not that useful if nobody has asked for
it before :-)

HTH,

Brian.


More information about the freebsd-questions mailing list