- 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:
parent
9c60a607f1
commit
b69c89adb3
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/head/; revision=271916
@ -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
|
||||
|
270
mail/spamass-milter/files/extra-patch-ipv6
Normal file
270
mail/spamass-milter/files/extra-patch-ipv6
Normal 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);
|
Loading…
Reference in New Issue
Block a user