Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153770383
D17572.id49185.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
46 KB
Referenced Files
None
Subscribers
None
D17572.id49185.diff
View Options
Index: sbin/rtsol/Makefile
===================================================================
--- sbin/rtsol/Makefile
+++ sbin/rtsol/Makefile
@@ -18,9 +18,10 @@
PACKAGE=runtime
PROG= rtsol
-SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
+SRCS= rtsold.c rtsol.c if.c cap_probe.c cap_script.c dump.c rtsock.c
MAN=
-CFLAGS+= -DSMALL
+CFLAGS+= -DWITH_CASPER
+LIBADD+= casper nv
.include <bsd.prog.mk>
Index: usr.sbin/rtsold/Makefile
===================================================================
--- usr.sbin/rtsold/Makefile
+++ usr.sbin/rtsold/Makefile
@@ -17,8 +17,9 @@
PROG= rtsold
MAN= rtsold.8
MLINKS= rtsold.8 rtsol.8
-SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
+SRCS= rtsold.c rtsol.c if.c cap_probe.c cap_script.c dump.c rtsock.c
-LIBADD+= util
+CFLAGS+= -DWITH_CASPER
+LIBADD+= casper cap_syslog util nv
.include <bsd.prog.mk>
Index: usr.sbin/rtsold/cap_probe.c
===================================================================
--- usr.sbin/rtsold/cap_probe.c
+++ usr.sbin/rtsold/cap_probe.c
@@ -34,12 +34,9 @@
*/
#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
+#include <sys/capsicum.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
-#include <sys/uio.h>
-#include <sys/queue.h>
#include <net/if.h>
#include <net/if_dl.h>
@@ -52,121 +49,78 @@
#include <arpa/inet.h>
#include <errno.h>
-#include <unistd.h>
+#include <stdlib.h>
#include <string.h>
#include <syslog.h>
-#include <stdlib.h>
+#include <unistd.h>
-#include "rtsold.h"
+#include <libcasper.h>
+#include <libcasper_service.h>
-static struct msghdr sndmhdr;
-static struct iovec sndiov[2];
-static int probesock;
-static void sendprobe(struct in6_addr *, struct ifinfo *);
+#include "rtsold.h"
-int
-probe_init(void)
+static int
+getsocket(int *sockp)
{
- int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
- CMSG_SPACE(sizeof(int));
- static u_char *sndcmsgbuf = NULL;
-
- if (sndcmsgbuf == NULL &&
- (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) {
- warnmsg(LOG_ERR, __func__, "malloc failed");
- return (-1);
- }
+ static int probesock = -1;
+ cap_rights_t rights;
+ int error, sock;
- if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
- warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
- return (-1);
+ if (probesock >= 0) {
+ *sockp = probesock;
+ return (0);
}
- /* initialize msghdr for sending packets */
- sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
- sndmhdr.msg_iov = sndiov;
- sndmhdr.msg_iovlen = 1;
- sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
- sndmhdr.msg_controllen = scmsglen;
-
- return (0);
-}
-
-/*
- * Probe if each router in the default router list is still alive.
- */
-void
-defrouter_probe(struct ifinfo *ifinfo)
-{
- struct in6_defrouter *p, *ep;
- int ifindex, mib[4];
- char *buf, ntopbuf[INET6_ADDRSTRLEN];
- size_t l;
-
- ifindex = ifinfo->sdl->sdl_index;
- if (ifindex == 0)
- return;
- mib[0] = CTL_NET;
- mib[1] = PF_INET6;
- mib[2] = IPPROTO_ICMPV6;
- mib[3] = ICMPV6CTL_ND6_DRLIST;
- if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0) {
- warnmsg(LOG_ERR, __func__, "sysctl(ICMPV6CTL_ND6_DRLIST): %s",
- strerror(errno));
- return;
- }
- if (l == 0)
- return;
- buf = malloc(l);
- if (buf == NULL) {
- warnmsg(LOG_ERR, __func__, "malloc(): %s", strerror(errno));
- return;
+ if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
+ error = errno;
+ warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
+ return (error);
}
- if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) {
- warnmsg(LOG_ERR, __func__, "sysctl(ICMPV6CTL_ND6_DRLIST): %s",
+ cap_rights_init(&rights, CAP_CONNECT, CAP_SEND);
+ if (cap_rights_limit(sock, &rights) != 0) {
+ error = errno;
+ warnmsg(LOG_ERR, __func__, "cap_rights_limit(): %s",
strerror(errno));
- free(buf);
- return;
+ return (error);
}
- ep = (struct in6_defrouter *)(void *)(buf + l);
- for (p = (struct in6_defrouter *)(void *)buf; p < ep; p++) {
- if (ifindex != p->if_index)
- continue;
- if (!IN6_IS_ADDR_LINKLOCAL(&p->rtaddr.sin6_addr)) {
- warnmsg(LOG_ERR, __func__,
- "default router list contains a "
- "non-link-local address(%s)",
- inet_ntop(AF_INET6, &p->rtaddr.sin6_addr, ntopbuf,
- INET6_ADDRSTRLEN));
- continue; /* ignore the address */
- }
- sendprobe(&p->rtaddr.sin6_addr, ifinfo);
- }
- free(buf);
+ *sockp = probesock = sock;
+
+ return (0);
}
static void
-sendprobe(struct in6_addr *addr, struct ifinfo *ifinfo)
+sendprobe(int sock, struct in6_addr *addr, uint32_t ifindex, uint32_t linkid)
{
+ uint8_t cmsg[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int))];
+ struct msghdr hdr;
+ struct iovec iov;
u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
struct sockaddr_in6 sa6_probe;
struct in6_pktinfo *pi;
struct cmsghdr *cm;
- u_int32_t ifindex = ifinfo->sdl->sdl_index;
- int hoplimit = 1;
+ ssize_t n;
+ int error, hoplimit;
memset(&sa6_probe, 0, sizeof(sa6_probe));
sa6_probe.sin6_family = AF_INET6;
sa6_probe.sin6_len = sizeof(sa6_probe);
sa6_probe.sin6_addr = *addr;
- sa6_probe.sin6_scope_id = ifinfo->linkid;
+ sa6_probe.sin6_scope_id = linkid;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_name = (caddr_t)&sa6_probe;
+ hdr.msg_namelen = sizeof(sa6_probe);
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+ hdr.msg_control = cmsg;
+ hdr.msg_controllen = sizeof(cmsg);
- sndmhdr.msg_name = (caddr_t)&sa6_probe;
- sndmhdr.msg_iov[0].iov_base = NULL;
- sndmhdr.msg_iov[0].iov_len = 0;
+ iov.iov_base = NULL;
+ iov.iov_len = 0;
- cm = CMSG_FIRSTHDR(&sndmhdr);
- /* specify the outgoing interface */
+ /* Specify the outbound interface. */
+ cm = CMSG_FIRSTHDR(&hdr);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
@@ -174,8 +128,9 @@
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
pi->ipi6_ifindex = ifindex;
- /* specify the hop limit of the packet for safety */
- cm = CMSG_NXTHDR(&sndmhdr, cm);
+ /* Specify the hop limit of the packet for safety. */
+ hoplimit = 1;
+ cm = CMSG_NXTHDR(&hdr, cm);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_HOPLIMIT;
cm->cmsg_len = CMSG_LEN(sizeof(int));
@@ -185,7 +140,92 @@
inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN),
if_indextoname(ifindex, ifnamebuf));
- if (sendmsg(probesock, &sndmhdr, 0))
+ n = sendmsg(sock, &hdr, 0);
+ if (n != 0) {
+ error = errno;
warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
- if_indextoname(ifindex, ifnamebuf), strerror(errno));
+ if_indextoname(ifindex, ifnamebuf), strerror(error));
+ }
}
+
+int
+cap_probe_defrouters(cap_channel_t *cap, struct ifinfo *ifinfo)
+{
+ nvlist_t *nvl;
+ int error;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "probe_defrouters");
+ nvlist_add_number(nvl, "ifindex", ifinfo->sdl->sdl_index);
+ nvlist_add_number(nvl, "linkid", ifinfo->linkid);
+
+ nvl = cap_xfer_nvlist(cap, nvl);
+ if (nvl == NULL)
+ return (errno);
+
+ error = 0;
+ if (nvlist_exists_number(nvl, "error"))
+ error = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+
+ return (error);
+}
+
+static int
+probe_command(const char *cmd, const nvlist_t *limits __unused, nvlist_t *nvlin,
+ nvlist_t *nvlout __unused)
+{
+ struct in6_defrouter *p, *ep;
+ char *buf;
+ int error, mib[4], sock;
+ size_t len;
+ uint32_t ifindex, linkid;
+
+ if (strcmp(cmd, "probe_defrouters") != 0)
+ return (EINVAL);
+
+ ifindex = (uint32_t)nvlist_get_number(nvlin, "ifindex");
+ linkid = (uint32_t)nvlist_get_number(nvlin, "linkid");
+ if (ifindex == 0)
+ return (EINVAL);
+
+ error = getsocket(&sock);
+ if (error != 0)
+ return (error);
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_ICMPV6;
+ mib[3] = ICMPV6CTL_ND6_DRLIST;
+ if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0)
+ return (errno);
+ if (len == 0)
+ return (0);
+
+ buf = malloc(len);
+ if (buf == NULL)
+ return (errno);
+ if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) < 0)
+ return (errno);
+ ep = (struct in6_defrouter *)(void *)(buf + len);
+ for (p = (struct in6_defrouter *)(void *)buf; p < ep; p++) {
+ if (ifindex != p->if_index)
+ continue;
+ if (!IN6_IS_ADDR_LINKLOCAL(&p->rtaddr.sin6_addr))
+ continue;
+ sendprobe(sock, &p->rtaddr.sin6_addr, ifindex, linkid);
+ }
+ free(buf);
+
+ return (0);
+}
+
+static int
+probe_limit(const nvlist_t *oldlimits __unused,
+ const nvlist_t *newlimits __unused)
+{
+
+ return (0);
+}
+
+CREATE_SERVICE("rtsold.defrouter_probe", probe_limit, probe_command, 0);
Index: usr.sbin/rtsold/cap_script.c
===================================================================
--- /dev/null
+++ usr.sbin/rtsold/cap_script.c
@@ -0,0 +1,203 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2018 The FreeBSD Foundation
+ *
+ * This software was developed by Mark Johnston under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/capsicum.h>
+#include <sys/nv.h>
+#include <sys/queue.h>
+#include <sys/wait.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcasper.h>
+#include <libcasper_service.h>
+
+#include "rtsold.h"
+
+int
+cap_script_run(cap_channel_t *cap, const char *const *argv)
+{
+ nvlist_t *nvl;
+ size_t argc;
+ int error, wfd;
+
+ for (argc = 0; argv[argc] != NULL; argc++) ;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "run");
+ nvlist_add_string_array(nvl, "argv", argv, argc);
+ nvl = cap_xfer_nvlist(cap, nvl);
+ if (nvl == NULL)
+ return (-1);
+
+ error = 0;
+ if (nvlist_exists_number(nvl, "error"))
+ error = (int)nvlist_get_number(nvl, "error");
+ if (error == 0)
+ wfd = nvlist_take_descriptor(nvl, "fd");
+ nvlist_destroy(nvl);
+ errno = error;
+ return (error == 0 ? wfd : -1);
+}
+
+int
+cap_script_wait(cap_channel_t *cap, int *statusp)
+{
+ nvlist_t *nvl;
+ int error;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "wait");
+ nvl = cap_xfer_nvlist(cap, nvl);
+ if (nvl == NULL)
+ return (-1);
+
+ error = 0;
+ if (nvlist_exists_number(nvl, "error"))
+ error = (int)nvlist_get_number(nvl, "error");
+ if (error == 0)
+ *statusp = (int)nvlist_get_number(nvl, "status");
+ nvlist_destroy(nvl);
+ errno = error;
+ return (error == 0 ? 0 : -1);
+}
+
+static int
+script_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ cap_rights_t rights;
+ const char *const *iargv, *const *scripts;
+ char **argv;
+ size_t argc, i, nscripts;
+ pid_t pid;
+ int fd[2], null, status;
+
+ if (strcmp(cmd, "wait") == 0) {
+ /* Wait for the result of a previous "run" command. */
+ if (wait(&status) == -1)
+ return (errno);
+ nvlist_add_number(nvlout, "status", status);
+ return (0);
+ }
+ if (strcmp(cmd, "run") != 0)
+ return (EINVAL);
+
+ /*
+ * Validate the argv against the limits specified at initialization
+ * time.
+ */
+ iargv = nvlist_get_string_array(nvlin, "argv", &argc);
+ if (argc == 0)
+ return (EINVAL);
+ scripts = nvlist_get_string_array(limits, "scripts", &nscripts);
+ for (i = 0; i < nscripts; i++)
+ if (strcmp(iargv[0], scripts[i]) == 0)
+ break;
+ if (i == nscripts)
+ return (EINVAL);
+
+ /*
+ * The nvlist API does not permit NULL pointers in an array, so we have
+ * to add the nul terminator ourselves. Yuck.
+ */
+ argv = calloc(argc + 1, sizeof(*argv));
+ if (argv == NULL)
+ return (errno);
+ memcpy(argv, iargv, sizeof(*argv) * argc);
+
+ /*
+ * Run the script and return the write end of a pipe to the main
+ * process.
+ */
+ if (pipe(fd) != 0)
+ return (errno);
+ if ((pid = fork()) < 0)
+ return (errno);
+ if (pid == 0) {
+ (void)close(fd[1]);
+ null = open("/dev/null", O_RDWR);
+ if (null < 0)
+ _exit(1);
+ if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO ||
+ dup2(null, STDOUT_FILENO) != STDOUT_FILENO ||
+ dup2(null, STDERR_FILENO) != STDERR_FILENO)
+ _exit(1);
+
+ (void)close(null);
+ (void)execve(argv[0], argv, NULL);
+ _exit(1);
+ } else {
+ (void)close(fd[0]);
+ (void)cap_rights_limit(fd[1],
+ cap_rights_init(&rights, CAP_WRITE));
+ nvlist_move_descriptor(nvlout, "fd", fd[1]);
+ }
+
+ return (0);
+}
+
+static int
+script_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits __unused)
+{
+ const char *name;
+ void *cookie;
+ int nvtype;
+ bool hasscripts;
+
+ /* Limits may only be set once. */
+ if (oldlimits != NULL)
+ return (ENOTCAPABLE);
+
+ cookie = NULL;
+ hasscripts = false;
+ while ((name = nvlist_next(newlimits, &nvtype, &cookie)) != NULL) {
+ if (nvtype == NV_TYPE_STRING_ARRAY &&
+ strcmp(name, "scripts") == 0)
+ hasscripts = true;
+ else
+ return (EINVAL);
+ }
+ if (!hasscripts)
+ return (EINVAL);
+ return (0);
+}
+
+CREATE_SERVICE("rtsold.script", script_limit, script_command,
+ CASPER_SERVICE_STDIO);
Index: usr.sbin/rtsold/dump.c
===================================================================
--- usr.sbin/rtsold/dump.c
+++ usr.sbin/rtsold/dump.c
@@ -34,6 +34,7 @@
*/
#include <sys/types.h>
+#include <sys/capsicum.h>
#include <sys/socket.h>
#include <sys/queue.h>
@@ -50,13 +51,11 @@
#include "rtsold.h"
-static FILE *fp;
+static const char * const ifstatstr[] =
+ { "IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE" };
-static void dump_interface_status(void);
-static const char * const ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE"};
-
-static void
-dump_interface_status(void)
+void
+rtsold_dump(FILE *fp)
{
struct ifinfo *ifi;
struct rainfo *rai;
@@ -64,9 +63,16 @@
struct timespec now;
char ntopbuf[INET6_ADDRSTRLEN];
- clock_gettime(CLOCK_MONOTONIC_FAST, &now);
+ if (fseek(fp, 0, SEEK_SET) != 0) {
+ warnmsg(LOG_ERR, __func__, "fseek(): %s", strerror(errno));
+ return;
+ }
+ (void)ftruncate(fileno(fp), 0);
+
+ (void)clock_gettime(CLOCK_MONOTONIC_FAST, &now);
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
+ printf("hello!\n");
fprintf(fp, "Interface %s\n", ifi->ifname);
fprintf(fp, " probe interval: ");
if (ifi->probeinterval) {
@@ -121,18 +127,28 @@
fprintf(fp, "\n");
}
}
+ fflush(fp);
}
-void
-rtsold_dump_file(const char *dumpfile)
+FILE *
+rtsold_init_dumpfile(const char *dumpfile)
{
+ cap_rights_t rights;
+ FILE *fp;
+
if ((fp = fopen(dumpfile, "w")) == NULL) {
- warnmsg(LOG_WARNING, __func__, "open a dump file(%s): %s",
+ warnmsg(LOG_WARNING, __func__, "opening a dump file(%s): %s",
dumpfile, strerror(errno));
- return;
+ return (NULL);
+ }
+
+ cap_rights_init(&rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE);
+ if (cap_rights_limit(fileno(fp), &rights) != 0) {
+ warnmsg(LOG_WARNING, __func__, "cap_rights_limit(%s): %s",
+ dumpfile, strerror(errno));
+ return (NULL);
}
- dump_interface_status();
- fclose(fp);
+ return (fp);
}
const char *
Index: usr.sbin/rtsold/if.c
===================================================================
--- usr.sbin/rtsold/if.c
+++ usr.sbin/rtsold/if.c
@@ -34,10 +34,11 @@
*/
#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
+#include <sys/capsicum.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -63,16 +64,29 @@
#include "rtsold.h"
static int ifsock;
-
static int get_llflag(const char *);
static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
int
ifinit(void)
{
- ifsock = rssock;
+ cap_rights_t rights;
+ int sock;
- return(0);
+ sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ if (sock < 0) {
+ warnmsg(LOG_ERR, __func__, "socket(): %s",
+ strerror(errno));
+ return (-1);
+ }
+ if (cap_rights_limit(sock, cap_rights_init(&rights, CAP_IOCTL)) < 0) {
+ warnmsg(LOG_ERR, __func__, "cap_rights_limit(): %s",
+ strerror(errno));
+ (void)close(sock);
+ return (-1);
+ }
+ ifsock = sock;
+ return (0);
}
int
Index: usr.sbin/rtsold/rtsock.c
===================================================================
--- usr.sbin/rtsold/rtsock.c
+++ usr.sbin/rtsold/rtsock.c
@@ -33,10 +33,11 @@
*/
#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/queue.h>
#include <sys/socket.h>
-#include <sys/uio.h>
#include <sys/time.h>
-#include <sys/queue.h>
+#include <sys/uio.h>
#include <net/if.h>
#include <net/route.h>
@@ -80,8 +81,18 @@
int
rtsock_open(void)
{
-
- return (socket(PF_ROUTE, SOCK_RAW, 0));
+ cap_rights_t rights;
+ int s;
+
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
+ return (s);
+ cap_rights_init(&rights, CAP_EVENT, CAP_READ);
+ if (cap_rights_limit(s, &rights) != 0) {
+ (void)close(s);
+ return (-1);
+ }
+ return (s);
}
int
Index: usr.sbin/rtsold/rtsol.c
===================================================================
--- usr.sbin/rtsold/rtsol.c
+++ usr.sbin/rtsold/rtsol.c
@@ -35,11 +35,12 @@
*/
#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/queue.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/uio.h>
-#include <sys/queue.h>
#include <sys/wait.h>
-#include <sys/stat.h>
#include <net/if.h>
#include <net/route.h>
@@ -67,17 +68,8 @@
#include <syslog.h>
#include "rtsold.h"
-static struct msghdr rcvmhdr;
-static struct msghdr sndmhdr;
-static struct iovec rcviov[2];
-static struct iovec sndiov[2];
-static struct sockaddr_in6 from;
-static int rcvcmsglen;
-
-int rssock;
static char rsid[IFNAMSIZ + 1 + sizeof(DNSINFO_ORIGIN_LABEL) + 1 + NI_MAXHOST];
-struct ifinfo_head_t ifinfo_head =
- TAILQ_HEAD_INITIALIZER(ifinfo_head);
+struct ifinfo_head_t ifinfo_head = TAILQ_HEAD_INITIALIZER(ifinfo_head);
static const struct sockaddr_in6 sin6_allrouters = {
.sin6_len = sizeof(sin6_allrouters),
@@ -85,10 +77,8 @@
.sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
};
-static void call_script(const int, const char *const *,
- struct script_msg_head_t *);
+static void call_script(const char *const *, struct script_msg_head_t *);
static size_t dname_labeldec(char *, size_t, const char *);
-static int safefile(const char *);
static struct ra_opt *find_raopt(struct rainfo *, int, void *, size_t);
static int ra_opt_rdnss_dispatch(struct ifinfo *, struct rainfo *,
struct script_msg_head_t *, struct script_msg_head_t *);
@@ -100,7 +90,7 @@
#define CALL_SCRIPT(name, sm_head) do { \
const char *const sarg[] = { _ARGS_##name, NULL }; \
- call_script(sizeof(sarg), sarg, sm_head); \
+ call_script(sarg, sm_head); \
} while (0)
#define ELM_MALLOC(p, error_action) do { \
@@ -114,94 +104,132 @@
} while (0)
int
-sockopen(void)
+recvsockopen(void)
{
- static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL;
- int sndcmsglen, on;
- static u_char answer[1500];
struct icmp6_filter filt;
+ cap_rights_t rights;
+ int on, sock;
- sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
- CMSG_SPACE(sizeof(int));
- if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
- warnmsg(LOG_ERR, __func__,
- "malloc for receive msghdr failed");
- return (-1);
- }
- if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) {
- warnmsg(LOG_ERR, __func__,
- "malloc for send msghdr failed");
- return (-1);
- }
- if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
- return (-1);
+ goto fail;
}
- /* specify to tell receiving interface */
+ /* Provide info about the receiving interface. */
on = 1;
- if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0) {
- warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s",
+ warnmsg(LOG_ERR, __func__, "setsockopt(IPV6_RECVPKTINFO): %s",
strerror(errno));
- exit(1);
+ goto fail;
}
- /* specify to tell value of hoplimit field of received IP6 hdr */
+ /* Include the hop limit from the received header. */
on = 1;
- if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof(on)) < 0) {
- warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s",
+ warnmsg(LOG_ERR, __func__, "setsockopt(IPV6_RECVHOPLIMIT): %s",
strerror(errno));
- exit(1);
+ goto fail;
}
- /* specfiy to accept only router advertisements on the socket */
+ /* Filter out everything except for Router Advertisements. */
ICMP6_FILTER_SETBLOCKALL(&filt);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
- if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) == -1) {
+ warnmsg(LOG_ERR, __func__, "setsockopt(ICMP6_FILTER): %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ (void)cap_rights_init(&rights, CAP_EVENT, CAP_RECV);
+ if (cap_rights_limit(sock, &rights) < 0) {
+ warnmsg(LOG_ERR, __func__, "cap_rights_limit(): %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ return (sock);
+
+fail:
+ if (sock >= 0)
+ (void)close(sock);
+ return (-1);
+}
+
+int
+sendsockopen(uint32_t linkid)
+{
+ struct icmp6_filter filt;
+ struct sockaddr_in6 dst;
+ cap_rights_t rights;
+ int sock;
+
+ if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
+ goto fail;
+ }
+
+ /*
+ * We don't want to receive data on send sockets.
+ */
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
sizeof(filt)) == -1) {
warnmsg(LOG_ERR, __func__, "setsockopt(ICMP6_FILTER): %s",
strerror(errno));
- return(-1);
+ goto fail;
+ }
+
+ /*
+ * Explicitly set the destination address now so that we can send on
+ * this socket in capability mode.
+ */
+ dst = sin6_allrouters;
+ dst.sin6_scope_id = linkid;
+ if (connect(sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) {
+ warnmsg(LOG_ERR, __func__, "connect(): %s", strerror(errno));
+ goto fail;
}
- /* initialize msghdr for receiving packets */
- rcviov[0].iov_base = (caddr_t)answer;
- rcviov[0].iov_len = sizeof(answer);
- rcvmhdr.msg_name = (caddr_t)&from;
- rcvmhdr.msg_iov = rcviov;
- rcvmhdr.msg_iovlen = 1;
- rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ if (cap_rights_limit(sock, cap_rights_init(&rights, CAP_SEND)) < 0) {
+ warnmsg(LOG_ERR, __func__, "cap_rights_limit(): %s",
+ strerror(errno));
+ goto fail;
+ }
- /* initialize msghdr for sending packets */
- sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
- sndmhdr.msg_iov = sndiov;
- sndmhdr.msg_iovlen = 1;
- sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
- sndmhdr.msg_controllen = sndcmsglen;
+ return (sock);
- return (rssock);
+fail:
+ if (sock >= 0)
+ (void)close(sock);
+ return (-1);
}
void
sendpacket(struct ifinfo *ifi)
{
+ uint8_t cmsg[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int))];
+ struct iovec iov;
+ struct msghdr hdr;
struct in6_pktinfo *pi;
struct cmsghdr *cm;
int hoplimit = 255;
- ssize_t i;
- struct sockaddr_in6 dst;
+ ssize_t n;
- dst = sin6_allrouters;
- dst.sin6_scope_id = ifi->linkid;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+ hdr.msg_control = cmsg;
+ hdr.msg_controllen = sizeof(cmsg);
- sndmhdr.msg_name = (caddr_t)&dst;
- sndmhdr.msg_iov[0].iov_base = (caddr_t)ifi->rs_data;
- sndmhdr.msg_iov[0].iov_len = ifi->rs_datalen;
+ iov.iov_base = (caddr_t)ifi->rs_data;
+ iov.iov_len = ifi->rs_datalen;
- cm = CMSG_FIRSTHDR(&sndmhdr);
- /* specify the outgoing interface */
+ /* Specify the outbound interface. */
+ cm = CMSG_FIRSTHDR(&hdr);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
@@ -209,35 +237,37 @@
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
pi->ipi6_ifindex = ifi->sdl->sdl_index;
- /* specify the hop limit of the packet */
- cm = CMSG_NXTHDR(&sndmhdr, cm);
+ /* Specify the packet's hop limit. */
+ cm = CMSG_NXTHDR(&hdr, cm);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_HOPLIMIT;
- cm->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
- warnmsg(LOG_DEBUG, __func__,
- "send RS on %s, whose state is %d",
+ warnmsg(LOG_DEBUG, __func__, "sent RS on %s, state is %d",
ifi->ifname, ifi->state);
- i = sendmsg(rssock, &sndmhdr, 0);
- if (i < 0 || (size_t)i != ifi->rs_datalen) {
+ n = sendmsg(ifi->ifi_sock, &hdr, 0);
+ if (n < 0 || (size_t)n != ifi->rs_datalen) {
/*
* ENETDOWN is not so serious, especially when using several
* network cards on a mobile node. We ignore it.
*/
if (errno != ENETDOWN || dflag > 0)
- warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
- ifi->ifname, strerror(errno));
+ warnmsg(LOG_ERR, __func__, "sendmsg on %s %zd: %s",
+ ifi->ifname, n, strerror(errno));
}
-
- /* update counter */
ifi->probes++;
}
void
-rtsol_input(int s)
+rtsol_input(int sock)
{
- char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ uint8_t cmsg[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int))];
+ struct iovec iov;
+ struct msghdr hdr;
+ struct sockaddr_in6 from;
+ char answer[1500], ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
int l, ifindex = 0, *hlimp = NULL;
ssize_t msglen;
struct in6_pktinfo *pi = NULL;
@@ -247,8 +277,7 @@
struct nd_router_advert *nd_ra;
struct cmsghdr *cm;
struct rainfo *rai;
- char *raoptp;
- char *p;
+ char *p, *raoptp;
struct in6_addr *addr;
struct nd_opt_hdr *ndo;
struct nd_opt_rdnss *rdnss;
@@ -256,22 +285,28 @@
size_t len;
char nsbuf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1];
char dname[NI_MAXHOST];
- struct timespec now;
- struct timespec lifetime;
- int newent_rai;
- int newent_rao;
-
- /* get message. namelen and controllen must always be initialized. */
- rcvmhdr.msg_namelen = sizeof(from);
- rcvmhdr.msg_controllen = rcvcmsglen;
- if ((msglen = recvmsg(s, &rcvmhdr, 0)) < 0) {
+ struct timespec lifetime, now;
+ int newent_rai, newent_rao;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+ hdr.msg_name = &from;
+ hdr.msg_namelen = sizeof(from);
+ hdr.msg_control = cmsg;
+ hdr.msg_controllen = sizeof(cmsg);
+
+ iov.iov_base = (caddr_t)answer;
+ iov.iov_len = sizeof(answer);
+
+ if ((msglen = recvmsg(sock, &hdr, 0)) < 0) {
warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
return;
}
- /* extract optional information via Advanced API */
- for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); cm;
- cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
+ /* Extract control message info. */
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&hdr); cm != NULL;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&hdr, cm)) {
if (cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_PKTINFO &&
cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
@@ -301,8 +336,7 @@
return;
}
- icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
-
+ icp = (struct icmp6_hdr *)iov.iov_base;
if (icp->icmp6_type != ND_ROUTER_ADVERT) {
/*
* this should not happen because we configured a filter
@@ -761,154 +795,40 @@
}
static void
-call_script(const int argc, const char *const argv[],
- struct script_msg_head_t *sm_head)
+call_script(const char *const argv[], struct script_msg_head_t *sm_head)
{
- const char *scriptpath;
- int fd[2];
- int error;
- pid_t pid, wpid;
+ struct script_msg *smp;
+ ssize_t len;
+ int status, wfd;
- if ((scriptpath = argv[0]) == NULL)
+ wfd = cap_script_run(capscript, argv);
+ if (wfd == -1) {
+ warnmsg(LOG_ERR, __func__,
+ "failed to run script: %s", strerror(errno));
return;
-
- fd[0] = fd[1] = -1;
- if (sm_head != NULL && !TAILQ_EMPTY(sm_head)) {
- error = pipe(fd);
- if (error) {
- warnmsg(LOG_ERR, __func__,
- "failed to create a pipe: %s", strerror(errno));
- return;
- }
}
- /* launch the script */
- pid = fork();
- if (pid < 0) {
- warnmsg(LOG_ERR, __func__,
- "failed to fork: %s", strerror(errno));
- return;
- } else if (pid) { /* parent */
- int wstatus;
-
- if (fd[0] != -1) { /* Send message to the child if any. */
- ssize_t len;
- struct script_msg *smp;
-
- close(fd[0]);
- TAILQ_FOREACH(smp, sm_head, sm_next) {
- len = strlen(smp->sm_msg);
- warnmsg(LOG_DEBUG, __func__,
- "write to child = %s(%zd)",
- smp->sm_msg, len);
- if (write(fd[1], smp->sm_msg, len) != len) {
- warnmsg(LOG_ERR, __func__,
- "write to child failed: %s",
- strerror(errno));
- break;
- }
- }
- close(fd[1]);
- }
- do {
- wpid = wait(&wstatus);
- } while (wpid != pid && wpid > 0);
-
- if (wpid < 0)
- warnmsg(LOG_ERR, __func__,
- "wait: %s", strerror(errno));
- else
- warnmsg(LOG_DEBUG, __func__,
- "script \"%s\" terminated", scriptpath);
- } else { /* child */
- int nullfd;
- char **_argv;
-
- if (safefile(scriptpath)) {
- warnmsg(LOG_ERR, __func__,
- "script \"%s\" cannot be executed safely",
- scriptpath);
- exit(1);
- }
- nullfd = open("/dev/null", O_RDWR);
- if (nullfd < 0) {
- warnmsg(LOG_ERR, __func__,
- "open /dev/null: %s", strerror(errno));
- exit(1);
- }
- if (fd[0] != -1) { /* Receive message from STDIN if any. */
- close(fd[1]);
- if (fd[0] != STDIN_FILENO) {
- /* Connect a pipe read-end to child's STDIN. */
- if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
- warnmsg(LOG_ERR, __func__,
- "dup2 STDIN: %s", strerror(errno));
- exit(1);
- }
- close(fd[0]);
+ if (sm_head != NULL) {
+ TAILQ_FOREACH(smp, sm_head, sm_next) {
+ len = strlen(smp->sm_msg);
+ warnmsg(LOG_DEBUG, __func__, "write to child = %s(%zd)",
+ smp->sm_msg, len);
+ if (write(wfd, smp->sm_msg, len) != len) {
+ warnmsg(LOG_ERR, __func__,
+ "write to child failed: %s",
+ strerror(errno));
+ break;
}
- } else
- dup2(nullfd, STDIN_FILENO);
-
- dup2(nullfd, STDOUT_FILENO);
- dup2(nullfd, STDERR_FILENO);
- if (nullfd > STDERR_FILENO)
- close(nullfd);
-
- _argv = malloc(sizeof(*_argv) * argc);
- if (_argv == NULL) {
- warnmsg(LOG_ERR, __func__,
- "malloc: %s", strerror(errno));
- exit(1);
}
- memcpy(_argv, argv, (size_t)argc);
- execv(scriptpath, (char *const *)_argv);
- warnmsg(LOG_ERR, __func__, "child: exec failed: %s",
- strerror(errno));
- exit(1);
}
- return;
-}
-
-static int
-safefile(const char *path)
-{
- struct stat s;
- uid_t myuid;
-
- /* no setuid */
- if (getuid() != geteuid()) {
- warnmsg(LOG_NOTICE, __func__,
- "setuid'ed execution not allowed\n");
- return (-1);
- }
+ (void)close(wfd);
- if (lstat(path, &s) != 0) {
- warnmsg(LOG_NOTICE, __func__, "lstat failed: %s",
- strerror(errno));
- return (-1);
- }
-
- /* the file must be owned by the running uid */
- myuid = getuid();
- if (s.st_uid != myuid) {
- warnmsg(LOG_NOTICE, __func__,
- "%s has invalid owner uid\n", path);
- return (-1);
- }
-
- switch (s.st_mode & S_IFMT) {
- case S_IFREG:
- break;
- default:
- warnmsg(LOG_NOTICE, __func__,
- "%s is an invalid file type 0x%o\n",
- path, (s.st_mode & S_IFMT));
- return (-1);
- }
-
- return (0);
+ if (cap_script_wait(capscript, &status) != 0)
+ warnmsg(LOG_ERR, __func__, "wait(): %s", strerror(errno));
+ else
+ warnmsg(LOG_DEBUG, __func__, "script \"%s\" status %d",
+ argv[0], status);
}
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
Index: usr.sbin/rtsold/rtsold.h
===================================================================
--- usr.sbin/rtsold/rtsold.h
+++ usr.sbin/rtsold/rtsold.h
@@ -60,12 +60,14 @@
TAILQ_HEAD(, ra_opt) rai_ra_opt;
};
+/* Per-interface tracking info. */
struct ifinfo {
- TAILQ_ENTRY(ifinfo) ifi_next; /* pointer to the next interface */
+ TAILQ_ENTRY(ifinfo) ifi_next; /* pointer to the next interface */
struct sockaddr_dl *sdl; /* link-layer address */
char ifname[IFNAMSIZ]; /* interface name */
- u_int32_t linkid; /* link ID of this interface */
+ uint32_t linkid; /* link ID of this interface */
+ int ifi_sock; /* socket for sending RS messages */
int active; /* interface status */
int probeinterval; /* interval of probe timer (if necessary) */
int probetimer; /* rest of probe timer */
@@ -77,7 +79,6 @@
int dadcount;
struct timespec timer;
struct timespec expire;
- int errors; /* # of errors we've got - detect wedge */
#define IFI_DNSOPT_STATE_NOINFO 0
#define IFI_DNSOPT_STATE_RECEIVED 1
int ifi_rdnss; /* RDNSS option state */
@@ -150,6 +151,7 @@
} while (0)
/* rtsold.c */
+struct cap_channel;
extern struct timespec tm_max;
extern int dflag;
extern int aflag;
@@ -157,6 +159,8 @@
extern int uflag;
extern const char *otherconf_script;
extern const char *resolvconf_script;
+extern struct cap_channel *capprobe, *capscript;
+
struct ifinfo *find_ifinfo(int);
struct rainfo *find_rainfo(struct ifinfo *, struct sockaddr_in6 *);
void rtsol_timer_update(struct ifinfo *);
@@ -165,6 +169,7 @@
extern int ra_opt_handler(struct ifinfo *);
/* if.c */
+struct nd_opt_hdr;
extern int ifinit(void);
extern int interface_up(char *);
extern int interface_status(struct ifinfo *);
@@ -173,17 +178,21 @@
extern struct sockaddr_dl *if_nametosdl(char *);
/* rtsol.c */
-extern int rssock;
-extern int sockopen(void);
+extern int recvsockopen(void);
+extern int sendsockopen(uint32_t);
extern void sendpacket(struct ifinfo *);
extern void rtsol_input(int);
-/* probe.c */
-extern int probe_init(void);
-extern void defrouter_probe(struct ifinfo *);
+/* cap_probe.c */
+extern int cap_probe_defrouters(struct cap_channel *, struct ifinfo *);
+
+/* cap_script.c */
+extern int cap_script_run(struct cap_channel *, const char *const *);
+extern int cap_script_wait(struct cap_channel *, int *);
/* dump.c */
-extern void rtsold_dump_file(const char *);
+extern FILE *rtsold_init_dumpfile(const char *);
+extern void rtsold_dump(FILE *);
extern const char *sec2str(const struct timespec *);
/* rtsock.c */
Index: usr.sbin/rtsold/rtsold.c
===================================================================
--- usr.sbin/rtsold/rtsold.c
+++ usr.sbin/rtsold/rtsold.c
@@ -35,6 +35,7 @@
#include <sys/param.h>
#include <sys/capsicum.h>
+#include <sys/event.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -48,24 +49,27 @@
#include <netinet6/nd6.h>
+#include <capsicum_helpers.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <libgen.h>
#include <signal.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <string.h>
-#include <stdlib.h>
+#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
#include <time.h>
-#include <errno.h>
-#include <err.h>
-#include <stdarg.h>
-#include <ifaddrs.h>
-#include <poll.h>
+#include <unistd.h>
+#include <libcasper.h>
+#include <casper/cap_syslog.h>
#include <libutil.h>
#include "rtsold.h"
-#define RTSOL_DUMPFILE "/var/run/rtsold.dump";
+#define RTSOL_DUMPFILE "/var/run/rtsold.dump"
struct timespec tm_max;
static int log_upto = 999;
@@ -79,6 +83,9 @@
const char *otherconf_script;
const char *resolvconf_script = "/sbin/resolvconf";
+cap_channel_t *capprobe, *capscript;
+static cap_channel_t *capsyslog;
+
/* protocol constants */
#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
@@ -93,43 +100,38 @@
/* static variables and functions */
static int mobile_node = 0;
-#ifndef SMALL
-static int do_dump;
-static const char *dumpfilename = RTSOL_DUMPFILE;
+static sig_atomic_t do_dump;
static struct pidfh *pfh;
-#endif
static char **autoifprobe(void);
static int ifconfig(char *ifname);
+static int init_capabilities(void);
static int make_packet(struct ifinfo *);
static struct timespec *rtsol_check_timer(void);
-#ifndef SMALL
-static void rtsold_set_dump_file(int);
-#endif
-static void usage(void);
+static void set_dumpfile(int);
+static void usage(const char *progname);
int
main(int argc, char **argv)
{
- int s, ch, once = 0;
+ struct kevent events[2];
+ FILE *dumpfp;
+ struct ifinfo *ifi;
struct timespec *timeout;
- const char *opts, *pidfilepath;
- struct pollfd set[2];
- int rtsock;
- char *argv0;
-
-#ifndef SMALL
- /* rtsold */
- opts = "adDfFm1O:p:R:u";
- pidfilepath = NULL;
-#else
- /* rtsol */
- opts = "adDFO:R:u";
- fflag = 1;
- once = 1;
-#endif
- argv0 = argv[0];
+ const char *opts, *pidfilepath, *progname;
+ int ch, error, kq, once, rcvsock, rtsock;
+
+ progname = basename(argv[0]);
+ if (strcmp(progname, "rtsold") == 0) {
+ opts = "adDfFm1O:p:R:u";
+ once = 0;
+ pidfilepath = NULL;
+ } else {
+ opts = "adDFO:R:u";
+ fflag = 1;
+ once = 1;
+ }
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
@@ -167,17 +169,14 @@
uflag = 1;
break;
default:
- usage();
- exit(1);
+ usage(progname);
}
}
argc -= optind;
argv += optind;
- if ((!aflag && argc == 0) || (aflag && argc != 0)) {
- usage();
- exit(1);
- }
+ if ((!aflag && argc == 0) || (aflag && argc != 0))
+ usage(progname);
/* Generate maximum time in timespec. */
tm_max.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1));
@@ -191,65 +190,62 @@
else
log_upto = LOG_NOTICE;
- if (!fflag) {
- char *ident;
-
- ident = strrchr(argv0, '/');
- if (!ident)
- ident = argv0;
- else
- ident++;
- openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
- if (log_upto >= 0)
- setlogmask(LOG_UPTO(log_upto));
- }
-
- if (otherconf_script && *otherconf_script != '/') {
+ if (otherconf_script != NULL && *otherconf_script != '/')
errx(1, "configuration script (%s) must be an absolute path",
otherconf_script);
- }
- if (resolvconf_script && *resolvconf_script != '/') {
+ if (*resolvconf_script != '/')
errx(1, "configuration script (%s) must be an absolute path",
resolvconf_script);
- }
-#ifndef SMALL
- pfh = pidfile_open(pidfilepath, 0644, NULL);
- if (pfh == NULL) {
- errx(1, "failed to open pidfile: %s", strerror(errno));
+ if (!fflag) {
+ pfh = pidfile_open(pidfilepath, 0644, NULL);
+ if (pfh == NULL)
+ errx(1, "failed to open pidfile: %s", strerror(errno));
+ if (daemon(0, 0) != 0)
+ errx(1, "failed to daemonize");
}
- /* initialization to dump internal status to a file */
- signal(SIGUSR1, rtsold_set_dump_file);
-#endif
+ if ((error = init_capabilities()) != 0) {
+ warnmsg(LOG_ERR, __func__, "failed to initialize capabilities: %s",
+ strerror(error));
+ exit(1);
+ }
- if (!fflag)
- daemon(0, 0); /* act as a daemon */
+ if (!fflag) {
+ cap_openlog(capsyslog, progname, LOG_NDELAY | LOG_PID,
+ LOG_DAEMON);
+ if (log_upto >= 0)
+ (void)cap_setlogmask(capsyslog, LOG_UPTO(log_upto));
+ (void)signal(SIGUSR1, set_dumpfile);
+ dumpfp = rtsold_init_dumpfile(RTSOL_DUMPFILE);
+ }
- /*
- * Open a socket for sending RS and receiving RA.
- * This should be done before calling ifinit(), since the function
- * uses the socket.
- */
- if ((s = sockopen()) < 0) {
- warnmsg(LOG_ERR, __func__, "failed to open a socket");
+ kq = kqueue();
+ if (kq < 0) {
+ warnmsg(LOG_ERR, __func__, "failed to create a kqueue: %s",
+ strerror(errno));
exit(1);
}
- set[0].fd = s;
- set[0].events = POLLIN;
- set[1].fd = -1;
+ /* Open global sockets and register for read events. */
if ((rtsock = rtsock_open()) < 0) {
- warnmsg(LOG_ERR, __func__, "failed to open a socket");
+ warnmsg(LOG_ERR, __func__, "failed to open routing socket");
+ exit(1);
+ }
+ if ((rcvsock = recvsockopen()) < 0) {
+ warnmsg(LOG_ERR, __func__, "failed to open receive socket");
+ exit(1);
+ }
+ EV_SET(&events[0], rtsock, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ EV_SET(&events[1], rcvsock, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ if (kevent(kq, events, 2, NULL, 0, NULL) < 0) {
+ warnmsg(LOG_ERR, __func__, "kevent(): %s", strerror(errno));
exit(1);
}
- set[1].fd = rtsock;
- set[1].events = POLLIN;
- /* configuration per interface */
- if (ifinit()) {
- warnmsg(LOG_ERR, __func__,
- "failed to initialize interfaces");
+ /* Probe network interfaces and set up tracking info. */
+ if (ifinit() != 0) {
+ warnmsg(LOG_ERR, __func__, "failed to initialize interfaces");
exit(1);
}
if (aflag)
@@ -263,35 +259,30 @@
argv++;
}
- /* setup for probing default routers */
- if (probe_init()) {
+ /* Write to our pidfile. */
+ if (pfh != NULL && pidfile_write(pfh) != 0) {
warnmsg(LOG_ERR, __func__,
- "failed to setup for probing routers");
+ "failed to open pidfile: %s", strerror(errno));
exit(1);
}
-#ifndef SMALL
- /* dump the current pid */
- if (pidfile_write(pfh) != 0) {
- warnmsg(LOG_ERR, __func__,
- "failed to open pidfile: %s", strerror(errno));
+ /* Enter capability mode. */
+ if (caph_enter() != 0) {
+ warnmsg(LOG_ERR, __func__, "caph_enter(): %s", strerror(errno));
exit(1);
}
-#endif
- while (1) { /* main loop */
- int e;
-#ifndef SMALL
- if (do_dump) { /* SIGUSR1 */
+
+ for (;;) {
+ if (do_dump) {
+ /* Handle SIGUSR1. */
do_dump = 0;
- rtsold_dump_file(dumpfilename);
+ if (dumpfp != NULL)
+ rtsold_dump(dumpfp);
}
-#endif
timeout = rtsol_check_timer();
if (once) {
- struct ifinfo *ifi;
-
/* if we have no timeout, we are done (or failed) */
if (timeout == NULL)
break;
@@ -304,23 +295,58 @@
if (ifi == NULL)
break;
}
- e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000 / 1000) : INFTIM);
- if (e < 1) {
- if (e < 0 && errno != EINTR) {
- warnmsg(LOG_ERR, __func__, "select: %s",
+
+ error = kevent(kq, NULL, 0, &events[0], 1, timeout);
+ if (error < 1) {
+ if (error < 0 && errno != EINTR)
+ warnmsg(LOG_ERR, __func__, "kevent(): %s",
strerror(errno));
- }
continue;
}
- /* packet reception */
- if (set[1].revents & POLLIN)
+ if (events[0].ident == (uintptr_t)rtsock)
rtsock_input(rtsock);
- if (set[0].revents & POLLIN)
- rtsol_input(s);
+ else
+ rtsol_input(rcvsock);
+ }
+
+ return (0);
+}
+
+static int
+init_capabilities(void)
+{
+ const char *const scripts[2] = { resolvconf_script, otherconf_script };
+ cap_channel_t *capcasper;
+ nvlist_t *limits;
+
+ capcasper = cap_init();
+ if (capcasper == NULL)
+ return (errno);
+
+ if (!fflag) {
+ capsyslog = cap_service_open(capcasper, "syslog");
+ if (capsyslog == NULL)
+ return (errno);
}
- /* NOTREACHED */
+ if (mobile_node) {
+ capprobe = cap_service_open(capcasper,
+ "rtsold.defrouter_probe");
+ if (capprobe == NULL)
+ return (errno);
+ }
+
+ capscript = cap_service_open(capcasper, "rtsold.script");
+ if (capscript == NULL)
+ return (errno);
+ limits = nvlist_create(0);
+ nvlist_add_string_array(limits, "scripts", scripts,
+ otherconf_script != NULL ? 2 : 1);
+ if (cap_limit_set(capscript, limits) != 0)
+ return (errno);
+
+ cap_close(capcasper);
return (0);
}
@@ -393,6 +419,10 @@
ifi->linkid = ifi->sdl->sdl_index;
#endif
+ ifi->ifi_sock = sendsockopen(ifi->linkid);
+ if (ifi->ifi_sock == -1)
+ goto bad;
+
/*
* check if the interface is available.
* also check if SIOCGIFMEDIA ioctl is OK on the interface.
@@ -498,7 +528,7 @@
struct ifinfo *ifi;
struct rainfo *rai;
struct ra_opt *rao, *raotmp;
- int flags;
+ int error, flags;
clock_gettime(CLOCK_MONOTONIC_FAST, &now);
@@ -565,9 +595,14 @@
*/
if (probe)
ifi->otherconfig = 0;
-
- if (probe && mobile_node)
- defrouter_probe(ifi);
+ if (probe && mobile_node) {
+ error = cap_probe_defrouters(capprobe,
+ ifi);
+ if (error != 0)
+ warnmsg(LOG_DEBUG, __func__,
+ "failed to probe routers: %d",
+ error);
+ }
break;
}
case IFS_DELAY:
@@ -657,10 +692,9 @@
ifi->timer.tv_sec = 1;
break;
case IFS_IDLE:
- if (mobile_node) {
+ if (mobile_node)
/* XXX should be configurable */
ifi->timer.tv_sec = 3;
- }
else
ifi->timer = tm_max; /* stop timer(valid?) */
break;
@@ -672,7 +706,7 @@
case IFS_PROBE:
if (ifi->probes < MAX_RTR_SOLICITATIONS)
ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
- else {
+ else
/*
* After sending MAX_RTR_SOLICITATIONS solicitations,
* we're just waiting for possible replies; there
@@ -681,7 +715,6 @@
* on RFC 2461, Section 6.3.7.
*/
ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
- }
break;
default:
warnmsg(LOG_ERR, __func__,
@@ -711,28 +744,29 @@
/* timer related utility functions */
#define MILLION 1000000
-#ifndef SMALL
static void
-rtsold_set_dump_file(int sig __unused)
+set_dumpfile(int sig __unused)
{
+
do_dump = 1;
}
-#endif
static void
-usage(void)
+usage(const char *progname)
{
-#ifndef SMALL
- fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
- "[-p pidfile] [-R script-name] interface ...\n");
- fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
- "[-p pidfile] [-R script-name] -a\n");
-#else
- fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
- "[-p pidfile] [-R script-name] interface ...\n");
- fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
- "[-p pidfile] [-R script-name] -a\n");
-#endif
+
+ if (strcmp(progname, "rtsold") == 0) {
+ fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
+ "[-p pidfile] [-R script-name] interface ...\n");
+ fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
+ "[-p pidfile] [-R script-name] -a\n");
+ } else {
+ fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
+ "[-p pidfile] [-R script-name] interface ...\n");
+ fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
+ "[-p pidfile] [-R script-name] -a\n");
+ }
+ exit(1);
}
void
@@ -750,7 +784,7 @@
} else {
snprintf(buf, sizeof(buf), "<%s> %s", func, msg);
msg = buf;
- vsyslog(priority, msg, ap);
+ cap_vsyslog(capsyslog, priority, msg, ap);
}
va_end(ap);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 24, 2:25 PM (9 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32080256
Default Alt Text
D17572.id49185.diff (46 KB)
Attached To
Mode
D17572: Run most of rtsold(8) and rtsol(8) in capability mode.
Attached
Detach File
Event Timeline
Log In to Comment