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]) AC_DEFINE([HAVE_PCAP_IMMEDIATE_MODE], [], [Have pcap_immediate_mode])
fi 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` MACHINE=`uname -m`
SYSTEM=`uname -s` 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 { typedef struct n2n_priv_config {
char tuntap_dev_name[N2N_IFNAMSIZ]; char tuntap_dev_name[N2N_IFNAMSIZ];
char ip_mode[N2N_IF_MODE_SIZE]; char ip_mode[N2N_IF_MODE_SIZE];
@ -681,6 +696,9 @@ int main(int argc, char* argv[]) {
#ifndef WIN32 #ifndef WIN32
struct passwd *pw = NULL; struct passwd *pw = NULL;
#endif #endif
#ifdef HAVE_LIBCAP
cap_t caps;
#endif
/* Defaults */ /* Defaults */
edge_init_conf_defaults(&conf); edge_init_conf_defaults(&conf);
@ -774,6 +792,22 @@ int main(int argc, char* argv[]) {
#endif /* #ifndef WIN32 */ #endif /* #ifndef WIN32 */
#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)) { if((ec.userid != 0) || (ec.groupid != 0)) {
traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d", traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d",
(signed int)ec.userid, (signed int)ec.groupid); (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); rc = run_edge_loop(eee, &keep_on_running);
print_edge_stats(eee); 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 */ /* Cleanup */
edge_term(eee); edge_term(eee);
edge_term_conf(&conf); 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) { switch(cmd) {
case RTM_NEWROUTE: case RTM_NEWROUTE:
cmd_str = "ADD"; cmd_str = "Add";
break; break;
case RTM_DELROUTE: case RTM_DELROUTE:
cmd_str = "DELETE"; cmd_str = "Delete";
break; break;
default: default:
cmd_str = "?"; 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; addr.s_addr = route->gateway;
inet_ntop(AF_INET, &addr, gwbuf, sizeof(gwbuf)); 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); return(buf);
} }
@ -2088,10 +2088,11 @@ static int rtattr_add(struct nlmsghdr *n, int maxlen, int type, const void *data
return 0; 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 rv = -1;
int rv2; int rv2;
char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */ char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */
char route_buf[256];
struct iovec iov; struct iovec iov;
struct msghdr msg; struct msghdr msg;
struct sockaddr_nl sa; 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; read_reply = 0;
if(nh->nlmsg_type == NLMSG_ERROR) { if(nh->nlmsg_type == NLMSG_ERROR) {
char buf[256];
struct nlmsgerr *err = NLMSG_DATA(nh); struct nlmsgerr *err = NLMSG_DATA(nh);
int errcode = err->error; 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; errcode = -errcode;
/* Ignore EEXIST as existing rules are ok */ /* Ignore EEXIST as existing rules are ok */
if(!ignore_failure && (errcode != EEXIST)) { if(errcode != EEXIST) {
traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, buf, sizeof(buf))); traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
goto out; 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) if(nh->nlmsg_type == NLMSG_DONE)
break; break;
if(nh->nlmsg_type == cmd) if(nh->nlmsg_type == cmd) {
traceEvent(TRACE_DEBUG, "Found netlink reply");
break; break;
}
} }
} }
traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
rv = 0; rv = 0;
out: 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 */ /* 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); return(-1);
/* Save the route to delete it when n2n is stopped */ /* 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.net_bitlen = 1;
custom_route.gateway = route->gateway; 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); return(-1);
} else { } else {
/* ip route add net via n2n_gateway */ /* 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); return(-1);
} }
} }
@ -2312,7 +2315,7 @@ static void edge_cleanup_routes(n2n_edge_t *eee) {
#ifdef __linux__ #ifdef __linux__
if(eee->sn_route_to_clean) { if(eee->sn_route_to_clean) {
/* ip route del supernode via internet_gateway */ /* 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); free(eee->sn_route_to_clean);
} }
#endif #endif