【背景】:
arm板有2个网口A和B,A口通过网线连接PC,PC的IP配置的网关为ARM的A网口IP,具体如下:
PC的IP配置: 172.20.0.111 255.255.0.0 172.20.0.16
ARM的网卡A: 172.20.0.16 255.255.0.0 default gw
ARM的网卡B: 172.21.0.17 255.255.0.0 default gw
【现象】:pc ping 172.21.0.17 能够ping通,在pc上通过wireshark抓包,发现icmp报文的mac地址是ARM的网卡A,ip地址是ARM的网卡B。
【分析1】:想到/proc/sys/net/ipv4/xx/arp_ignore和arp_announce这2个参数,对于arp报文的多网口转发,查看ARM的板卡配置,arp_ignore=1 arp_announce=2,已经禁止网口间arp转发;并且pc的arp表查看,没有学到网口B的mac地址。
【分析2】:想到linux的Ip转发,/proc/sys/net/ipv4/ip_forward这个参数,查看ARM板卡的配置,ip_forward这个参数是0,表示默认关闭ip报文转发。
【分析3】:分析Linux内核ipv4的路由查找代码,在ipv4收到包后,分析如果非广播和多播报文,会进行路由查找,先查找local route表,没有找到再查找main route表。local route表总查找到dstip地址就是网口B的ip地址,直接建立路由连接。
【更改】:在local route查找过程中,匹配dstip和本网卡的ip,如果不是同一个网段,则直接丢弃该IP包。
【代码】:在net/ipv4/fib_frontend.c的__fib_validate_source()函数中,增加如下:
if (!rpf && !fib_num_tclassid_users(net) &&
(dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev)))
#if 0
{
struct in_ifaddr **ifap = NULL;
struct in_ifaddr *ifa = NULL;
if(idev->ifa_list)
{
for (ifap = &idev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next)
{
if((fl4.saddr & ifa->ifa_mask) == (ifa->ifa_local & ifa->ifa_mask))
{
//pr_info("net:%s saddr:%pI4 ifa_address:%pI4 ifa_local:%pI4 mask:%d", idev->dev->name, &fl4.saddr, &ifa->ifa_address,
// &ifa->ifa_local, ifa->ifa_mask);
goto last_resort;
}
}
}
goto e_inval;
}
#endif
goto last_resort;