Page MenuHomeFreeBSD

D29824.id87667.diff
No OneTemporary

D29824.id87667.diff

Index: sbin/rtsol/Makefile
===================================================================
--- sbin/rtsol/Makefile
+++ sbin/rtsol/Makefile
@@ -18,7 +18,7 @@
PACKAGE=runtime
PROG= rtsol
-SRCS= cap_llflags.c \
+SRCS= cap_if.c \
cap_script.c \
cap_sendmsg.c \
dump.c \
Index: usr.sbin/rtsold/Makefile
===================================================================
--- usr.sbin/rtsold/Makefile
+++ usr.sbin/rtsold/Makefile
@@ -17,7 +17,7 @@
PROG= rtsold
MAN= rtsold.8
MLINKS= rtsold.8 rtsol.8
-SRCS= cap_llflags.c \
+SRCS= cap_if.c \
cap_script.c \
cap_sendmsg.c \
dump.c \
Index: usr.sbin/rtsold/cap_llflags.c
===================================================================
--- usr.sbin/rtsold/cap_llflags.c
+++ usr.sbin/rtsold/cap_llflags.c
@@ -40,6 +40,7 @@
#include <net/if.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
#include <errno.h>
#include <ifaddrs.h>
@@ -52,14 +53,75 @@
#include "rtsold.h"
/*
- * A service to fetch the flags for the link-local IPv6 address on the specified
- * interface. This cannot easily be done in capability mode because we need to
- * use the routing socket sysctl API to find the link-local address of a
- * particular interface. The SIOCGIFCONF ioctl is one other option, but as
- * currently implemented it is less flexible (it cannot report the required
- * buffer length), and hard-codes a buffer length limit.
+ * A service providing access to network interfaces. Currently this is
+ * restricted to fetching interface info and bringing an interface up.
*/
+#ifdef WITH_CASPER
+#define CMD_IFFLAGS_GET "ifflags_get"
+#define CMD_IFMEDIA_GET "ifmedia_get"
+#define CMD_LLFLAGS_GET "llflags_get"
+#define CMD_IF_UP "if_up"
+
+static const char *const *ifnames;
+static size_t ifcnt;
+#endif
+
+static int
+return_errno(int error)
+{
+ if (error != 0) {
+ errno = error;
+ error = -1;
+ }
+ return (error);
+}
+
+/* Fetch interface flags for the specified interface. */
+static int
+ifflags_get(const char *ifname, int *flagsp)
+{
+ struct ifreq ifr;
+ int error, s;
+
+ error = 0;
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (-1);
+ memset(&ifr, 0, sizeof(ifr));
+ (void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)
+ *flagsp = ifr.ifr_flags;
+ else
+ error = errno;
+
+ (void)close(s);
+ return (return_errno(error));
+}
+
+/* Fetch media info for the specified interface. */
+static int
+ifmedia_get(const char *ifname, struct ifmediareq *ifmr)
+{
+ int error, s;
+
+ error = 0;
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (-1);
+ memset(ifmr, 0, sizeof(*ifmr));
+ (void)strlcpy(ifmr->ifm_name, ifname, sizeof(ifmr->ifm_name));
+ if (ioctl(s, SIOCGIFMEDIA, ifmr) != 0)
+ error = errno;
+
+ (void)close(s);
+ return (return_errno(error));
+}
+
+/*
+ * Fetch interface address flags for the first link-local address assigned to
+ * the specified interface.
+ */
static int
llflags_get(const char *ifname, int *flagsp)
{
@@ -108,12 +170,156 @@
(void)close(s);
if (ifap != NULL)
freeifaddrs(ifap);
+ return (return_errno(error));
+}
+
+/*
+ * Bring the interface up, and optionally enable IPv6 networking and proccessing
+ * of router advertisements.
+ */
+static int
+if_up(const char *ifname, bool in6en)
+{
+ struct ifreq ifr;
+ struct in6_ndireq nd;
+ int error, ndflags, s;
+
+ error = 0;
+
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (-1);
+
+ memset(&ifr, 0, sizeof(ifr));
+ (void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) != 0) {
+ error = errno;
+ goto out;
+ }
+ if ((ifr.ifr_flags & IFF_UP) == 0) {
+ memset(&ifr, 0, sizeof(ifr));
+ (void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_flags = IFF_UP;
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) != 0) {
+ error = errno;
+ goto out;
+ }
+ }
+
+ memset(&nd, 0, sizeof(nd));
+ strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
+ if (ioctl(s, SIOCGIFINFO_IN6, &nd) != 0) {
+ error = errno;
+ goto out;
+ }
+
+ ndflags = nd.ndi.flags;
+ memset(&nd, 0, sizeof(nd));
+ strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
+ if ((ndflags & ND6_IFF_IFDISABLED) != 0) {
+ if (in6en) {
+ nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
+ if (ioctl(s, SIOCSIFINFO_IN6, &nd) != 0) {
+ error = errno;
+ goto out;
+ }
+ } else {
+ error = ENETDOWN;
+ goto out;
+ }
+ }
+ if ((ndflags & ND6_IFF_ACCEPT_RTADV) == 0) {
+ if (in6en) {
+ nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV;
+ if (ioctl(s, SIOCSIFINFO_IN6, &nd) != 0) {
+ error = errno;
+ goto out;
+ }
+ } else {
+ error = EHOSTDOWN;
+ goto out;
+ }
+ }
+
+out:
+ (void)close(s);
+ return (return_errno(error));
+}
+
+#ifdef WITH_CASPER
+static nvlist_t *
+cap_if_op(cap_channel_t *cap, const char *cmd, const char *ifname, int *errorp)
+{
+ nvlist_t *nvl;
+ int error;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", cmd);
+ nvlist_add_string(nvl, "ifname", ifname);
+ nvl = cap_xfer_nvlist(cap, nvl);
+ if (nvl == NULL) {
+ *errorp = errno;
+ return (NULL);
+ }
+ error = (int)dnvlist_get_number(nvl, "error", 0);
if (error != 0) {
+ *errorp = error;
+ nvlist_destroy(nvl);
+ nvl = NULL;
+ }
+ return (nvl);
+}
+#endif
+
+int
+cap_ifflags_get(cap_channel_t *cap, const char *ifname, int *flagsp)
+{
+#ifdef WITH_CASPER
+ nvlist_t *nvl;
+ int error;
+
+ nvl = cap_if_op(cap, CMD_IFFLAGS_GET, ifname, &error);
+ if (nvl == NULL) {
errno = error;
return (-1);
- } else {
- return (0);
}
+ *flagsp = (int)nvlist_get_number(nvl, "flags");
+ nvlist_destroy(nvl);
+ return (0);
+#else
+ (void)cap;
+ return (ifflags_get(ifname, flagsp));
+#endif
+}
+
+int
+cap_ifmedia_get(cap_channel_t *cap, const char *ifname, struct ifmediareq *ifmr)
+{
+#ifdef WITH_CASPER
+ struct ifmediareq *ret;
+ nvlist_t *nvl;
+ size_t sz;
+ int error;
+
+ nvl = cap_if_op(cap, CMD_IFMEDIA_GET, ifname, &error);
+ if (nvl == NULL) {
+ errno = error;
+ return (-1);
+ }
+ ret = nvlist_take_binary(nvl, "ifmedia", &sz);
+ nvlist_destroy(nvl);
+ if (sz != sizeof(*ifmr)) {
+ free(ret);
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy(ifmr, ret, sizeof(*ifmr));
+ free(ret);
+ return (0);
+#else
+ (void)cap;
+ return (ifmedia_get(ifname, ifmr));
+#endif
}
int
@@ -123,41 +329,106 @@
nvlist_t *nvl;
int error;
+ nvl = cap_if_op(cap, CMD_IFFLAGS_GET, ifname, &error);
+ if (nvl == NULL) {
+ errno = error;
+ return (-1);
+ }
+ *flagsp = (int)nvlist_get_number(nvl, "flags");
+ nvlist_destroy(nvl);
+ return (0);
+#else
+ (void)cap;
+ return (llflags_get(ifname, flagsp));
+#endif
+}
+
+int
+cap_if_up(cap_channel_t *cap, const char *ifname, bool in6en)
+{
+#ifdef WITH_CASPER
+ nvlist_t *nvl;
+ int error;
+
nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "get");
+ nvlist_add_string(nvl, "cmd", CMD_IF_UP);
nvlist_add_string(nvl, "ifname", ifname);
+ nvlist_add_bool(nvl, "in6en", in6en);
nvl = cap_xfer_nvlist(cap, nvl);
if (nvl == NULL)
return (-1);
error = (int)dnvlist_get_number(nvl, "error", 0);
- if (error == 0)
- *flagsp = (int)nvlist_get_number(nvl, "flags");
- nvlist_destroy(nvl);
- if (error != 0)
+ if (error != 0) {
errno = error;
- return (error == 0 ? 0 : -1);
+ error = -1;
+ }
+ nvlist_destroy(nvl);
+ return (error);
#else
(void)cap;
- return (llflags_get(ifname, flagsp));
+ return (if_up(ifname, in6en));
#endif
}
#ifdef WITH_CASPER
static int
-llflags_command(const char *cmd, const nvlist_t *limits __unused,
+if_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ if (oldlimits != NULL)
+ return (ENOTCAPABLE);
+ ifnames = nvlist_get_string_array(newlimits, "ifnames", &ifcnt);
+ return (0);
+}
+
+static int
+if_command(const char *cmd, const nvlist_t *limits __unused,
nvlist_t *nvlin, nvlist_t *nvlout)
{
const char *ifname;
- int flags;
+ size_t i;
+ int error, flags;
- if (strcmp(cmd, "get") != 0)
- return (EINVAL);
+ /*
+ * Check whether the specified interface belongs to the allowed list.
+ */
ifname = nvlist_get_string(nvlin, "ifname");
- if (llflags_get(ifname, &flags) != 0)
- return (errno);
- nvlist_add_number(nvlout, "flags", flags);
- return (0);
+ for (i = 0; i < ifcnt; i++)
+ if (strcmp(ifnames[i], ifname) == 0)
+ break;
+ if (i == ifcnt)
+ return (ENOTCAPABLE);
+
+ error = 0;
+ if (strcmp(cmd, CMD_IFFLAGS_GET) == 0) {
+ if (ifflags_get(ifname, &flags) != 0)
+ error = errno;
+ else
+ nvlist_add_number(nvlout, "flags", flags);
+ } else if (strcmp(cmd, CMD_IFMEDIA_GET) == 0) {
+ struct ifmediareq ifmr;
+
+ if (ifmedia_get(ifname, &ifmr) != 0)
+ error = errno;
+ else
+ nvlist_add_binary(nvlout, "ifmedia", &ifmr,
+ sizeof(ifmr));
+ } else if (strcmp(cmd, CMD_LLFLAGS_GET) == 0) {
+ if (llflags_get(ifname, &flags) != 0)
+ error = errno;
+ else
+ nvlist_add_number(nvlout, "flags", flags);
+ } else if (strcmp(cmd, CMD_IF_UP) == 0) {
+ bool in6en;
+
+ in6en = nvlist_get_bool(nvlin, "in6en");
+ if (if_up(ifname, in6en) != 0)
+ error = errno;
+ } else {
+ error = EINVAL;
+ }
+
+ return (error);
}
-CREATE_SERVICE("rtsold.llflags", NULL, llflags_command, 0);
+CREATE_SERVICE("rtsold.if", if_limit, if_command, 0);
#endif /* WITH_CASPER */
Index: usr.sbin/rtsold/if.c
===================================================================
--- usr.sbin/rtsold/if.c
+++ usr.sbin/rtsold/if.c
@@ -64,122 +64,35 @@
#include <ifaddrs.h>
#include "rtsold.h"
-static int ifsock;
static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
-int
-ifinit(void)
-{
- cap_rights_t rights;
- int sock;
-
- sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
- if (sock < 0) {
- warnmsg(LOG_ERR, __func__, "socket(): %s",
- strerror(errno));
- return (-1);
- }
- if (caph_rights_limit(sock, cap_rights_init(&rights, CAP_IOCTL)) < 0) {
- warnmsg(LOG_ERR, __func__, "caph_rights_limit(): %s",
- strerror(errno));
- (void)close(sock);
- return (-1);
- }
- ifsock = sock;
- return (0);
-}
-
int
interface_up(char *name)
{
- struct ifreq ifr;
- struct in6_ndireq nd;
- int llflag;
- int s;
+ int llflags;
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- memset(&nd, 0, sizeof(nd));
- strlcpy(nd.ifname, name, sizeof(nd.ifname));
-
- if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
- warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s",
- strerror(errno));
- return (-1);
- }
- if (!(ifr.ifr_flags & IFF_UP)) {
- ifr.ifr_flags |= IFF_UP;
- if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
- warnmsg(LOG_ERR, __func__,
- "ioctl(SIOCSIFFLAGS): %s", strerror(errno));
- return (-1);
- }
- if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s",
- strerror(errno));
- return (-1);
- }
- if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
- warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s",
+ if (cap_if_up(capif, name, Fflag != 0) != 0) {
+ warnmsg(LOG_WARNING, __func__, "cap_ifflags_get(): %s",
strerror(errno));
- close(s);
return (-1);
}
- warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name);
-
- if (nd.ndi.flags & ND6_IFF_IFDISABLED) {
- if (Fflag) {
- nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
- if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) {
- warnmsg(LOG_WARNING, __func__,
- "ioctl(SIOCSIFINFO_IN6): %s",
- strerror(errno));
- close(s);
- return (-1);
- }
- } else {
- warnmsg(LOG_WARNING, __func__,
- "%s is disabled.", name);
- close(s);
- return (-1);
- }
- }
- if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) {
- if (Fflag) {
- nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV;
- if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) {
- warnmsg(LOG_WARNING, __func__,
- "ioctl(SIOCSIFINFO_IN6): %s",
- strerror(errno));
- close(s);
- return (-1);
- }
- } else {
- warnmsg(LOG_WARNING, __func__,
- "%s does not accept Router Advertisement.", name);
- close(s);
- return (-1);
- }
- }
- close(s);
-
- if (cap_llflags_get(capllflags, name, &llflag) != 0) {
+ if (cap_llflags_get(capif, name, &llflags) != 0) {
warnmsg(LOG_WARNING, __func__,
"cap_llflags_get() failed, anyway I'll try");
return (0);
}
- if (!(llflag & IN6_IFF_NOTREADY)) {
+ if ((llflags & IN6_IFF_NOTREADY) == 0) {
warnmsg(LOG_DEBUG, __func__, "%s is ready", name);
return (0);
} else {
- if (llflag & IN6_IFF_TENTATIVE) {
+ if (llflags & IN6_IFF_TENTATIVE) {
warnmsg(LOG_DEBUG, __func__, "%s is tentative",
name);
return (IFS_TENTATIVE);
}
- if (llflag & IN6_IFF_DUPLICATED)
+ if (llflags & IN6_IFF_DUPLICATED)
warnmsg(LOG_DEBUG, __func__, "%s is duplicated",
name);
return (-1);
@@ -190,14 +103,12 @@
interface_status(struct ifinfo *ifinfo)
{
char *ifname = ifinfo->ifname;
- struct ifreq ifr;
struct ifmediareq ifmr;
+ int ifflags;
/* get interface flags */
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
- warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s",
+ if (cap_ifflags_get(capif, ifname, &ifflags) != 0) {
+ warnmsg(LOG_ERR, __func__, "cap_ifflags_get() on %s: %s",
ifname, strerror(errno));
return (-1);
}
@@ -205,21 +116,20 @@
* if one of UP and RUNNING flags is dropped,
* the interface is not active.
*/
- if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+ if ((ifflags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
goto inactive;
/* Next, check carrier on the interface, if possible */
if (!ifinfo->mediareqok)
goto active;
- memset(&ifmr, 0, sizeof(ifmr));
- strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
- if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ if (cap_ifmedia_get(capif, ifname, &ifmr) != 0) {
if (errno != EINVAL) {
warnmsg(LOG_DEBUG, __func__,
- "ioctl(SIOCGIFMEDIA) on %s: %s",
+ "cap_ifmedia_get() on %s: %s",
ifname, strerror(errno));
return(-1);
}
+
/*
* EINVAL simply means that the interface does not support
* the SIOCGIFMEDIA ioctl. We regard it alive.
Index: usr.sbin/rtsold/rtsold.h
===================================================================
--- usr.sbin/rtsold/rtsold.h
+++ usr.sbin/rtsold/rtsold.h
@@ -161,7 +161,7 @@
extern const char *managedconf_script;
extern const char *otherconf_script;
extern const char *resolvconf_script;
-extern struct cap_channel *capllflags, *capscript, *capsendmsg, *capsyslog;
+extern struct cap_channel *capif, *capscript, *capsendmsg, *capsyslog;
struct ifinfo *find_ifinfo(int);
struct rainfo *find_rainfo(struct ifinfo *, struct sockaddr_in6 *);
@@ -172,7 +172,6 @@
/* if.c */
struct nd_opt_hdr;
-extern int ifinit(void);
extern int interface_up(char *);
extern int interface_status(struct ifinfo *);
extern int lladdropt_length(struct sockaddr_dl *);
@@ -183,8 +182,13 @@
extern int recvsockopen(void);
extern void rtsol_input(int);
-/* cap_llflags.c */
+/* cap_if.c */
+struct ifmediareq;
+extern int cap_ifflags_get(struct cap_channel *, const char *, int *);
+extern int cap_ifmedia_get(struct cap_channel *, const char *,
+ struct ifmediareq *);
extern int cap_llflags_get(struct cap_channel *, const char *, int *);
+extern int cap_if_up(struct cap_channel *, const char *, bool);
/* cap_script.c */
extern int cap_script_run(struct cap_channel *, const char *const *);
Index: usr.sbin/rtsold/rtsold.c
===================================================================
--- usr.sbin/rtsold/rtsold.c
+++ usr.sbin/rtsold/rtsold.c
@@ -84,7 +84,7 @@
const char *otherconf_script;
const char *resolvconf_script = "/sbin/resolvconf";
-cap_channel_t *capllflags, *capscript, *capsendmsg, *capsyslog;
+cap_channel_t *capif, *capscript, *capsendmsg, *capsyslog;
/* protocol constants */
#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
@@ -106,6 +106,7 @@
static char **autoifprobe(void);
static int ifconfig(char *ifname);
static int init_capabilities(void);
+static int limit_capabilities(char *const *);
static int make_packet(struct ifinfo *);
static struct timespec *rtsol_check_timer(void);
@@ -251,12 +252,12 @@
}
/* Probe network interfaces and set up tracking info. */
- if (ifinit() != 0) {
- warnmsg(LOG_ERR, __func__, "failed to initialize interfaces");
- exit(1);
- }
if (aflag)
argv = autoifprobe();
+
+ /* Limit the interface service to the specified interfaces. */
+ limit_capabilities(argv);
+
while (argv && *argv) {
if (ifconfig(*argv)) {
warnmsg(LOG_ERR, __func__,
@@ -340,8 +341,8 @@
if (capcasper == NULL)
return (-1);
- capllflags = cap_service_open(capcasper, "rtsold.llflags");
- if (capllflags == NULL)
+ capif = cap_service_open(capcasper, "rtsold.if");
+ if (capif == NULL)
return (-1);
capscript = cap_service_open(capcasper, "rtsold.script");
@@ -370,6 +371,24 @@
return (0);
}
+static int
+limit_capabilities(char *const *ifs)
+{
+#ifdef WITH_CASPER
+ nvlist_t *limits;
+
+ limits = nvlist_create(0);
+ for (int i = 0; ifs[i] != NULL; i++)
+ nvlist_append_string_array(limits, "ifnames", ifs[i]);
+ if (cap_limit_set(capif, limits) != 0)
+ return (-1);
+ return (0);
+#else
+ (void)ifs;
+ return (0);
+#endif
+}
+
static int
ifconfig(char *ifname)
{

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 7, 2:21 PM (10 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36180254
Default Alt Text
D29824.id87667.diff (16 KB)

Event Timeline