Hi

So I have an IPv6 capable interface on my router.
When I run route monitor, I get a lot of RTM_MISS for non-existant nodes on my prefix. Logging this to the ERLITE takes a fair chunk of CPU time. I added a small patch to the kernel to add the source address of the requesting node here:
https://mail-index.netbsd.org/source-changes/2020/03/09/msg114961.html

I would like to move this to the next level - blacklisting the source address!

I've added two patches to blacklistd:
https://mail-index.netbsd.org/source-changes/2020/03/11/msg114980.html
https://mail-index.netbsd.org/source-changes/2020/03/11/msg114981.html

This now allows a userland application to poll route(4) messages for RTM_MISS and blacklist the RTA_AUTHOR if his address does not belong to a prefix on our network.

I have authored such an application, routemissd (although I'm not beholden to the name).
Patch against current attached, comments welcome.

For the record, I have one node probing my network in random burst lengths, maybe two or three times a minute, sometimes nothing for a few minutes. Currently the smallest gap is about 8 minutes.

When routemissd is running, my load averages are pratically zero on my ERLITE,
even with route monitor constantly logging.

I doubt this will be of any use for systems that are not routers, but I would still like to include it in NetBSD base system.

Comments, as ever, welcome.

Roy
diff -r 4403ed553577 distrib/sets/lists/base/mi
--- a/distrib/sets/lists/base/mi        Tue Mar 10 22:38:41 2020 +0000
+++ b/distrib/sets/lists/base/mi        Wed Mar 11 05:29:04 2020 +0000
@@ -1960,6 +1960,7 @@
 ./usr/sbin/rndc                                        base-bind-bin
 ./usr/sbin/rndc-confgen                                base-bind-bin
 ./usr/sbin/route6d                             base-router-bin         
use_inet6
+./usr/sbin/routemissd                          base-router-root
 ./usr/sbin/rpc.bootparamd                      base-bootserver-bin
 ./usr/sbin/rpc.lockd                           base-nfsserver-bin
 ./usr/sbin/rpc.pcnfsd                          base-nfsserver-bin
diff -r 4403ed553577 distrib/sets/lists/etc/mi
--- a/distrib/sets/lists/etc/mi Tue Mar 10 22:38:41 2020 +0000
+++ b/distrib/sets/lists/etc/mi Wed Mar 11 05:29:04 2020 +0000
@@ -290,6 +290,7 @@
 ./etc/rc.d/root                                        etc-sys-rc
 ./etc/rc.d/route6d                             etc-router-rc
 ./etc/rc.d/routed                              etc-router-rc
+./etc/rc.d/routemissd                          etc-router-rc
 ./etc/rc.d/rpcbind                             etc-rpcbind-rc
 ./etc/rc.d/rtadvd                              etc-net-rc
 ./etc/rc.d/rtclocaltime                                etc-sys-rc
diff -r 4403ed553577 distrib/sets/lists/man/mi
--- a/distrib/sets/lists/man/mi Tue Mar 10 22:38:41 2020 +0000
+++ b/distrib/sets/lists/man/mi Wed Mar 11 05:29:04 2020 +0000
@@ -3048,6 +3048,7 @@
 ./usr/share/man/cat8/route.0                   man-netutil-catman      .cat
 ./usr/share/man/cat8/route6d.0                 man-router-catman       
use_inet6,.cat
 ./usr/share/man/cat8/routed.0                  man-router-catman       .cat
+./usr/share/man/cat8/routemissd.0              man-router-catman       .cat
 ./usr/share/man/cat8/rpc.bootparamd.0          man-bootserver-catman   .cat
 ./usr/share/man/cat8/rpc.lockd.0               man-nfsserver-catman    .cat
 ./usr/share/man/cat8/rpc.pcnfsd.0              man-nfsserver-catman    .cat
@@ -6012,6 +6013,7 @@
 ./usr/share/man/html8/route.html               man-netutil-htmlman     html
 ./usr/share/man/html8/route6d.html             man-router-htmlman      
use_inet6,html
 ./usr/share/man/html8/routed.html              man-router-htmlman      html
+./usr/share/man/html8/routemissd.html          man-router-htmlman      html
 ./usr/share/man/html8/rpc.bootparamd.html      man-bootserver-htmlman  html
 ./usr/share/man/html8/rpc.lockd.html           man-nfsserver-htmlman   html
 ./usr/share/man/html8/rpc.pcnfsd.html          man-nfsserver-htmlman   html
@@ -9049,6 +9051,7 @@
 ./usr/share/man/man8/moused.8                  man-sysutil-man         .man
 ./usr/share/man/man8/mrinfo.8                  man-netutil-man         .man
 ./usr/share/man/man8/mrouted.8                 man-router-man          .man
+./usr/share/man/man8/routemissd.8              man-router-man          .man
 ./usr/share/man/man8/mscdlabel.8               man-sysutil-man         .man
 ./usr/share/man/man8/mtrace.8                  man-netutil-man         .man
 ./usr/share/man/man8/mtrace6.8                 man-obsolete            obsolete
diff -r 4403ed553577 etc/defaults/rc.conf
--- a/etc/defaults/rc.conf      Tue Mar 10 22:38:41 2020 +0000
+++ b/etc/defaults/rc.conf      Wed Mar 11 05:29:04 2020 +0000
@@ -266,6 +266,7 @@
 gated=NO
 mrouted=NO             mrouted_flags=""
 route6d=NO             route6d_flags=""
+routemissd=NO
 ldpd=NO
 
 # Daemons used to boot other hosts over a network.
diff -r 4403ed553577 etc/rc.d/Makefile
--- a/etc/rc.d/Makefile Tue Mar 10 22:38:41 2020 +0000
+++ b/etc/rc.d/Makefile Wed Mar 11 05:29:04 2020 +0000
@@ -35,7 +35,8 @@
                perusertmp pf pf_boot pflogd postfix powerd ppp pwcheck \
                quota \
                racoon rpcbind raidframe raidframeparity random_seed rarpd \
-               rbootd resize_root rndctl root route6d routed rtadvd \
+               rbootd resize_root rndctl root route6d routed routemissd \
+               rtadvd \
                rtclocaltime rwho \
                savecore screenblank securelevel smtoff sshd \
                staticroute swap1 swap2 sysctl sysdb syslogd \
diff -r 4403ed553577 usr.sbin/Makefile
--- a/usr.sbin/Makefile Tue Mar 10 22:38:41 2020 +0000
+++ b/usr.sbin/Makefile Wed Mar 11 05:29:04 2020 +0000
@@ -22,7 +22,7 @@
        paxctl pcictl perfused psrset pstat pwd_mkdb postinstall \
        powerd puffs \
        quot quotacheck quotaon quotarestore \
-       rarpd rbootd rdate repquota rmt rpc.bootparamd rpc.lockd \
+       rarpd rbootd rdate repquota rmt routemissd rpc.bootparamd rpc.lockd \
        rpc.pcnfsd rpc.statd rpcbind rwhod \
        sa screenblank sdpd service services_mkdb sesd schedctl \
        sliplogin spray \
diff -r 4403ed553577 usr.sbin/routemissd/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.sbin/routemissd/Makefile      Wed Mar 11 05:29:04 2020 +0000
@@ -0,0 +1,12 @@
+#      $NetBSD: $
+#
+
+WARNS?=        6
+
+PROG=  routemissd
+MAN=   routemissd.8
+
+LDADD+=        -lblacklist
+DPADD+=        ${LIBBLACKLIST}
+
+.include <bsd.prog.mk>
diff -r 4403ed553577 usr.sbin/routemissd/routemissd.8
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.sbin/routemissd/routemissd.8  Wed Mar 11 05:29:04 2020 +0000
@@ -0,0 +1,65 @@
+.\"    $NetBSD: $
+.\"
+.\" Copyright (c) 2020 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Roy Marples.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (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 March 10, 2020
+.Dt ROUTEMISSD 8
+.Os
+.Sh NAME
+.Nm routemissd
+.Nd blacklists nodes who probe non-existant nodes on our prefix
+.Sh SYNOPSIS
+.Nm routemissd
+.Op Fl dfu
+.Sh DESCRIPTION
+With the emergence of IPv6, edge routers are seeing OS finger-printing
+probes to random addresses within their allocated prefix in the hope
+of finding a victim to attack.
+.Pp
+.Nm
+works by reading RTM_MISS messages from a
+.Xr route 4
+socket and extracting RTA_AUTHOR as the source address.
+If the source address does not match any of our on-link prefixes then
+.Nm
+sends it to
+.Xr blacklistd 8 ,
+which will then block the source address at the firewall.
+.Pp
+The command line options are:
+.Bl -tag -width indent
+.It Fl d
+Log debugging informaton.
+.It Fl f
+Run in foreground mode.
+Useful when debugging.
+.It Fl u Ar username
+Run as this user and chroot to their home directory.
+.El
+.Sh AUTHORS
+.An Roy Marples Aq Mt r...@marples.name
diff -r 4403ed553577 usr.sbin/routemissd/routemissd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.sbin/routemissd/routemissd.c  Wed Mar 11 05:29:04 2020 +0000
@@ -0,0 +1,457 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Roy Marples.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <arpa/inet.h>
+
+#include <blacklist.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#ifndef __STRING
+#define        __STRING(x)     #x
+#endif
+
+/* Allow for AF_INET, AF_INET6 and AF_LINK */
+#define MAX_ADDRSTRLEN (20 * 3)
+static const char opts[] = "dfu";
+
+static bool exit_now = false;
+static int exit_code = EXIT_FAILURE;
+static int rtm_seq = 0;
+
+static struct blacklist *bl;
+
+static const char *
+hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
+{
+       const unsigned char *hp, *ep;
+       char *p;
+
+       if (buf == NULL)
+               return NULL;
+
+       if (hwlen * 3 > buflen) {
+               errno = ENOBUFS;
+               return NULL;
+       }
+
+       hp = hwaddr;
+       ep = hp + hwlen;
+       p = buf;
+
+       while (hp < ep) {
+               if (hp != hwaddr)
+                       *p ++= ':';
+               p += snprintf(p, 3, "%.2x", *hp++);
+       }
+       *p ++= '\0';
+       return buf;
+}
+
+static const char *
+sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
+{
+       const void *addr;
+
+       if (sa == NULL || sa->sa_family == 0) {
+               *buf = '\0';
+               return NULL;
+       }
+
+#ifndef CLLADDR
+#define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
+#endif
+       if (sa->sa_family == AF_LINK) {
+               const struct sockaddr_dl *sdl;
+
+               sdl = (const void *)sa;
+               if (sdl->sdl_alen == 0) {
+                       if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1)
+                               return NULL;
+                       return buf;
+               }
+               return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
+       }
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               addr = &((const struct sockaddr_in *)sa)->sin_addr;
+               break;
+       case AF_INET6:
+               addr = &((const struct sockaddr_in6 *)sa)->sin6_addr;
+               break;
+       default:
+               errno = EAFNOSUPPORT;
+               return NULL;
+       }
+       return inet_ntop(sa->sa_family, addr, buf, len);
+}
+
+static bool
+sa_is_unspecified(const struct sockaddr *sa)
+{
+
+       switch(sa->sa_family) {
+       case AF_UNSPEC:
+               return true;
+#ifdef INET
+       case AF_INET:
+               return satocsin(sa)->sin_addr.s_addr == INADDR_ANY;
+#endif /* INET */
+#ifdef INET6
+       case AF_INET6:
+               return IN6_IS_ADDR_UNSPECIFIED(&satocsin6(sa)->sin6_addr);
+#endif /* INET6 */
+       default:
+               errno = EAFNOSUPPORT;
+               return false;
+       }
+}
+
+static int
+extract_addrs(const char *cp, size_t msglen,
+    int addrs, const struct sockaddr *sa[])
+{
+       int i;
+       const char *ep = cp + msglen;
+
+       for (i = 0; i < RTAX_MAX; i++) {
+               if ((1 << i) & addrs) {
+                       if (cp >= ep) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       sa[i] = (const struct sockaddr *)cp;
+                       RT_ADVANCE(cp, sa[i]);
+               } else
+                       sa[i] = NULL;
+       }
+
+       return 0;
+}
+
+static int
+route_is_default(const struct sockaddr *dst)
+{
+       union {
+               char buf[2048];
+               struct rt_msghdr hdr;
+       } u;
+       struct rt_msghdr *rtm = &u.hdr;
+       pid_t pid = getpid();
+       char *cp = u.buf + sizeof(*rtm);
+       int s;
+       ssize_t msglen;
+       const struct sockaddr *sa[RTAX_MAX];
+
+       memset(&u, 0, sizeof(u));
+       rtm->rtm_version = RTM_VERSION;
+       rtm->rtm_seq = ++rtm_seq;
+       rtm->rtm_pid = pid;
+       rtm->rtm_type = RTM_GET;
+       rtm->rtm_addrs = RTA_DST;
+
+       memcpy(cp, dst, dst->sa_len);
+       cp += RT_ROUNDUP(dst->sa_len);
+
+       rtm->rtm_msglen = (unsigned short)(cp - (char *)rtm);
+
+       s = socket(PF_ROUTE, SOCK_RAW, 0);
+       if (s == -1)
+               return -1;
+       if (write(s, rtm, rtm->rtm_msglen) == -1) {
+               int serrno = errno;
+
+               close(s);
+               /* If we didn't find any route, pretend it
+                * belongs to the default route. */
+               return serrno == ESRCH ? 1 : -1;
+       }
+       do {
+               msglen = read(s, &u, sizeof(u));
+       } while (msglen >= (ssize_t)
+           MAX(offsetof(struct rt_msghdr, rtm_pid),
+               offsetof(struct rt_msghdr, rtm_seq)) &&
+           rtm->rtm_pid != pid && rtm->rtm_seq != rtm_seq);
+       close(s);
+       if (msglen == -1)
+               return -1;
+
+       if (extract_addrs((char *)rtm + sizeof(*rtm),
+           (size_t)msglen - sizeof(*rtm), rtm->rtm_addrs, sa) == -1)
+               return -1;
+
+       if (sa[RTAX_DST] == NULL) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       return sa_is_unspecified(sa[RTAX_DST]) ? 1 : 0;
+}
+
+static void
+dispatch_rtm(struct rt_msghdr *rtm, size_t msglen)
+{
+       const struct sockaddr *sa[RTAX_MAX];
+       char dst[MAX_ADDRSTRLEN], gate[MAX_ADDRSTRLEN], author[MAX_ADDRSTRLEN];
+       char msg[256];
+       int is_default_route;
+
+       if ((size_t)msglen < sizeof(*rtm)) {
+               syslog(LOG_ERR, "truncated route message of %zd", msglen);
+               return;
+       }
+
+       if (rtm->rtm_type != RTM_MISS || rtm->rtm_pid == getpid())
+               return;
+
+       if (extract_addrs((char *)rtm + sizeof(*rtm), msglen - sizeof(*rtm),
+           rtm->rtm_addrs, sa) == -1)
+       {
+               syslog(LOG_ERR, "extract_addrs: %m");
+               return;
+       }
+
+       if (sa[RTAX_DST] == NULL) {
+               syslog(LOG_ERR, "no destination address");
+               return;
+       }
+
+       if (sa_addrtop(sa[RTAX_DST], dst, sizeof(dst)) == NULL)
+               syslog(LOG_ERR, "sa_addrtop: RTAX_DST: %m");
+       if (sa_addrtop(sa[RTAX_GATEWAY], gate, sizeof(gate)) == NULL &&
+           sa[RTAX_GATEWAY] != NULL)
+               syslog(LOG_ERR, "sa_addrtop: RTAX_GATEWAY: %m");
+
+       if (sa[RTAX_AUTHOR] == NULL) {
+               syslog(LOG_DEBUG, "RTM_MISS %s on %s", dst, gate);
+               return;
+       }
+
+       if (sa_addrtop(sa[RTAX_AUTHOR], author, sizeof(author)) == NULL)
+               syslog(LOG_ERR, "sa_addrtop: RTAX_AUTHOR: %m");
+
+       is_default_route = route_is_default(sa[RTAX_AUTHOR]);
+       if (is_default_route == -1)
+               syslog(LOG_ERR, "route_is_default: %m");
+       if (is_default_route != 0) {
+               /* This address exists on a prefix we have, ignore it. */
+               syslog(LOG_DEBUG, "RTM_MISS %s on %s from %s",
+                   dst, gate, author);
+               return;
+       }
+
+       if (snprintf(msg, sizeof(msg),
+           "RTM_MISS %s on %s, blacklisting %s",
+           dst, gate, author) >= (int)sizeof(msg))
+               syslog(LOG_ERR, "snprintf: %m");
+       syslog(LOG_INFO, "%s", msg);
+
+       /* BLACKLIST_AUTH_FAIL isn't really an authentication failure, but it's
+        * the best message type we can work with. */
+       if (blacklist_sa_r(bl, BLACKLIST_AUTH_FAIL, -1,
+           sa[RTAX_AUTHOR], sa[RTAX_AUTHOR]->sa_len, msg) == -1)
+               syslog(LOG_ERR, "blacklist_sa_r: %m");
+}
+
+static void
+dispatch_signal(int sig)
+{
+
+       if (sig == SIGTERM)
+               exit_code = EXIT_SUCCESS;
+       if (sig != SIGHUP)
+               exit_now = true;
+}
+
+static void
+setup_signals(void)
+{
+       struct sigaction sa = { .sa_handler = dispatch_signal };
+
+       if (sigaction(SIGHUP, &sa, NULL) == -1)
+               warn("sigaction: SIGHUP");
+       if (sigaction(SIGINT, &sa, NULL) == -1)
+               warn("sigaction: SIGINT");
+       if (sigaction(SIGTERM, &sa, NULL) == -1)
+               warn("sigaction: SIGTERM");
+}
+
+static int
+setup_overflow(int s)
+{
+#if defined(SO_RERROR)
+       int on = 1;
+
+       return setsockopt(s, SOL_SOCKET, SO_RERROR, &on, sizeof(on));
+#else
+#warning No socket receive buffer overflow detection
+       return 0;
+#endif
+}
+
+static int
+setup_msgfilter(int s)
+{
+#if defined(RO_MSGFILTER)
+       unsigned char msgfilter[] = { RTM_MISS };
+
+       return setsockopt(s, PF_ROUTE, RO_MSGFILTER,
+           &msgfilter, sizeof(msgfilter));
+#elif defined(ROUTE_MSGFILTER)
+       unsigned int msgfilter_mask = ROUTE_FILTER(RTM_MISS);
+
+       return setsockopt(s, PF_ROUTE, ROUTE_MSGFILTER,
+           &msgfilter_mask, sizeof(msgfilter_mask));
+#else
+#warning No route(4) message filtering
+       return 0;
+#endif
+}
+
+static void
+usage(void)
+{
+
+       fprintf(stderr, "usage: %s [-%s]\n", getprogname(), opts);
+       exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char * const *argv)
+{
+       bool foreground = false, debug = false;
+       int ch, s, logopts = 0;
+       struct passwd *pw;
+       const char *username;
+       ssize_t msglen;
+       union {
+               char buf[2048];
+               struct rt_msghdr hdr;
+       } rtm;
+
+#ifdef ROUTEMISSD_USER
+       username = __STRING(ROUTEMISSD_USER);
+#else
+       username = NULL;
+#endif
+
+       while ((ch = getopt(argc, argv, opts)) != -1) {
+               switch (ch) {
+               case 'd':
+                       debug = true;
+                       break;
+               case 'f':
+                       foreground = true;
+                       logopts |= LOG_PERROR;
+                       break;
+               case 'u':
+                       username = argv[optind];
+                       break;
+               case '?': /* FALLTHROUGH */
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+       }
+
+       setup_signals();
+
+       if (username != NULL) {
+               pw = getpwnam(username);
+               if (pw == NULL) {
+                       if (errno != 0)
+                               err(EXIT_FAILURE, "getpwnam");
+                       errx(EXIT_FAILURE, "no such user %s", username);
+               }
+               if (setgroups(1, &pw->pw_gid) == -1 ||
+                    setgid(pw->pw_gid) == -1 ||
+                    setuid(pw->pw_uid) == -1)
+                       err(EXIT_FAILURE, "failed to drop privileges");
+       } else
+               pw = NULL;
+
+       bl = blacklist_open();
+       if (bl == NULL)
+               err(EXIT_FAILURE, "blacklist_open");
+
+       s = socket(PF_ROUTE, SOCK_RAW, 0);
+       if (s == -1)
+               err(EXIT_FAILURE, "socket");
+
+       if (setup_msgfilter(s) == -1)
+               warn("setup_msgfilter");
+       if (setup_overflow(s) == -1)
+               warn("setup_overflow");
+
+       openlog(getprogname(), LOG_PID | logopts, LOG_DAEMON);
+       if (!debug)
+               setlogmask(LOG_UPTO(LOG_INFO));
+
+       if (!foreground) {
+               if (daemon(0, 0) == -1)
+                       err(EXIT_FAILURE, "daemon");
+       }
+
+       if (pw != NULL) {
+               if (chroot(pw->pw_dir) == -1)
+                       err(EXIT_FAILURE, "chroot: %s:", pw->pw_dir);
+               if (chdir("/") == -1)
+                       err(EXIT_FAILURE, "chdir: /:");
+       }
+
+       for (exit_now = false; !exit_now ;) {
+               msglen = read(s, &rtm, sizeof(rtm));
+               if (msglen == -1) {
+                       if (errno != EINTR)
+                               syslog(LOG_WARNING, "read: %m");
+                       continue;
+               }
+               dispatch_rtm(&rtm.hdr, (size_t)msglen);
+       }
+
+       close(s);
+       blacklist_close(bl);
+       closelog();
+       return exit_code;
+}

Reply via email to