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

Philip A. Prindeville philipp_subx at redfish-solutions.com
Mon May 3 20:04:24 EDT 2010


On 05/03/2010 04:22 PM, Philip A. Prindeville wrote:
> What am I missing to send additional arguments to filter_relay()?
>

Nevermind, figured it out.

Here's the patch.  I'm running it locally.

Works nicely with IPTables::libiptc if you want to plumb new iptables
rules on the fly, or add traffic shaping for a host that's trying to
spam you, etc.

Yes, I'm aware that you can use access.db and ClientConn: and
ClientRate:, but that assumes that you can easily match against an IP
address (you can't with subnets that aren't a multiple of 8 bits
long)...  you also can't do useful things like apply traffic shaping
that makes each connection use 1/2 as much bandwidth as the previous
connection from the same host or subnet, etc.

And lastly, a lot of sites require you to log the source port number on
the connection when reporting abuse (such as blatant attempts to exploit
your site as an open relay).

Only question is: should we also pass the ports and the local address to
filter_helo()?

There are reasons to want to do this.

For instance, if you're a multihomed relay, you might accept hosts on
your "inside" saying "EHLO [192.168.1.x]" but not if they're connecting
to you from your public interface.

I could go either way.

-------------- next part --------------
--- mimedefang-2.68/mimedefang.pl.in.orig	2010-02-24 07:55:03.000000000 -0700
+++ mimedefang-2.68/mimedefang.pl.in	2010-05-03 17:13:45.000000000 -0600
@@ -5640,7 +5640,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,10 +5726,13 @@ 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;
 	}
@@ -7066,22 +7070,25 @@ 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)");
+			   "filter_relay", "host $hostip ($hostname) $port $myip $myport");
 	return;
     }
 
     # Set up globals
     $RelayAddr     = $hostip;
     $RelayHostname = $hostname;
-    my($ok, $msg, $code, $dsn, $delay) = filter_relay($hostip, $hostname);
-    send_filter_answer($ok, $msg, "filter_relay", "host $hostip ($hostname)", $code, $dsn, $delay);
+    my($ok, $msg, $code, $dsn, $delay) = filter_relay($hostip, $hostname, $port, $myip, $myport);
+    send_filter_answer($ok, $msg, "filter_relay", "host $hostip ($hostname) $port $myip $myport", $code, $dsn, $delay);
 }
 
 #***********************************************************************
--- mimedefang-2.68/mimedefang.h.orig	2009-09-03 14:59:15.000000000 -0600
+++ mimedefang-2.68/mimedefang.h	2010-05-03 16:19:48.000000000 -0600
@@ -29,7 +29,8 @@ 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, const char *myip, int myport);
 extern int MXHeloOK(char const *sockname, char *msg,
 		    char const *helo, char const *ip, char const *name);
 extern int MXSenderOK(char const *sockname, char *msg,
--- mimedefang-2.68/mimedefang.c.orig	2010-02-03 08:11:32.000000000 -0700
+++ mimedefang-2.68/mimedefang.c	2010-05-03 17:21:33.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); */
@@ -788,7 +814,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 +969,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 +1025,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-03 16:20:35.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;


More information about the MIMEDefang mailing list