summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbeck <beck@openbsd.org>2007-03-06 23:38:36 +0000
committerbeck <beck@openbsd.org>2007-03-06 23:38:36 +0000
commit2c79ec664ba1bf7103daafb6727bf242b197f324 (patch)
treebb7c25e444529218c43178214dab32bcd4b7a297
parentget vfs size snapshotted and restored so that pkg_add -u has a harder (diff)
downloadwireguard-openbsd-2c79ec664ba1bf7103daafb6727bf242b197f324.tar.xz
wireguard-openbsd-2c79ec664ba1bf7103daafb6727bf242b197f324.zip
Add -M option to specify a local address that is a lower priority MX
address than the primary one. spamd will trap hosts that contact this address first without first contacting the primary. - get it in, deraadt@
-rw-r--r--libexec/spamd/grey.c129
-rw-r--r--libexec/spamd/grey.h5
-rw-r--r--libexec/spamd/spamd.830
-rw-r--r--libexec/spamd/spamd.c51
4 files changed, 193 insertions, 22 deletions
diff --git a/libexec/spamd/grey.c b/libexec/spamd/grey.c
index 0699873af4e..d417301f1d4 100644
--- a/libexec/spamd/grey.c
+++ b/libexec/spamd/grey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: grey.c,v 1.33 2007/03/05 15:09:01 beck Exp $ */
+/* $OpenBSD: grey.c,v 1.34 2007/03/06 23:38:36 beck Exp $ */
/*
* Copyright (c) 2004-2006 Bob Beck. All rights reserved.
@@ -53,6 +53,14 @@ extern FILE *grey;
extern int debug;
extern int syncsend;
+/* From netinet/in.h, but only _KERNEL_ gets them. */
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
+int server_lookup4(struct sockaddr_in *, struct sockaddr_in *,
+ struct sockaddr_in *);
+int server_lookup6(struct sockaddr_in6 *, struct sockaddr_in6 *,
+ struct sockaddr_in6 *);
+
size_t whitecount, whitealloc;
size_t trapcount, trapalloc;
char **whitelist;
@@ -87,6 +95,8 @@ struct mail_addr {
SLIST_HEAD(, mail_addr) match_suffix = SLIST_HEAD_INITIALIZER(match_suffix);
char *alloweddomains_file = PATH_SPAMD_ALLOWEDDOMAINS;
+char *low_prio_mx_ip;
+
static char *pargv[11]= {
"pfctl", "-p", "/dev/pf", "-q", "-t",
"spamd-white", "-T", "replace", "-f" "-", NULL
@@ -124,6 +134,80 @@ configure_spamd(char **addrs, int count, FILE *sdc)
return(0);
}
+
+/* Stolen from ftp-proxy */
+int
+server_lookup(struct sockaddr *client, struct sockaddr *proxy,
+ struct sockaddr *server)
+{
+ if (client->sa_family == AF_INET)
+ return (server_lookup4(satosin(client), satosin(proxy),
+ satosin(server)));
+
+ if (client->sa_family == AF_INET6)
+ return (server_lookup6(satosin6(client), satosin6(proxy),
+ satosin6(server)));
+
+ errno = EPROTONOSUPPORT;
+ return (-1);
+}
+
+int
+server_lookup4(struct sockaddr_in *client, struct sockaddr_in *proxy,
+ struct sockaddr_in *server)
+{
+ struct pfioc_natlook pnl;
+
+ memset(&pnl, 0, sizeof pnl);
+ pnl.direction = PF_OUT;
+ pnl.af = AF_INET;
+ pnl.proto = IPPROTO_TCP;
+ memcpy(&pnl.saddr.v4, &client->sin_addr.s_addr, sizeof pnl.saddr.v4);
+ memcpy(&pnl.daddr.v4, &proxy->sin_addr.s_addr, sizeof pnl.daddr.v4);
+ pnl.sport = client->sin_port;
+ pnl.dport = proxy->sin_port;
+
+ if (ioctl(pfdev, DIOCNATLOOK, &pnl) == -1)
+ return (-1);
+
+ memset(server, 0, sizeof(struct sockaddr_in));
+ server->sin_len = sizeof(struct sockaddr_in);
+ server->sin_family = AF_INET;
+ memcpy(&server->sin_addr.s_addr, &pnl.rdaddr.v4,
+ sizeof server->sin_addr.s_addr);
+ server->sin_port = pnl.rdport;
+
+ return (0);
+}
+
+int
+server_lookup6(struct sockaddr_in6 *client, struct sockaddr_in6 *proxy,
+ struct sockaddr_in6 *server)
+{
+ struct pfioc_natlook pnl;
+
+ memset(&pnl, 0, sizeof pnl);
+ pnl.direction = PF_OUT;
+ pnl.af = AF_INET6;
+ pnl.proto = IPPROTO_TCP;
+ memcpy(&pnl.saddr.v6, &client->sin6_addr.s6_addr, sizeof pnl.saddr.v6);
+ memcpy(&pnl.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof pnl.daddr.v6);
+ pnl.sport = client->sin6_port;
+ pnl.dport = proxy->sin6_port;
+
+ if (ioctl(pfdev, DIOCNATLOOK, &pnl) == -1)
+ return (-1);
+
+ memset(server, 0, sizeof(struct sockaddr_in6));
+ server->sin6_len = sizeof(struct sockaddr_in6);
+ server->sin6_family = AF_INET6;
+ memcpy(&server->sin6_addr.s6_addr, &pnl.rdaddr.v6,
+ sizeof server->sin6_addr);
+ server->sin6_port = pnl.rdport;
+
+ return (0);
+}
+
int
configure_pf(char **addrs, int count)
{
@@ -636,6 +720,9 @@ twupdate(char *dbname, char *what, char *ip, char *source, char *expires)
if (debug)
fprintf(stderr, "added %s %s\n",
spamtrap ? "trap entry for" : "", ip);
+ syslog_r(LOG_DEBUG, &sdata,
+ "New %s from %s for %s, expires %s", what, source, ip,
+ expires);
} else {
/* existing entry */
if (dbd.size != sizeof(gd)) {
@@ -664,8 +751,6 @@ twupdate(char *dbname, char *what, char *ip, char *source, char *expires)
fprintf(stderr, "updated %s\n", ip);
}
db->close(db);
- syslog_r(LOG_DEBUG, &sdata, "Update from %s for %s %s, expires %s",
- source, what, ip, expires);
return(0);
bad:
db->close(db);
@@ -674,7 +759,8 @@ twupdate(char *dbname, char *what, char *ip, char *source, char *expires)
}
int
-greyupdate(char *dbname, char *helo, char *ip, char *from, char *to, int sync)
+greyupdate(char *dbname, char *helo, char *ip, char *from, char *to, int sync,
+ char *cip)
{
HASHINFO hashinfo;
DBT dbk, dbd;
@@ -721,6 +807,19 @@ greyupdate(char *dbname, char *helo, char *ip, char *from, char *to, int sync)
goto bad;
if (r) {
/* new entry */
+ if (sync && low_prio_mx_ip && (strcmp(cip, low_prio_mx_ip) == 0)) {
+ /* we haven't seen a greylist entry for this tuple,
+ * and yet the connection was to a low priority MX
+ * which we know can't be hit first if the client
+ * is adhering to the RFC's - soo.. kill it!
+ */
+ spamtrap = 1;
+ lookup = ip;
+ expire = trapexp;
+ syslog_r(LOG_DEBUG, &sdata,
+ "Trapping %s for trying %s first for tuple %s",
+ ip, low_prio_mx_ip, key);
+ }
memset(&gd, 0, sizeof(gd));
gd.first = now;
gd.bcount = 1;
@@ -773,8 +872,11 @@ greyupdate(char *dbname, char *helo, char *ip, char *from, char *to, int sync)
/* Entry successfully update, sent out sync message */
if (syncsend && sync) {
- if (spamtrap)
+ if (spamtrap) {
+ syslog_r(LOG_DEBUG, &sdata,
+ "sync_trap %s", ip);
sync_trapped(now, now + expire, ip);
+ }
else
sync_update(now, helo, ip, from, to);
}
@@ -813,7 +915,8 @@ twread(char *buf)
int
greyreader(void)
{
- char ip[32], helo[MAX_MAIL], from[MAX_MAIL], to[MAX_MAIL], *buf;
+ char cip[32], ip[32], helo[MAX_MAIL], from[MAX_MAIL], to[MAX_MAIL];
+ char *buf;
size_t len;
int state, sync;
struct addrinfo hints, *res;
@@ -855,6 +958,8 @@ greyreader(void)
break;
}
if (strncmp(buf, "HE:", 3) != 0) {
+ if (strncmp(buf, "CO:", 3) == 0)
+ strlcpy(cip, buf+3, sizeof(cip));
state = 0;
break;
}
@@ -889,7 +994,7 @@ greyreader(void)
fprintf(stderr,
"Got Grey HELO %s, IP %s from %s to %s\n",
helo, ip, from, to);
- greyupdate(PATH_SPAMD_DB, helo, ip, from, to, sync);
+ greyupdate(PATH_SPAMD_DB, helo, ip, from, to, sync, cip);
sync = 1;
state = 0;
break;
@@ -1044,12 +1149,6 @@ greywatcher(void)
{
struct sigaction sa;
- pfdev = open("/dev/pf", O_RDWR);
- if (pfdev == -1) {
- syslog_r(LOG_ERR, &sdata, "open of /dev/pf failed (%m)");
- exit(1);
- }
-
check_spamd_db();
db_pid = fork();
@@ -1069,11 +1168,13 @@ greywatcher(void)
_exit(1);
}
+
+ fclose(grey);
/*
* parent, scans db periodically for changes and updates
* pf whitelist table accordingly.
*/
- fclose(grey);
+
sigfillset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = sig_term_chld;
diff --git a/libexec/spamd/grey.h b/libexec/spamd/grey.h
index b355818ac07..c76e4e95297 100644
--- a/libexec/spamd/grey.h
+++ b/libexec/spamd/grey.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: grey.h,v 1.8 2007/03/04 03:19:41 beck Exp $ */
+/* $OpenBSD: grey.h,v 1.9 2007/03/06 23:38:36 beck Exp $ */
/*
* Copyright (c) 2004 Bob Beck. All rights reserved.
@@ -24,6 +24,7 @@
#define PATH_PFCTL "/sbin/pfctl"
#define PATH_SPAMD_ALLOWEDDOMAINS "/etc/mail/spamd.alloweddomains"
#define DB_SCAN_INTERVAL 60
+#define DB_TRAP_INTERVAL 60 * 10
#define PATH_SPAMD_DB "/var/db/spamd"
struct gdata {
@@ -35,4 +36,4 @@ struct gdata {
};
extern int greywatcher(void);
-extern int greyupdate(char *, char *, char *, char *, char *, int);
+extern int greyupdate(char *, char *, char *, char *, char *, int, char *);
diff --git a/libexec/spamd/spamd.8 b/libexec/spamd/spamd.8
index 9dafad185ce..0ea7cd539c3 100644
--- a/libexec/spamd/spamd.8
+++ b/libexec/spamd/spamd.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: spamd.8,v 1.92 2007/03/06 09:00:13 jmc Exp $
+.\" $OpenBSD: spamd.8,v 1.93 2007/03/06 23:38:36 beck Exp $
.\"
.\" Copyright (c) 2002 Theo de Raadt. All rights reserved.
.\"
@@ -40,6 +40,7 @@
.Oc
.Op Fl h Ar hostname
.Op Fl l Ar address
+.Op Fl M Ar address
.Op Fl n Ar name
.Op Fl p Ar port
.Op Fl S Ar secs
@@ -151,6 +152,10 @@ is to
By default
.Nm
listens on all local addresses.
+.It Fl M Ar address
+Specify a local address which is listed as a low priority
+MX record, used to identify and trap hosts that connect to MX
+hosts out of order. See GREYTRAPPING below for details.
.It Fl n Ar name
The SMTP version banner that is reported upon initial connection.
.It Fl p Ar port
@@ -387,6 +392,29 @@ However the addresses
or
.Em bigbutts@bofh.ucs.ualberta.ca
would cause the sending host to be trapped.
+.Pp
+A low priority MX ip address may be specified with the -M option.
+When
+.Nm
+has such an address specified, no host may enter new greylist
+tuples when connecting to this address, only existing entries
+may be updated. Any host attempting to make new deliveries to
+the low priority MX for which a tuple has not previously
+been seen will be trapped.
+.Pp
+Note that is is important to ensure that a host running
+.Nm
+with the low priorty MX address active must see all the greylist
+changes for a higher priority MX host for the same domains, either by
+being synchonised with it, or by receiving the connections itself to
+the higher priority MX on another ip address.
+This will ensure that hosts are not trapped erroneously if the higher
+priority MX is unavailable.
+For example, on a host which is an existing MX record for a domain of
+value 10, A second IP address with MX of value 99 (a higher number, and
+therfore lower priority) would ensure that any RFC conformant client
+would attempt delivery to the IP address with the MX value of 10
+first, and should not attempt to deliver to the address with MV value 99.
.Sh BLACKLISTING
The normal way that spam has been dealt with in the past is to either
accept and drop, or outright block.
diff --git a/libexec/spamd/spamd.c b/libexec/spamd/spamd.c
index 1457b8a0f45..85b12f49cd0 100644
--- a/libexec/spamd/spamd.c
+++ b/libexec/spamd/spamd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spamd.c,v 1.96 2007/03/06 01:59:43 beck Exp $ */
+/* $OpenBSD: spamd.c,v 1.97 2007/03/06 23:38:36 beck Exp $ */
/*
* Copyright (c) 2002 Theo de Raadt. All rights reserved.
@@ -50,6 +50,9 @@
#include "grey.h"
#include "sync.h"
+extern int server_lookup(struct sockaddr *, struct sockaddr *,
+ struct sockaddr *);
+
struct con {
int fd;
int state;
@@ -58,6 +61,7 @@ struct con {
struct sockaddr_storage ss;
void *ia;
char addr[32];
+ char caddr[32];
char helo[MAX_MAIL], mail[MAX_MAIL], rcpt[MAX_MAIL];
struct sdlist **blacklists;
@@ -119,6 +123,8 @@ u_short cfg_port;
u_short sync_port;
extern struct sdlist *blacklists;
+extern int pfdev;
+extern char *low_prio_mx_ip;
int conffd = -1;
int trapfd = -1;
@@ -557,6 +563,31 @@ setlog(char *p, size_t len, char *f)
*s = '\0';
}
+/*
+ * Get address client connected to, by doing a DIOCNATLOOK call.
+ * Uses server_lookup code from ftp-proxy.
+ */
+void
+getcaddr(struct con *cp) {
+ struct sockaddr_storage spamd_end;
+ struct sockaddr *sep = (struct sockaddr *) &spamd_end;
+ struct sockaddr_storage original_destination;
+ struct sockaddr *odp = (struct sockaddr *) &original_destination;
+ socklen_t len = sizeof(struct sockaddr_storage);
+ int error;
+
+ cp->caddr[0] = '\0';
+ if (getsockname(cp->fd, sep, &len) == -1)
+ return;
+ if (server_lookup((struct sockaddr *)&cp->ss, sep, odp) != 0)
+ return;
+ error = getnameinfo(odp, odp->sa_len, cp->caddr, sizeof(cp->caddr),
+ NULL, 0, NI_NUMERICHOST);
+ if (error)
+ cp->caddr[0] = '\0';
+}
+
+
void
gethelo(char *p, size_t len, char *f)
{
@@ -779,10 +810,11 @@ nextstate(struct con *cp)
cp->addr, cp->mail, cp->rcpt);
if (greylist && cp->blacklists == NULL) {
/* send this info to the greylister */
+ getcaddr(cp);
fprintf(grey,
- "HE:%s\nIP:%s\nFR:%s\nTO:%s\n",
- cp->helo, cp->addr, cp->mail,
- cp->rcpt);
+ "CO:%s\nHE:%s\nIP:%s\nFR:%s\nTO:%s\n",
+ cp->caddr, cp->helo, cp->addr,
+ cp->mail, cp->rcpt);
fflush(grey);
}
}
@@ -1018,7 +1050,7 @@ main(int argc, char *argv[])
if (maxblack > maxfiles)
maxblack = maxfiles;
while ((ch =
- getopt(argc, argv, "45l:c:B:p:bdG:h:r:s:S:n:vw:y:Y:")) != -1) {
+ getopt(argc, argv, "45l:c:B:p:bdG:h:r:s:S:M:n:vw:y:Y:")) != -1) {
switch (ch) {
case '4':
nreply = "450";
@@ -1082,6 +1114,9 @@ main(int argc, char *argv[])
usage();
grey_stutter = i;
break;
+ case 'M':
+ low_prio_mx_ip = optarg;
+ break;
case 'n':
spamd = optarg;
break;
@@ -1190,6 +1225,12 @@ main(int argc, char *argv[])
}
if (greylist) {
+ pfdev = open("/dev/pf", O_RDWR);
+ if (pfdev == -1) {
+ syslog_r(LOG_ERR, &sdata, "open /dev/pf: %m");
+ exit(1);
+ }
+
maxblack = (maxblack >= maxcon) ? maxcon - 100 : maxblack;
if (maxblack < 0)
maxblack = 0;