ipv4-in-ipv6是将ipv4报文封装在ipv6中传输,这是ipv6过渡技术中用到的一种隧道封装技术,通常用在IPV6过渡的后期,此时组网大部分是ipv6网络,但仍然存在少许ipv4网络,ipv4-in-ipv6就是用来解决在ipv6网络的汪洋大海中各个ipv4孤岛间的互相通信。
首先准备两台linux pc(暂且称为hostB and hostC),两台pc间网卡用网线直接相连。每台PC上的ethernet nic上配置一个global的ipv6地址。
host B: ip -6 addr add 2001::2/64 dev ens33
hostC: ip -6 addr add 2001::3/64 dev ens33
此时在hostB上ping6 2001::3 可以ping通表明底层的ipv6网络已经互通,当然实际的底层ipv6网络可能比这复杂的多,但是最终通过ipv6的路由都能够互通,这里只是一个简单的同网段的ipv6互通的演示。此时route --inet6 还可以查看到以下ipv6路由项,表明去2001::/64网络的包都要从ens33 interface出来。
创建ipip6隧道:
hostB:
modprobe ip6_tunnel
ip -6 tunnel add tun0 mode ipip6 remote 2001::3 local 2001::2 dev ens33 encaplimit none
ip link set tun0 up
ip addr add 192.0.1.2 peer 192.0.0.1 dev tun0
hostC:
modprobe ip6_tunnel
ip -6 tunnel add tun0 mode ipip6 remote 2001::2 local 2001::3 dev ens33 encaplimit none
ip link set tun0 up
ip addr add 192.0.0.1 peer 192.0.1.2 dev tun0
ipip6隧道创建完成,可以用 ip -6 tunnel show 显示创建的隧道信息。 此时route -n会在hostB 和hostC上发现以下ipv4路由表项:
hostB
hostC
分别表明 hostB上目的ip为192.0.0.1的packet和hostC上目的地址为192.0.1.2的packet均路由到tun0处理。这个路由表项是在配置
ip addr add 192.0.1.2 peer 192.0.0.1 dev tun0 时自动添加的,我们也可以用ip addr add 192.0.1.2 dev tun0只给tun配置ip地址,然后手动添加ip route add 192.0.0.0/24 dev tun0 路由表让去192.0.0.0/24的网络都转到tun0处理。此时从hostB上ping 192.0.0.1可以ping通,hostB 物理网卡ens33上抓包可以看到隧道封装报文。
下面对上述拓扑做一个拓展,在连接一台host A, hostA ethernet网卡与hostB ethernet网卡相连。hostA 与hostB相连etherent interface的ip地址分别为192.168.148.132, 192.168.148.129。 在hostA上设置去192.0.0.0/24网络的网关为192.168.148.129。hostB上enable ipv4 forward模拟路由器,同时配置NAT伪装,让从tun0出去的packet SNAT src address转为tun0的IPv4地址.
host A:
route add -net 192.0.0.0 netmask 255.255.255.0 gw 192.168.148.129
hostB:
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -I POSTROUTING -p icmp -o tun0 -j MASQUERADE --to-port 60000-60999
iptables -t nat -I POSTROUTING -p tcp -o tun0 -j MASQUERADE --to-port 60000-60999
iptables -t nat -I POSTROUTING -p udp -o tun0 -j MASQUERADE --to-port 60000-60999
//iptables -t nat -n -L //show nat tables
//iptables -t nat -D POSTROUTING 1 //delete the 1th nat POSTROUTING items
此时再host A上ping 192.0.0.1可以ping通, conntrack -L 查看连接跟踪表项,如下:
hostC: iperf -s -p 5001
host A: iperf -c 192.0.0.1 -p 5001 -l 1000
hostC: iperf -s -u -p 5001 //server listening on the l4 port 5001
hostA: iperf -c 192.0.0.1 -u -p 5001 -l 1400 -t 60 -i 2 //client, serverip is 192.0.0.1, dst l4 port 5001, udp length 1400bytes, run 60s
下面以ping过程为例来说明traffic的过程:
hostA上ping 192.0.0.1, 发现目的地址192.0.0.1与自己ethernet interface 地址192.168.148.132不在一个网段,因此需要找网关转发,但是它也不知道网关的mac地址,因此通过ARP获取网关的mac地址, 然后组成完整的ICMP request包(src mac :hosta ethernet nic mac address, dst mac: gateway (host B etherent nic )mac address, src ip:192.168.148.132, dst ip 192.0.0.1)。 该ICMP报文到达网关即hostB ethernet interface后,进入协议栈,协议栈处理到IP层后经过routing将ip报文路由到tun0 interface,同时在POSTROUTING hook点对源ipv4报文进行SNAT转换, tun0 对ip报文进行加封装,在原来ip报文前面加上ipv6 header,ipv6 header的src ip 为2001::2 , dst ip 为2001::3,加封后的报文在out出去进过查找路由(按照外层ipv6地址查找路由)将从hostB 物理网口出去,出去时加上mac header(mac src address 为2001::2 interface 的mac 地址,dst address 为对端2001::3 interface的mac 地址)。
当对端2001::3 interface 收到ipv4-in-ipv6封装的packet后,进入ipv6的协议栈进行处理,ipv6 next header 协议号为IPIP(4), 进入事先注册的L4层处理函数(隧道接收处理函数)对skb进行decap后重新调用netif_rx这时候解封后的ipv4报文重新进入协议栈处理,最后到达目的地。
ICMP reply过程与此类似,不在分析。