Hi,
since we introduced divert-to, we converted most userland proxies and
relays to use this new interface instead of rdr-to. spamd is still
missing and should switch to divert-to as well.
divert-to has many advantages over rdr-to for proxies. For example,
it is much easier to use (most of the attached diff is removing code),
does not depend on /dev/pf, works in-band without the asynchronous
lookup (DIOCNATLOOK ioctl), saves us from additional port allocations
by the rdr/NAT code, and even avoids potential collisions and race
conditions that could theoretically happen with the lookup.
The attached diff raises two questions:
- divert-to doesn't seem to work with spamd listening on ANY/0.0.0.0,
so you explicitly have to set the listen address. I changed the
default to 127.0.0.1 because I don't understand why spamd should
listen on anything else by default (even our default pf.conf uses
127.0.0.1 for spamd). But divert-to could probably be fixed to work
with ANY; I suggest to look at it independently from this diff.
- Users will have to update their PF configurations. It is almost as
simple as changing rdr-to to divert-to in the default spamd line. It
additionally requires to set the spamd listen address (-l) if the pf
rule is not forwarding to 127.0.0.1 (see above).
- We could keep support for both, rdr-to and divert-to, but I dislike
this approach. This is what I did in relayd after divert-to was
introduced, but I think it is generally not a good approach to keep
compat stuff around (and relayd's rdr-to support will go away soon).
This diff might change, based on the direction we want to go, but it
does need some testing and feedback.
Reyk
Index: etc/pf.conf
===================================================================
RCS file: /cvs/src/etc/pf.conf,v
retrieving revision 1.52
diff -u -p -r1.52 pf.conf
--- etc/pf.conf 13 Feb 2013 23:11:14 -0000 1.52
+++ etc/pf.conf 19 Jun 2013 16:25:21 -0000
@@ -23,7 +23,7 @@ pass # establish keep-state
#table <spamd-white> persist
#table <nospamd> persist file "/etc/mail/nospamd"
#pass in on egress proto tcp from any to any port smtp \
-# rdr-to 127.0.0.1 port spamd
+# divert-to 127.0.0.1 port spamd
#pass in on egress proto tcp from <nospamd> to any port smtp
#pass in log on egress proto tcp from <spamd-white> to any port smtp
#pass out log on egress proto tcp to any port smtp
Index: libexec/spamd/grey.c
===================================================================
RCS file: /cvs/src/libexec/spamd/grey.c,v
retrieving revision 1.52
diff -u -p -r1.52 grey.c
--- libexec/spamd/grey.c 2 Oct 2012 15:26:17 -0000 1.52
+++ libexec/spamd/grey.c 19 Jun 2013 16:25:21 -0000
@@ -56,10 +56,6 @@ 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;
@@ -135,80 +131,6 @@ configure_spamd(char **addrs, size_t cou
fprintf(sdc, "\n");
if (fflush(sdc) == EOF)
syslog_r(LOG_DEBUG, &sdata, "configure_spamd: fflush failed
(%m)");
-}
-
-
-/* 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
Index: libexec/spamd/sdl.c
===================================================================
RCS file: /cvs/src/libexec/spamd/sdl.c,v
retrieving revision 1.18
diff -u -p -r1.18 sdl.c
--- libexec/spamd/sdl.c 3 Nov 2007 19:16:07 -0000 1.18
+++ libexec/spamd/sdl.c 19 Jun 2013 16:25:21 -0000
@@ -23,7 +23,7 @@
* someone is on. Spamd gets the connecting address, and looks it up
* against all lists to determine what deferral messages to feed back
* to the connecting machine. - The redirection to spamd will happen
- * from pf in the kernel, first macth will rdr to us. Spamd (along with
+ * from pf in the kernel, first match will divert to us. Spamd (along with
* setup) must keep track of *all* matches, so as to tell someone all the
* lists that they are on.
*/
Index: libexec/spamd/spamd.8
===================================================================
RCS file: /cvs/src/libexec/spamd/spamd.8,v
retrieving revision 1.119
diff -u -p -r1.119 spamd.8
--- libexec/spamd/spamd.8 27 Sep 2012 20:12:32 -0000 1.119
+++ libexec/spamd/spamd.8 19 Jun 2013 16:25:21 -0000
@@ -61,7 +61,7 @@ receiving machine.
considers sending hosts to be of three types:
.Pp
.Em blacklisted
-hosts are redirected to
+hosts are diverted to
.Nm
and
.Em tarpitted
@@ -78,7 +78,7 @@ such as
.Xr sendmail 8 .
.Pp
.Em greylisted
-hosts are redirected to
+hosts are diverted to
.Nm ,
but
.Nm
@@ -165,7 +165,7 @@ is to
.Xr bind 2 .
By default
.Nm
-listens on all local addresses.
+listens on the localhost address 127.0.0.1.
.It Fl M Ar address
Specify a local IP address which is listed as a low priority MX record,
used to identify and trap hosts that connect to MX hosts out of order.
@@ -177,7 +177,7 @@ The SMTP version banner that is reported
.It Fl p Ar port
Specify a different port number from the default port that
.Nm
-should listen for redirected SMTP connections on.
+should listen for diverted SMTP connections on.
The default port is found by looking for the named service
.Dq spamd
using
@@ -275,7 +275,7 @@ table,
allowing connections to pass to the real MTA.
Any addresses not found in
.Aq spamd-white
-are redirected to
+are diverted to
.Nm .
.Pp
An example
@@ -290,7 +290,7 @@ to the SMTP agent (thus bypassing
table \*(Ltspamd-white\*(Gt persist
table \*(Ltnospamd\*(Gt persist file "/etc/mail/nospamd"
pass in on egress proto tcp from any to any port smtp \e
- rdr-to 127.0.0.1 port spamd
+ divert-to 127.0.0.1 port spamd
pass in on egress proto tcp from \*(Ltnospamd\*(Gt to any port smtp
pass in log on egress proto tcp from \*(Ltspamd-white\*(Gt to any port smtp
pass out log on egress proto tcp to any port smtp
@@ -469,7 +469,7 @@ However when running in blacklist-only m
a slightly modified
.Xr pf.conf 5
ruleset is required,
-redirecting any addresses found in the
+diverting any addresses found in the
.Aq spamd
table to
.Nm .
@@ -478,7 +478,7 @@ are passed to the real MTA.
.Bd -literal -offset 4n
table \*(Ltspamd\*(Gt persist
pass in on egress proto tcp from \*(Ltspamd\*(Gt to any port smtp \e
- rdr-to 127.0.0.1 port spamd
+ divert-to 127.0.0.1 port spamd
.Ed
.Pp
Addresses can be loaded into the
Index: libexec/spamd/spamd.c
===================================================================
RCS file: /cvs/src/libexec/spamd/spamd.c,v
retrieving revision 1.112
diff -u -p -r1.112 spamd.c
--- libexec/spamd/spamd.c 19 Jun 2012 17:43:40 -0000 1.112
+++ libexec/spamd/spamd.c 19 Jun 2013 16:25:21 -0000
@@ -43,9 +43,6 @@
#include "grey.h"
#include "sync.h"
-extern int server_lookup(struct sockaddr *, struct sockaddr *,
- struct sockaddr *);
-
struct con {
int fd;
int state;
@@ -565,23 +562,19 @@ setlog(char *p, size_t len, char *f)
}
/*
- * Get address client connected to, by doing a DIOCNATLOOK call.
- * Uses server_lookup code from ftp-proxy.
+ * Get address client connected to, by doing a getsockname call.
+ * Must not be used with a NAT'ed connection (use divert-to instead of rdr-to).
*/
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)
+ if (getsockname(cp->fd, odp, &len) == -1)
return;
error = getnameinfo(odp, odp->sa_len, cp->caddr, sizeof(cp->caddr),
NULL, 0, NI_NUMERICHOST);
@@ -1221,7 +1214,7 @@ main(int argc, char *argv[])
if (inet_pton(AF_INET, bind_address, &sin.sin_addr) != 1)
err(1, "inet_pton");
} else
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);