#include "common.h" #include #include #include #include #include #include #include #include static int tun_fd, utun_fd; static struct sockaddr_in utun_peer; static void setup_tundev(const char *in_ifname) { #define DEVNETTUN "/dev/net/tun" int fd = open(DEVNETTUN, O_RDWR); if (fd < 0) fatal("setup_tundev: open("DEVNETTUN"): %s", strerror(errno)); // Now configure the interface. First set the interface name struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP|IFF_NO_PI; strncpy(ifr.ifr_name, in_ifname, IFNAMSIZ - 1); if (ioctl(fd, TUNSETIFF, &ifr) < 0) fatal("setup_tundev: ioctl(TUNSETIFF): %s", strerror(errno)); debug("setup_tundev: created tuntap interface: %s", in_ifname); // A temporary fd is required int tmpfd = socket(AF_INET, SOCK_DGRAM, 0); if (tmpfd < 0) fatal("setup_tundev: socket(): %s", strerror(errno)); struct ifreq ifr2; memset(&ifr2, 0, sizeof(ifr2)); strncpy(ifr2.ifr_name, in_ifname, IFNAMSIZ - 1); // Bring the interface up. Get current flags first if (ioctl(tmpfd, SIOCGIFFLAGS, &ifr2) < 0) fatal("setup_tundev: ioctl(SIOCGIFFLAGS): %s", strerror(errno)); ifr2.ifr_flags |= IFF_UP|IFF_RUNNING; if (ioctl(tmpfd, SIOCSIFFLAGS, &ifr2) < 0) fatal("setup_tundev: ioctl(SIOCSIFFLAGS): %s", strerror(errno)); // Set MTU to 1438 by default ifr2.ifr_mtu = 1438; if (ioctl(tmpfd, SIOCSIFMTU, &ifr2) < 0) fatal("setup_tundev: ioctl(SIOCSIFMTU): %s", strerror(errno)); close(tmpfd); tun_fd = fd; } static void setup_utun(struct in_addr local_addr, uint16_t local_port, struct in_addr remote_addr, uint16_t remote_port) { int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) fatal("setup_utun: socket(): %s", strerror(errno)); struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(local_port); local.sin_addr = local_addr; if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) fatal("setup_utun: bind(port=%d): %s", (int)local_port, strerror(errno)); debug("setup_utun: created utun socket: %s:%d", inet_ntoa(local_addr), (int)local_port); struct sockaddr_in remote; remote.sin_family = AF_INET; remote.sin_port = htons(remote_port); remote.sin_addr = remote_addr; utun_peer = remote; utun_fd = fd; } static void read_tundev(void) { const ssize_t gre_header_len = 4; uint8_t buf[2048]; // GRE header comes first, inside the UDP packet buf[0] = 0; buf[1] = 0; *(uint16_t *)&buf[2] = htons(0x6558); // Ethernet frame follows ssize_t nread = read(tun_fd, buf + gre_header_len, sizeof(buf) - gre_header_len); if (nread < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return; fatal("tundev: read(): %s", strerror(errno)); } ssize_t nsent = sendto(utun_fd, buf, nread + gre_header_len, 0, (struct sockaddr *)&utun_peer, sizeof(utun_peer)); if (nsent != nread + gre_header_len) fatal("tundev: sendto(utun): %s", strerror(errno)); if (TUN_DEBUG > 0) fprintf(stderr, ">"); } static void read_utun(void) { const ssize_t gre_header_len = 4; uint8_t buf[2048]; struct sockaddr_in remote; socklen_t remote_len = sizeof(remote); ssize_t nread = recvfrom(utun_fd, buf, sizeof(buf), 0, (struct sockaddr *)&remote, &remote_len); if (nread < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return; fatal("utun: read(): %s", strerror(errno)); } if (memcmp(&utun_peer, &remote, sizeof(remote))) { debug("utun: packet from unexpected peer; expected=%s:%d, " "actual=%s:%d", inet_ntoa(utun_peer.sin_addr), (int)utun_peer.sin_port, inet_ntoa(remote.sin_addr), (int)remote.sin_port); return; } if (nread < gre_header_len || buf[0] != 0 || buf[1] != 0 || ntohs(*(uint16_t *)&buf[2]) != 0x6558) { debug("utun: packet in unexpected format"); return; } ssize_t nwritten = write(tun_fd, buf + gre_header_len, nread - gre_header_len); if (nwritten != nread - gre_header_len) fatal("utun: write(tundev) failed: %s", strerror(errno)); if (TUN_DEBUG > 0) fprintf(stderr, "<"); } int main(int argc, char **argv) { if (argc != 6) fatal("usage: ulfougretap " \ " \n"); setup_tundev(argv[1]); setup_utun(parse_ipv4(argv[2]), parse_u16(argv[3]), parse_ipv4(argv[4]), parse_u16(argv[5])); struct pollfd pollfds[2] = { { .fd = tun_fd, .events = POLLIN, }, { .fd = utun_fd, .events = POLLIN, }, }; while (1) { if (poll(pollfds, numberof(pollfds), -1) < 0) fatal("poll(): %s", strerror(errno)); if (pollfds[0].revents) read_tundev(); if (pollfds[1].revents) read_utun(); } }