一、IP隧道技術
IP隧道技術:是路由器把一種網絡層協議封裝到另一個協議中以跨過網絡傳送到另一個路由器的處理過程。IP 隧道(IP tunneling)是將一個IP報文封裝在另一個IP報文的技術,這可以使得目標為一個IP地址的數據報文能被封裝和轉發到另一個IP地址。IP隧道技術亦稱為IP封裝技術(IP encapsulation)。IP隧道主要用於移動主機和虛擬私有網絡(Virtual Private Network),在其中隧道都是靜態建立的,隧道一端有一個IP地址,另一端也有唯一的IP地址。移動IPv4主要有三種隧道技術,它們分別是:IP in IP、最小封裝以及通用路由封裝。更多信息可以參看百度百科:IP隧道 和 隧道技術 。
Linux系統內核實現的IP隧道技術主要有三種(PPP、PPTP和L2TP等協議或軟件不是基於內核模塊的):ipip、gre、sit 。這三種隧道技術都需要內核模塊 tunnel4.ko 的支持。
- ipip 需要內核模塊 ipip.ko ,該方式最為簡單!但是你不能通過IP-in-IP隧道轉發廣播或者IPv6數據包。你只是連接了兩個一般情況下無法直接通訊的IPv4網絡而已。至於兼容性,這部分代碼已經有很長一段歷史了,它的兼容性可以上溯到1.3版的內核。據網上查到信息,Linux的IP-in-IP隧道不能與其他操作系統或路由器互相通訊。它很簡單,也很有效。
- GRE 需要內核模塊 ip_gre.ko ,GRE是最初由CISCO開發出來的隧道協議,能夠做一些IP-in-IP隧道做不到的事情。比如,你可以使用GRE隧道傳輸多播數據包和IPv6數據包。
- sit 他的作用是連接 ipv4 與 ipv6 的網絡。個人感覺不如gre使用廣泛 。
三個模塊的信息如下:
- # sit模塊
- [root@localhost ~]# modinfo sit
- filename: /lib/modules/2.6.32-642.el6.x86_64/kernel/net/ipv6/sit.ko
- alias: netdev-sit0
- license: GPL
- srcversion: AF73F62BA39C407E20C4F05
- depends: ipv6,tunnel4
- vermagic: 2.6.32-642.el6.x86_64 SMP mod_unload modversions
- # ipip模塊
- [root@localhost ~]# modinfo ipip
- filename: /lib/modules/2.6.32-642.el6.x86_64/kernel/net/ipv4/ipip.ko
- alias: netdev-tunl0
- license: GPL
- srcversion: AF7433BD67CBFC54C10C108
- depends: tunnel4
- vermagic: 2.6.32-642.el6.x86_64 SMP mod_unload modversions
- # ip_gre模塊
- [root@localhost ~]# modinfo ip_gre
- filename: /lib/modules/2.6.32-642.el6.x86_64/kernel/net/ipv4/ip_gre.ko
- alias: netdev-gretap0
- alias: netdev-gre0
- alias: rtnl-link-gretap
- alias: rtnl-link-gre
- license: GPL
- srcversion: 163303A830259507CA00C15
- depends: ip_tunnel
- vermagic: 2.6.32-642.el6.x86_64 SMP mod_unload modversions
二、ip tunnel 配置
實際應用中,以上提到的三種ip tunnel 技術和VPN技術一樣,多用於跨公網的網絡中(當然跨網段的內網環境也適用)。如上圖所示,我搞了兩台虛機,其中eth0網段就類似於常見的公網網絡。 eth1網絡為各自的私網 。最終實現效果是實現兩台主機的 eth1網絡可以互通。這里測試中使用的是基於gre模式進行的實現,如果使用ipip、sit,只需要把modprobe后面的模塊換掉,把ip tunnel 命令中mode后面的字符替換掉即可。
1、ipv4網絡中的配置
a主機配置如下:
- #modprobe ipip
- #modprobe ip_gre
- #ip tunnel add tun0 mode gre remote 192.168.122.90 local 192.168.122.80 ttl 64
- #ip link set tun0 up
- #ip addr add 192.168.1.80 peer 192.168.2.90 dev tun0
- #ip route add 192.168.2.0/24 dev tun0
- #iptables -F
b主機配置如下:
- #modprobe ipip
- #modprobe ip_gre
- #ip tunnel add tun0 mode gre remote 192.168.122.80 local 192.168.122.90 ttl 64
- #ip link set tun0 up
- #ip addr add 192.168.2.90 peer 192.168.1.80 dev tun0
- #ip route add 192.168.1.0/24 dev tun0
- #iptables -F
兩邊互ping發現可以ping ,即為實驗成功。這里需要注意iptables項,執行iptables -F是必須的,不然兩邊不通。如果在需要開啟防火牆的情況下,也可以執行如下步驟:
- iptables -I INPUT -p gre -j ACCEPT
- 或
- firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i eth0 -p gre -j ACCEPT (rhel7下默認使有的firewalld)
假如這邊還有台主機C,C主機只有一塊網卡,其IP為192.168.1.100,和a主機同在eth1網段,可以將a主機配置為一個簡單的種由器,其可以訪問b主機的IP 192.168.2.90 。只需要在a主機中做如下配置即可。
- echo 1 > /proc/sys/net/ipv4/ip_forward
- iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
注意:該場景下,需要將C主機的網關指向a主機 。
2、ipv6網絡中的配置
兩台主機的信息如下:
- a. PC1 eth0:2001::1/64; eth1:192.168.1.1/24;
- b. PC2 eth0:2001::2/64; eth1:192.168.2.1/24;
配置如下:
- a主機配置
- #modprobe ip6_tunnel
- #ip -6 tunnel add tun0 mode ipip6 remote 2001::2 local 2001::1 ttl 64
- #ip link set tun0 up
- #ip addr add 192.168.1.1 peer 192.168.2.1 dev tun0
- #ip route add 192.168.2.0/24 dev tun0
- #iptables -F
- b主機配置
- #modprobe ip6_tunnel
- #ip -6 tunnel add tun0 mode ipip6 remote 2001::1 local 2001::2 ttl 64
- #ip link set tun0 up
- #ip addr add 192.168.2.1 peer 192.168.1.1 dev tun0
- #ip route add 192.168.1.0/24 dev tun0
- #iptables -F
三、其他及拓展
提到的linux下的三種模塊級的tunnel技術傳輸都是不加密的,這是和 很多VPN技術比較大的一個區別。同時三都之間在實現原理上也略有區別。
上圖是ipip tunnel 的原理圖,明顯是其點對點的一種tunnel 。這個非常容易理解,這也是其不能廣播的原因。據網上的資料說sit 也屬於點對點的tunnel,這個由於未翻閱到sit tunnel 比較詳細的信息,不能確定其屬於不屬於簡單的點對點 tunnel ,個人感覺sit 不屬於簡單的點對點 tunnel ,因為在一些路由網絡設備中發現其有支持,和gre tunnel 一樣。
由於ip tunnel 技術目前只技術linux技術 ,所以上面的兩台主機只能運行在類linux主機上。
重點說下gre tunnel,除了外層的 IP 頭和內層的 IP 頭之間多了一個GRE頭之外,它最大的不同是, tunnel不是建立在最終的 host 上,而是在中間的 router 上 !換句話說,對於端點host A 和 host B來說,該tunnel是透明的(對比上面的 ipip tunnel)。添加外部的 IP 頭是在 router A 上完成的,而去掉外面的 IP 頭是在 router B上完成的,兩個端點的 host 上幾乎什么都不用做(除了配置路由,把發送到 10.0.2.0 的包路由到 router A)!
從這個原理就可以了解到,gre tunnel 是支持廣播和多播的。所以除了上面的route A和route B需要為類linux平台,上面的host a 和host b選用什么類型的系統無所謂。
發送過程是很簡單的,因為 router A 上配置了一條路由規則,凡是發往 10.0.2.0 網絡的包都要經過 netb 這個 tunnel 設備,在內核中經過 forward 之后就最終到達這個 GRE tunnel 設備的 ndo_start_xmit(),也就是 ipgre_tunnel_xmit() 函數。這個函數所做的事情無非就是通過 tunnel 的 header_ops 構造一個新的頭,並把對應的外部 IP 地址填進去,最后發送出去。
稍微難理解的是接收過程,即 router B 上面進行的操作。這里需要指出的一點是,GRE tunnel 自己定義了一個新的 IP proto,也就是 IPPROTO_GRE。當 router B 收到從 router A 過來的這個包時,它暫時還不知道這個是 GRE 的包,它首先會把它當作普通的 IP 包處理。因為外部的 IP 頭的目的地址是該路由器的地址,所以它自己會接收這個包,把它交給上層,到了 IP 層之后才發現這個包不是 TCP,UDP,而是 GRE,這時內核會轉交給 GRE 模塊處理。
GRE 模塊注冊了一個 hook:
- static const struct gre_protocol ipgre_protocol = {
- . handler = ipgre_rcv,
- . err_handler = ipgre_err,
- } ;
所以真正處理這個包的函數是 ipgre_rcv() 。ipgre_rcv() 所做的工作是:通過外層IP 頭找到對應的 tunnel,然后剝去外層 IP 頭,把這個“新的”包重新交給 IP 棧去處理,像接收到普通 IP 包一樣。到了這里,“新的”包處理和其它普通的 IP 包已經沒有什么兩樣了:根據 IP 頭中目的地址轉發給相應的 host。注意:這里我所謂的“新的”包其實並不新,內核用的還是同一個copy,只是skbuff 里相應的指針變了。
五、參考頁面
http://blog.chinaunix.net/uid-23392781-id-2426607.html (linux的tunnel技術實現 代碼級分析)
http://www.chinaunix.net/old_jh/4/1055425.html (linux tunnel 技術)
http://docs.oracle.com/cd/E26926_01/html/E25874/gepbe.html (IP 隧道概述)
https://wiki.linuxfoundation.org/networking/tunneling (wiki頁面,三種tunnel的配置)
http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml (協議相關)