diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2017-10-18 17:31:02 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2017-10-18 17:31:02 +0000 |
commit | 65d86a7cda4586200aa0762205c74f415b9823b2 (patch) | |
tree | b87bbac2b5376dbd2ea30873ffa973e3fd06390d /libexec/spamd | |
parent | 36821cb22128b4c947eb7618266688578ce46c0c (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.c | 43 | ||||
-rw-r--r-- | libexec/spamd/sdl.c | 46 | ||||
-rw-r--r-- | libexec/spamd/sdl.h | 3 | ||||
-rw-r--r-- | libexec/spamd/spamd.c | 58 |
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; + } +} |