summaryrefslogtreecommitdiff
path: root/mail/spamass-milter
diff options
context:
space:
mode:
authorWen Heping <wen@FreeBSD.org>2011-03-28 03:08:45 +0000
committerWen Heping <wen@FreeBSD.org>2011-03-28 03:08:45 +0000
commitb69c89adb37234853e74d18184996feb701c2023 (patch)
tree6d864d27b5afaabe41af60cc5a8ddf77f4c01016 /mail/spamass-milter
parent- Bump PORTREVISION to chase the update of audio/libdiscid (diff)
- Allow IPv6 subnets to be whitelisted/auto-accepted
Obtained from http://wilmer.gaa.st/blog/archives/61-spamass-milter-and-IPv6.html PR: ports/155979 Submitted by: "Mikhail T." <m.tsatsenko@gmail.com> (maintainer)
Notes
Notes: svn path=/head/; revision=271916
Diffstat (limited to 'mail/spamass-milter')
-rw-r--r--mail/spamass-milter/Makefile7
-rw-r--r--mail/spamass-milter/files/extra-patch-ipv6270
2 files changed, 276 insertions, 1 deletions
diff --git a/mail/spamass-milter/Makefile b/mail/spamass-milter/Makefile
index f8352e671bbb..1fffd3f1088b 100644
--- a/mail/spamass-milter/Makefile
+++ b/mail/spamass-milter/Makefile
@@ -25,7 +25,8 @@ MAKE_JOBS_SAFE= yes
OPTIONS= ADDAUTH_PATCH "Bypass checks for SMTP AUTH connections" off \
REJECTTEXT_PATCH "Customize SMTP reject message" off \
LDAP "LDAP support" off \
- SENDMAIL_PORT "Build against sendmail port" off
+ SENDMAIL_PORT "Build against sendmail port" off \
+ IPV6 "Apply IPv6 whitelist patch" off
.include <bsd.port.pre.mk>
@@ -42,6 +43,10 @@ EXTRA_PATCHES+= ${FILESDIR}/extra-patch-rejecttext1
NEW_ARGS:= ${NEW_ARGS}R:
.endif
+.if defined(WITH_IPV6)
+EXTRA_PATCHES+= ${FILESDIR}/extra-patch-ipv6
+.endif
+
# extra-patch-options is modified in pre-patch
.if ${ORIG_ARGS} != ${NEW_ARGS}
EXTRA_PATCHES+= ${WRKDIR}/extra-patch-options
diff --git a/mail/spamass-milter/files/extra-patch-ipv6 b/mail/spamass-milter/files/extra-patch-ipv6
new file mode 100644
index 000000000000..e5ee5c62724c
--- /dev/null
+++ b/mail/spamass-milter/files/extra-patch-ipv6
@@ -0,0 +1,270 @@
+diff -ur orig/spamass-milter.cpp spamass-milter.cpp
+--- orig/spamass-milter.cpp 2010-01-31 11:35:47.000000000 +0000
++++ spamass-milter.cpp 2008-01-09 01:20:38.000000000 +0000
+@@ -88,6 +88,7 @@
+ #include "subst_poll.h"
+ #endif
+ #include <errno.h>
++#include <netdb.h>
+
+ // C++ includes
+ #include <cstdio>
+@@ -721,12 +722,19 @@
+ 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);
++ debug(D_FUNC, "Remote address: %s", sctx->connect_ip);
+ }
+ sctx->assassin = NULL;
+ sctx->helo = NULL;
+@@ -740,10 +748,12 @@
+ }
+ /* debug(D_ALWAYS, "ZZZ set private context to %p", sctx); */
+
+- if (ip_in_networklist(sctx->connect_ip, &ignorenets))
++ //debug(D_FUNC, "sctx->connect_ip: `%d'", sctx->connect_ip.sin_family);
++
++ 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;
+ }
+@@ -815,7 +825,7 @@
+ 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;
+@@ -2089,69 +2099,119 @@
+ {
+ 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;
++
++ {
++ char *snet = strdup(inet_ntoa(net));
++ debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
++ free(snet);
++ }
+
+- if (tmask)
++ 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;
++ list->num_nets++;
++ } else if (inet_pton(AF_INET6, tnet, &net6))
+ {
+- if (strchr(tmask, '.') == NULL)
++ 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;
++ list->num_nets++;
+ } else
+- mask.s_addr = 0xffffffff;
+-
+ {
+- char *snet = strdup(inet_ntoa(net));
+- debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
+- free(snet);
++ fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
++ exit(1);
+ }
+
+- 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));
++
++ //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", inet_ntoa(list->nets[i].net4.network));
++ debug(D_NET, "/%s", inet_ntoa(list->nets[i].net4.netmask));
++ 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;
++
++ 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 -ur orig/spamass-milter.h spamass-milter.h
+--- orig/spamass-milter.h 2006-03-23 22:07:55.000000000 +0000
++++ spamass-milter.h 2008-01-01 23:55:44.000000000 +0000
+@@ -56,16 +56,30 @@
+ 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;
++ } net4;
++ struct
++ {
++ uint8_t af;
++ struct in6_addr network;
++ int netmask; /* Just the number of bits for IPv6 */
++ } net6;
+ };
+
+ /* an array of networks */
+ struct networklist
+ {
+- struct net *nets;
++ union net *nets;
+ int num_nets;
+ };
+
+@@ -165,7 +179,7 @@
+ /* 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;
+ SpamAssassin *assassin; // pointer to the SA object if we're processing a message
+ };
+@@ -182,7 +196,7 @@
+ 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(char *macro, char *scope);