diff --git a/init/init.c b/init/init.c index 4b205db69..59a5c3d94 100644 --- a/init/init.c +++ b/init/init.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -1285,6 +1286,109 @@ char *clone_str(const char *str) return strdup(str); } +#if __linux__ +static bool tsi_enabled() +{ + const char *const option = "tsi_hijack"; + bool enabled = false; + char *cmdline = NULL; + size_t cmdline_length = 0; + FILE *f; + const char *const delimiters = " \n"; + char *token; + + f = fopen("/proc/cmdline", "r"); + if (f == NULL) { + perror("fopen(/proc/cmdline)"); + return false; + } + + if (getline(&cmdline, &cmdline_length, f) < 0) { + perror("getline(/proc/cmdline)"); + fclose(f); + goto cleanup; + } + fclose(f); + + token = strtok(cmdline, delimiters); + while (token != NULL) { + if (strcmp(token, "--") == 0) { + break; + } + if (strcmp(token, option) == 0) { + enabled = true; + break; + } + token = strtok(NULL, delimiters); + } + +cleanup: + free(cmdline); + + return enabled; +} + +static int enable_dummy_interface() +{ + // See https://www.man7.org/linux/man-pages/man7/netdevice.7.html + + const char *const name = "dummy0"; + struct ifreq ifr; + int sockfd; + struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr; + struct sockaddr_in *netmask = (struct sockaddr_in *)&ifr.ifr_netmask; + int result = -1; + + if (snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name) >= IFNAMSIZ) { + printf("dummy interface name too long\n"); + return -1; + } + + sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + perror("dummy interface socket"); + return -1; + } + + ifr.ifr_flags = IFF_UP; + if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { + if (errno == ENODEV) { + // Most likely not enabled in the kernel, ignore quietly + result = 0; + goto close_socket; + } + perror("dummy interface up"); + goto close_socket; + } + + addr->sin_family = AF_INET; + if (inet_pton(AF_INET, "10.0.0.1", &addr->sin_addr) <= 0) { + printf("inet_pton address conversion failed\n"); + goto close_socket; + } + if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { + perror("dummy interface address"); + goto close_socket; + } + + netmask->sin_family = AF_INET; + if (inet_pton(AF_INET, "255.0.0.0", &netmask->sin_addr) <= 0) { + printf("inet_pton netmask conversion failed\n"); + goto close_socket; + } + if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) { + perror("dummy interface mask"); + goto close_socket; + } + + result = 0; + +close_socket: + close(sockfd); + return result; +} +#endif + int main(int argc, char **argv) { struct ifreq ifr; @@ -1435,6 +1539,14 @@ int main(int argc, char **argv) close(sockfd); } +#if __linux__ + if (tsi_enabled()) { + if (enable_dummy_interface() < 0) { + printf("Warning: Couldn't enable dummy interface\n"); + } + } +#endif + config_argv = NULL; config_workdir = NULL; config_tmpfs = NULL;