Sophie

Sophie

distrib > Fedora > 13 > i386 > media > updates-src > by-pkgid > 2f7e4f1e3b0cba9e0bebc1d9497ea9ac > files > 4

spamass-milter-0.3.1-21.fc13.src.rpm

diff -up spamass-milter-0.3.1/spamass-milter.cpp.ipv6 spamass-milter-0.3.1/spamass-milter.cpp
--- spamass-milter-0.3.1/spamass-milter.cpp.ipv6	2010-09-23 16:26:36.227224902 +0100
+++ spamass-milter-0.3.1/spamass-milter.cpp	2010-09-23 17:25:22.307099331 +0100
@@ -88,6 +88,7 @@
 #include "subst_poll.h"
 #endif
 #include <errno.h>
+#include <netdb.h>
 
 #include <grp.h>
 
@@ -718,12 +719,18 @@ mlfi_connect(SMFICTX * ctx, char *hostna
 	sctx = (struct context *)malloc(sizeof(*sctx));
 	if (!hostaddr)
 	{
+		static struct sockaddr_in localhost;
+		
 		/* not a socket; probably a local user calling sendmail directly */
 		/* set to 127.0.0.1 */
-		sctx->connect_ip.s_addr = htonl(INADDR_LOOPBACK);
+		strcpy(sctx->connect_ip, "127.0.0.1");
+		localhost.sin_family = AF_INET;
+		localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+		hostaddr = (struct sockaddr*) &localhost;
 	} else
 	{
-		sctx->connect_ip = ((struct sockaddr_in *) hostaddr)->sin_addr;
+		getnameinfo(hostaddr, sizeof(struct sockaddr_in6),
+		            sctx->connect_ip, 63, NULL, 0, NI_NUMERICHOST);
 	}
 	sctx->assassin = NULL;
 	sctx->helo = NULL;
@@ -758,12 +765,12 @@ mlfi_connect(SMFICTX * ctx, char *hostna
 		debug(D_ALWAYS, "smfi_setpriv failed!");
 		return SMFIS_TEMPFAIL;
 	}
-	/* debug(D_ALWAYS, "ZZZ set private context to %p", sctx); */
 
-	if (ip_in_networklist(sctx->connect_ip, &ignorenets))
+	debug(D_NET, "Checking %s against:", sctx->connect_ip);
+	if (ip_in_networklist(hostaddr, &ignorenets))
 	{
 		debug(D_NET, "%s is in our ignore list - accepting message",
-		    inet_ntoa(sctx->connect_ip));
+		      sctx->connect_ip);
 		debug(D_FUNC, "mlfi_connect: exit ignore");
 		return SMFIS_ACCEPT;
 	}
@@ -807,7 +814,6 @@ mlfi_envfrom(SMFICTX* ctx, char** envfro
     debug(D_ALWAYS, "smfi_getpriv failed!");
     return SMFIS_TEMPFAIL;
   }
-  /* debug(D_ALWAYS, "ZZZ got private context %p", sctx); */
 
   if (ignore_authenticated_senders)
   {
@@ -835,7 +841,7 @@ mlfi_envfrom(SMFICTX* ctx, char** envfro
       return SMFIS_TEMPFAIL;
     };
   
-  assassin->set_connectip(string(inet_ntoa(sctx->connect_ip)));
+  assassin->set_connectip(string(sctx->connect_ip));
 
   // Store a pointer to the assassin object in our context struct
   sctx->assassin = assassin;
@@ -2128,69 +2134,135 @@ void parse_networklist(char *string, str
 	{
 		char *tnet = strsep(&token, "/");
 		char *tmask = token;
-		struct in_addr net, mask;
+		struct in_addr net;
+		struct in6_addr net6;
 
 		if (list->num_nets % 10 == 0)
-			list->nets = (struct net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));
+			list->nets = (union net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));
 
-		if (!inet_aton(tnet, &net))
+		if (inet_pton(AF_INET, tnet, &net))
 		{
-			fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
-			exit(1);
-		}
+			struct in_addr mask;
+			
+			if (tmask)
+			{
+				if (strchr(tmask, '.') == NULL)
+				{
+					/* CIDR */
+					unsigned int bits;
+					int ret;
+					ret = sscanf(tmask, "%u", &bits);
+					if (ret != 1 || bits > 32)
+					{
+						fprintf(stderr,"%s: bad CIDR value", tmask);
+						exit(1);
+					}
+					mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
+				} else if (!inet_pton(AF_INET6, tmask, &mask))
+				{
+					fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
+					exit(1);
+				}
+			} else
+				mask.s_addr = 0xffffffff;
 
-		if (tmask)
-		{
-			if (strchr(tmask, '.') == NULL)
+			net.s_addr = net.s_addr & mask.s_addr;
+			list->nets[list->num_nets].net4.af = AF_INET;
+			list->nets[list->num_nets].net4.network = net;
+			list->nets[list->num_nets].net4.netmask = mask;
+		} else if (inet_pton(AF_INET6, tnet, &net6))
+		{
+			int mask;
+			
+			if (tmask)
 			{
-				/* CIDR */
-				unsigned int bits;
-				int ret;
-				ret = sscanf(tmask, "%u", &bits);
-				if (ret != 1 || bits > 32)
+				if (sscanf(tmask, "%d", &mask) != 1 || mask > 128)
 				{
 					fprintf(stderr,"%s: bad CIDR value", tmask);
 					exit(1);
 				}
-				mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
-			} else if (!inet_aton(tmask, &mask))
-			{
-				fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
-				exit(1);
-			}
+			} else
+				mask = 128;
+			
+			list->nets[list->num_nets].net6.af = AF_INET6;
+			list->nets[list->num_nets].net6.network = net6;
+			list->nets[list->num_nets].net6.netmask = mask;
 		} else
-			mask.s_addr = 0xffffffff;
+		{
+			fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
+			exit(1);
+		}
 
 		{
-			char *snet = strdup(inet_ntoa(net));
-			debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
-			free(snet);
+			int af = list->nets[list->num_nets].net.af;
+			char addrbuf[INET6_ADDRSTRLEN];
+			char maskbuf[4];
+			char *maskstr;
+
+			if (af == AF_INET6) {
+				inet_ntop(af, &list->nets[list->num_nets].net6.network,
+					addrbuf, INET6_ADDRSTRLEN);
+				sprintf(maskbuf, "%d", list->nets[list->num_nets].net6.netmask);
+				maskstr = maskbuf;
+				list->nets[list->num_nets].net6.addrstr = strdup(addrbuf);
+				list->nets[list->num_nets].net6.maskstr = strdup(maskbuf);
+			} else
+			{
+				inet_ntop(af, &list->nets[list->num_nets].net4.network,
+					addrbuf, INET6_ADDRSTRLEN);
+				maskstr = inet_ntoa(list->nets[list->num_nets].net4.netmask);
+				list->nets[list->num_nets].net4.addrstr = strdup(addrbuf);
+				list->nets[list->num_nets].net4.maskstr = strdup(maskstr);
+			}
+			debug(D_MISC, "Added %s/%s to network list", addrbuf, maskstr);
 		}
 
-		net.s_addr = net.s_addr & mask.s_addr;
-		list->nets[list->num_nets].network = net;
-		list->nets[list->num_nets].netmask = mask;
 		list->num_nets++;
 	}
 	free(string);
 }
 
-int ip_in_networklist(struct in_addr ip, struct networklist *list)
+int ip_in_networklist(struct sockaddr *addr, struct networklist *list)
 {
 	int i;
 
 	if (list->num_nets == 0)
 		return 0;
-		
-	debug(D_NET, "Checking %s against:", inet_ntoa(ip));
+	
 	for (i = 0; i < list->num_nets; i++)
 	{
-		debug(D_NET, "%s", inet_ntoa(list->nets[i].network));
-		debug(D_NET, "/%s", inet_ntoa(list->nets[i].netmask));
-		if ((ip.s_addr & list->nets[i].netmask.s_addr) == list->nets[i].network.s_addr)
-        {
-        	debug(D_NET, "Hit!");
-			return 1;
+		if (list->nets[i].net.af == AF_INET && addr->sa_family == AF_INET)
+		{
+			struct in_addr ip = ((struct sockaddr_in *)addr)->sin_addr;
+			
+			debug(D_NET, "%s/%s", list->nets[i].net4.addrstr, list->nets[i].net4.maskstr);
+			if ((ip.s_addr & list->nets[i].net4.netmask.s_addr) == list->nets[i].net4.network.s_addr)
+			{
+				debug(D_NET, "Hit!");
+				return 1;
+			}
+		} else if (list->nets[i].net.af == AF_INET6 && addr->sa_family == AF_INET6)
+		{
+			u_int8_t *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr;
+			int mask, j;
+
+			debug(D_NET, "%s/%s", list->nets[i].net6.addrstr, list->nets[i].net6.maskstr);
+			mask = list->nets[i].net6.netmask;
+			for (j = 0; j < 16 && mask > 0; j++, mask -= 8)
+			{
+				unsigned char bytemask;
+				
+				bytemask = (mask < 8) ? ~((1L << (8 - mask)) - 1) : 0xff;
+				
+				if ((ip[j] & bytemask) != (list->nets[i].net6.network.s6_addr[j] & bytemask))
+					break;
+			}
+			
+			if (mask <= 0)
+			{
+				debug(D_NET, "Hit!");
+				return 1;
+			}
 		}
 	}
 
diff -up spamass-milter-0.3.1/spamass-milter.h.ipv6 spamass-milter-0.3.1/spamass-milter.h
--- spamass-milter-0.3.1/spamass-milter.h.ipv6	2010-09-23 16:26:36.224160445 +0100
+++ spamass-milter-0.3.1/spamass-milter.h	2010-09-23 17:00:16.487410690 +0100
@@ -56,16 +56,34 @@ sfsistat mlfi_abort(SMFICTX*);
 extern struct smfiDesc smfilter;
 
 /* struct describing a single network */
-struct net
+union net
 {
-	struct in_addr network;
-	struct in_addr netmask;
+	struct
+	{
+		uint8_t af;
+	} net;
+	struct
+	{
+		uint8_t af;
+		struct in_addr network;
+		struct in_addr netmask;
+		char *addrstr;
+		char *maskstr;
+	} net4;
+	struct
+	{
+		uint8_t af;
+		struct in6_addr network;
+		int netmask; /* Just the number of bits for IPv6 */
+		char *addrstr;
+		char *maskstr;
+	} net6;
 };
 
 /* an array of networks */
 struct networklist
 {
-	struct net *nets;
+	union net *nets;
 	int num_nets;
 };
 
@@ -162,7 +180,7 @@ public:  
 /* Private data structure to carry per-client data between calls */
 struct context
 {
-	struct in_addr connect_ip;	// remote IP address
+	char connect_ip[64];	// remote IP address
 	char *helo;
 	char *our_fqdn;
 	char *sender_address;
@@ -184,7 +202,7 @@ string::size_type find_nocase(const stri
 int cmp_nocase_partial(const string&, const string&);
 void closeall(int fd);
 void parse_networklist(char *string, struct networklist *list);
-int ip_in_networklist(struct in_addr ip, struct networklist *list);
+int ip_in_networklist(struct sockaddr *addr, struct networklist *list);
 void parse_debuglevel(char* string);
 char *strlwr(char *str);
 void warnmacro(const char *macro, const char *scope);