1. 程式人生 > >arp ignore背後的rp filter與arp filter

arp ignore背後的rp filter與arp filter

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

作業系統:Debian 3
機器和網路配置:
測試機器eth0:
inet addr:192.168.1.82
當事機配置:
eth0:
inet addr:192.168.1.247/HWaddr 00:15:17:F4:9A:E0
eth1:
inet addr:192.168.1.246/HWaddr 00:15:17:F4:9A:E1
eth0和eth1插於同一臺交換機上,配置同一網段ip,路由如下:
192.168.1.0 * 255.255.255.0 eth0
192.168.1.0 * 255.255.255.0 eth1
測試過程:
1.將當事機的核心引數net.ipv4.conf.XXX.arp_ignore設定為0
2.清除測試機的arp快取
3.在測試機上ping當事機的eth0或者eth1
期望結果:
既然arp_ignore設定成了0,那麼如果在測試機上抓取arp的回覆包的話,應該有兩條回覆,分別來自當事機的eth0和eth1:
15:20:34.665840 arp reply 192.168.1.247 is-at 00:15:17:f4:9a:e1
15:20:34.665856 arp reply 192.168.1.247 is-at 00:15:17:f4:9a:e0
然後測試機取晚到的那一個作為自己的arp快取項。可是隻抓取到了一個arp回覆包,並且在當事機的eth1上抓取arp請求包,已經抓到了,只是eth1沒有回覆:
15:20:34.665856 arp reply 192.168.1.247 is-at 00:15:17:f4:9a:e0
很顯然只有eth0回覆了,而eth1沒有回覆,這是怎麼回事呢?檢視當事機的路由,發現始終是:
192.168.1.0 * 255.255.255.0 eth0
192.168.1.0 * 255.255.255.0 eth1
...
即使將eth1 down掉然後再起來路由也依然如此,並沒有交換位置,而arp回覆的恰恰就是eth0的mac地址,直觀感覺和路由有關係,再看arp處理的原始碼,發現核心功能全在arp_process,而最最核心的莫非下面的小段:
if (arp->ar_op == htons(ARPOP_REQUEST) && [0]ip_route_input(skb, tip, sip, 0, dev) == 0) {
    rt = (struct rtable*)skb->dst;
    addr_type = rt->rt_type;
    if (addr_type == RTN_LOCAL) { //查詢本機的ip地址對應的mac,路由結果必然是local的
        n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
        if (n) {
            int dont_send = 0;
            if (!dont_send) //ignore判斷,太熟悉了,略過
                [2]dont_send |= arp_ignore(in_dev,dev,sip,tip);
            [1]if (!dont_send && IN_DEV_ARPFILTER(in_dev)) //filter判斷,本質上也是在確保arp回覆包路由結果的出口裝置和arp請求的入口裝置相一致
                dont_send |= arp_filter(sip,tip,dev);
            if (!dont_send)
                arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
            neigh_release(n);
...
可見影響arp回覆的是上述的[0],[1]和[2],而不僅僅是[2],因此肯定是[0]或者[1]中使得arp回覆沒能傳送,先看[0],那就是一個路由選擇,注意,一般情況下,路由選擇僅僅根據目的ip地址進行查詢,一般不管出入口裝置資訊的,因此,根據當事機上的路由表情況,如果發現要有包去往192.168.1.0/24網段,那麼肯定會選擇第一個找到的路由,就是eth0出口的路由,在ip_route_input的內部如果路由的結果是本機的話(對於一般的arp請求,這是肯定的),那麼會呼叫fib_validate_source(細節在rfc1812):
if (res.type == RTN_LOCAL) {
    int result;
    result = fib_validate_source(saddr, daddr, tos,
                loopback_dev.ifindex,
                dev, &spec_dst, &itag);
正是這個fib_validate_source使得本來能成功的路由查詢失敗了:
int fib_validate_source(...)
{
    struct in_device *in_dev;
    //將目的地址和源地址反轉,驗證如此的路由出口是否和正方向的入口一致。比如如果一個包的源地址是s1,目的地址是d1,從e1進入,那麼在開啟源驗證的情況下,源為d1,目的為s1的路由出口必須是e1,正所謂從哪裡進入,從哪裡出去
    struct flowi fl = { .nl_u = { .ip4_u =
                      { .daddr = src,
                    .saddr = dst,
                    .tos = tos } },
                .iif = oif };
    ...
    in_dev = __in_dev_get(dev);
    if (in_dev) {
        no_addr = in_dev->ifa_list == NULL;
        rpf = IN_DEV_RPFILTER(in_dev); //是否啟用源地址驗證,這是通過核心引數net.ipv4.conf.eth0.rp_filter的值來決定的
    }
    ...
    if (fib_lookup(&fl, &res))
        goto last_resort;
    ...
    if (FIB_RES_DEV(res) == dev)
    {
        //...如果反方向向的路由出口裝置和正方向的入口裝置一致,那麼不會有問題,也是期望的
        return ret;
    }
    ...
    if (rpf) //如果開啟了源地址驗證,而反方向的出口又和正方向的入口不一致,那麼出錯!
        goto e_inval;
    ...
}
現在由於eth1已經抓到了arp請求包,並且ip_route_input也可以路由:
192.168.1.0 * 255.255.255.0 eth1
可是卻沒有傳送arp回覆,根據上面的理論分析看一下net.ipv4.conf.eth0.rp_filter這個值,果然在當事機上該值為1,很顯然是在fib_validate_source失敗了,現在將其改為0,再次進行上述測試,和期望的一樣,得到了兩條arp回覆,核心文件Documentation/networking/ip-sysctl.txt中有rp_filter的條目,其最後:
Default value is 0. Note that some distributions enable it in startup scripts.
因此我們知道,Debian 3就是這裡的one of 'some distributions'。
     除了這個rp_filter之外,另一個影響arp回覆的就是arp_filter,net.ipv4.conf.XXX.arp_filter這個值得預設值是0,也就是不做檢查,如果將之設定成1,即使rp_filter為0(停用源地址驗證),arp回覆也是不會發送的,看arp_filter的程式碼,發現其和fib_validate_source的實現很類似,只是簡單很多。既然rp_filter已經能搞定出口入口相一致的問題,為何要在arp模組中再次存在arp_filter呢?這是一個層次的問題,rp_filter是對整個路由系統起作用的,而arp_filter僅僅針對arp系統,二者的共存旨在解決路由系統和arp系統的配置策略不一致的問題。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述