I am trying this tutorial for creating and using tun
interface. In my case, I want to use it inside a docker container. My host and docker container both are Linux with mknod support. I am trying to get tun interface inside the container to read packets from host but without using --network=host
.
Based on the docker run doc, I am mapping host /dev/net/tun
inside docker using --device
. Then adding capabilities NET_ADMIN
(also tried adding MKNOD
, NET_RAW
but does not seem to help). Then using the example tun reader below; which is example from above tutorial; with code added to create interface; tried to read the packets.
It can read packets from ping on 10.0.0.2 from within the container. But not able to read from ping on host. With --network=host
flag to docker run
, the tunx
interface is created on host and therefore ping works.
My question is, is there a to get it to work without using host network? Do I need any explicit iptables
rules to forward traffic between container and host?
tun_alloc
function is from this tutorial
docker command
docker run -it --device=/dev/net/tun:/dev/net/tun -cap-add=NET_ADMIN <image>
reader code
int main(void) {
const char *ifname = "tunx";
const char *ifaddr = "10.0.0.1/24";
char tun_name[IFNAMSIZ];
char buffer[2096];
int tun_fd = -1;
char cmd[1024] = "";
int err = -1;
strcpy(tun_name, ifname);
tun_fd = tun_alloc(tun_name, IFF_TUN); /* tun interface */
if (tun_fd < 0) {
fprintf(stderr, "failed to alloc_tun. tun_fd: %d\n", tun_fd);
exit(1);
}
printf("tun_fd: %d\n", tun_fd);
printf("ip commands \n");
snprintf(cmd, sizeof(cmd), "/bin/ip addr add dev %s %s", ifname, ifaddr);
err = system(cmd);
fprintf(stdout, "Running: %s, err: %d\n", cmd, err);
if (err < 0) {
fprintf(stderr, "failed system. Cmd:%s, err: %d (%s)\n", cmd, err, strerror(errno));
exit(1);
}
snprintf(cmd, sizeof(cmd), "/bin/ip link set %s up", ifname);
err = system(cmd);
fprintf(stdout, "Running: %s, err: %d\n", cmd, err);
if (err < 0) {
fprintf(stderr, "failed system. Cmd:%s, err: %d (%s)\n", cmd, err, strerror(errno));
exit(1);
}
while (1) {
/* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
int nread = read(tun_fd,buffer,sizeof(buffer));
if(nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
}
/* Do whatever with the data */
printf("Read %d bytes from device %s\n", nread, tun_name);
}
return 0;
}
--network host
(and you generally shouldn't) a container will run in its own network namespace and the tunnel interface will be local to the container. I'd run this process directly on the host and not in a container. – Recurrent