一 背景
arping 命令是(shi)用于(yu)發送arp請求到相鄰主(zhu)(zhu)機的工具,通過目(mu)的主(zhu)(zhu)機ip獲取目(mu)的主(zhu)(zhu)機mac地址,可用于(yu)探測局(ju)域網內某個ip是(shi)否已(yi)經被使用。
前段(duan)時間碰到一個問題,源(mask 16)和目的(de)(mask 24)配置(zhi)的(de)網(wang)段(duan)長度(du)不一致,且源端(duan)使用了*.0 結尾的(de)地(di)址,導(dao)致網(wang)絡(luo)不通,arping探測被當作為網(wang)絡(luo)地(di)址返回失敗,那么(me)具體流程(cheng)是什(shen)么(me)樣的(de)呢。
二 現場模擬

正常(chang)情況下,同網段arping返回對方mac地址

指定源ip為網段(duan)地址,訪問同(tong)一(yi)server端,返回失敗。
三 流程分析
1 server端通過tcpdump抓包(bao)

如上(shang)圖,上(shang)半(ban)部分(fen)為(wei)正常arping請(qing)求,下半(ban)部為(wei)sip為(wei)*.0情況下報文(wen)(wen)信(xin)息,可以(yi)看到該情況下,沒有回復reply報文(wen)(wen)。
2 代碼分析
static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
const struct arphdr *arp;
/* do not tweak dropwatch on an ARP we will ignore */
if (dev->flags & IFF_NOARP ||
skb->pkt_type == PACKET_OTHERHOST ||
skb->pkt_type == PACKET_LOOPBACK)
goto consumeskb;
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto out_of_mem;
/* ARP header, plus 2 device addresses, plus 2 IP addresses. */
if (!pskb_may_pull(skb, arp_hdr_len(dev)))
goto freeskb;
arp = arp_hdr(skb);
if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4)
goto freeskb;
memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
return NF_HOOK(NFPROTO_ARP, NF_ARP_IN,
dev_net(dev), NULL, skb, dev, NULL,
arp_process);
consumeskb:
consume_skb(skb);
return NET_RX_SUCCESS;
freeskb:
kfree_skb(skb);
out_of_mem:
return NET_RX_DROP;
}
在(zai)經過(guo)(guo)一系(xi)列校(xiao)驗和hook函數過(guo)(guo)濾后,進入arp_process(), 該函數流(liu)程(cheng)比較復雜,正常流(liu)程(cheng)會在(zai)通過(guo)(guo)ip_route_input_noref()一系(xi)列路由(you)檢查后,返回 reply報文(wen)。

下面是ip_route_input_noref調用(yong)流程
ip_route_input_noref
ip_route_input_rcu
ip_route_input_slow
fib_validate_source
__fib_validate_source
最終通過fib_lookup(), 進行反向路由查找,其中*.0會被(bei)當做網(wang)絡地址,返回res.type為RTN_BROADCAST

不(bu)滿足條(tiao)件,導致__fib_validate_source()返(fan)回(hui)EINVAL,最終結(jie)果就是沒有回(hui)復reply報(bao)文,探測不(bu)通(tong)。