Change spamd to use divert-to instead of rdr-to.
authorreyk <reyk@openbsd.org>
Mon, 18 May 2015 16:04:21 +0000 (16:04 +0000)
committerreyk <reyk@openbsd.org>
Mon, 18 May 2015 16:04:21 +0000 (16:04 +0000)
divert-to has many advantages over rdr-to for proxies.  For example,
it is much easier to use, requires less 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.

Heads up: users will have to update their spamd PF rules from rdr-to
to divert-to.  spamd now also listens to 127.0.0.1 instead of "any"
(0.0.0.0) by default which should be fine with most setups but has to
be considered for some special configurations.

Based on a diff is almost two years old but got delayed several times
... beck@: "now is the time to get it in" :)

Tested by many
With help from okan@
OK okan@ beck@ millert@

etc/examples/pf.conf
libexec/spamd/grey.c
libexec/spamd/sdl.c
libexec/spamd/spamd.8
libexec/spamd/spamd.c

index 6cb9c92..2dd043a 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: pf.conf,v 1.1 2014/07/16 12:46:16 deraadt Exp $
+#      $OpenBSD: pf.conf,v 1.2 2015/05/18 16:04:21 reyk Exp $
 #
 # See pf.conf(5) for syntax and examples.
 # Remember to set net.inet.ip.forwarding=1 and/or net.inet6.ip6.forwarding=1
@@ -22,8 +22,8 @@ pass          # establish keep-state
 # rules for spamd(8)
 #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
+#pass in on egress inet proto tcp from any to any port smtp \
+#    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 71b9f35..e91c437 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: grey.c,v 1.58 2015/01/13 21:42:59 millert Exp $       */
+/*     $OpenBSD: grey.c,v 1.59 2015/05/18 16:04:21 reyk Exp $  */
 
 /*
  * Copyright (c) 2004-2006 Bob Beck.  All rights reserved.
@@ -53,14 +53,8 @@ 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 *);
 
 void   configure_spamd(char **, u_int, FILE *);
-int    server_lookup(struct sockaddr *, struct sockaddr *,
-           struct sockaddr *);
 int    configure_pf(char **, int);
 char   *dequotetolower(const char *);
 void   readsuffixlists(void);
@@ -153,80 +147,6 @@ configure_spamd(char **addrs, u_int count, FILE *sdc)
                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
 configure_pf(char **addrs, int count)
 {
index ae2826d..2fbf36e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sdl.c,v 1.21 2015/01/13 21:42:59 millert Exp $ */
+/*     $OpenBSD: sdl.c,v 1.22 2015/05/18 16:04:21 reyk Exp $ */
 
 /*
  * Copyright (c) 2003-2007 Bob Beck.  All rights reserved.
@@ -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 6380e25..5144e50 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: spamd.8,v 1.127 2015/04/14 17:29:06 deraadt Exp $
+.\"    $OpenBSD: spamd.8,v 1.128 2015/05/18 16:04:21 reyk Exp $
 .\"
 .\" Copyright (c) 2002 Theo de Raadt.  All rights reserved.
 .\"
@@ -22,7 +22,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: April 14 2015 $
+.Dd $Mdocdate: May 18 2015 $
 .Dt SPAMD 8
 .Os
 .Sh NAME
@@ -58,7 +58,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
@@ -75,7 +75,7 @@ such as
 .Xr smtpd 8 .
 .Pp
 .Em greylisted
-hosts are redirected to
+hosts are diverted to
 .Nm ,
 but
 .Nm
@@ -168,7 +168,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.
@@ -180,7 +180,7 @@ The SMTP version banner that is reported upon initial connection.
 .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
@@ -273,7 +273,7 @@ table,
 allowing connections to pass to the real MTA.
 Any addresses not found in
 <spamd-white>
-are redirected to
+are diverted to
 .Nm .
 .Pp
 An example
@@ -288,7 +288,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
@@ -467,7 +467,7 @@ However when running in blacklist-only mode,
 a slightly modified
 .Xr pf.conf 5
 ruleset is required,
-redirecting any addresses found in the
+diverting any addresses found in the
 <spamd>
 table to
 .Nm .
@@ -476,7 +476,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 3f4933c..a43aaf7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: spamd.c,v 1.127 2015/04/18 18:28:37 deraadt Exp $     */
+/*     $OpenBSD: spamd.c,v 1.128 2015/05/18 16:04:21 reyk Exp $        */
 
 /*
  * Copyright (c) 2015 Henning Brauer <henning@openbsd.org>
@@ -48,9 +48,6 @@
 #include "grey.h"
 #include "sync.h"
 
-extern int server_lookup(struct sockaddr *, struct sockaddr *,
-    struct sockaddr *);
-
 struct con {
        struct pollfd *pfd;
        int state;
@@ -648,23 +645,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->pfd->fd, sep, &len) == -1)
-               return;
-       if (server_lookup((struct sockaddr *)&cp->ss, sep, odp) != 0)
+       if (getsockname(cp->pfd->fd, odp, &len) == -1)
                return;
        error = getnameinfo(odp, odp->sa_len, cp->caddr, sizeof(cp->caddr),
            NULL, 0, NI_NUMERICHOST);
@@ -1389,7 +1382,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);