smtprox -- Transparent SMTP proxy
smtpprox [options] listen.addr:port talk.addr:port options: --children=16 --minperchild=100 --maxperchild=200 --debugtrace=filename_prefix
smtpprox listens on the addr and port specified by its first arg, and sends the traffic unmodified to the SMTP server whose addr and port are listed as its second arg. The SMTP dialogue is propogated literally, all commands from the client are copied to the server and the responses from the server are copied back from to the client, but the envelope info and message bodies are captured for analysis, and code has the option of modifying the body before sending it on, manipulating the envelope, or intervening in the SMTP dialogue to reject senders, recipients, or content at the SMTP level. The children option, defaulting to 16, allows adjusting how many child processes will be maintained in the service pool. Each child will kill itself after servicing some random number of messages between minperchild and maxperchild (100-200 default), after which the parent will immediately fork another child to pick up its share of the load. If debugtrace is specified, the prefix will have the PID appended to it for a separate logfile for each child, which will capture all the SMTP dialogues that child services. It looks like a snooper on the client side of the proxy. And if debugtracefile is defined, it returns its own banner including its PID for debugging at startup, otherwise it copies the server's banner back to the client transparently.
smtpprox 127.0.0.1:10025 127.0.0.1:10026
While the richness or lack thereof in the SMTP dialect spoken lies in the hands of the next SMTP server down the chain, this proxy was not designed to run on the front lines listening for traffic from the internet; neither its performance characteristics nor its paranoia were tuned for that role. Rather, it's designed as an intermediate component, suitable for use as the framework for a content-scanning proxy for use with Postfix's content-filtering hooks.
This proxy is tuned to some specific assumptions: execing perl is wickedly expensive, forking perl is fairly expensive, messages will vary rather widely in size, and memory footprint efficiency is somewhat more important than CPU utilization. It uses Apache-style preforking to almost entirely eliminate the need to fork perls, with controlled child restart to defend against resource leaks in children; it stores the body of the message in an unlinked file under /tmp, which should be a tmpfs; this prevents the allocation overhead associated with large strings (often 2-3x) and ensures that space will be returned to the OS as soon as it's not needed.