我正在使用以下命令打开 TAP 设备
p->fd = open("/dev/net/tun", O_RDWR);
// skipping error handling code
ifr.ifr_flags = IFF_TAP | IFF_ONE_QUEUE | IFF_NO_PI;
strncpy(ifr.ifr_name, p->name, IFNAMSIZ-1);
result = ioctl(p->fd, TUNSETIFF, &ifr);
// skipping error handling and setting ipv4 address & netmask code
ifr.ifr_flags = (IFF_UP | IFF_RUNNING);
result = ioctl(dummySock, SIOCSIFFLAGS, &ifr);
我面临的问题是,当应用程序(比如 mozilla)想要通过 Tap 设备发送数据包时,它需要获取 dst mac 地址。于是内核发出了一个ARP请求。我正在编写的应用程序转发 arp 请求(通过物理 eth 设备上的原始套接字)并获取 arp 回复。这个arp回复被转发回tap设备,但是内核拒绝接受这个。如果我手动添加 arp 条目,则不会生成 arp 请求,并且有两种方式的 ip 数据包交换(mozilla 很高兴)。
Wireshark 能够接收数据包并且没有发现任何错误。 ICMPv6 数据包(邻居请求和通告)的情况也是如此。设备上侦听的任何应用程序都会完整地获取数据包。但内核不对其进行 ARP/ICMP 处理。
我的问题是,为什么内核不接受 arp 回复/ICMPv6 消息?我们需要调用一些 ioctl 调用吗?
Edit:
以下是在 Tap 设备“ethgress”处捕获的数据包(tshark 输出)的详细信息
9 16.548328 fc00:1::2 -> ff02::1:ff00:1 ICMPv6 86 Neighbor Solicitation
10 17.243247 fc00:1::100 -> fc00:1::2 ICMPv6 86 Neighbor Advertisement
11 17.548652 fc00:1::2 -> ff02::1:ff00:1 ICMPv6 86 Neighbor Solicitation
12 17.668736 fc00:1::100 -> fc00:1::2 ICMPv6 86 Neighbor Advertisement
这是“ethgress”的 ifconfig 输出
ethgress Link encap:Ethernet HWaddr 00:01:02:03:04:05
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:83 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10000
RX bytes:0 (0.0 b) TX bytes:7062 (6.8 KiB)
可以看出,内核拒绝接受收到的 ICMPv6 数据包。但 tx 数据包会增加。
Tap 设备“ethgress”配置有 IPv6 地址 fc00:1::2,应用程序希望与 fc00:1::1 进行通信。 fc00:1::1 与 fc00:1:100 位于同一接口,后者使用正确的 MAC 地址响应邻居通告(目标 IP 是该数据包中的 fc00:1::1)。 Tcpdump 能够捕获它,wireshark/tshark 能够解码它,并表示它是一个正确形成的数据包。但 Rx 计数器不会由内核递增,也不会更新其 arp 缓存。 ARP 数据包的情况也是如此。
Edit 2:
网络看起来像这样。有两个外部盒被配置为冗余。只有其中之一会处于活动状态。它们分别通过物理网卡连接到一台电脑。我正在编写的应用程序在这台电脑上运行,并在每个网卡上打开一个原始套接字。它还会打开 TAP 设备。 NIC 未配置 IP 地址。 TAP 设备配置有 IPv4 和 IPv6 地址。一个标准应用程序,比如 mozilla,通过 Tap 设备打开一个套接字,并希望连接到活动盒。为此,内核在 Tap 设备上生成 ARP 请求/邻居请求消息。应用程序读取此消息并将其转发到两个 NIC。活动框使用 ARP 回复来响应 ARP 请求,应用程序将其读取并将其写入 TAP 设备。这个arp回复数据包被tcpdump捕获,但内核不会更新其arp缓存。两个 NIC 和 TAP 设备的 MAC 地址相同。
要求的其他参数。
cat /proc/sys/net/ipv4/conf/all/log_martians
0
cat /proc/sys/net/ipv4/conf/all/rp_filter
1
cat /proc/sys/net/ipv4/conf/all/arp_filter
0