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

Reply via email to