From 0e48e2f24c33391ab9a0b73e5fba636089cabbfb Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Sat, 23 May 2020 17:17:32 +0200 Subject: [PATCH] Add support for linux capabilities to proper routes cleanup --- configure.seed | 6 ++++++ edge.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ edge_utils.c | 27 +++++++++++++++------------ 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/configure.seed b/configure.seed index d1f0004..067351c 100644 --- a/configure.seed +++ b/configure.seed @@ -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` diff --git a/edge.c b/edge.c index c303240..17b7b40 100644 --- a/edge.c +++ b/edge.c @@ -37,6 +37,21 @@ /* ***************************************************** */ +#ifdef HAVE_LIBCAP + +#include +#include + +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); diff --git a/edge_utils.c b/edge_utils.c index e6f0580..182eb91 100644 --- a/edge_utils.c +++ b/edge_utils.c @@ -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