问题:
如何在代码中创建一个双线程桥接器(不使用brctl addbr br0
或一些类似的网络方法,而是编写代码),其中一个从 ETH1 获取以太网帧并将它们放在 ETH2 上,而另一个从 ETH2 获取它们并将它们放在ETH1 以某种方式使两个进程不连续读取彼此的以太网帧?
细节:
我正在尝试创建一个设备来保护系统之间的连接(对于很多我们无法更新的旧系统),为了做到这一点,我们需要将这个设备与另一个系统连接到旧系统的以太网端口上面向网络的以太网端口。基本上是一个硬件中间人。
我可以使用标准以太网桥和一些花哨的 IPTables 前后路由规则来完成几乎所有我需要的事情,但我想尝试实现一些代码来做到这一点。我已经在 C 和 Python 中尝试过这个,我最终创建了一个无限循环的以太网帧。例如,在 C 中,我可以打开一个到 ETH1 的套接字,以便在混杂模式下读取:
int open_eth_read_socket(char *interface_name) {
int socket_fd;
struct ifreq if_options;
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
// Get socket
socket_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(socket_fd < 0) exit(EXIT_ERROR);
// Zero ifreq
memset(&if_options, 0, sizeof(struct ifreq));
// Put interface_name in
strcpy(if_options.ifr_name, interface_name);
// Set timout
int ret = setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO,
(char *)&timeout,sizeof(timeout));
if(ret < 0) exit(EXIT_ERROR);
// Bind this socket to the specified interface.
ret = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
interface_name, strlen(interface_name));
if(ret < 0) exit(EXIT_ERROR);
// Get flags
if(ioctl(socket_fd, SIOCGIFFLAGS, &ifopts) < 0) exit(EXIT_ERROR);
// Add promisc flag
ifopts.ifr_flags |= IFF_PROMISC;
// Set flags
if(ioctl(socket_fd, SIOCSIFFLAGS, &ifopts) < 0) exit(EXIT_ERROR);
return socket_fd;
}
然后我打开一个到 ETH2 的套接字进行写入,我可以在两者之间设置程序逻辑。只要两个线程(C 中的 pthreads,Python 中的 threading.Thread)没有同时运行,ETH1->ETH2 就可以像 ETH2->ETH1 一样完美地工作。如果是这样,那么这个过程就像一座桥梁,所有的地狱都失败了。
ETH1->ETH2 线程从 ETH1 读取以太网帧并将它们写入 ETH2。当 ETH2->ETH1 线程去读取 ETH2 以太网套接字时,它会读取另一个线程写入的帧,然后无限循环开始。
Python 版本看起来很相似,但我尝试过使用 pcapy 和 dpkt,但都不起作用。我遇到了一个似乎遇到过类似问题的Scapy 桥问题,但那里的答案似乎并没有解释为什么会发生这种情况或真正如何解决它,而且Bogdan Paun的代码很好,但掩盖了如何如果一个人想学习来解决这个问题。