diff --git a/plugins/tuntap/common.c b/plugins/tuntap/common.c index 22d09f53..e845fdf2 100644 --- a/plugins/tuntap/common.c +++ b/plugins/tuntap/common.c @@ -3,7 +3,7 @@ extern struct uwsgi_tuntap utt; // create a new peer -struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *uttr, int fd) { +struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *uttr, int fd, int is_router) { struct uwsgi_tuntap_peer *uttp = uwsgi_calloc(sizeof(struct uwsgi_tuntap_peer)); uttp->fd = fd; @@ -21,6 +21,19 @@ struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *u uttr->peers_tail = uttp; } + if (!is_router && utt.use_credentials) { + uwsgi_log_verbose("[uwsgi-tuntap] waiting for privileges drop...\n"); + for(;;) { + if (getuid() > 0) break; + sleep(1); + } + uwsgi_log_verbose("[uwsgi-tuntap] privileges dropped\n"); + if (uwsgi_pass_cred(fd, "uwsgi-tuntap", 12)) { + // better to exit + exit(1); + } + } + return uttp; } @@ -159,6 +172,24 @@ retry: } } +int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp) { + + struct uwsgi_tuntap_peer *tmp_uttp = uwsgi_tuntap_peer_get_by_addr(uttr, uttp->addr); + char ip[INET_ADDRSTRLEN + 1]; + memset(ip, 0, INET_ADDRSTRLEN + 1); + if (!inet_ntop(AF_INET, &uttp->addr, ip, INET_ADDRSTRLEN)) { + uwsgi_error("uwsgi_tuntap_register_addr()/inet_ntop()"); + return -1; + } + if (uttp != tmp_uttp) { + uwsgi_log("[tuntap-router] detected ip collision for %s\n", ip); + uwsgi_tuntap_peer_destroy(uttr, tmp_uttp); + } + uwsgi_log("[tuntap-router] registered new peer %s (fd: %d)\n", ip, uttp->fd); + memcpy(uttp->ip, ip, INET_ADDRSTRLEN + 1); + return 0; +} + // receive a packet from the client int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp, int is_router) { // get body @@ -192,19 +223,10 @@ int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun if (!uttp->addr) return -1; - struct uwsgi_tuntap_peer *tmp_uttp = uwsgi_tuntap_peer_get_by_addr(uttr, uttp->addr); - char ip[INET_ADDRSTRLEN + 1]; - memset(ip, 0, INET_ADDRSTRLEN + 1); - if (!inet_ntop(AF_INET, &uttp->addr, ip, INET_ADDRSTRLEN)) { - uwsgi_error("inet_ntop()"); + if (uwsgi_tuntap_register_addr(uttr, uttp)) { return -1; } - if (uttp != tmp_uttp) { - uwsgi_log("[tuntap-router] detected ip collision for %s\n", ip); - uwsgi_tuntap_peer_destroy(uttr, tmp_uttp); - } - uwsgi_log("[tuntap-router] registered new peer %s (fd: %d)\n", ip, uttp->fd); - memcpy(uttp->ip, ip, INET_ADDRSTRLEN + 1); + } enqueue: diff --git a/plugins/tuntap/common.h b/plugins/tuntap/common.h index a6a6d598..c788ee22 100644 --- a/plugins/tuntap/common.h +++ b/plugins/tuntap/common.h @@ -33,6 +33,10 @@ struct uwsgi_tuntap_peer { uint64_t tx; uint64_t rx; uint64_t dropped; + uint8_t sent_credentials; + pid_t pid; + uid_t uid; + gid_t gid; }; struct uwsgi_tuntap_firewall_rule { @@ -65,6 +69,8 @@ struct uwsgi_tuntap { struct uwsgi_tuntap_firewall_rule *fw_in; struct uwsgi_tuntap_firewall_rule *fw_out; char *stats_server; + char *use_credentials; + uint32_t (*addr_by_credentials)(pid_t, uid_t, gid_t); }; int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *, int); @@ -73,10 +79,11 @@ void uwsgi_tuntap_enqueue(struct uwsgi_tuntap_router *); int uwsgi_tuntap_firewall_check(struct uwsgi_tuntap_firewall_rule *, char *, uint16_t); -struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *, int); +struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *, int, int); struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_get_by_addr(struct uwsgi_tuntap_router *,uint32_t); void uwsgi_tuntap_peer_destroy(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *); int uwsgi_tuntap_device(char *); void uwsgi_tuntap_opt_firewall(char *, char *, void *); +int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *); diff --git a/plugins/tuntap/tuntap.c b/plugins/tuntap/tuntap.c index 285c24f8..919290d4 100644 --- a/plugins/tuntap/tuntap.c +++ b/plugins/tuntap/tuntap.c @@ -59,6 +59,7 @@ struct uwsgi_tuntap utt; static struct uwsgi_option uwsgi_tuntap_options[] = { {"tuntap-router", required_argument, 0, "run the tuntap router (syntax: [stats])", uwsgi_opt_add_string_list, &utt.routers, 0}, {"tuntap-device", required_argument, 0, "add a tuntap device to the instance (syntax: [ ])", uwsgi_opt_add_string_list, &utt.devices, 0}, + {"tuntap-use-credentials", optional_argument, 0, "enable check of SCM_CREDENTIALS for tuntap client/server", uwsgi_opt_set_str, &utt.use_credentials, 0}, {"tuntap-router-firewall-in", required_argument, 0, "add a firewall rule to the tuntap router (syntax: )", uwsgi_tuntap_opt_firewall, &utt.fw_in, 0}, {"tuntap-router-firewall-out", required_argument, 0, "add a firewall rule to the tuntap router (syntax: )", uwsgi_tuntap_opt_firewall, &utt.fw_out, 0}, {"tuntap-router-stats", required_argument, 0, "run the tuntap router stats server", uwsgi_opt_set_str, &utt.stats_server, 0}, @@ -95,7 +96,7 @@ static void *uwsgi_tuntap_loop(void *arg) { uwsgi_socket_nb(uttr->server_fd); - struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, uttr->server_fd); + struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, uttr->server_fd, 0); for (;;) { int interesting_fd = -1; @@ -270,7 +271,13 @@ void uwsgi_tuntap_router_loop(int id, void *arg) { uwsgi_error("uwsgi_tuntap_server_loop()/accept()"); continue; } - struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, client_fd); + if (utt.use_credentials) { + if (uwsgi_socket_passcred(client_fd)) { + close(client_fd); + continue; + } + } + struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, client_fd, 1); if (event_queue_add_fd_read(uttr->queue, uttp->fd)) { uwsgi_tuntap_peer_destroy(uttr, uttp); } @@ -287,6 +294,33 @@ void uwsgi_tuntap_router_loop(int id, void *arg) { if (interesting_fd == uttp->fd) { // read from the client if (event_queue_interesting_fd_is_read(events, i)) { + if (utt.use_credentials) { + if (uttp->addr == 0) { + if (!uttp->sent_credentials) { + if (uwsgi_recv_cred(uttp->fd, "uwsgi-tuntap", 12, &uttp->pid, &uttp->uid, &uttp->gid)) { + uwsgi_tuntap_peer_destroy(uttr, uttp); + break; + } + if (utt.addr_by_credentials) { + uttp->addr = utt.addr_by_credentials(uttp->pid, uttp->uid, uttp->gid); + if (!uttp->addr) { + uwsgi_tuntap_peer_destroy(uttr, uttp); + break; + } + if (uwsgi_tuntap_register_addr(uttr, uttp)) { + uwsgi_tuntap_peer_destroy(uttr, uttp); + break; + } + } + break; + } + else { + uwsgi_tuntap_peer_destroy(uttr, uttp); + break; + } + } + } + if (uwsgi_tuntap_peer_dequeue(uttr, uttp, 1)) { uwsgi_tuntap_peer_destroy(uttr, uttp); break; @@ -319,6 +353,16 @@ static void uwsgi_tuntap_router() { if (!utt.buffer_size) utt.buffer_size = 8192; + if (utt.use_credentials) { + if (utt.use_credentials[0] != 0) { + utt.addr_by_credentials = (uint32_t (*)(pid_t, uid_t, gid_t)) dlsym(RTLD_DEFAULT, utt.use_credentials); + if (!utt.addr_by_credentials) { + uwsgi_log("[uwsgi-tuntap] unable to find symbol %s\n", utt.use_credentials); + exit(1); + } + } + } + struct uwsgi_string_list *usl; uwsgi_foreach(usl, utt.routers) { char *space = strchr(usl->value, ' ');