[Mimedefang] Fwd: Re: Accessing the source/destination port #'s at filter_relay

Philip Prindeville philipp_subx at redfish-solutions.com
Thu Sep 30 23:36:56 EDT 2010


  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 <philipp_subx at redfish-solutions.com>
Reply-To: 	mimedefang at lists.roaringpenguin.com
To: 	mimedefang at lists.roaringpenguin.com



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.


-------------- next part --------------
--- 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  <philipp at redfish-solutions.com>
+
+	* 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  <dfs at roaringpenguin.com>
 
 	* 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;

-------------- next part --------------
_______________________________________________
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 MIMEDefang at lists.roaringpenguin.com
http://lists.roaringpenguin.com/mailman/listinfo/mimedefang



More information about the MIMEDefang mailing list