動機
IPsec 轉(zhuǎn)發(fā)流量有兩種方式逐纬,一種是基于策略,另外一種是基于路由削樊。本文將嘗試闡述基于路由的 IPsec 核心概念和實現(xiàn)原理并引出一些花式玩法豁生。
IPsec 帶給計算機世界的困惑
在計算機世界里面,核心的一個概念就是路由嫉父,其定義了某個指定的數(shù)據(jù)包要從哪個接口出去的規(guī)則沛硅。很多軟件和命令都是基于這個事實來設(shè)計的眼刃。譬如 iproute 包绕辖,各類路由軟件,iptables 等等擂红。
但是在 IPsec 的世界里面仪际,默認(rèn)是根據(jù)內(nèi)核里面的規(guī)則直接就進行了封裝和轉(zhuǎn)發(fā)围小,這導(dǎo)致用戶理解困難,軟件無法正常運作树碱。舉例而言肯适,你沒有辦法通過增加一條路由來告訴計算機某個地址要通過 IPsec 隧道來走。
要解決這個問題成榜,就只能用計算機世界里面最常用的手段:增加一層封裝框舔,虛擬出來一個設(shè)備,使其符合原來的世界規(guī)則赎婚。
這樣從設(shè)計上來說就變成了:
- IPsec 只管建立通道和進行封裝轉(zhuǎn)發(fā)
- 虛擬設(shè)備只管數(shù)據(jù)包怎么處理和路由
打通虛擬設(shè)備和 IPsec 的任督二脈
要從實際上解決這個問題刘绣,有兩種方法。
第一種方法:VTI (Virtual Tunnel Interface) 的原理
最初往 Linux 增加 VTI 功能的作者提到:Virtual tunnel interface is a way to represent policy based IPsec tunnels as virtual interfaces in linux. This is similar to Cisco's VTI (virtual tunnel interface) and Juniper's representaion of secure tunnel (st.xx). The advantage of representing an IPsec tunnel as an interface is that it is possible to plug Ipsec tunnels into the routing protocol infrastructure of a router. Therefore it becomes possible to influence the packet path by toggling the link state of the tunnel or based on routing metrics.
這表明了 VTI 是一種虛擬網(wǎng)絡(luò)設(shè)備挣输。在 Linux 的實現(xiàn)中該設(shè)備主要作用是將經(jīng)過這個設(shè)備的網(wǎng)絡(luò)流量打上標(biāo)簽纬凤,IPsec的策略根據(jù)這個標(biāo)簽和相關(guān)信息來判斷流量該怎么轉(zhuǎn)發(fā)岳瞭。
看到這個做法寸痢,對 iptables 熟悉的同學(xué)肯定馬上就聯(lián)想到了 iptables 打標(biāo)簽給 tc 來控制流量,通過 iptables 打標(biāo)簽來給 iproute 來控制路由等做法瞒窒。是的完丽,他們是師出同門恋技,做法上是類同的。所以逻族,如果你通過 iptables 給網(wǎng)絡(luò)流量打上標(biāo)簽猖任,也是能夠?qū)崿F(xiàn)讓其數(shù)據(jù)包被 IPsec 轉(zhuǎn)發(fā)的效果的。
第一種方法:VTI 的實踐
- 要實現(xiàn)這種做法瓷耙,需要在 IPsec 的配置里面約定好標(biāo)簽(配置項為mark)的值朱躺。
- VTI 里面 local 和 remote 地址至少需要有一項跟 IPsec 里面的 left,remote相同搁痛,key 的參數(shù)要跟 IPsec 里面的 mark 一致长搀。
- VTI 設(shè)備本身可以單獨配置地址,該地址可以用來做 NAT 等
sudo ip tunnel add vti6 mode vti local ${local_ip) remote 0.0.0.0 key 6
sudo ip addr add ${tunnel_ip) dev vti6
sudo ip link set vti6 up
sudo ip route add ${remote_site_lan) dev vti6 src ${tunnel_ip)
sudo iptables -t nat -A POSTROUTING -o vti6 -j SNAT --to-source ${tunnel_ip}
第一種方法:花式玩法 iptables 篇
如果要僅僅通過 iptables 打標(biāo)簽就使得數(shù)據(jù)包通過 IPsec 轉(zhuǎn)發(fā)鸡典,那么要怎么做呢源请?
參考下面的命令:
sudo iptables -t mangle -I PREROUTING -s ${remote_peer} -j MARK --set-mark 0x6
sudo iptables -t mangle -I PREROUTING -d ${remote_site_lan} -j MARK --set-mark 0x6
sudo iptables -t mangle -I OUTPUT -d ${remote_site_lan} -j MARK --set-mark 0x6
小竅門:可以通過 ip xfrm policy 查看 ipsec 的策略,包括其 mark 值等彻况∷可以通過 iptables -L 來查看 mark 的匹配情況。tcpdump 是看不到 mark 值的纽甘,因為 mark 值在內(nèi)核維護良蛮,不體現(xiàn)在包的內(nèi)容上面。
注意:
- 要注意發(fā)送出去的地址跟規(guī)則相符合悍赢,必要的話可以做個 SNAT
- 可以通過抓 remote_peer 的包來判斷包是不是通過 IPsec 發(fā)送出去决瞳。
第一種方法:VTI 的作用和用其他虛擬設(shè)備的可能性
用 tuntap 設(shè)備货徙,然后用 iptables fwmark 是不是可以和 VTI 有同樣的效果呢?
如果是這樣皮胡,那么 VTI 里面的 local 和 remote 有什么用途呢痴颊?
第一種方法:一些解答 - VTI 的地址
VTI 代碼里面會去檢查 IPsec 相關(guān)的策略(代碼net/ipv4/ip_vti.c),這里涉及到 local 和 remote 地址屡贺,所以這兩個地址不能隨意設(shè)置蠢棱,要不然就會被拒絕轉(zhuǎn)發(fā)。從某種意義上來說甩栈,做這個檢查是多余的裳扯,會使得系統(tǒng)耦合比較重。不過既然VTI作者的本意是通過 VTI 來表示 IPsec谤职,這本身也是無可厚非饰豺。
第一種方法:另一種玩法實踐 - 用 tuntap 設(shè)備
ip tuntap add tuntap mode tap ${tap_name}
ip link set ${tap_name} up
ip addr add ${tunnel_ip} dev ${tap_name}
ip route add ${remote_site_lan} dev ${tap_name} src ${tunnel_ip}
iptables -t mangle -A PREROUTING -s ${remote_peer} -j MARK --set-mark ${mark}
iptables -t mangle -A OUTPUT -o ${tap_name} -j MARK --set-mark ${mark}
你會看到 tap 設(shè)備的狀態(tài)是 link down,NO-CARRIER允蜈,不過沒關(guān)系冤吨,照樣能用,只要數(shù)據(jù)包丟到內(nèi)核去了就會被處理掉饶套。
第二種方法:內(nèi)部封裝(GRE封裝)
在 Strongswan 里面提到了 GRE 封裝漩蟆,相當(dāng)于IPsec將GRE封裝的包傳過去,然后 GRE 封裝里面又有源地址和目的地址妓蛮。這種做法其實只要允許兩個 Peer 之間加密就好了怠李,底層怎么路由,封裝 IPsec 都不管蛤克。我們常見的 L2TP捺癞,譬如 IP over IP 等等,其實也都是屬于這個范疇的构挤。
這種做法的缺點是兩端需要單獨再起一個服務(wù)來實現(xiàn)這些封裝髓介。
參考鏈接
https://www.spinics.net/lists/netdev/msg202714.html
https://wiki.strongswan.org/projects/strongswan/wiki/RouteBasedVPN
https://vincent.bernat.ch/en/blog/2017-route-based-vpn
https://www.juniper.net/documentation/software/screenos/screenos6.3.0/630_ce_VPN.pdf
https://www.inetzero.com/bgp-over-ipsec/
https://www.juniper.net/documentation/en_US/junos/topics/topic-map/security-route-based-ipsec-vpns.html
https://github.com/strongswan/strongswan/blob/master/testing/tests/ikev2/nat-virtual-ip/hosts/moon/etc/nat_updown
https://networkengineering.stackexchange.com/questions/10342/backup-ip-for-site-2-site-vpn-juniper-srx
https://kb.juniper.net/InfoCenter/index?page=content&id=KB14330
https://wiki.strongswan.org/projects/strongswan/wiki/Strongswanconf
https://libreswan.org/wiki/Route-based_VPN_using_VTI
https://www.ibm.com/support/knowledgecenter/en/SST55W_4.3.0/liaca/liaca_cfg_ipsec_vti.html
https://elixir.bootlin.com/linux/v4.1/source/net/ipv4/ip_vti.c#L78