From 22649108c50575e74dd4fae01e9066f3e4e6c618 Mon Sep 17 00:00:00 2001 From: jvdfiuph Date: Tue, 4 Oct 2022 21:01:54 +0200 Subject: [PATCH] Use unshare from C (unfinished) --- .gitignore | 3 +- Makefile | 13 +- besides-ns-helper.sh | 35 --- common.c | 139 ------------ common.h | 6 - inside-ns-helper.sh | 23 -- netns-socks | 40 ---- netns-socks.c | 598 +++++++++++++++++++++++++++++++++++++++++++++++++++ tun2socks4netns.c | 177 --------------- udp-forw.c | 115 ---------- 10 files changed, 602 insertions(+), 547 deletions(-) delete mode 100755 besides-ns-helper.sh delete mode 100644 common.c delete mode 100644 common.h delete mode 100755 inside-ns-helper.sh delete mode 100755 netns-socks create mode 100644 netns-socks.c delete mode 100644 tun2socks4netns.c delete mode 100644 udp-forw.c diff --git a/.gitignore b/.gitignore index 5c31854..9ef5af3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ *.o -tun2socks4netns -udp-forw +netns-socks diff --git a/Makefile b/Makefile index 1f3a12a..61a010e 100644 --- a/Makefile +++ b/Makefile @@ -3,22 +3,15 @@ PREFIX ?= /usr/local SRC = drw.c dwm.c util.c OBJ = ${SRC:.c=.o} -all: tun2socks4netns udp-forw +all: netns-socks clean: - rm -f tun2socks4netns udp-forw udp-forw.o tun2socks4netns.o common.o + rm -f netns-socks netns-socks.o .c.o: ${CC} -c ${CFLAGS} $< -common.o: common.h -tun2socks4netns.o: common.h -udp-forw.o: common.h - -tun2socks4netns: tun2socks4netns.o common.o - ${CC} -o $@ $^ ${LDFLAGS} - -udp-forw: udp-forw.o common.o +netns-socks: netns-socks.o ${CC} -o $@ $^ ${LDFLAGS} install: all diff --git a/besides-ns-helper.sh b/besides-ns-helper.sh deleted file mode 100755 index 82bbbbf..0000000 --- a/besides-ns-helper.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -set -e - -cleanup () { - [ -n "$cleanup_done" ] && return - cleanup_done=1 - [ -n "$tmp" ] && rm -rf "$tmp" - trap : EXIT HUP TERM INT - kill 0 -} - -tmp=$1 -LIB_DIR=$2 -pid=$3 - -trap cleanup EXIT HUP TERM INT - -# Wait for a signal that the namespace is fully created -exec 7< "$tmp/1" - -"$LIB_DIR/udp-forw" "$pid" "$tmp/2" & -exec 7< "$tmp/2" - -"$LIB_DIR/tun2socks4netns" "$pid" 2>&1 | { - read -r discard - read -r discard - # After reading two lines from tun2socks, we know that the tun - # interface is up and ready for traffic, so send the signal - exec 7> "$tmp/3" - tee > /dev/null -} & - -exec 8<> "$tmp/lock" -flock 8 diff --git a/common.c b/common.c deleted file mode 100644 index 4a9239e..0000000 --- a/common.c +++ /dev/null @@ -1,139 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int open_tun(const char *tunname) -{ - int fd; - struct ifreq ifr; - if (tunname == NULL) { - fprintf(stderr, "tunname is NULL\n"); - return -1; - } - if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { - perror("open(\"/dev/net/tun\")"); - return fd; - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - strncpy(ifr.ifr_name, tunname, sizeof(ifr.ifr_name) - 1); - if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) { - perror("ioctl(TUNSETIFF)"); - close(fd); - return -1; - } - return fd; -} - -int nsenter(pid_t target_pid) -{ - - int usernsfd = -1, netnsfd = -1; - char *netns, *userns; - int ret = -1; - - if (asprintf(&netns, "/proc/%d/ns/net", target_pid) < 0) { - perror("cannot get netns path"); - goto free0; - } - if (asprintf(&userns, "/proc/%d/ns/user", target_pid) < 0) { - perror("cannot get userns path"); - goto free1; - } - if ((netnsfd = open(netns, O_RDONLY)) < 0) { - perror(netns); - goto free2; - } - if ((usernsfd = open(userns, O_RDONLY)) < 0) { - perror(userns); - goto free3; - } - - if (setns(usernsfd, CLONE_NEWUSER) < 0) { - perror("setns(CLONE_NEWUSER)"); - goto free4; - } - if (setns(netnsfd, CLONE_NEWNET) < 0) { - perror("setns(CLONE_NEWNET)"); - goto free4; - } - - ret = 0; - - free4: - close(usernsfd); - free3: - close(netnsfd); - free2: - free(userns); - free1: - free(netns); - free0: - return ret; -} - -int sendfd(int sock, int fd) -{ - ssize_t rc; - struct msghdr msg = {0}; - struct cmsghdr *cmsg; - char cmsgbuf[CMSG_SPACE(sizeof(fd))]; - struct iovec iov; - char dummy = '\0'; - iov.iov_base = &dummy; - iov.iov_len = 1; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); - msg.msg_controllen = cmsg->cmsg_len; - if ((rc = sendmsg(sock, &msg, 0)) < 0) { - perror("sendmsg"); - } - return rc; -} - -int recvfd(int sock) -{ - int fd; - ssize_t rc; - struct msghdr msg; - struct cmsghdr *cmsg; - char cmsgbuf[CMSG_SPACE(sizeof(fd))]; - struct iovec iov; - char dummy = '\0'; - memset(&msg, 0, sizeof(msg)); - iov.iov_base = &dummy; - iov.iov_len = 1; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - if ((rc = recvmsg(sock, &msg, 0)) < 0) { - perror("recvmsg"); - return (int)rc; - } - if (rc == 0) { - fprintf(stderr, "the message is empty\n"); - return -1; - } - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS) { - fprintf(stderr, "the message does not contain fd\n"); - return -1; - } - memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); - return fd; -} diff --git a/common.h b/common.h deleted file mode 100644 index 37edb4e..0000000 --- a/common.h +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int open_tun(const char *tunname); -int nsenter(pid_t target_pid); -int sendfd(int sock, int fd); -int recvfd(int sock); diff --git a/inside-ns-helper.sh b/inside-ns-helper.sh deleted file mode 100755 index 1bb9bf5..0000000 --- a/inside-ns-helper.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -set -e - -# Wait for calling process to signal that it is done and then execute the given -# COMMAND. - -tmp=$1 -etc_resolv_conf=$2 -shift; shift - -mount --bind "$etc_resolv_conf" /etc/resolv.conf - -exec 8<> "$tmp/lock" -flock 8 - -# Send a signal that the namespace is fully created -exec 7> "$tmp/1" - -# Wait for a signal that the tun interface and DNS udp forwarder is active -exec 7< "$tmp/3" - -exec "$@" diff --git a/netns-socks b/netns-socks deleted file mode 100755 index 2c9b834..0000000 --- a/netns-socks +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -set -e - -LIB_DIR=$(dirname "$(readlink -f "$0")") - -usage () { - echo "\ -$0 [--] [COMMAND [ARGS ...]] - -Run COMMAND in a network namespace such that all network activity is forwarded -through a socks proxy. If COMMAND isn't given, it defaults to your \$SHELL. - -For this script to work, you must have 'tun2socks' installed somewhere in your -\$PATH, a socks server listening on localhost:9050 and a DNS server listening -on localhost:9051/udp. See Readme.txt on how to configure your tor daemon to -listen on these ports." -} - -while getopts "h?" options; do - case $options in - h|\? ) usage; exit 0;; - * ) usage; exit 1;; - esac -done -shift $((OPTIND - 1)) - -[ $# = 0 ] && set -- "$SHELL" - -tmp=$(mktemp -d) -# These are "semaphore fifos". Process A can wait for process B to raise a -# signal on a fifo like this: A opens a fifo for reading (exec 7< "$tmp/1"), -# which blocks until B opens this fifo for writing (exec 7> "$tmp/1). -mkfifo "$tmp/1" "$tmp/2" "$tmp/3" - -"$LIB_DIR/besides-ns-helper.sh" "$tmp" "$LIB_DIR" $$ & - -exec unshare --user --map-root-user --net --mount \ - "$LIB_DIR/inside-ns-helper.sh" \ - "$tmp" "$LIB_DIR/etc-resolv.conf" "$@" diff --git a/netns-socks.c b/netns-socks.c new file mode 100644 index 0000000..4435a15 --- /dev/null +++ b/netns-socks.c @@ -0,0 +1,598 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFS 1024 + +static int sendfd(int sock, int fd) +{ + ssize_t rc; + struct msghdr msg = {0}; + struct cmsghdr *cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(fd))]; + struct iovec iov; + char dummy = '\0'; + iov.iov_base = &dummy; + iov.iov_len = 1; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + msg.msg_controllen = cmsg->cmsg_len; + if ((rc = sendmsg(sock, &msg, 0)) < 0) { + perror("sendmsg"); + } + return rc; +} + +static int recvfd(int sock) +{ + int fd; + ssize_t rc; + struct msghdr msg; + struct cmsghdr *cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(fd))]; + struct iovec iov; + char dummy = '\0'; + memset(&msg, 0, sizeof(msg)); + iov.iov_base = &dummy; + iov.iov_len = 1; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + if ((rc = recvmsg(sock, &msg, MSG_WAITALL)) < 0) { + perror("recvmsg"); + return (int)rc; + } + if (rc == 0) { + fprintf(stderr, "the message is empty\n"); + return -1; + } + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS) { + fprintf(stderr, "the message does not contain fd\n"); + return -1; + } + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); + return fd; +} + +static int open_tun(const char *tunname) +{ + int fd; + struct ifreq ifr; + if (tunname == NULL) { + fprintf(stderr, "tunname is NULL\n"); + return -1; + } + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { + perror("open(\"/dev/net/tun\")"); + return fd; + } + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr.ifr_name, tunname, sizeof(ifr.ifr_name) - 1); + if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) { + perror("ioctl(TUNSETIFF)"); + close(fd); + return -1; + } + return fd; +} + +static int configure_network(const char *tunname) { + struct rtentry route = {0}; + struct ifreq ifr; + struct sockaddr_in *sai = (struct sockaddr_in *)&ifr.ifr_addr; + int sockfd; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + perror("cannot create socket"); + return -1; + } + + // set loopback device to UP + struct ifreq ifr_lo = { .ifr_name = "lo", + .ifr_flags = IFF_UP | IFF_RUNNING }; + if (ioctl(sockfd, SIOCSIFFLAGS, &ifr_lo) < 0) { + perror("cannot set device up"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_UP | IFF_RUNNING; + strncpy(ifr.ifr_name, tunname, sizeof(ifr.ifr_name) - 1); + + if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { + perror("cannot set device up"); + return -1; + } + + sai->sin_family = AF_INET; + sai->sin_port = 0; + sai->sin_addr.s_addr = inet_addr("10.18.0.100"); + + if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { + perror("cannot set device address"); + return -1; + } + + sai->sin_addr.s_addr = inet_addr("255.255.255.0"); + if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) { + perror("cannot set device netmask"); + return -1; + } + + sai = (struct sockaddr_in *)&route.rt_gateway; + sai->sin_family = AF_INET; + sai->sin_addr.s_addr = inet_addr("10.18.0.1"); + sai = (struct sockaddr_in *)&route.rt_dst; + sai->sin_family = AF_INET; + sai->sin_addr.s_addr = INADDR_ANY; + sai = (struct sockaddr_in *)&route.rt_genmask; + sai->sin_family = AF_INET; + sai->sin_addr.s_addr = INADDR_ANY; + + route.rt_flags = RTF_UP | RTF_GATEWAY; + route.rt_metric = 0; + route.rt_dev = (char *)tunname; + + if (ioctl(sockfd, SIOCADDRT, &route) < 0) { + perror("set route"); + return -1; + } + return 0; +} + +static int make_and_send_tun(int sock) { + int ret = -1; + int rc, tunfd; + if ((tunfd = open_tun("tun0")) < 0) + goto free0; + if (configure_network("tun0") < 0) + goto free1; + if (sendfd(sock, tunfd) < 0) + goto free1; + + ret = 0; + + free1: + close(tunfd); + free0: + return ret; +} + +static int listen_udp() { + int fd = -1; + struct sockaddr_in servaddr = {0}; + + if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + perror("socket"); + return fd; + } + + // Filling server information + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + servaddr.sin_port = htons(53); + + // Bind the socket with the server address + if ( bind(fd, (const struct sockaddr *)&servaddr, + sizeof(servaddr)) < 0 ) { + close(fd); + return -1; + } + return fd; +} + +static int mount_resolv(char *const argv0) { + char *binpath, *slash, *etcresolv; + int ret = -1; + + /* etc-resolv.conf file must be in the same directory as this executable and + this must be executed with a slash inside argv[0] to make searching for + etc-resolv.conf easier. */ + if ((binpath = strdup(argv0)) == NULL) { + perror("strdup"); + return -1; + } + if ((slash = strrchr(binpath, '/')) == NULL){ + fprintf(stderr, + "netns-socks binary must be with an absolute or relative path"); + goto free1; + } + *slash = '\0'; + if (asprintf(&etcresolv, "%s/etc-resolv.conf", binpath) < 0) { + perror("Cannot get allocate etc-resolv.conf path"); + goto free1; + } + + if (mount(etcresolv, "/etc/resolv.conf", NULL, MS_BIND, NULL) != 0){ + perror("mount"); + goto free2; + } + + ret = 0; + + free2: + free(etcresolv); + free1: + free(binpath); + return ret; +} + +static int write_str_file(const char *fn, const char *buf) { + int fd, ret = -1; + + fd = open(fn, O_WRONLY); + if (fd < 0) { + perror("open"); + return -1; + } + + while (1) { + if (write(fd, buf, strlen(buf)) != strlen(buf)) { + if (errno == EINTR) + continue; + perror("write"); + goto free1; + } + break; + } + ret = 0; + free1: + close(fd); + return ret; +} + +static int write_uid_map(const char *map_file, int id) { + int ret; + char *buf; + + if (asprintf(&buf, "%u %u 1", id, id) < 0) { + perror("asprintf"); + return -1; + } + ret = write_str_file(map_file, buf); + free(buf); + return ret; +} + +static int inside_namespace(int startfd, int socket, int argc, + char *const argv[]) { + char buf[8]; + int udpfd; + uid_t uid = geteuid(); + gid_t gid = getegid(); + + if (-1 == unshare(CLONE_NEWUSER | CLONE_NEWNET | CLONE_NEWNS)) { + perror("unshare"); + return -1; + } + if (make_and_send_tun(socket) != 0) + return -1; + + if ((udpfd = listen_udp()) < 0) + return -1; + + if (sendfd(socket, udpfd) < 0) { + close(udpfd); + return -1; + } + close(udpfd); + + if (mount_resolv(argv[0]) < 0) + return -1; + + if (write_uid_map("/proc/self/uid_map", uid) < 0) + return -1; + if (write_str_file("/proc/self/setgroups", "deny") < 0) + return -1; + if (write_uid_map("/proc/self/gid_map", gid) < 0) + return -1; + + /* Block until we receive a signal on STARTFD */ + read(startfd, buf, 8); + close(startfd); + + execvp(argv[1], argv + 1); + perror("exec"); + return -1; +} + +/* Fork off a child in a new namespace. + + Open a new tun interface inside the namespace and return its file descriptor + in *TUNFD. + + Listen for UDP packets on port 53 inside the namespace and return the socket + fd in *UDPSERV. + + After a signal arrives on eventfd(2) given in STARTFD, execute the program + given in ARGC and ARGV in the newly created namespace. */ +static pid_t fork_ns(int *tunfd, int *udpserv, int startfd, int argc, + char *const argv[]) { + int ret = -1; + pid_t ns_pid; + int s[2]; + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) < 0) { + perror("socketpair"); + goto free1; + } + + if ((ns_pid = fork()) < 0) { + perror("fork"); + goto free2; + } + + if (ns_pid == 0) { + close(s[1]); + return inside_namespace(startfd, s[0], argc, argv); + } + + if ((*tunfd = recvfd(s[1])) < 0) + goto free3; + + if ((*udpserv = recvfd(s[1])) < 0) { + close(*tunfd); + goto free3; + } + + ret = 0; + goto free2; + + free3: + kill(ns_pid, SIGTERM); + free2: + close(s[0]); + close(s[1]); + free1: + return ret; +} + +/* Execute tun2socks and block until it starts forwarding. Return its PID or a + negative number if unsuccessful. */ +int run_tun2socks(int tunfd, int *pipefd) { + int ret = -1; + char *fd_arg; + int p[2]; + char buf[BUFS]; + int lines = 0; + + if (asprintf(&fd_arg, "fd://%d", tunfd) < 0) { + perror("Cannot get fd:// argument"); + goto free0; + } + + if (pipe(p) < 0) { + perror("pipe"); + goto free1; + } + + if ((ret = fork()) < 0) { + perror("fork"); + goto free2; + } + + if (ret == 0) { + close(p[0]); + dup2(p[1], 2); + dup2(p[1], 1); + if (p[1] != 2 && p[1] != 1) + close(p[1]); + execlp("tun2socks", "tun2socks", "--device", fd_arg, "--proxy", + "socks5://127.0.0.1:9050", (char *)NULL); + ret = -1; + perror("exec"); + goto free1; + } + + /* Block until tun2socks outputs one line. */ + while (1) { + ssize_t s; + + s = read(p[0], buf, BUFS); + if (s == -1) { + if (errno == EINTR) + continue; + perror("read"); + goto free3; + } + + buf[s] = '\0'; + if ((strchr(buf, '\n')) != NULL) + break; + } + + *pipefd = p[0]; + goto free2; + + free3: + kill(ret, SIGTERM); + ret = -1; + close(p[0]); + free2: + close(p[1]); + free1: + free(fd_arg); + free0: + return ret; +} + +void * read_and_discard(void * arg) { + char *buf[BUFS]; + int fd = *(int *)arg; + + while (1) { + ssize_t s; + + s = read(fd, buf, BUFS); + if (s == -1) { + if (errno == EINTR) + continue; + break; + } +#if 0 + write(2, buf, s); +#endif + } + + return NULL; +} + +static void *udp_forward(void *arg) { + char *buf[BUFS]; + int serverfd = *(int *)arg; + + struct sockaddr_in servaddr = {0}; + char buffer[BUFS]; + int clientfd; + int n; + socklen_t len; + + if ( (clientfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + perror("socket"); + goto free1; + } + + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(9051); + servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + if (connect(clientfd, &servaddr, sizeof(servaddr)) < 0) { + perror("connect"); + goto free2; + } + + len = sizeof(servaddr); + + for (;;) { + n = recvfrom(serverfd, (char *)buffer, BUFS, MSG_WAITALL, + (struct sockaddr *)&servaddr, &len); + if (n < 0) { + perror("recvfrom"); + break; + } + if (send(clientfd, buffer, n, 0) < 0) { + perror("send as client"); + break; + } + n = recv(clientfd, buffer, BUFS, MSG_WAITALL); + if (n < 0) { + perror("receive as client"); + break; + } + + if (sendto(serverfd, (const char *)buffer, n, MSG_CONFIRM, + (const struct sockaddr *)&servaddr, len) < 0) { + perror("send as server"); + break; + } + } + + free2: + close(clientfd); + free1: + return NULL; +} + +int main(int argc, char *const argv[]) { + pid_t ns_pid; + int startfd; + int tunfd; + int udpserv; + pid_t tun2sockspid; + int tun2socksfd; + char *fallback_argv[3]; + int ret = 1; + int kill_ns_pid = 1; + int wstatus; + + pthread_t thread1, thread2, thread3; + + if (argc == 1) { + argc = 2; + fallback_argv[0] = argv[0]; + fallback_argv[1] = getenv("SHELL"); + fallback_argv[2] = NULL; + argv = fallback_argv; + } + + if ((startfd = eventfd(0, EFD_SEMAPHORE)) < 0) { + perror("eventfd"); + return 1; + } + + if ((ns_pid = fork_ns(&tunfd, &udpserv, startfd, argc, argv)) < 0) + goto free1; + + if ((tun2sockspid = run_tun2socks(tunfd, &tun2socksfd)) < 0) { + goto free2; + } + + if (pthread_create(&thread1, NULL, read_and_discard, &tun2socksfd) != 0) { + perror("pthread_create"); + goto free3; + } + + if (pthread_create(&thread2, NULL, udp_forward, &udpserv) != 0) { + perror("pthread_create"); + goto free4; + } + + /* Notify the namespace process that it can execute the given COMMAND now. */ + write(startfd, (uint64_t[]){1}, sizeof(uint64_t)); + + kill_ns_pid = 0; + if (waitpid(ns_pid, &wstatus, 0) < 0) { + perror("waitpid"); + goto free5; + } + + if (WIFEXITED(wstatus)) + ret = WEXITSTATUS(wstatus); + + free5: + if (pthread_cancel(thread2) == 0) + pthread_join(thread2, NULL); + free4: + if (pthread_cancel(thread1) == 0) + pthread_join(thread1, NULL); + free3: + close(tun2socksfd); + kill(tun2sockspid, SIGTERM); + waitpid(tun2sockspid, NULL, 0); + free2: + close(tunfd); + close(udpserv); + if (kill_ns_pid) { + kill(ns_pid, SIGTERM); + waitpid(ns_pid, NULL, 0); + } + free1: + close(startfd); + return ret; +} diff --git a/tun2socks4netns.c b/tun2socks4netns.c deleted file mode 100644 index f38f9e1..0000000 --- a/tun2socks4netns.c +++ /dev/null @@ -1,177 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -static int configure_network(const char *tunname) -{ - struct rtentry route = {0}; - struct ifreq ifr; - struct sockaddr_in *sai = (struct sockaddr_in *)&ifr.ifr_addr; - int sockfd; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) { - perror("cannot create socket"); - return -1; - } - - // set loopback device to UP - struct ifreq ifr_lo = { .ifr_name = "lo", - .ifr_flags = IFF_UP | IFF_RUNNING }; - if (ioctl(sockfd, SIOCSIFFLAGS, &ifr_lo) < 0) { - perror("cannot set device up"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_UP | IFF_RUNNING; - strncpy(ifr.ifr_name, tunname, sizeof(ifr.ifr_name) - 1); - - if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { - perror("cannot set device up"); - return -1; - } - - sai->sin_family = AF_INET; - sai->sin_port = 0; - sai->sin_addr.s_addr = inet_addr("10.18.0.100"); - - if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { - perror("cannot set device address"); - return -1; - } - - sai->sin_addr.s_addr = inet_addr("255.255.255.0"); - if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) { - perror("cannot set device netmask"); - return -1; - } - - sai = (struct sockaddr_in *)&route.rt_gateway; - sai->sin_family = AF_INET; - sai->sin_addr.s_addr = inet_addr("10.18.0.1"); - sai = (struct sockaddr_in *)&route.rt_dst; - sai->sin_family = AF_INET; - sai->sin_addr.s_addr = INADDR_ANY; - sai = (struct sockaddr_in *)&route.rt_genmask; - sai->sin_family = AF_INET; - sai->sin_addr.s_addr = INADDR_ANY; - - route.rt_flags = RTF_UP | RTF_GATEWAY; - route.rt_metric = 0; - route.rt_dev = (char *)tunname; - - if (ioctl(sockfd, SIOCADDRT, &route) < 0) { - perror("set route"); - return -1; - } - return 0; -} - -static int child(int sock, pid_t target_pid) - -{ - int ret = -1; - int rc, tunfd; - if ((rc = nsenter(target_pid)) < 0) - goto free0; - if ((tunfd = open_tun("tun0")) < 0) - goto free0; - if (configure_network("tun0") < 0) - goto free1; - if (sendfd(sock, tunfd) < 0) - goto free1; - - fprintf(stderr, "sent tunfd=%d for tun0\n", tunfd); - ret = 0; - - free1: - close(tunfd); - free0: - return ret; -} - -int main (int argc, char *const argv[]) -{ - int sv[2]; - int child_pid; - int target_pid; - char *strtol_e; - - if (argc != 2) { - fprintf(stderr, "Usage:"); - return 1; - } - - target_pid = strtol(argv[1], &strtol_e, 10); - if (errno || strtol_e[0] != '\0' || target_pid <= 0) { - fprintf(stderr, "PID must be a positive integer\n"); - return 1; - } - - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) { - perror("socketpair"); - return 1; - } - if ((child_pid = fork()) < 0) { - perror("fork"); - return 1; - } - if (child_pid == 0) { - int ret; - ret = child(sv[1], target_pid); - close(sv[1]); - if (ret < 0) - return 1; - } else { - int ret, child_wstatus, child_status; - int tunfd; - char *fd_arg; - do - ret = waitpid(child_pid, &child_wstatus, 0); - while (ret < 0 && errno == EINTR); - if (ret < 0) { - perror("waitpid"); - return 1; - } - if (!WIFEXITED(child_wstatus)) { - fprintf(stderr, "child failed(wstatus=%d, !WIFEXITED)\n", - child_wstatus); - return 1; - } - child_status = WEXITSTATUS(child_wstatus); - if (child_status != 0) { - fprintf(stderr, "child failed(%d)\n", child_status); - return 1; - } - if ((tunfd = recvfd(sv[0])) < 0) { - return tunfd; - } - - if (asprintf(&fd_arg, "fd://%d", tunfd) < 0) { - close(tunfd); - perror("Cannot get fd:// argument"); - return 1; - } - if (execlp("tun2socks", "tun2socks", - "--device", fd_arg, "--proxy", "socks5://127.0.0.1:9050", - (char *) NULL) - < 0) { - close(tunfd); - perror("exec"); - free(fd_arg); - return 1; - } - } -} diff --git a/udp-forw.c b/udp-forw.c deleted file mode 100644 index 32e6782..0000000 --- a/udp-forw.c +++ /dev/null @@ -1,115 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -#define DPORT 9051 -#define SPORT 53 -#define BUFSIZE 1600 - -int main(int argc, char *const argv[]) { - int clientfd, target_pid, ret = 1; - int serverfd; - int signalfd = -1; - char buffer[BUFSIZE]; - char *strtol_e; - struct sockaddr_in servaddr = {0}; - int n; - socklen_t len; - - if (argc != 2 && argc != 3) { - fprintf(stderr, "Usage:"); - return 1; - } - - target_pid = strtol(argv[1], &strtol_e, 10); - if (errno || strtol_e[0] != '\0' || target_pid <= 0) { - fprintf(stderr, "PID must be a positive integer\n"); - goto free0; - } - - if ( (clientfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { - perror("socket"); - goto free0; - } - - // Filling server information - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(DPORT); - servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); - - if (connect(clientfd, &servaddr, sizeof(servaddr)) < 0) { - perror("connect"); - goto free1; - } - - if (nsenter(target_pid) < 0) - goto free1; - - - if ( (serverfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { - perror("socket"); - goto free1; - } - - // Filling server information - servaddr.sin_family = AF_INET; // IPv4 - servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); - servaddr.sin_port = htons(SPORT); - - // Bind the socket with the server address - if ( bind(serverfd, (const struct sockaddr *)&servaddr, - sizeof(servaddr)) < 0 ) { - perror("bind failed"); - goto free2; - } - - /* Signal that we have started listening by opening argv[2] for writing */ - if (argc >= 3) { - signalfd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC); - if (signalfd < 0) { - perror("open"); - goto free2; - } - } - - len = sizeof(servaddr); //len is value/result - - for (;;) { - n = recvfrom(serverfd, (char *)buffer, BUFSIZE, MSG_WAITALL, - (struct sockaddr *)&servaddr, &len); - if (n < 0) { - perror("recvfrom"); - goto free3; - } - if (send(clientfd, buffer, n, 0) < 0) { - perror("send as client"); - goto free3; - } - n = recv(clientfd, buffer, BUFSIZE, MSG_WAITALL); - if (n < 0) { - perror("receive as client"); - goto free3; - } - - if (sendto(serverfd, (const char *)buffer, n, MSG_CONFIRM, - (const struct sockaddr *)&servaddr, len) < 0) { - perror("send as server"); - goto free3; - } - } - - free3: - signalfd != -1 && close(signalfd); - free2: - close(serverfd); - free1: - close(clientfd); - free0: - return ret; -} -- 2.11.4.GIT