#include "common.h" #include #include #include #include #include #include #include #include #include #include #include #define GT_BUFFER_SIZE (256*1024) volatile sig_atomic_t running; static void fd_set_nonblock (int fd) { int val, ret; do { val = 1; ret = ioctl(fd, FIONBIO, &val); } while (ret==-1 && errno==EINTR); if (ret==-1) printf("ioctl FIONBIO: %m\n"); } static void fd_set_nodelay (int fd) { int val = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY , &val, sizeof(val))==-1) printf("setsockopt TCP_NODELAY: %m\n"); } static void fd_set_reuseaddr (int fd) { int val = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))==-1) printf("setsockopt SO_REUSEADDR: %m\n"); } static int gt_open_sock (struct addrinfo *res) // bad { for (struct addrinfo *ai=res; ai; ai=ai->ai_next) { int fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd!=-1) return fd; } return -1; } static int gt_open_tun (char *name) { int fd = open("/dev/net/tun", O_RDWR); if (fd<0) { printf("open /dev/net/tun: %m\n"); return -1; } struct ifreq ifr = { .ifr_flags = IFF_TUN|IFF_NO_PI, }; str_cpy(ifr.ifr_name, name, IFNAMSIZ-1); int ret = ioctl(fd, TUNSETIFF, &ifr); if (ret<0) { printf("ioctl TUNSETIFF: %m\n"); return -1; } printf("tun name: %s\n", ifr.ifr_name); return fd; } static void gt_sa_stop (int sig) { switch (sig) { case SIGINT: case SIGTERM: running = 0; } } static void gt_set_signal (void) { struct sigaction sa = {0}; running = 1; sa.sa_handler = gt_sa_stop; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGHUP, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); } static int read_to_buffer (int fd, buffer_t *buffer, size_t size) { if (!size || buffer_write_size(buffer)write, size); if (!ret) return 0; if (ret==-1) { if (errno==EAGAIN || errno==EINTR) return -1; if (errno) printf("read: %m\n"); return 0; } buffer->write += ret; return ret; } static int write_from_buffer (int fd, buffer_t *buffer, size_t size) { if (!size || buffer_read_size(buffer)read, size); if (!ret) return 0; if (ret==-1) { if (errno==EAGAIN || errno==EINTR) return -1; if (errno) printf("write: %m\n"); return 0; } buffer->read += ret; return ret; } enum option_type { option_flag, option_string, }; struct option { char *name; void *data; enum option_type type; }; static int option (int argc, char **argv, int n, struct option *opt) { for (int i=1; iai_addr, ai->ai_addrlen); if (ret==-1) { printf("bind: %m\n"); return 1; } ret = listen(fd, 1); if (ret==-1) { printf("listen: %m\n"); return 1; } } struct netio tun = { .fd = -1 }; struct netio sock = { .fd = -1 }; tun.fd = gt_open_tun(dev); if (tun.fd==-1) return 1; buffer_setup(&tun.recv, NULL, GT_BUFFER_SIZE); buffer_setup(&sock.recv, NULL, GT_BUFFER_SIZE); while (running) { if (listener) { printf("waiting for a client...\n"); struct sockaddr_storage addr_storage; struct sockaddr *addr = (struct sockaddr *)&addr_storage; socklen_t addr_size = sizeof(addr_storage); sock.fd = accept(fd, addr, &addr_size); if (sock.fd==-1) { printf("accept: %m\n"); return 1; } } else { sock.fd = gt_open_sock(ai); if (sock.fd==-1) return 1; int ret = connect(sock.fd, ai->ai_addr, ai->ai_addrlen); if (ret==-1) { // check errno close(sock.fd); sock.fd = -1; continue; } } fd_set_nonblock(sock.fd); fd_set_nodelay(sock.fd); printf("running...\n"); buffer_format(&tun.recv); buffer_format(&sock.recv); while (running) { struct pollfd fds[] = { { .fd = tun.fd, .events = POLLIN }, { .fd = sock.fd, .events = POLLIN }, }; int ret = poll(fds, COUNT(fds), -1); if (ret==-1) { if (errno==EINTR) continue; printf("poll: %m\n"); return 1; } if (ret==0) continue; buffer_shift(&tun.recv); if (fds[0].revents & POLLIN) { if (buffer_write_size(&tun.recv)) { uint8_t *tmp = tun.recv.write; int r = read_to_buffer(fds[0].fd, &tun.recv, buffer_write_size(&tun.recv)); if (!r) return 2; if (r>0 && r!=((tmp[2]<<8)|tmp[3])) tun.recv.write = tmp; } } if (fds[1].revents & POLLOUT) fds[1].events = POLLIN; if (buffer_read_size(&tun.recv)) { int r = write_from_buffer(fds[1].fd, &tun.recv, buffer_read_size(&tun.recv)); if (!r) goto restart; if (r==-1) fds[1].events = POLLIN|POLLOUT; } buffer_shift(&sock.recv); if (fds[1].revents & POLLIN) { int r = read_to_buffer(fds[1].fd, &sock.recv, buffer_write_size(&sock.recv)); if (!r) goto restart; } if (fds[0].revents & POLLOUT) fds[0].events = POLLIN; if (buffer_read_size(&sock.recv)>=20) { if ((sock.recv.read[0]>>4)!=4) return 4; size_t ps = (sock.recv.read[2]<<8)|sock.recv.read[3]; if (buffer_read_size(&sock.recv)>=ps) { int r = write_from_buffer(fds[0].fd, &sock.recv, ps); if (!r) return 2; if (r==-1) fds[0].events = POLLIN|POLLOUT; } } } restart: close(sock.fd); sock.fd = -1; } if (ai) freeaddrinfo(ai); free(tun.recv.data); free(sock.recv.data); return 0; }