校园网SLAAC环境下IPv6的桥接与中继

笔者所在的校园网中开通了IPv6,本以为会像家庭宽带那样,路由器自动DHCPv6桥接让小内网中的设备获取到全球v6地址,但经过探索发现其采用了无PD(Prefix Delegation)下发的SLAAC(Stateless Address Auto-Configuration,无状态地址自动配置)。

本文基于该校园网环境,首先介绍v6基础知识,随后在Cisco设备用不那么优雅的方法完成配置。

本文参考了SLAAC 环境下的 IPv6 桥接与中继-Menci’s Blog这篇文章,下面部分基础知识也是摘抄而来。建议没有接触过v6的读者先阅读并理解这些基础知识,对后续会有很大帮助。

原理

SLAAC

SLAAC(Stateless Address Auto-Configuration,无状态地址自动配置)是 IPv6 网络中最常见的为单一主机分配地址的方式。一般来说,IPv6 终端网络使用 /64 的前缀长度,并使用 SLAAC 来配置每个主机的 /64 后缀。主机使用其网卡 MAC 地址来生成后缀,确保地址不会冲突。
iShot_2023-10-28_22.05.51.png

这种配置方式的存在,得益于 IPv6 地址高达 128 位的地址空间。ISP 能够为每个用户网络分配 /64 乃至更大的地址空间,终端网络无需使用 DHCP 小心翼翼地在有限的地址池中为设备分配地址,也不需要使用 NAT 来让网络中的设备共享一个公网地址。

SLAAC 协议由两种数据包组成,它们都属于 ICMPv6:

  • Router Solicitation(路由请求),由需要配置 IPv6 的主机发送的组播包,向网络中的路由器请求路由宣告。
  • Router Advertisement(路由宣告),由路由器在收到请求后发送,或配置变更时发送。包含前缀、路由、有效时长等信息,也包含 DNS 服务器地址等一些扩展。
    一些时候 SLAAC 不足以配置网络中的所有信息,仍然需要 DHCP,这种情况不是本文所介绍的重点,但可以用类似的方法解决。

主机在收到路由宣告后,会使用其中的信息来为自己配置 IPv6 地址和路由表。注意,由于 SLAAC 是无状态的,主机并不需要将选择的地址上报给路由器。

NDP

与 IPv4 的 ARP 协议类似,IPv6 使用 NDP(Neighbor Discovery Protocol)协议来将同一网络中其他主机的 IP 地址对应到 MAC 地址。

这个过程与 ARP 基本一致,一方发送Neighbor Solicitation(邻居请求)组播包,包含所查询的 IPv6 地址,持有该地址主机返回Neighbor Advertisement(邻居宣告)。

PD

PD(Prefix Delegation)是 DHCPv6 的一项扩展,用于 DHCP 服务器将一整段地址分配给 DHCP 客户端。这种情况一般常见于 ISP 为用户分配 IPv6 地址。在客户端获取地址时,DHCPv6 服务器(作为上级路由器)会添加一条路由,将整个被下发的网段路由到客户端。这样一来,整个地址块(一般为 /64 或者 /60)均可被客户端网络使用。

DHCPv6 客户端收到由 PD 下发的前缀后,即可通过 SLAAC 等方式为整个网络内的所有主机配置 IPv6 地址,这个过程不再需要上级路由的参与。这也是一般家用网络中最常见的 IPv6 地址分配方式。

问题

如果我们的路由器本身处于一个没有 DHCPv6 PD 分配的环境中,只能通过 SLAAC 从上级路由(WAN)获得单个 IPv6 地址,应该如何为网络中(LAN)的主机分配 IPv6 地址?

这种情况常见于校园网环境中,不存在 PD 前缀下发,只有 SLAAC 地址分配。以及,在一些家庭宽带环境下,ISP 提供的光猫完成了 PPPoE 拨号、DHCPv6 PD 获取前缀、SLAAC 下发地址的整个过程,接入光猫(上级路由)的路由器同样无法获得前缀。

解决方案总结

经过总结,主要有以下较为方便可行的方式实现WAN和LAN间PD和NDP报文的转发。

中继(Openwrt为例)

在这种情况下,除 NAT 之外,使 LAN 中的终端设备接入 IPv6 的主要思路是,假装这些设备被直接接入到 WAN 中,从 WAN 上的上级路由获得 IPv6 地址,并在 LAN 和 WAN 之间对 SLAAC 和 NDP 协议进行代理 —— 双向转发 SLAAC 与 NDP 包,并将源 MAC 地址改为我们的路由器的 MAC 地址。在 WAN 和 LAN 中的设备看来,对方网络中的 IP 地址由我们的路由器所持有,所有流量均由我们的路由器。

这种实现思路被称为 IPv6 中继(Relay)。OpenWrt 的 6relayd(早期)与 odhcpd(目前)实现了这个功能,在一般的 Linux 路由器上,我们也可以通过抓包来手动实现它(见 Menci/magpie),但实现较为复杂,运行效果并不好。

中继方案可能出现的问题

在某些网络环境使用中继方案时,可能会遇到NDP中继无法学习到正确路由表的问题,该问题所表现的现象包括并不限于:

  • 同属于br-lan中的设备可以IPv6相互通信,其他情况无法通信。
  • br-lan中的设备刚接入时与公网IPv6设备可以通信,过一会(实际上是过了邻居条目有效期)后无法通信了。
  • br-lan中的设备始终可以与公网IPv6设备通信,但每次建立通信时前几个包延迟会特别大。

这几种问题现象大概率说明 odhcpd 的 NDP 中继无法学习到正确的路由表(也就一直无法让目的地是 LAN 的分组进入 LAN 区域)。这个问题在博主Slient Blog的 odhcpd 中继模式原理、局限以及解决方案 中有详细分析,如下:

  1. 目的地是 LAN 侧客户端 A 的 IPv6 分组直接到达 WAN 口;
  2. 路由器内核根据现有路由表进行转发,发现该分组属于 WAN 口的 /64 子网,所以在 WAN 口发送 NS 寻找 A 的 MAC 地址;
  3. 错误配置的 WAN 口上游回答了 NA 消息,导致 odhcpd 错误地学习了邻居信息并添加了 A 地址在 WAN 侧的错误路由表项;
  4. 路由器将该 IPv6 分组发回给了 WAN 口上游节点,导致丢包。

至此后续到达 WAN 口的分组会不停重复上述过程,导致 LAN 侧的 A 虽然有 IPv6 地址却无法正常通信。

博主借助openwrt的 hotplug 机制,编写了一个脚本,用于在 WAN 口获得 IPv6 地址后添加一条路由表,让整个子网重定向到 LAN 口。将以下脚本放在 /etc/hotplug.d/iface/80-reset-route6 并重启 WAN 接口即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/bin/sh

wan_dev="wan6"

[ "$HOTPLUG_TYPE" = "iface" ] || exit 0
[ "$INTERFACE" = "$wan_dev" ] || exit 0

RTMETRIC=127

. /lib/functions/network.sh

network_get_physdev lan_dev lan || exit 0

ifup_cb() {
local _lan_dev="$1"
local _metric="$2"

local wan_subnet
network_get_subnet6 wan_subnet "$wan_dev" || return
_wan_network=$(owipcalc "${wan_subnet}" network)

ip -6 route replace "$_wan_network" dev "$_lan_dev" metric "$_metric"
}

ifdown_cb() {
local _lan_dev="$1"
local _metric="$2"

ip -6 route flush dev "$_lan_dev" metric "$_metric"
}

case "$ACTION" in
ifup)
ifup_cb "$lan_dev" "$RTMETRIC"
;;
ifdown)
ifdown_cb "$lan_dev" "$RTMETRIC"
;;
ifupdate)
ifdown_cb "$lan_dev" "$RTMETRIC"
sleep 1
ifup_cb "$lan_dev" "$RTMETRIC"
;;
*)
;;
esac

exit 0

直接桥接(Iptables为例)

直接桥接是指将 IPv4 和 IPv6 视作独立的网络接口。
假设我们有 WAN4、WAN6、LAN4、LAN6,将 WAN6 与 LAN6 桥接,保持 WAN4 与 LAN4 上原有的 NAT 配置。这样一来,桥接会使得 WAN 与 LAN 中主机的 IPv6 流量互通,无需关心地址分配与邻居发现上的任何问题。
配置方法请见:
SLAAC 环境下的 IPv6 桥接与中继-Menci’s Blog

基于桥接的中继(Iptables为例)

考虑到桥接的实现方式,内核会在 MAC 表中记录每个 MAC 地址所在的接口,在需要时进行泛洪,所以能够天然地正确转发 NDP 的 NS 与 NA 包。不考虑对数据流量的转发,桥接的机制相当于为我们实现了 NDP 中继。

与手动实现中继有一点不同,桥接会直接双向转发 SLAAC 与 NDP 包,不改变包的 MAC 地址。在 WAN 和 LAN 中的设备看来,他们互相可以直接在同一二层中收到对方的 ICMPv6 消息,但实际上这些数据包由我们的路由器进行转发。WAN 和 LAN 上的交换机会分别记录对方网络中设备的 MAC 地址的所属方为我们的路由器,所以,双方会认为它们在同一个网络中,而双方之间的流量则自然而然地到达了我们的路由器。而我们希望不对数据流量进行二层交换,而是在利用桥接带来的连通性的同时,让数据流量经过三层进行路由。

配置方法请见:
SLAAC 环境下的 IPv6 桥接与中继-Menci’s Blog

端口桥接+ACL方式(Cisco交换机为例)

该方法是笔者着重介绍的方法。如果你没有Openwrt或者其他能DIY Iptables的软路由设备,但拥有一台支持ACL的网管交换机,则可采取以下方案。(以下配置命令均以Cisco IOS为例)

笔者实验室网络拓扑可看作有1台交换机、1台路由器。交换机只有一个默认Vlan,接入校园网网线,充当普通交换机用来扩展网口。

只需要简单地将交换机出来的两根线,分别连接到路由器WAN口和LAN口。但稍微懂一点网络知识就会发现,只这样操作肯定是不行的,甚至可能把校园网同一个广播域的设备搞断网。

例如你交换机G0/0/1插了路由器WAN口,G0/0/19插了路由器LAN口,那么我们需要添加两条ACL。

L2 ACL:允许核心设备ICMPv6报文通过

首先通过Wireshark抓包拿到校园网核心设备的MAC地址,即发布路由通告的地址。
iShot_2023-10-28_22.23.59.png

随后,登录交换机,添加一条MAC ACL。

1
2
3
4
5
enable
config t
mac access-list extended allow_compus_icmpv6
permit host 80e4.557a.0002 any
permit any host 80e4.557a.0002

L3 ACL:屏蔽所有IPv4报文

添加一条标准ACL即可。

1
2
3
enable
config t
access list 10 deny any

应用到端口

应用到插路由器LAN口的G0/19。

1
2
3
4
5
6
7
8
en
config t
interface GigabitEthernet0/29
description to_router_ipv6
switchport access vlan 2
switchport mode access
ip access-group 10 in
mac access-group allow_compus_icmpv6 in

查看一下,发现ACL添加成功。

1
2
3
4
5
6
7
Cisco106#show access-lists
Standard IP access list 10
10 deny any
Extended MAC access list allow_compus_icmpv6
permit host 80e4.557a.0002 any
permit any host 80e4.557a.0002
Cisco106#

完整配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
en
config t

mac access-list extended allow_compus_icmpv6
permit host 80e4.557a.0002 any
permit any host 80e4.557a.0002
exit

access list 10 deny any

int g0/29
desc to_router_ipv6
switchp access vlan 2
switchp mode access
ip access-group 10 in
mac access-group allow_compus_icmpv6 in

即可实现局域网内终端拿到v6地址,同时内外网不会混杂。

校园网SLAAC环境下IPv6的桥接与中继

https://www.catop.top/2023/10/28/ipv6-relay-in-slaac/

作者

Catop

发布于

2023-10-28

更新于

2024-11-10

许可协议

评论