Add support for linux capabilities to proper routes cleanup

This commit is contained in:
emanuele-f 2020-05-23 17:17:32 +02:00
parent 62b9530425
commit 0e48e2f24c
3 changed files with 66 additions and 12 deletions

View File

@ -49,6 +49,12 @@ if test x$pcap_immediate_mode != x; then
AC_DEFINE([HAVE_PCAP_IMMEDIATE_MODE], [], [Have pcap_immediate_mode])
fi
AC_CHECK_LIB([cap], [cap_get_proc], cap=true)
if test x$cap != x; then
LDFLAGS="${LDFLAGS} -lcap"
AC_DEFINE([HAVE_LIBCAP],[1],[Support for linux capabilities])
fi
MACHINE=`uname -m`
SYSTEM=`uname -s`

45
edge.c
View File

@ -37,6 +37,21 @@
/* ***************************************************** */
#ifdef HAVE_LIBCAP
#include <sys/capability.h>
#include <sys/prctl.h>
static cap_value_t cap_values[] = {
//CAP_NET_RAW, /* Use RAW and PACKET sockets */
CAP_NET_ADMIN /* Needed to performs routes cleanup at exit */
};
int num_cap = sizeof(cap_values)/sizeof(cap_value_t);
#endif
/* ***************************************************** */
typedef struct n2n_priv_config {
char tuntap_dev_name[N2N_IFNAMSIZ];
char ip_mode[N2N_IF_MODE_SIZE];
@ -681,6 +696,9 @@ int main(int argc, char* argv[]) {
#ifndef WIN32
struct passwd *pw = NULL;
#endif
#ifdef HAVE_LIBCAP
cap_t caps;
#endif
/* Defaults */
edge_init_conf_defaults(&conf);
@ -774,6 +792,22 @@ int main(int argc, char* argv[]) {
#endif /* #ifndef WIN32 */
#ifndef WIN32
#ifdef HAVE_LIBCAP
/* Before dropping the privileges, retain capabilities to regain them in future. */
caps = cap_get_proc();
cap_set_flag(caps, CAP_PERMITTED, num_cap, cap_values, CAP_SET);
cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET);
if((cap_set_proc(caps) != 0) || (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0))
traceEvent(TRACE_WARNING, "Unable to retain permitted capabilities [%s]\n", strerror(errno));
#else
#ifndef __APPLE__
traceEvent(TRACE_WARNING, "n2n has not been compiled with libcap-dev. Some commands may fail.");
#endif
#endif /* HAVE_LIBCAP */
if((ec.userid != 0) || (ec.groupid != 0)) {
traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d",
(signed int)ec.userid, (signed int)ec.groupid);
@ -803,6 +837,17 @@ int main(int argc, char* argv[]) {
rc = run_edge_loop(eee, &keep_on_running);
print_edge_stats(eee);
#ifdef HAVE_LIBCAP
/* Before completing the cleanup, regain the capabilities as some
* cleanup tasks require them (e.g. routes cleanup). */
cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET);
if(cap_set_proc(caps) != 0)
traceEvent(TRACE_WARNING, "Could not regain the capabilities [%s]\n", strerror(errno));
cap_free(caps);
#endif
/* Cleanup */
edge_term(eee);
edge_term_conf(&conf);

View File

@ -2042,10 +2042,10 @@ static char* route_cmd_to_str(int cmd, const n2n_route_t *route, char *buf, size
switch(cmd) {
case RTM_NEWROUTE:
cmd_str = "ADD";
cmd_str = "Add";
break;
case RTM_DELROUTE:
cmd_str = "DELETE";
cmd_str = "Delete";
break;
default:
cmd_str = "?";
@ -2056,7 +2056,7 @@ static char* route_cmd_to_str(int cmd, const n2n_route_t *route, char *buf, size
addr.s_addr = route->gateway;
inet_ntop(AF_INET, &addr, gwbuf, sizeof(gwbuf));
snprintf(buf, bufsize, "[%s] %s/%d via %s", cmd_str, netbuf, route->net_bitlen, gwbuf);
snprintf(buf, bufsize, "%s %s/%d via %s", cmd_str, netbuf, route->net_bitlen, gwbuf);
return(buf);
}
@ -2088,10 +2088,11 @@ static int rtattr_add(struct nlmsghdr *n, int maxlen, int type, const void *data
return 0;
}
static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx, uint8_t ignore_failure) {
static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx) {
int rv = -1;
int rv2;
char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */
char route_buf[256];
struct iovec iov;
struct msghdr msg;
struct sockaddr_nl sa;
@ -2194,7 +2195,6 @@ static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx, uint8_t
read_reply = 0;
if(nh->nlmsg_type == NLMSG_ERROR) {
char buf[256];
struct nlmsgerr *err = NLMSG_DATA(nh);
int errcode = err->error;
@ -2202,8 +2202,8 @@ static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx, uint8_t
errcode = -errcode;
/* Ignore EEXIST as existing rules are ok */
if(!ignore_failure && (errcode != EEXIST)) {
traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, buf, sizeof(buf)));
if(errcode != EEXIST) {
traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
goto out;
}
}
@ -2211,11 +2211,14 @@ static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx, uint8_t
if(nh->nlmsg_type == NLMSG_DONE)
break;
if(nh->nlmsg_type == cmd)
if(nh->nlmsg_type == cmd) {
traceEvent(TRACE_DEBUG, "Found netlink reply");
break;
}
}
}
traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
rv = 0;
out:
@ -2278,7 +2281,7 @@ static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_r
}
/* ip route add supernode via internet_gateway */
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1, 0) < 0)
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0)
return(-1);
/* Save the route to delete it when n2n is stopped */
@ -2293,11 +2296,11 @@ static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_r
custom_route.net_bitlen = 1;
custom_route.gateway = route->gateway;
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx, 0) < 0)
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0)
return(-1);
} else {
/* ip route add net via n2n_gateway */
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx, 0) < 0)
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0)
return(-1);
}
}
@ -2312,7 +2315,7 @@ static void edge_cleanup_routes(n2n_edge_t *eee) {
#ifdef __linux__
if(eee->sn_route_to_clean) {
/* ip route del supernode via internet_gateway */
routectl(RTM_DELROUTE, 0, eee->sn_route_to_clean, -1, 1 /* can fail as we have dropped capabilities */);
routectl(RTM_DELROUTE, 0, eee->sn_route_to_clean, -1);
free(eee->sn_route_to_clean);
}
#endif