- 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)
This commit is contained in:
Wen Heping 2011-03-28 03:08:45 +00:00
parent 9c60a607f1
commit b69c89adb3
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=271916
2 changed files with 276 additions and 1 deletions

View File

@ -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

View File

@ -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);