Skip to content

Commit bc3b065

Browse files
committed
init: Set up a dummy network interface with TSI
Some applications check for network availability by looking for a network device configured for Internet access. When TSI is used, there is no such device available by default, although Internet is accessible. Then those applications behave like when the connection is not available. Let's solve this problem by setting up a dummy network interface. The dummy interface is automatically created when CONFIG_DUMMY is enabled in kernel or the corresponding kernel module is loaded. This means a sufficiently recent libkrunfw version is needed (see containers/libkrunfw#116). The dummy interface is initially down. In order to make the applications happy, the interface must be brought up and set up for Internet connections. This is ensured by setting the IP address to 10.0.0.1/0 (an arbitrary choice without any special reason) in init.c if TSI is enabled. TSI availability is determined by checking the presence of `tsi_hijack' in the kernel command line. The dummy interface simply swallows all packets. But it is effectively bypassed by TSI for practical purposes. Things like ICMP don't work in either case. When the kernel support is not available, the device is not present and init.c cannot set it up. We skip the configuration silently in such a case, to not spam users with errors if they use older libkrunfw or custom kernels. Fixes: #576 Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
1 parent 7c5292c commit bc3b065

1 file changed

Lines changed: 108 additions & 0 deletions

File tree

init/init.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <time.h>
1212
#include <unistd.h>
1313

14+
#include <arpa/inet.h>
1415
#include <net/if.h>
1516
#include <sys/ioctl.h>
1617
#include <sys/mount.h>
@@ -1059,6 +1060,107 @@ int try_mount(const char *source, const char *target, const char *fstype,
10591060
return mount_status;
10601061
}
10611062

1063+
bool tsi_enabled()
1064+
{
1065+
const char *const option = "tsi_hijack";
1066+
size_t length = strlen(option);
1067+
bool enabled = false;
1068+
FILE *f;
1069+
unsigned int i = 0;
1070+
1071+
f = fopen("/proc/cmdline", "r");
1072+
if (f == NULL) {
1073+
perror("fopen(/proc/cmdline)");
1074+
return false;
1075+
}
1076+
1077+
while (1) {
1078+
int c = fgetc(f);
1079+
if (c == ' ' || c == EOF) {
1080+
if (i == length) {
1081+
enabled = true;
1082+
break;
1083+
}
1084+
if (c == EOF) {
1085+
break;
1086+
}
1087+
i = 0;
1088+
} else if (c == option[i]) {
1089+
i++;
1090+
} else {
1091+
do {
1092+
c = fgetc(f);
1093+
} while (c != EOF && c != ' ');
1094+
i = 0;
1095+
}
1096+
}
1097+
1098+
fclose(f);
1099+
1100+
return enabled;
1101+
}
1102+
1103+
int enable_dummy_interface()
1104+
{
1105+
// See https://www.man7.org/linux/man-pages/man7/netdevice.7.html
1106+
1107+
const char *const name = "dummy0";
1108+
struct ifreq ifr;
1109+
int sockfd;
1110+
struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
1111+
struct sockaddr_in *netmask = (struct sockaddr_in *)&ifr.ifr_netmask;
1112+
1113+
if (snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name) >= IFNAMSIZ) {
1114+
perror("dummy interface name too long");
1115+
return -1;
1116+
}
1117+
1118+
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
1119+
if (sockfd < 0) {
1120+
perror("dummy interface socket");
1121+
return -1;
1122+
}
1123+
1124+
ifr.ifr_flags = IFF_UP;
1125+
if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
1126+
if (errno == ENODEV) {
1127+
// Most likely not enabled in the kernel, ignore quietly
1128+
close(sockfd);
1129+
return 0;
1130+
}
1131+
perror("dummy interface up");
1132+
close(sockfd);
1133+
return -1;
1134+
}
1135+
1136+
addr->sin_family = AF_INET;
1137+
if (inet_pton(AF_INET, "10.0.0.1", &addr->sin_addr) <= 0) {
1138+
perror("inet_pton address");
1139+
close(sockfd);
1140+
return -1;
1141+
}
1142+
if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
1143+
perror("dummy interface address");
1144+
close(sockfd);
1145+
return -1;
1146+
}
1147+
1148+
netmask->sin_family = AF_INET;
1149+
if (inet_pton(AF_INET, "0.0.0.0", &netmask->sin_addr) <= 0) {
1150+
perror("inet_pton mask");
1151+
close(sockfd);
1152+
return -1;
1153+
}
1154+
if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
1155+
perror("dummy interface mask");
1156+
close(sockfd);
1157+
return -1;
1158+
}
1159+
1160+
close(sockfd);
1161+
return 0;
1162+
}
1163+
10621164
int main(int argc, char **argv)
10631165
{
10641166
struct ifreq ifr;
@@ -1171,6 +1273,12 @@ int main(int argc, char **argv)
11711273
close(sockfd);
11721274
}
11731275

1276+
if (tsi_enabled()) {
1277+
if (enable_dummy_interface() < 0) {
1278+
printf("Warning: Couldn't enable dummy interface\n");
1279+
}
1280+
}
1281+
11741282
config_argv = NULL;
11751283
config_workdir = NULL;
11761284

0 commit comments

Comments
 (0)