On 09/22/2008 08:02:44 AM, Wietse Venema wrote:
This is a shell script that sits between a Postfix SMTP client and a Postfix SMTP server. It is implemented with awk and nc. awk reads from the SMTP client and sends modified content into nc. The shell script runs as a child process of the spawn daemon. Postfix --> awk -\ Postfix SMTP nc <---> SMTP client <--------/ server The biggest problem with this script are: 1) Your script only works if the Postfix SMTP server closes the connection immediately after the completion of a MAIL FROM transaction. Otherwise, the nc process will hang until the Postfix SMTP server times out after 1000 seconds.
I did indeed see this behavior, and wrote to the list with both a question as to whether the SMTP exchange should really finish before the SMTP server closes the connection (the answer is yes), and proposed code which (see below) works under every test condition I've come up with..
2) Your script assumes that every SMTP connection will have only one MAIL FROM transaction. However, the SMTP protocol supports more than one MAIL FROM transaction per SMTP connection, and Postfix expects that SMTP clients implement this part of the SMTP standard.
Could you please elaborate as to where this failure is? The awk script was written to distinguish between: mail headers and body. the SMTP commands the the mail content (by detecting the SMTP DATA command and it's ending period <cr> <lf>) no matter how many MAIL FROM transactions succeed or fail. I did find a bug concerning email messages with no body, but your concern appears more general than that. The filter does not care whether the mail is accepted for delivery or not, or any other SMTP semantics or state because it does not reject mail. It's purpose is to filter mail content and otherwise pass SMTP commands untouched. Having distinguished SMTP commands from mail headers from mail body alteration of mail content is a straightforward enhancement away. As far as I can tell it works with respect to multiple MAIL FROM transactions. (Specifically, it removes Sender: message headers. Note that this is a stupid way to do this. The header_checks IGNORE feature, IIRC, would be the right way to do this. But that's not the point. The point is having some simple working code as a starting point for when I want to quickly put together some correct but not necessarily efficient filtering.) Here's the script again, patched with DELAY set to 0 and the conditional fixed to support messages with no body: #!/bin/sh DELAY=0 host=$1 port=$2 awk -W interactive \ 'BEGIN {headers = 1; data = 0;}; /^DATA\r$/ {data = 1;}; /^\r$/ {if (data == 1) { headers = 0; } }; {if (data == 1) { if (headers == 0 || $1 == "Sender:") { print; } if ($0 == ".\r") { # End of data, smtp loops and allows another message headers = 1; data = 0; } } else { print; } }; ' \ | nc -q $DELAY $host $port
... and your script is not built to handle the case where the Postfix SMTP server does not close a connection immediately.
The bug is that you use nc, which does not terminate until it encounters an end-of-file condition on input from BOTH stdin AND from the network.
The classic nc terminates ONLY when the network side closes. The -q (Debian patch) will tell nc to terminate upon encountering an end-of-file condition on stdin, after flushing all output to the network, irrespective of whether the network has an end-of-file condition. When used with -q nc ALSO terminates when the network side is closed. nc -q takes a value, the number of seconds before terminating, so nc -q 0 means terminate when STDIN closes, after flushing the network buffers. Victor Duchovni informs me that it's expected for postfix to disconnect rather than sending an SMTP QUIT, so I can safely set DELAY to 0 and eliminate the problem I was having with nc hanging. This makes complete sense in the context of what SMTP says about unexpected closure of the TCP connections, but I thought it was safer to ask instead of guessing about the results of unfamiliar behavior. This takes care of the end-of-file condition on the stdin side.
A properly implemented SMTP proxy filter takes action immediately when it encounters an end-of-file condition on input from EITHER stdin OR from the network.
Since nc always terminates when the network side closes, the script should work. As it appeared to do. I wrote because I was wondering about the hanging nc (and it's connected smtpd) process; now I know I can safely get rid of that by setting DELAY to 0. (It's too bad -q is Debian and not part of the stock nc.) This exchange has been like pulling teeth. Is there something wrong with the way I'm interacting with the list or something I can do differently to make things easier in the future? The only thing I can't do is eliminate the confusion on my part because if I weren't confused I wouldn't be asking questions of the list in the first place. Thank you for the help with this. Karl <[EMAIL PROTECTED]> Free Software: "You don't pay back, you pay forward." -- Robert A. Heinlein