天天看點

arp/ip位址/路由--總之很亂

正常情況下,隻要有到一台機器的路由,不管服務監聽的哪個網卡的哪個位址,也不管請求從哪個網卡進入,隻要這個請求的目的ip是該機器的一個ip,連接配接就能成功,當然你可以設定政策路由或者多表路由表項阻止的目的位址沒有配置在資料進入網卡上的情況。

執行個體:

R有兩塊網卡,各個網卡以及環回口配置如下:

eth0:172.16.0.1

eth1:192.168.0.1

lo:127.0.0.1

lo:0:1.2.3.4

為了隐藏lo口上的ip,配置如下

sysctl -w net.ipv4.conf.lo.arp_ignore=2

PC有一塊網卡,和R的eth0直連:

eth0:172.16.0.3

在PC上ping 1.2.3.4,不通。随後在PC上添加一條路由:

1.2.3.4 gw 192.168.0.1

然後再ping 1.2.3.4,通了。

arp_ignore的作用:

1.值為0--隻要arp請求能被接收,均回複arp請求,mac位址為接收arp請求的網卡的mac

2.值為1--隻有ip配置在arp請求進入的網卡上才回複

3.值為2--2的情況必須滿足,并且arp請求的來源ip和請求ip屬于同一個子網才回複

4.值為3--如果arp請求的ip是scope為host的,則不回複

5.值為7--一律不回複

注解:

1.scope的作用:scope表示一個範圍,它是ip位址的屬性,也就是說ip在該範圍内是可用的,可被尋址的,核心的安排很好,枚舉rt_scope_t實際上表示的是一個到目的地的“距離”,越往後數值越大,範圍越小。比如127開頭的ip隻有本機可以使用,是以它的scope就是host,這個scope在為網卡配置ip位址的時候是可以設定的,如果你設定該ip的scope是host,那麼這意味着很可能隻有你自己機器内部需要這個ip,可以很友善的将arp_ignore設為4來對外隐藏這個ip位址。host位址可以用于負載均衡和實作虛拟網卡或者多網卡綁定,link位址用于直連主機,global可以随意使用。不僅僅ip位址有scope屬性,路由也有scope屬性,最後簡述。

2.arp請求從哪個網口進入,那麼arp回複則一定從該網卡出去,參見arp_process函數,因為入口dev也是路由查找鍵的一部分

源碼級别:

1.值為0--直接傳回“可回複arp請求入口的mac”

2.值為1--以dst = 0;scope = RT_SCOPE_HOST;調用inet_confirm_addr,由後者抉擇

3.值為2--僅以scope為host調用inet_confirm_addr

4.值為3--以scope為link調用inet_confirm_addr

不管值為幾,最終如果要回複arp請求的話,回複的都是arp請求入口的mac位址,這個arp_ignore函數僅僅判斷“能不能回複”而已,它随着核心參數的配置不同,限制條件也不同。下面看一下inet_confirm_addr函數的實作:

u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)

{

...

    if (dev) {   //對于接收到arp廣播,将要發送arp單點傳播回應的主機,dev嚴格是arp請求到來的dev,是以在dev被設定的情況下不能指望非arp請求進入網卡上的ip回應

        if ((in_dev = __in_dev_get_rcu(dev)))

            addr = confirm_addr_indev(in_dev, dst, local, scope);

        return addr;

    }

    for (dev = dev_base; dev; dev = dev->next) {  //如果沒有指定dev,則周遊所有的dev,但是仍然不能指望配置在loopback上的一個ip位址回應,因為loopback根本就沒有mac位址,并且既然它永遠不會接收arp請求,它也就永遠不會回複之,見實驗0。

        if ((in_dev = __in_dev_get_rcu(dev))) {

            if (addr)

                break;

        }

    return addr;

}

實驗0(注:在進行下一步的ping時,清掉arp緩存):

PC1的eth0:192.168.1.3  UP

PC1的eth1:172.16.1.3    沒插網線

PC1的eth1:1:1.2.3.4 scope link

PC1的lo:1:4.3.2.1 scope link

PC2的eth0:192.168.1.4    UP 和PC1的eth0直連

1.PC1的eth0的arp_ignore設定為3

在PC2上ping 1.2.3.4,不通,ping 4.3.2.1,不通。

在PC2上添加到1.2.3.4和到4.3.2.1的路由,再ping,全通,并且arp檢視到的二ip的mac位址為PC1的eth0的mac位址

2.PC1的eth0的arp_ignore設定為0

按照1重新ping,全部通,因為arp請求隻要被接收就被回複

3.PC1的eth0的arp_ignore設定為1和2

按照1重新ping,全部不通,因為目的ip沒有配置在接收arp請求的網卡上,另發送者的ip和ping的目的位址也沒有在一個子網

4.PC1的eth0的arp_ignore設定為3,但是重新如下配置:

PC1的eth1:1:1.2.3.4 scope host

PC2上ping 1.2.3.4,不通,因為arp_ignore為3的話雖然不檢查網卡裝置和ip的關聯性,但是卻不允許回複scope為host的位址

     最後通過上述的分析以SO_DONTROUTE選項為基準來分析一下路由的scope屬性。路由的scope屬性表示目的位址距離本地的遠近,和ip位址的scope一樣,也分為host,link,global之類的,在通過ip route指令添加路由的時候,如果為一條路由添加了網關(通過via參數),那麼你就無法使用scope link參數,也就是說通過網關進行路由(via)和直連路由隻能采取一種,是以在路由添加的時候,這個限制條件使得scope不會混亂。而SO_DONTROUTE參數的實質就是不通過網關進行路由,是以帶有該選項的連接配接發送資料前查找路由時僅會查找scope為link的表項,如果你不相信dontroute的行為真的是這樣,你可能會想辦法設定一條路由,然後逼着dontroute的資料包走向你設定的路由,也就是給它一個“下一跳”,而不讓它直接到達目的地,那麼你能把這條路由加入嗎?如果你設定了via nexthop參數,那麼scope就不能為link,是以查找路由就會失敗,然後轉入直接發送,如果你添加了一條直連路由,那麼很好,路由查找不會失敗,協定棧會使用查找到的結果。因為dontroute的政策是查到路由就按照路由發送,查不到就直接發送,前提設定了一個出口網卡裝置,帶有dontroute标志的套結字發送的資料包不是不查找路由,相反它還可能會找到一條路由并使用它,如果它是直連路由的話。

 本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1271756

繼續閱讀