#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 void fd_set_congestion (int fd, const char *name) { size_t len = str_len(name); if (!len) return; if (setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, name, len+1)==-1) printf("setsockopt TCP_CONGESTION: %m\n"); } static int fd_listen (int fd, struct addrinfo *ai) { fd_set_reuseaddr(fd); int ret = bind(fd, ai->ai_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; } return 0; } static int fd_connect (int fd, struct addrinfo *ai) { return connect(fd, ai->ai_addr, ai->ai_addrlen); } static int fd_create (struct addrinfo *res, int(*func)(int, struct addrinfo *)) { 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) continue; if (func(fd, ai)!=-1) return fd; close(fd); } return -1; } static int tun_create (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; i0 && 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; }