NA(192.168.1.0/24)--(eth0)R(eth1)--NB(192.168.2.0/24)
a(eth0:192.168.1.2)--(eth0:192.168.1.1)R(eth1:192.168.2.1)--b(eth0:192.168.2.2)
一:a配置指向NB的路由的情況:
在R開啟arp代理的情況下如果在a上ping b,結果是什麼,顯然資料要發送出去首先需要arp,此時arp請求的mac地址實際上R的mac地址,
並不需要arp代理功能,因為有路由,ping包在出去前就已經得知下一跳是R,因此arp會直接請求R的mac地址。
二:a沒有配置路由的情況:
此時如果直接ping的話,會得到“沒有路由”的錯誤資訊,也就是說資料在出去的過程中,查詢路由這一步就會失敗,arp請求是根本不會發出
的,因此R的arp代理根本不會影響到這次ping。
問題:那麼怎樣使得R的arp代理其作用呢?
答案:這個問題可以轉化為如何發出arp請求的問題,只要arp發出了,接下來必然要傳輸資料了,再者,arp對於上層是不可見的。兩種方式,
一種是將a的ip位址遮罩設為n位,n為a和b從最高位開始一直保持一致的位元,這樣a會認為b和自己在一個網段,arp最終會發出去,並且直
接請求b的mac地址;第二種情況就是不使用ping,而是自己寫一個發送程式,設定SO_DONTROUTE標誌並且綁定一個出口裝置即可,這樣
的話,無論有沒有路由,資料都會按照既定的出口發出。上述兩種情況下,R均會收到這個arp請求,此時arp代理將要起作用了。
R會檢查自己的路由表,看看自己能否處理這個arp請求包中的ip地址,如果能的話,R會回複自己的mac地址來代理b或者說欺騙a,注意,
R會尋找自己的路由表,看看自己能否處理或者代理處理,linux的核心使用了一種一致的方式:首先arp_process會調用ip_route_input來
以arp請求包中的ip作為尋找鍵來尋找路由表,接著要麼有個結果,要麼沒有查到,沒有查到的話就不會發送arp回應,僅僅更新自己的arp表,
如果查到的話分為兩種情況,一種情況是這個ip就是自己的一個ip,另一種情況是這個ip不是自己的ip,linux的代碼如下(arp_process函數):if (addr_type == RTN_LOCAL) { //如果自己有這個ip地址 (***)
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n) {
...//可能的話發送arp回複
} else if (IN_DEV_FORWARD(in_dev)) { //如果請求的ip地址不是自己的,但是自己可能代理之
if ((rt->rt_flags&RTCF_DNAT) ||
(addr_type == RTN_UNICAST && rt->u.dst.dev != dev && //注意這裡的裝置判斷,如果尋找到的出口和arp請求的入口是一個裝置的話就不必發送arp代理回應了,因為這樣沒有意義
(arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
...//可能的話發送arp代理的回複
}
}
因此,只要arp請求能夠發送到R,R的arp_process總是會有所動作的,要麼僅僅回複自己的mac地址,要麼不回複自己的mac地址。不管在
arp請求中ip地址是自己的情況還是雖然不是自己的但是自己可以代理的情況,R都會發送自己的mac地址作為arp回應的。可是,有個對ip地
址配置理解很深的傢伙破壞了這一切。
他知道一個裝置可以配置多個ip地址,於是他索性為a的eth0配置了一個192.168.2.3,這樣a和b不就在同一個網段了嗎?但是他不知道,
任何邏輯的東西必然需要物理設施的支撐。我們可以在同一物理網段隨意配置不同的邏輯網段,但是反過來我們卻不能在不同的物理網段配置
同一個邏輯網段。下面看一下發生了什麼:由於linux是先尋找路由再填寫源ip的(將源ip寫成出口裝置的ip,並且盡量[忽略複雜情況]和下一跳
在同一網段),那麼route模組肯定會將源ip寫成192.168.2.3,於是將192.168.2.3作為arp請求發送出去了,R收到後會以192.168.2.3進
行路由,不考慮細節的情況下或者對路由不求甚解的情況下會得出這個這條路由在eth1一端的結論,可是,這是錯誤的結論,正確的結論是根
本不會找到路由。因為: 添加一條路由的時候,該路由項會綁定一個裝置(inet_rtm_newrule函數):
new_r->r_ifname[IFNAMSIZ-1] = 0;
new_r->r_ifindex = -1;
dev = __dev_get_by_name(new_r->r_ifname);
if (dev)
new_r->r_ifindex = dev->ifindex;
一條路由決定了一個目的地的出口為該裝置,反過來任何從這個目的地網段來的資料包必須從該裝置進入,這就是路由器隔離網段的實質。如
果一個路由器有eth0和eth1兩個網口,通往NET1的資料從eth0出去,此時從eth1進來一個NET1的包,那是不合法的。既然資料通訊必然
需要鏈路層解析arp,因此只要arp邏輯卡得嚴格的話就能起到隔離網段的作用,上述(***)完全做到了這一點,ip_route_input要麼因為
arp的入口網卡裝置和路由的出口網卡裝置不一致而失敗,要麼尋找到路由,該路由的出口裝置正是arp請求的入口裝置,然後
rt->u.dst.dev != dev判斷將會失敗,只有在路由尋找的結果就是本機地址或者完全符合代理條件時才有可能發送arp回應,確保裝置
(主機/路由器等三層以及三層以上裝置)接收到和自己某個ip同一網段的arp請求時,僅在和自己某個ip相等時才回應,並且只能從收到arp請求
的裝置回應,在裝置接收到不同網段的arp請求時,會代理回複arp回應,並且被代理的ip的路由出口裝置一定不是arp請求的入口裝置。因此
不能指望將兩個由一台路由器串連的不同物理網段配製成一個邏輯網段而實現鏈路層意義的互連(通過直接或者代理的arp),必須使用路由配
置這樣的三層機制才能實現互連。