IP隧道技术
简介
IP 隧道(IP tunneling):是将一个IP报文封装在另一个IP报文的技术,这可以使得目标为一个IP地址的数据报文能被封装和转发到另一个IP地址。IP隧道技术亦称为IP封装技术(IP encapsulation)。IP隧道主要用于移动主机和虚拟私有网络(Virtual Private Network),在其中隧道都是静态建立的,隧道一端有一个IP地址,另一端也有唯一的IP地址。
Linux系统内核实现的IP隧道技术主要有三种(PPP、PPTP和L2TP等协议或软件不是基于内核模块的):IPIP (IPv4 in IPv4),GRE (IPv4/IPv6 over IPv4) ,SIT (IPv6 over IPv4) 。这三种隧道技术都需要内核模块 tunnel4.ko 的支持。
- IPIP :需要内核模块
ipip.ko
,是最简单的一种。它具有最低的开销,但是只能封装IPv4单播流量,因此您将无法设置OSPF,RIP或任何其他基于多播的协议,只能为唯一的隧道端点对设置一个隧道 - GRE : 需要内核模块
ip_gre.ko
,GRE隧道可以封装IPv4 / IPv6单播/多播流量,因此它是动态路由网络的事实上的隧道标准。可以为唯一的隧道端点对最多设置64K隧道 - SIT :代表"Simple Internet Transition",需要内核模块
sit.ko
。其主要目的是互连位于全球IPv4 Internet中的隔离的IPv6网络。SIT的工作方式类似于IPIP。内核模块是ipv6
,加载后,无法卸载ipv6模块。您可以从隧道代理获取自己的IPv6前缀和SIT隧道 。
内核模块
隧道 | 内核模块 | 虚拟网卡 |
---|---|---|
IPIP | ipip.ko |
tunl0 |
GRE | ip_gre.ko |
gre0 |
SIT | sit.ko |
sit0 |
ip tunnel
shell
$ ip tunnel help
Usage: ip tunnel { add | change | del | show | prl | 6rd } [ NAME ]
[ mode { ipip | gre | sit | isatap | vti } ] [ remote ADDR ] [ local ADDR ]
[ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]
[ prl-default ADDR ] [ prl-nodefault ADDR ] [ prl-delete ADDR ]
[ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]
[ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]
Where: NAME := STRING
ADDR := { IP_ADDRESS | any }
TOS := { STRING | 00..ff | inherit | inherit/STRING | inherit/00..ff }
TTL := { 1..255 | inherit }
KEY := { DOTTED_QUAD | NUMBER }
# mode 代表不同的 IPIP 隧道类型
ipip
one to one

A 节点
shell
# ip link add name mybr0 type bridge
# ip addr add 10.42.1.1/24 dev mybr0
# ip link set dev mybr0 up
B 节点
shell
# ip link add name mybr0 type bridge
# ip addr add 10.42.2.1/24 dev mybr0
# ip link set dev mybr0 up
现在 A 节点的10.42.1.1/24是不通 B 节点的 10.42.2.1/24
A 节点上添加隧道,指定了remote和local,为点对点的隧道
shell
# modprobe ipip
# ip tunnel add tunl0 mode ipip remote 172.16.232.194 local 172.16.232.172
# ip addr add 10.42.1.1/24 dev tunl0
# ip link set tunl0 up
A 节点上添加10.42.2.0/24路由,执行点对点的tunl0
# ip route add 10.42.2.0/24 dev tunl0
B 节点上也添加隧道
shell
# modprobe ipip
# ip tunnel add tunl0 mode ipip remote 172.16.232.172 local 172.16.232.194
# ip addr add 10.42.2.1/24 dev tunl0
# ip link set tunl0 up
B 节点上添加10.42.1.0/24路由,执行点对点的tunl0
# ip route add 10.42.1.0/24 dev tunl0
现在,A、B节点上的10.42.1.0/24、10.42.2.0/24 就实现了互通
one to many
实际上,在创建 IPIP 隧道的时候完全可以不指定 remote 地址,只要在 TUN 设备上增加对应的路由,IPIP 隧道就知道如何封装新的 IP 数据包并发送到路由指定的目标地址。
shell
A: 172.16.165.33 10.42.1.0/24
B: 172.16.165.244 10.42.2.0/24
C: 172.16.168.113 10.42.3.0/24
A 节点上创建隧道,并把B、C的路由指向tunl0
shell
# modprobe ipip
# ip tunnel add tunl0 mode ipip
# ip link set tunl0 up
# ip addr add 10.42.1.0/32 dev tunl0
# ip route add 10.42.2.0/24 via 172.16.165.244 dev tunl0 onlink
# ip route add 10.42.3.0/24 via 172.16.168.113 dev tunl0 onlink
B 节点、 C节点同理
shell
B 节点
# modprobe ipip
# ip tunnel add tunl0 mode ipip
# ip link set tunl0 up
# ip addr add 10.42.2.0/32 dev tunl0
# ip route add 10.42.1.0/24 via 172.16.165.33 dev tunl0 onlink
# ip route add 10.42.3.0/24 via 172.16.168.113 dev tunl0 onlink
C 节点
# modprobe ipip
# ip tunnel add tunl0 mode ipip
# ip link set tunl0 up
# ip addr add 10.42.3.0/32 dev tunl0
# ip route add 10.42.1.0/24 via 172.16.165.33 dev tunl0 onlink
# ip route add 10.42.2.0/24 via 172.16.165.244 dev tunl0 onlink
现在,A、B、C节点上的10.42.1.0/24、10.42.2.0/24、10.42.3.0/24 就实现了互通
使用ipip实现三层软网关
客户端
bash
# 加载ipip模块,实现基于三层的软网关
$ sudo /usr/sbin/modprobe ipip
# 添加default路由,并测试到114的联通性
$ sudo ip link set tunl0 up
$ sudp ip r add default via $gw dev tunl0 onlink
# /etc/network/interfaces固化tunl0的软网关配置
$ vi /etc/network/interfaces
auto bond0
......
post-up ip link set tunl0 up
post-up ip r add default via 10.122.43.252 dev tunl0 onlink
服务端
bash
$ echo 1 > /proc/sys/net/ipv4/ip_forward
$ sudo vi /etc/network/interfaces # 启动tunl口
auto tunl0
iface tunl0 inet manual
up ip link set tunl0 up
down ip link set tunl0 down
$ sudo ifup tunl0
$ cat /etc/shorewall/masq # nat的地址
bond1.564 10.122.40.0/22
bond1.564 10.239.81.0/26
bond1.564 10.239.83.64/26
bond1.564 10.239.83.128/26
bond1.564 10.239.83.192/26
$ sudo iptables -L -n -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
bond1.564_masq all -- 0.0.0.0/0 0.0.0.0/0
Chain bond1.564_masq (1 references)
target prot opt source destination
MASQUERADE all -- 10.122.40.0/22 0.0.0.0/0
MASQUERADE all -- 10.239.81.0/26 0.0.0.0/0
MASQUERADE all -- 10.239.83.64/26 0.0.0.0/0
MASQUERADE all -- 10.239.83.128/26 0.0.0.0/0 # snat的ip段
MASQUERADE all -- 10.239.83.192/26 0.0.0.0/0
如果做了2层snat,例如装机、容器里,将源ip不是本机的转换为本机ip
bash
iptables -t nat -A POSTROUTING ! -s `hostname -I` -o tunl0 -j SNAT --to `hostname -I`
异常可以通过抓包分析
bash
sudo tcpdump -eni any net $需要nat的地址