So we concluded that Postfix can't generate the queue id early enough to make read_commands_file() work from filter_relay()...
Can we consider my patch as the next best thing? Thanks. Oh, for what it's worth, I've been running this in-house for 4 months and it works fine. -------- Original Message -------- Subject: Re: [Mimedefang] Accessing the source/destination port #'s at filter_relay Date: Tue, 04 May 2010 11:40:40 -0600 From: Philip A. Prindeville <[email protected]> Reply-To: [email protected] To: [email protected] Decided it was cleaner to use globals than to change the signature (prototype) of filter_relay() and filter_helo(). Introduced therefore 3 new globals: $RelayPort $OurAddr $OurPort which are set in the context of both of these hooks. As a side-effect of introducing these variables, I can make tests now in filter_relay() like: if ($hostname eq "[$hostip]"&& $OurPort != 587) { md_syslog('debug', "no rDNS: reject [$hostip]"); return ('TEMPFAIL', "No rDNS records found; try again when you've properly configured your DNS."); } i.e. require rDNS for relays (but not for clients that are submitting locally). Another test I can do in filter_helo(): if ($helo =~ /^\[(\d{1,3}\.\d{1,3}.\d{1,3}\.\d{1,3})\]$/) { my $inet = inet_aton($1); # check for a valid dotted-quad. # use the same error message as above... don't make it too easy # to guess what our checks are. if (!defined($inet) || $inet eq INADDR_NONE) { md_syslog('debug', "badquad: $helo ($hostname [$hostip])"); return ('REJECT', "Incorrect format for address-literal"); } ... # lastly, check to see if what he thinks is his address is # what we think is his address. Hosts behind NATting gateways # or that are multi-homed might get this wrong, so don't be # surprised if you need to yank this test. if ($helo ne "[$hostip]"&& $OurPort != 587) { md_syslog('debug', "wrong ip: [$hostip] claims to be $helo"); return ('REJECT', "Address forgery attempt, [$hostip] claims to be $helo"); } # we could do more tests... For instance, only allow # bracketed quads for local connections... return ('CONTINUE', "OK"); } A common attempt to subvert our filters is to either say "HELO [192.168.x.x]" from outside, or else to say "HELO [66.232.79.143]" which is of course my own IP address. Relays should know their own addresses (and indeed, be using names, not dotted-quads). Clients, on the other hand, are often laptops or phones in hotspots behind a NATting Wifi/DSL router, and hence will get this wrong. But that's ok, since we require authentication on port 587. Indeed, if you have an iPhone on AT&T's 3G network, you'll have a 10.x.x.x address, but their NATting gateway will *not* rewrite your HELO string with your public address.
--- mimedefang-2.68/Changelog.orig 2010-05-03 18:51:03.000000000 -0600 +++ mimedefang-2.68/Changelog 2010-05-03 17:30:04.000000000 -0600 @@ -2,6 +2,12 @@ WARNING: Before upgrading MIMEDefang, pl *** NOTE INCOMPATIBILITY ** to see if anything has changed that might affect your filter. +2010-05-03 Philip A. Prindeville <[email protected]> + + * Add remote port, local address, local port as args to + filter_relay(). Useful if you're using IPTables::libiptc to + perform tarpitting for example. + 2010-02-24 David F. Skoll <[email protected]> * MIMEDefang 2.68 RELEASED --- mimedefang-2.68/mimedefang.pl.in.orig 2010-02-24 07:55:03.000000000 -0700 +++ mimedefang-2.68/mimedefang.pl.in 2010-05-04 11:15:43.000000000 -0600 @@ -36,8 +36,9 @@ use vars qw($AddWarningsInline @StatusTa $DefangCounter $Domain $EntireMessageQuarantined $MessageID $Rebuild $QuarantineCount $QuarantineSubdir $QueueID $MsgID $MIMEDefangID - $RelayAddr $WasResent $RelayHostname + $RelayAddr $WasResent $RelayHostname $RelayPort $RealRelayAddr $RealRelayHostname + $OurAddr $OurPort $ReplacementEntity $Sender $ServerMode $Subject $SubjectCount $ClamdSock $SophieSock $TrophieSock $SuspiciousCharsInHeaders @@ -5640,7 +5641,8 @@ sub md_get_bogus_mx_hosts { sub do_main_loop () { # Infinite server loop... well, not quite infinite; we stop on EOF # from STDIN. - my ($workdir, $map, $key, $ip, $name, $helo, $sender, $recip, $firstRecip); + my ($workdir, $map, $key, $ip, $name, $helo, $sender, $recip, $firstRecip, + $port, $myip, $myport); # Try to open the status descriptor if ($DoStatusTags) { @@ -5725,18 +5727,24 @@ sub do_main_loop () { next; } - if ($_ =~ /^relayok (\S*)\s+(\S*)/) { + if ($_ =~ /^relayok (\S*)\s+(\S*)\s+(\S*)\s+(\S*)\s+(\S*)/) { $ip = percent_decode($1); $name = percent_decode($2); - relay_ok($ip, $name); + $port = percent_decode($3); + $myip = percent_decode($4); + $myport = percent_decode($5); + relay_ok($ip, $name, $port, $myip, $myport); chdir($Features{'Path:SPOOLDIR'}); next; } - if ($_ =~ /^helook (\S*)\s+(\S*)\s+(\S*)/) { + if ($_ =~ /^helook (\S*)\s+(\S*)\s+(\S*)\s+(\S*)\s+(\S*)\s+(\S*)/) { $ip = percent_decode($1); $name = percent_decode($2); $helo = percent_decode($3); - helo_ok($ip, $name, $helo); + $port = percent_decode($4); + $myip = percent_decode($5); + $myport = percent_decode($6); + helo_ok($ip, $name, $helo, $port, $myip, $myport); chdir($Features{'Path:SPOOLDIR'}); next; } @@ -5859,12 +5867,15 @@ sub init_globals () { $MsgID = "NOQUEUE"; $MessageID = "NOQUEUE"; $Helo = ""; + $OurAddr = ""; + $OurPort = 0; $QueueID = "NOQUEUE"; $QuarantineCount = 0; $Rebuild = 0; $EntireMessageQuarantined = 0; $QuarantineSubdir = ""; $RelayAddr = ""; + $RelayPort = 0; $RealRelayAddr = ""; $WasResent = 0; $RelayHostname = ""; @@ -7066,11 +7077,14 @@ sub send_filter_answer ($$$$;$$$) { # %ARGUMENTS: # hostip -- IP address of relay host # hostname -- name of relay host +# port -- TCP port of relay host +# myip -- IP address of server +# myport -- TCP port of server # %RETURNS: # Nothing, but prints "ok 1" if we accept connection, "ok 0" if not. #*********************************************************************** sub relay_ok ($$) { - my($hostip, $hostname) = @_; + my($hostip, $hostname, $port, $myip, $myport) = @_; if (!defined(&filter_relay)) { send_filter_answer('CONTINUE', "ok", "filter_relay", "host $hostip ($hostname)"); @@ -7080,6 +7094,10 @@ sub relay_ok ($$) { # Set up globals $RelayAddr = $hostip; $RelayHostname = $hostname; + $RelayPort = $port; + $OurAddr = $myip; + $OurPort = $myport; + my($ok, $msg, $code, $dsn, $delay) = filter_relay($hostip, $hostname); send_filter_answer($ok, $msg, "filter_relay", "host $hostip ($hostname)", $code, $dsn, $delay); } @@ -7090,12 +7108,15 @@ sub relay_ok ($$) { # ip -- IP address of relay host # name -- name of relay host # helo -- arg to SMTP HELO command +# port -- TCP port of relay host +# myip -- IP address of server +# myport -- TCP port of server # %RETURNS: # Nothing, but prints "ok 1" if we accept connections from this host. # "ok 0" if not. #*********************************************************************** -sub helo_ok ($$$) { - my($ip, $name, $helo) = @_; +sub helo_ok ($$$$$$) { + my($ip, $name, $helo, $port, $myip, $myport) = @_; if (!defined(&filter_helo)) { send_filter_answer('CONTINUE', "ok", "filter_helo", "helo $helo"); @@ -7106,6 +7127,9 @@ sub helo_ok ($$$) { $RelayAddr = $ip; $RelayHostname = $name; $Helo = $helo; + $RelayPort = $port; + $OurAddr = $myip; + $OurPort = $myport; my($ok, $msg, $code, $dsn, $delay) = filter_helo($ip, $name, $helo); send_filter_answer($ok, $msg, "filter_helo", "helo $helo", --- mimedefang-2.68/mimedefang.h.orig 2009-09-03 14:59:15.000000000 -0600 +++ mimedefang-2.68/mimedefang.h 2010-05-04 10:41:25.000000000 -0600 @@ -29,9 +29,11 @@ extern int MXCheckFreeSlaves(char const extern int MXScanDir(char const *sockname, char const *dir); extern int MXCommand(char const *sockname, char const *cmd, char *buf, int len); extern int MXRelayOK(char const *sockname, char *msg, - char const *ip, char const *name); + char const *ip, char const *name, + int port, char const *myip, int myport); extern int MXHeloOK(char const *sockname, char *msg, - char const *helo, char const *ip, char const *name); + char const *helo, char const *ip, char const *name, + int port, char const *myip, int myport); extern int MXSenderOK(char const *sockname, char *msg, char const **sender_argv, char const *ip, char const *name, char const *helo, char const *dir, char const *qid); --- mimedefang-2.68/mimedefang.c.orig 2010-02-03 08:11:32.000000000 -0700 +++ mimedefang-2.68/mimedefang.c 2010-05-04 11:07:08.000000000 -0600 @@ -159,7 +159,9 @@ static int NumAdditionalMacros = 0; struct privdata { char *hostname; /* Name of connecting host */ char *hostip; /* IP address of connecting host */ + int hostport; /* TCP port of connecting host */ char *myip; /* My IP address, from Sendmail macro */ + int myport; /* My TCP port, from Sendmail macro */ char *sender; /* Envelope sender */ char *firstRecip; /* Address of first recipient */ char *dir; /* Work directory */ @@ -504,6 +506,9 @@ mfconnect(SMFICTX *ctx, char *hostname, #if defined(AF_INET6) && defined(HAVE_INET_NTOP) struct sockaddr_in6 *in6sa = (struct sockaddr_in6 *) sa; #endif + char *me; + char *val; + unsigned n; DEBUG_ENTER("mfconnect"); @@ -555,7 +560,9 @@ mfconnect(SMFICTX *ctx, char *hostname, } data->hostname = NULL; data->hostip = NULL; + data->hostport = -1; data->myip = NULL; + data->myport = -1; data->sender = NULL; data->firstRecip = NULL; data->dir = NULL; @@ -621,10 +628,12 @@ mfconnect(SMFICTX *ctx, char *hostname, } } } + data->hostport = ntohs(in6sa->sin6_port); } else #endif if (sa->sa_family == AF_INET) { tmp = inet_ntop(AF_INET, &insa->sin_addr, data->hostip, 65); + data->hostport = ntohs(insa->sin_port); } else if (sa->sa_family == AF_LOCAL) { tmp = "127.0.0.1"; strcpy(data->hostip, tmp); @@ -658,6 +667,23 @@ mfconnect(SMFICTX *ctx, char *hostname, strcpy(data->hostip, "127.0.0.1"); } + /* Get my IP address */ + me = smfi_getsymval(ctx, "{if_addr}"); + if (me && *me && MyIPAddress && !strcmp(me, MyIPAddress)) { + data->myip = MyIPAddress; + } else if (me && *me && strcmp(me, "127.0.0.1")) { + data->myip = strdup_with_log(me); + } else { + /* Sigh... use our computed address */ + data->myip = MyIPAddress; + } + + /* get our local port */ + val = smfi_getsymval(ctx, "{daemon_port}"); + if (val && *val && (sscanf(val, "%u", &n) == 1)) { + data->myport = n; + } + data->dir = NULL; data->fd = -1; data->headerFD = -1; @@ -668,7 +694,7 @@ mfconnect(SMFICTX *ctx, char *hostname, if (doRelayCheck) { char buf2[SMALLBUF]; int n = MXRelayOK(MultiplexorSocketName, buf2, data->hostip, - data->hostname); + data->hostname, data->hostport, data->myip, data->myport); if (n == MD_REJECT) { /* Can't call smfi_setreply from connect callback */ /* set_dsn(ctx, buf2, 5); */ @@ -731,7 +757,8 @@ helo(SMFICTX *ctx, char *helohost) if (doHeloCheck) { char buf2[SMALLBUF]; int n = MXHeloOK(MultiplexorSocketName, buf2, data->hostip, - data->hostname, data->heloArg); + data->hostname, data->heloArg, data->hostport, + data->myip, data->myport); if (n == MD_REJECT) { set_dsn(ctx, buf2, 5); cleanup(ctx); @@ -788,7 +815,6 @@ envfrom(SMFICTX *ctx, char **from) time_t now = time(NULL); unsigned long ulnow = (unsigned long) now; char *queueid; - char *me; dynamic_buffer dbuf; char mxid[MX_ID_LEN+1]; @@ -944,7 +970,9 @@ envfrom(SMFICTX *ctx, char **from) append_macro_value(&dbuf, ctx, "cert_subject"); append_macro_value(&dbuf, ctx, "cipher"); append_macro_value(&dbuf, ctx, "cipher_bits"); + append_macro_value(&dbuf, ctx, "client_port"); append_macro_value(&dbuf, ctx, "daemon_name"); + append_macro_value(&dbuf, ctx, "daemon_port"); append_macro_value(&dbuf, ctx, "i"); append_macro_value(&dbuf, ctx, "if_addr"); append_macro_value(&dbuf, ctx, "if_name"); @@ -998,18 +1026,6 @@ envfrom(SMFICTX *ctx, char **from) data->cmdFD = put_fd(data->cmdFD); - /* Get my IP address */ - me = smfi_getsymval(ctx, "{if_addr}"); - if (me && *me && MyIPAddress && !strcmp(me, MyIPAddress)) { - data->myip = MyIPAddress; - } else if (me && *me && strcmp(me, "127.0.0.1")) { - data->myip = strdup_with_log(me); - } else { - /* Sigh... use our computed address */ - data->myip = MyIPAddress; - } - - if (doSenderCheck) { int n = MXSenderOK(MultiplexorSocketName, buf2, (char const **) from, data->hostip, data->hostname, --- mimedefang-2.68/utils.c.orig 2009-05-04 09:34:32.000000000 -0600 +++ mimedefang-2.68/utils.c 2010-05-04 10:43:22.000000000 -0600 @@ -547,6 +547,9 @@ munch_mx_return(char *ans, char *msg) * msg -- buffer for holding error message, at least SMALLBUF chars * ip -- relay IP address * name -- relay name +* port -- relay TCP port +* myip -- server's IP address +* myport -- server's TCP port * %RETURNS: * 1 if it's OK to accept connections from this host; 0 if not, -1 if error. * If connection is rejected, error message *may* be set. @@ -555,20 +558,30 @@ int MXRelayOK(char const *sockname, char *msg, char const *ip, - char const *name) + char const *name, + int port, + char const *myip, + int myport +) { char cmd[SMALLBUF]; char ans[SMALLBUF]; + char remport[6]; + char localport[6]; *msg = 0; + snprintf(remport, sizeof(remport), "%d", port); + snprintf(localport, sizeof(localport), "%d", myport); + if (!ip || !*ip) { ip = "UNKNOWN"; } if (!name || !*name) { name = ip; } - if (percent_encode_command(1, cmd, sizeof(cmd), "relayok", ip, name, NULL) < 0) { + if (percent_encode_command(1, cmd, sizeof(cmd), "relayok", ip, name, + remport, myip, localport, NULL) < 0) { return MD_TEMPFAIL; } if (MXCommand(sockname, cmd, ans, SMALLBUF-1) < 0) return MD_TEMPFAIL; @@ -590,13 +603,21 @@ MXHeloOK(char const *sockname, char *msg, char const *ip, char const *name, - char const *helo) + char const *helo, + int port, + char const *myip, + int myport) { char cmd[SMALLBUF]; char ans[SMALLBUF]; + char remport[6]; + char localport[6]; *msg = 0; + snprintf(remport, sizeof(remport), "%d", port); + snprintf(localport, sizeof(localport), "%d", myport); + if (!ip || !*ip) { ip = "UNKNOWN"; } @@ -606,7 +627,8 @@ MXHeloOK(char const *sockname, if (!helo) { helo = "UNKNOWN"; } - if (percent_encode_command(1, cmd, sizeof(cmd), "helook", ip, name, helo, NULL) < 0) { + if (percent_encode_command(1, cmd, sizeof(cmd), "helook", ip, name, helo, + remport, myip, localport, NULL) < 0) { return MD_TEMPFAIL; } if (MXCommand(sockname, cmd, ans, SMALLBUF-1) < 0) return MD_TEMPFAIL;
_______________________________________________ NOTE: If there is a disclaimer or other legal boilerplate in the above message, it is NULL AND VOID. You may ignore it. Visit http://www.mimedefang.org and http://www.roaringpenguin.com MIMEDefang mailing list [email protected] http://lists.roaringpenguin.com/mailman/listinfo/mimedefang
_______________________________________________ NOTE: If there is a disclaimer or other legal boilerplate in the above message, it is NULL AND VOID. You may ignore it. Visit http://www.mimedefang.org and http://www.roaringpenguin.com MIMEDefang mailing list [email protected] http://lists.roaringpenguin.com/mailman/listinfo/mimedefang

