summaryrefslogtreecommitdiff
path: root/libexec/spamd
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2017-10-18 17:31:02 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2017-10-18 17:31:02 +0000
commit65d86a7cda4586200aa0762205c74f415b9823b2 (patch)
treeb87bbac2b5376dbd2ea30873ffa973e3fd06390d /libexec/spamd
parent36821cb22128b4c947eb7618266688578ce46c0c (diff)
Make blacklist entries override the whitelist. When running spamd
in greylisting mode, it is not uncommon for an IP to get whitelisted before it shows up on a spam blacklist. With this change, spamd will check its blacklists before adding a WHITE entry to the <spamd-white> pf table. If the IP matches a blacklist, the WHITE entry will be removed. OK phessler@
Diffstat (limited to 'libexec/spamd')
-rw-r--r--libexec/spamd/grey.c43
-rw-r--r--libexec/spamd/sdl.c46
-rw-r--r--libexec/spamd/sdl.h3
-rw-r--r--libexec/spamd/spamd.c58
4 files changed, 133 insertions, 17 deletions
diff --git a/libexec/spamd/grey.c b/libexec/spamd/grey.c
index cb375af1318..c75d0dad2f5 100644
--- a/libexec/spamd/grey.c
+++ b/libexec/spamd/grey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: grey.c,v 1.64 2016/10/20 21:09:46 mestre Exp $ */
+/* $OpenBSD: grey.c,v 1.65 2017/10/18 17:31:01 millert Exp $ */
/*
* Copyright (c) 2004-2006 Bob Beck. All rights reserved.
@@ -49,6 +49,7 @@ extern FILE *trapcfg;
extern FILE *grey;
extern int debug;
extern int syncsend;
+extern int greyback[2];
/* From netinet/in.h, but only _KERNEL_ gets them. */
#define satosin(sa) ((struct sockaddr_in *)(sa))
@@ -323,6 +324,7 @@ int
addwhiteaddr(char *addr)
{
struct addrinfo hints, *res;
+ char ch;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; /*for now*/
@@ -330,28 +332,43 @@ addwhiteaddr(char *addr)
hints.ai_protocol = IPPROTO_UDP; /*dummy*/
hints.ai_flags = AI_NUMERICHOST;
- if (getaddrinfo(addr, NULL, &hints, &res) == 0) {
- if (whitecount == whitealloc) {
- char **tmp;
+ if (getaddrinfo(addr, NULL, &hints, &res) != 0)
+ return(-1);
- tmp = reallocarray(whitelist,
- whitealloc + 1024, sizeof(char *));
- if (tmp == NULL) {
+ /* Check spamd blacklists in main process. */
+ if (send(greyback[0], res->ai_addr, res->ai_addr->sa_len, 0) == -1) {
+ syslog_r(LOG_ERR, &sdata, "%s: send: %m", __func__);
+ } else {
+ if (recv(greyback[0], &ch, sizeof(ch), 0) == 1) {
+ if (ch == '1') {
+ syslog_r(LOG_DEBUG, &sdata,
+ "%s blacklisted, removing from whitelist",
+ addr);
freeaddrinfo(res);
return(-1);
}
- whitelist = tmp;
- whitealloc += 1024;
}
- whitelist[whitecount] = strdup(addr);
- if (whitelist[whitecount] == NULL) {
+ }
+
+ if (whitecount == whitealloc) {
+ char **tmp;
+
+ tmp = reallocarray(whitelist,
+ whitealloc + 1024, sizeof(char *));
+ if (tmp == NULL) {
freeaddrinfo(res);
return(-1);
}
- whitecount++;
+ whitelist = tmp;
+ whitealloc += 1024;
+ }
+ whitelist[whitecount] = strdup(addr);
+ if (whitelist[whitecount] == NULL) {
freeaddrinfo(res);
- } else
return(-1);
+ }
+ whitecount++;
+ freeaddrinfo(res);
return(0);
}
diff --git a/libexec/spamd/sdl.c b/libexec/spamd/sdl.c
index b403fda2338..2593c86600a 100644
--- a/libexec/spamd/sdl.c
+++ b/libexec/spamd/sdl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdl.c,v 1.23 2017/10/17 13:52:10 millert Exp $ */
+/* $OpenBSD: sdl.c,v 1.24 2017/10/18 17:31:01 millert Exp $ */
/*
* Copyright (c) 2003-2007 Bob Beck. All rights reserved.
@@ -431,6 +431,50 @@ sdl_lookup(struct sdlist *head, int af, void *src)
}
}
+static int
+sdl_check_v4(struct sdlist *sdl, struct in_addr *src)
+{
+ while (sdl->tag != NULL) {
+ if (bsearch(src, sdl->v4.addrs, sdl->v4.naddrs,
+ sizeof(struct sdentry_v4), match_addr_v4) != NULL)
+ return (1);
+ sdl++;
+ }
+ return (0);
+}
+
+static int
+sdl_check_v6(struct sdlist *sdl, struct sdaddr_v6 *src)
+{
+ while (sdl->tag != NULL) {
+ if (bsearch(src, sdl->v6.addrs, sdl->v6.naddrs,
+ sizeof(struct sdentry_v6), match_addr_v6) != NULL)
+ return (1);
+ sdl++;
+ }
+ return (0);
+}
+
+/*
+ * Given an address and address family
+ * returns 1 if address is on a blacklist, else 0.
+ */
+int
+sdl_check(struct sdlist *head, int af, void *src)
+{
+ if (head == NULL)
+ return (0);
+
+ switch (af) {
+ case AF_INET:
+ return (sdl_check_v4(head, src));
+ case AF_INET6:
+ return (sdl_check_v6(head, src));
+ default:
+ return (0);
+ }
+}
+
static void
sdl_free(struct sdlist *sdl)
{
diff --git a/libexec/spamd/sdl.h b/libexec/spamd/sdl.h
index 84b752453f7..aef0093f1fe 100644
--- a/libexec/spamd/sdl.h
+++ b/libexec/spamd/sdl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdl.h,v 1.8 2017/10/17 13:52:10 millert Exp $ */
+/* $OpenBSD: sdl.h,v 1.9 2017/10/18 17:31:01 millert Exp $ */
/*
* Copyright (c) 2003-2007 Bob Beck. All rights reserved.
@@ -62,6 +62,7 @@ struct sdlist {
int sdl_add(char *, char *, char **, u_int, char **, u_int);
void sdl_del(char *);
+int sdl_check(struct sdlist *, int, void *);
struct sdlist **sdl_lookup(struct sdlist *, int, void *);
#endif /* _SDL_H_ */
diff --git a/libexec/spamd/spamd.c b/libexec/spamd/spamd.c
index 7ccd5639465..adeff40485f 100644
--- a/libexec/spamd/spamd.c
+++ b/libexec/spamd/spamd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spamd.c,v 1.152 2017/10/12 16:22:33 millert Exp $ */
+/* $OpenBSD: spamd.c,v 1.153 2017/10/18 17:31:01 millert Exp $ */
/*
* Copyright (c) 2015 Henning Brauer <henning@openbsd.org>
@@ -115,11 +115,13 @@ void gethelo(char *, size_t, char *);
int read_configline(FILE *);
void spamd_tls_init(void);
void check_spamd_db(void);
+void blackcheck(int);
char hostname[HOST_NAME_MAX+1];
struct syslog_data sdata = SYSLOG_DATA_INIT;
char *nreply = "450";
char *spamd = "spamd IP-based SPAM blocker";
+int greyback[2];
int greypipe[2];
int trappipe[2];
FILE *grey;
@@ -1226,7 +1228,8 @@ get_maxfiles(void)
#define PFD_SYNCFD 2
#define PFD_CONFFD 3
#define PFD_TRAPFD 4
-#define PFD_FIRSTCON 5
+#define PFD_GREYBACK 5
+#define PFD_FIRSTCON 6
int
main(int argc, char *argv[])
@@ -1480,6 +1483,10 @@ main(int argc, char *argv[])
maxblack = 0;
/* open pipe to talk to greylister */
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, greyback) == -1) {
+ syslog(LOG_ERR, "socketpair (%m)");
+ exit(1);
+ }
if (pipe(greypipe) == -1) {
syslog(LOG_ERR, "pipe (%m)");
exit(1);
@@ -1502,6 +1509,7 @@ main(int argc, char *argv[])
syslog(LOG_ERR, "fdopen (%m)");
_exit(1);
}
+ close(greyback[0]);
close(greypipe[0]);
trapfd = trappipe[0];
trapcfg = fdopen(trappipe[0], "r");
@@ -1528,6 +1536,7 @@ main(int argc, char *argv[])
goto jail;
}
/* parent - run greylister */
+ close(greyback[1]);
grey = fdopen(greypipe[0], "r");
if (grey == NULL) {
syslog(LOG_ERR, "fdopen (%m)");
@@ -1574,6 +1583,13 @@ jail:
pfd[PFD_SYNCFD].fd = -1;
pfd[PFD_SYNCFD].events = 0;
}
+ if (greylist) {
+ pfd[PFD_GREYBACK].fd = greyback[1];
+ pfd[PFD_GREYBACK].events = POLLIN;
+ } else {
+ pfd[PFD_GREYBACK].fd = -1;
+ pfd[PFD_GREYBACK].events = 0;
+ }
/* events and pfd entries for con[] are filled in below. */
pfd[PFD_SMTPLISTEN].fd = smtplisten;
@@ -1736,6 +1752,44 @@ jail:
read_configline(trapcfg);
if (pfd[PFD_SYNCFD].revents & (POLLIN|POLLHUP))
sync_recv();
+ if (pfd[PFD_GREYBACK].revents & (POLLIN|POLLHUP))
+ blackcheck(greyback[1]);
}
exit(1);
}
+
+void
+blackcheck(int fd)
+{
+ struct sockaddr_storage ss;
+ ssize_t nread;
+ void *ia;
+ char ch;
+
+ /* Read sockaddr from greylister and look it up in the blacklists. */
+ nread = recv(fd, &ss, sizeof(ss), 0);
+ if (nread == -1) {
+ syslog(LOG_ERR, "%s: recv: %m", __func__);
+ return;
+ }
+ if (nread != sizeof(struct sockaddr_in) &&
+ nread != sizeof(struct sockaddr_in6)) {
+ syslog(LOG_ERR, "%s: invalid size %zd", __func__, nread);
+ return;
+ }
+ if (ss.ss_family == AF_INET) {
+ ia = &((struct sockaddr_in *)&ss)->sin_addr;
+ } else if (ss.ss_family == AF_INET6) {
+ ia = &((struct sockaddr_in6 *)&ss)->sin6_addr;
+ } else {
+ syslog(LOG_ERR, "%s: bad family %d", __func__, ss.ss_family);
+ return;
+ }
+ ch = sdl_check(blacklists, ss.ss_family, ia) ? '1' : '0';
+
+ /* Send '1' for match or '0' for no match. */
+ if (send(fd, &ch, sizeof(ch), 0) == -1) {
+ syslog(LOG_ERR, "%s: send: %m", __func__);
+ return;
+ }
+}