Skip to content

Commit

Permalink
Handle fds that are pointing to routing sockets. If the fd has access to
Browse files Browse the repository at this point in the history
make changes via the routing socket, grant full permission to make filter
changes.
  • Loading branch information
zoulasc committed Mar 12, 2020
1 parent bce4d50 commit 1b9475b
Showing 1 changed file with 125 additions and 46 deletions.
171 changes: 125 additions & 46 deletions bin/conf.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $NetBSD: conf.c,v 1.26 2020/03/10 13:36:07 roy Exp $ */
/* $NetBSD: conf.c,v 1.28 2020/03/12 11:31:23 roy Exp $ */

/*-
* Copyright (c) 2015 The NetBSD Foundation, Inc.
Expand Down Expand Up @@ -33,7 +33,7 @@
#endif

#include <sys/cdefs.h>
__RCSID("$NetBSD: conf.c,v 1.26 2020/03/10 13:36:07 roy Exp $");
__RCSID("$NetBSD: conf.c,v 1.28 2020/03/12 11:31:23 roy Exp $");

#include <stdio.h>
#ifdef HAVE_LIBUTIL_H
Expand All @@ -46,6 +46,7 @@ __RCSID("$NetBSD: conf.c,v 1.26 2020/03/10 13:36:07 roy Exp $");
#include <ctype.h>
#include <inttypes.h>
#include <netdb.h>
#include <unistd.h>
#include <pwd.h>
#include <syslog.h>
#include <errno.h>
Expand All @@ -55,6 +56,7 @@ __RCSID("$NetBSD: conf.c,v 1.26 2020/03/10 13:36:07 roy Exp $");
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/route.h>
#include <sys/socket.h>

#include "bl.h"
Expand Down Expand Up @@ -90,7 +92,7 @@ advance(char **p)
}

static int
getnum(const char *f, size_t l, bool local, void *rp, const char *name,
conf_getnum(const char *f, size_t l, bool local, void *rp, const char *name,
const char *p)
{
int e;
Expand Down Expand Up @@ -127,13 +129,14 @@ getnum(const char *f, size_t l, bool local, void *rp, const char *name,
}

static int
getnfail(const char *f, size_t l, bool local, struct conf *c, const char *p)
conf_getnfail(const char *f, size_t l, bool local, struct conf *c,
const char *p)
{
return getnum(f, l, local, &c->c_nfail, "nfail", p);
return conf_getnum(f, l, local, &c->c_nfail, "nfail", p);
}

static int
getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p)
conf_getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p)
{
int e;
char *ep;
Expand Down Expand Up @@ -193,7 +196,7 @@ getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p)
}

static int
getport(const char *f, size_t l, bool local, void *r, const char *p)
conf_getport(const char *f, size_t l, bool local, void *r, const char *p)
{
struct servent *sv;

Expand All @@ -207,11 +210,11 @@ getport(const char *f, size_t l, bool local, void *r, const char *p)
return 0;
}

return getnum(f, l, local, r, "service", p);
return conf_getnum(f, l, local, r, "service", p);
}

static int
getmask(const char *f, size_t l, bool local, const char **p, int *mask)
conf_getmask(const char *f, size_t l, bool local, const char **p, int *mask)
{
char *d;
const char *s = *p;
Expand All @@ -226,11 +229,12 @@ getmask(const char *f, size_t l, bool local, const char **p, int *mask)
}

*d++ = '\0';
return getnum(f, l, local, mask, "mask", d);
return conf_getnum(f, l, local, mask, "mask", d);
}

static int
gethostport(const char *f, size_t l, bool local, struct conf *c, const char *p)
conf_gethostport(const char *f, size_t l, bool local, struct conf *c,
const char *p)
{
char *d; // XXX: Ok to write to string.
in_port_t *port = NULL;
Expand All @@ -249,7 +253,7 @@ gethostport(const char *f, size_t l, bool local, struct conf *c, const char *p)
} else
pstr = p;

if (getmask(f, l, local, &pstr, &c->c_lmask) == -1)
if (conf_getmask(f, l, local, &pstr, &c->c_lmask) == -1)
goto out;

if (d) {
Expand Down Expand Up @@ -300,7 +304,7 @@ gethostport(const char *f, size_t l, bool local, struct conf *c, const char *p)
}
}

if (getport(f, l, local, &c->c_port, pstr) == -1)
if (conf_getport(f, l, local, &c->c_port, pstr) == -1)
return -1;

if (port && c->c_port != FSTAR && c->c_port != FEQUAL)
Expand All @@ -320,7 +324,7 @@ gethostport(const char *f, size_t l, bool local, struct conf *c, const char *p)
}

static int
getproto(const char *f, size_t l, bool local __unused, struct conf *c,
conf_getproto(const char *f, size_t l, bool local __unused, struct conf *c,
const char *p)
{
if (strcmp(p, "stream") == 0) {
Expand All @@ -331,22 +335,22 @@ getproto(const char *f, size_t l, bool local __unused, struct conf *c,
c->c_proto = IPPROTO_UDP;
return 0;
}
return getnum(f, l, local, &c->c_proto, "protocol", p);
return conf_getnum(f, l, local, &c->c_proto, "protocol", p);
}

static int
getfamily(const char *f, size_t l, bool local __unused, struct conf *c,
conf_getfamily(const char *f, size_t l, bool local __unused, struct conf *c,
const char *p)
{
if (strncmp(p, "tcp", 3) == 0 || strncmp(p, "udp", 3) == 0) {
c->c_family = p[3] == '6' ? AF_INET6 : AF_INET;
return 0;
}
return getnum(f, l, local, &c->c_family, "family", p);
return conf_getnum(f, l, local, &c->c_family, "family", p);
}

static int
getuid(const char *f, size_t l, bool local __unused, struct conf *c,
conf_getuid(const char *f, size_t l, bool local __unused, struct conf *c,
const char *p)
{
struct passwd *pw;
Expand All @@ -356,15 +360,15 @@ getuid(const char *f, size_t l, bool local __unused, struct conf *c,
return 0;
}

return getnum(f, l, local, &c->c_uid, "user", p);
return conf_getnum(f, l, local, &c->c_uid, "user", p);
}


static int
getname(const char *f, size_t l, bool local, struct conf *c,
conf_getname(const char *f, size_t l, bool local, struct conf *c,
const char *p)
{
if (getmask(f, l, local, &p, &c->c_rmask) == -1)
if (conf_getmask(f, l, local, &p, &c->c_rmask) == -1)
return -1;

if (strcmp(p, "*") == 0) {
Expand Down Expand Up @@ -407,19 +411,19 @@ conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local)
p++;

memset(c, 0, sizeof(*c));
e = getvalue(f, l, local, c, &p, gethostport);
e = getvalue(f, l, local, c, &p, conf_gethostport);
if (e) return -1;
e = getvalue(f, l, local, c, &p, getproto);
e = getvalue(f, l, local, c, &p, conf_getproto);
if (e) return -1;
e = getvalue(f, l, local, c, &p, getfamily);
e = getvalue(f, l, local, c, &p, conf_getfamily);
if (e) return -1;
e = getvalue(f, l, local, c, &p, getuid);
e = getvalue(f, l, local, c, &p, conf_getuid);
if (e) return -1;
e = getvalue(f, l, local, c, &p, getname);
e = getvalue(f, l, local, c, &p, conf_getname);
if (e) return -1;
e = getvalue(f, l, local, c, &p, getnfail);
e = getvalue(f, l, local, c, &p, conf_getnfail);
if (e) return -1;
e = getvalue(f, l, local, c, &p, getsecs);
e = getvalue(f, l, local, c, &p, conf_getsecs);
if (e) return -1;

return 0;
Expand Down Expand Up @@ -998,32 +1002,72 @@ confset_match(const struct confset *cs, struct conf *c,
return i;
}

const struct conf *
conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
struct conf *cr)
#ifdef AF_ROUTE
static int
conf_route_perm(int fd) {
#if defined(RTM_IFANNOUNCE) && defined(RT_ROUNDUP)
/*
* Send a routing message that is not supported to check for access
* We expect EOPNOTSUPP for having access, since we are sending a
* request the system does not understand and EACCES if we don't have
* access.
*/
static struct sockaddr_in sin = {
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
.sin_len = sizeof(sin),
#endif
.sin_family = AF_INET,
};
char buf[4096];
struct rt_msghdr *rtm = (void *)buf;
char *cp = (char *)(rtm + 1);
size_t l;

#define NEXTADDR(s) \
l = RT_ROUNDUP(sizeof(*s)); memmove(cp, s, l); cp += l;
memset(buf, 0, sizeof(buf));
rtm->rtm_type = RTM_IFANNOUNCE;
rtm->rtm_flags = 0;
rtm->rtm_addrs = RTA_DST|RTA_GATEWAY;
rtm->rtm_version = RTM_VERSION;
rtm->rtm_seq = 666;
NEXTADDR(&sin);
NEXTADDR(&sin);
rtm->rtm_msglen = (u_short)((char *)cp - (char *)rtm);
if (write(fd, rtm, rtm->rtm_msglen) != -1) {
(*lfun)(LOG_ERR, "Writing to routing socket succeeded!");
return 0;
}
switch (errno) {
case EACCES:
return 0;
case EOPNOTSUPP:
return 1;
default:
(*lfun)(LOG_ERR,
"Unexpected error writing to routing socket (%m)");
return 0;
}
#else
return 0;
#endif
}
#endif

static int
conf_handle_inet(int fd, const void *lss, struct conf *cr)
{
int proto;
socklen_t slen;
struct sockaddr_storage lss;
size_t i;
char buf[BUFSIZ];
int proto;
socklen_t slen = sizeof(proto);

memset(cr, 0, sizeof(*cr));
slen = sizeof(lss);
memset(&lss, 0, slen);
if (getsockname(fd, (void *)&lss, &slen) == -1) {
(*lfun)(LOG_ERR, "getsockname failed (%m)");
return NULL;
}

slen = sizeof(proto);
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) {
(*lfun)(LOG_ERR, "getsockopt failed (%m)");
return NULL;
return -1;
}

if (debug) {
sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&lss);
sockaddr_snprintf(buf, sizeof(buf), "%a:%p", lss);
(*lfun)(LOG_DEBUG, "listening socket: %s", buf);
}

Expand All @@ -1036,16 +1080,51 @@ conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
break;
default:
(*lfun)(LOG_ERR, "unsupported protocol %d", proto);
return -1;
}
return 0;
}

const struct conf *
conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
struct conf *cr)
{
socklen_t slen;
struct sockaddr_storage lss;
size_t i;
char buf[BUFSIZ];

memset(cr, 0, sizeof(*cr));
slen = sizeof(lss);
memset(&lss, 0, slen);
if (getsockname(fd, (void *)&lss, &slen) == -1) {
(*lfun)(LOG_ERR, "getsockname failed (%m)");
return NULL;
}

switch (lss.ss_family) {
case AF_INET:
cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port);
if (conf_handle_inet(fd, &lss, cr) == -1)
return NULL;
break;
case AF_INET6:
cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port);
if (conf_handle_inet(fd, &lss, cr) == -1)
return NULL;
break;
#ifdef AF_ROUTE
case AF_ROUTE:
if (!conf_route_perm(fd)) {
(*lfun)(LOG_ERR,
"permission denied to routing socket (%m)");
return NULL;
}
cr->c_proto = FSTAR;
cr->c_port = FSTAR;
memcpy(&lss, rss, sizeof(lss));
break;
#endif
default:
(*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family);
return NULL;
Expand Down

0 comments on commit 1b9475b

Please sign in to comment.