tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

blacklisting nodes that probe non-existant nodes



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 roy%marples.name@localhost
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;
+}


Home | Main Index | Thread Index | Old Index