Linux邻居子系统的细节之confirm-OpenVPN server模式的MAC地址学习

在《Linux实现的ARP缓存老化时间原理解析》一文中,我剖析了Linux协议栈IPv4的邻居子系统的转化,再次贴出那个状态机转化图,可是这个图更详细了些,因为它有一个外部输入,那就是confirm:




       请注意,如果socket或者路由子系统在上层confirm了一个neighbour,那么该arp将持续留在reachable状态而可以不用转换到stale状态。这个特性是有意义的。请观察一个现象:
1.本机IP地址为192.168.1.10/24,直连的机器IP地址为192.168.1.20/24,从本机ping对端;
2.将本机的/proc/sys/net/ipv4/neigh/eth0/base_reachable_time设置为4秒,对端的对应值设置为8秒;
3.抓包发现每隔8秒左右会有一个一个arp request从对端发来,符合上述的图示;
4.抓包始终未见有本端到对端的arp request,按说应该每隔4秒左右发出一个的啊;
5.修改对端设备的IP地址为192.168.1.30/24,本端在间隔4秒左右后,马上发出了arp request;

以上现象有2个疑点:为何本端在reachable状态到期了仍然不切换状态,不重新解析对端IP地址?为何对端的IP地址修改掉或者删除掉之后,本端马上发现了这一事实,间隔reachable到期时间后发出了arp request?
       要澄清上述两个疑点,就要从下向上来逐步定位,当我设置了iptables规则在INPUT上禁止ping reply接收时,和修改删除对端IP的效果一样,ping马上发现了这一点,间隔4秒左右发出了arp request。因此问题就在ping本身,对ping进行strace,发现其sendmsg的最后一个参数为MSG_CONFIRM,查阅man手册,发现:
MSG_CONFIRM (Since Linux 2.3.15)
              Tell the link layer that forward progress happened: you got a successful reply from the other side.  If  the  link
              layer doesn‘t get this it will regularly reprobe the neighbor (e.g., via a unicast ARP).  Only valid on SOCK_DGRAM
              and SOCK_RAW sockets and currently only implemented for IPv4 and IPv6.  See arp(7) for details.

由于对端只是接收ping request,进而直接在协议栈中回应ping reply,因此不会涉及socket,并且也没有涉及路由子系统中关于redirect等关联的confirm,因此对端严格按照IPv4邻居子系统的状态图转换,而本端则每每收到ping reply,就会confirm,进而使arp表项维持在reachable状态,一旦收不到ping reply,便不会再confirm,等到reachable状态到期,便进入短暂的stale,delay状态了,进而进入probe发出arp request。
       说了这么多关于arp的一个细节,旨在解释一个tap模式的OpenVPN运行在multi模式,即server模式时的MAC地址学习的问题。
       我们知道,OpenVPN在tap模式下可以看作一个虚拟的交换机,而且是学习型的,它学习的内容为:为每一个multi_instance关联一个MAC地址链表,凡是来自该multi_instance的以太帧的源MAC地址都会进入这个链表。这个链表的作用在于为从OpenVPN服务端返回到客户端的数据包关联一个multi_instance。对于一个从OpenVPN服务端发往客户端方向的数据包,其目的MAC地址肯定在某一个OpenVPN客户端后面或者是OpenVPN客户端的tap网卡本身。OpenVPN服务端用这个MAC地址作为键值检查MAC/instance表,最终找出一个multi_instance发送出去。
       现在考虑一个主动从OpenVPN服务端发送的数据包,当它到OpenVPN进程的时候,由于事先没有从OpenVPN客户端过来的任何数据包供OpenVPN服务端学习,因此数据包必须丢弃,因为它无法对应到任何一个multi_instance。是这样吗?NO!因为你没有考虑到arp。在以太网发送任何数据包之前,都要经过arp解析对端的IP地址,而arp请求是广播,将发送到所有的multi_instance,只有有来自某个OpenVPN客户端方向的arp回应,OpenVPN服务端将会学习到一条MAC/instance表项。因此不存在数据包被drop的可能。
       但是,如果OpenVPN服务端后面的机器发送数据包的时候,IP/MAC地址映射已经存在了,那么就不会发送arp请求了,也就没有机会让OpenVPN服务端从arp回应中学习了,此时数据包将会被丢弃。是这样吗?是的,但是如果你看懂了IPv4邻居子系统的状态转换图,就会等待reachable到期时间后再次重试。由于根本不可能有数据从OpenVPN客户端发来,因此就没有机会被confirm,所有最久的等待时间就是reachable+stale+delay的定时器时间和。然而有一种情况,如果服务端这边设置了一条永久的arp表项,那就完蛋了。
       OpenVPN运行在tap模式时,可以通过arp来自动学习MAC/instance映射,那么运行在tun模式下呢?由于IPv4除了DHCP等不具备任何自动配置机制,且DHCP又不是必须使用的,因此只能手工配置,这个在OpenVPN中就是iroute选项,即Internal route。
       自动学习比较不易,那么如果你仅仅只是为了使用OpenVPN连接两个远程网络,那么就别用server模式了,使用p2p,即pointopoint模式比较好,它只是进行简单的tun-link-link-tun的转发而已。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。