docker内部的tun接口无法从主机读取数据包

docker内部的tun接口无法从主机读取数据包,docker,dockerfile,iptables,tun,mknod,Docker,Dockerfile,Iptables,Tun,Mknod,我正在尝试创建和使用tun接口。在我的例子中,我想在docker容器中使用它。我的主机和docker容器都是支持mknod的Linux。我试图让容器内的tun接口从主机读取数据包,但不使用--network=host 基于,我正在使用--device在docker内部映射主机/dev/net/tun。然后添加功能NET\u ADMIN(也尝试添加MKNOD,NET\u RAW,但似乎没有帮助)。然后使用下面的示例tun阅读器;这是上面教程中的示例;添加代码创建接口;我试着读那些包 它可以从容器中

我正在尝试创建和使用
tun
接口。在我的例子中,我想在docker容器中使用它。我的主机和docker容器都是支持mknod的Linux。我试图让容器内的tun接口从主机读取数据包,但不使用
--network=host

基于,我正在使用
--device
在docker内部映射主机
/dev/net/tun
。然后添加功能
NET\u ADMIN
(也尝试添加
MKNOD
NET\u RAW
,但似乎没有帮助)。然后使用下面的示例tun阅读器;这是上面教程中的示例;添加代码创建接口;我试着读那些包

它可以从容器中读取10.0.0.2上ping的数据包。但无法从主机上的ping读取。通过将
--network=host
标志设置为
docker run
,将在主机上创建
tunx
接口,因此ping工作

我的问题是,在不使用主机网络的情况下,是否有一种方法可以让它工作?我是否需要任何明确的
iptables
规则来转发容器和主机之间的流量

tun_alloc
函数来自

docker命令

docker run -it --device=/dev/net/tun:/dev/net/tun -cap-add=NET_ADMIN <image>
docker run-it--device=/dev/net/tun:/dev/net/tun-cap add=net\u ADMIN
读卡器代码

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;
}
int main(无效){
常量字符*ifname=“tunx”;
常量字符*ifaddr=“10.0.0.1/24”;
char tun_名称[IFNAMSIZ];
字符缓冲区[2096];
int tun_fd=-1;
char cmd[1024]=“”;
int err=-1;
strcpy(tun_name,ifname);
tun_fd=tun_alloc(tun_名称,IFF_tun);/*tun接口*/
如果(tun_fd<0){
fprintf(stderr,“分配tun失败。tun\u fd:%d\n”,tun\u fd);
出口(1);
}
printf(“tun\u fd:%d\n”,tun\u fd);
printf(“ip命令\n”);
snprintf(cmd,sizeof(cmd),“/bin/ip addr add dev%s%s”,ifname,ifaddr);
err=系统(cmd);
fprintf(标准输出,“运行:%s,错误:%d\n”,命令,错误);
如果(误差<0){
fprintf(stderr,“失败的系统。Cmd:%s,错误:%d(%s)\n)”,Cmd,err,strerror(errno));
出口(1);
}
snprintf(cmd,sizeof(cmd),“/bin/ip链接设置%s”,ifname);
err=系统(cmd);
fprintf(标准输出,“运行:%s,错误:%d\n”,命令,错误);
如果(误差<0){
fprintf(stderr,“失败的系统。Cmd:%s,错误:%d(%s)\n)”,Cmd,err,strerror(errno));
出口(1);
}
而(1){
/*请注意,“缓冲区”应至少为接口的MTU大小,例如1500字节*/
int nread=读取(tun_fd,buffer,sizeof(buffer));
如果(nread<0){
perror(“从接口读取”);
关闭(tun_fd);
出口(1);
}
/*对数据做任何事*/
printf(“从设备%s\n读取%d字节”,nread,tun_name);
}
返回0;
}

Docker的一个具体目标是,容器进程不能执行主机全局操作,例如修改网络环境。如果不使用
--networkhost
(通常不应该),容器将在其自己的网络命名空间中运行,并且隧道接口将是容器的本地接口。我会直接在主机上运行这个过程,而不是在容器中运行。@DavidMaze有没有办法限制容器对特定接口的访问?然后,也许我可以在主机上创建tunx接口,并限制容器对该接口的访问。我不需要完全访问主机网络,只需要一个tun接口。Docker的一个具体目标是容器进程不能做主机全局的事情,比如修改网络环境。如果不使用
--networkhost
(通常不应该),容器将在其自己的网络命名空间中运行,并且隧道接口将是容器的本地接口。我会直接在主机上运行这个过程,而不是在容器中运行。@DavidMaze有没有办法限制容器对特定接口的访问?然后,也许我可以在主机上创建tunx接口,并限制容器对该接口的访问。我不需要完全访问主机网络,只需要一个tun接口。