/* * wnix, a Unix-like operating system for WebAssembly applications. * Copyright (C) 2025 Xavier Del Campo Romero * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int getport(const char *const s, unsigned short *const port) { char *end; unsigned long v; errno = 0; v = strtoull(s, &end, 10); if (errno || *end || v > USHRT_MAX) return -1; *port = v; return 0; } int main(int argc, char *argv[]) { static const char path[] = "/dev/net/tun"; char *s = NULL; int ret = EXIT_FAILURE, cfd = -1, tfd = -1; unsigned short port; if (argc != 2) { fprintf(stderr, "%s \n", *argv); goto end; } else if (getport(argv[1], &port)) { fprintf(stderr, "invalid port: %s\n", argv[1]); goto end; } else if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket(2)"); goto end; } const struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = inet_addr("127.0.0.1"), .sin_port = htons(port) }; const struct ifreq ifr = {.ifr_flags = IFF_TUN | IFF_NO_PI}; if (connect(cfd, (const struct sockaddr *)&addr, sizeof addr)) { perror("connect(2)"); goto end; } else if ((tfd = open(path, O_RDWR)) < 0) { fprintf(stderr, "open(2) %s: %s\n", path, strerror(errno)); goto end; } else if (ioctl(tfd, TUNSETIFF, &ifr) < 0) { perror("ioctl(2)"); goto end; } else if (!(s = strdup(ifr.ifr_name))) { perror("strdup(3)"); goto end; } fprintf(stderr, "set up TUN device %s\n", s); unsigned long long total = 0; for (;;) { char b[1500]; ssize_t n = read(tfd, &b, sizeof b); if (n < 0) { perror("read(2)"); goto end; } fprintf(stderr, "read %zu bytes\n", n); size_t rem = n; while (rem) { const void *p = b; fprintf(stderr, "sending %zu bytes\n", rem); if ((n = write(cfd, p, rem)) < 0) { perror("write(2)"); goto end; } fprintf(stderr, "sent %zu bytes, total: %llu\n", n, total += n); p = (const char *)p + n; rem -= n; } } ret = EXIT_SUCCESS; end: if (cfd >= 0 && close(cfd)) { ret = EXIT_FAILURE; perror("close(2)"); } if (tfd >= 0 && close(tfd)) { ret = EXIT_FAILURE; fprintf(stderr, "close(2) %s: %s\n", path, strerror(errno)); } free(s); return ret; }