一种无 PD 情况下给内网设备配置公网 IPv6 的方法
2021-05-01 / 猫村 あおい 🍭

TLDR: radvd ndppd

简介

某些环境(如傻逼 CERNET)下的 ipv6 是没有 prefix delegation 的,路由器获取不到前缀。这种情况内网设备想使用 v6 特别是公网 v6 就有困难。

网上对于无 PD 的情况下配置内网 IPv6 的方法普遍有以下几种,各有优劣。

偷来的图

这几种方法可以参考以下链接

https://koolshare.cn/thread-46415-1-1.html

https://zhuanlan.zhihu.com/p/50356712

https://i-meto.com/openwrt-ipv6/

我全都要

划分子网的方案可以考虑,但是 Android 设备不支持 DHCPv6。

中继实测可用性低,不考虑。

桥接不适用于 ipv6 有验证的情况。

NAT 太屑不考虑。

所以可以在划分子网的方案基础上改造,让内网有 /64 这么大,其实这就是代理 ipv6 ndp,有点像 relay 但是这样更稳定。

适用情况

网络可以通过 IPv6 Stateless Address Autoconfiguration 获取地址,一般看一下 ip a,如果有 inet6 2001:xxx/64 scope global dynamic 类似输出的基本就是了。如果只有 /128 的,多半是只能通过 DHCPv6 获取,本文不适用于这种情况。

配置

先看方案一的操作。 来自 https://koolshare.cn/thread-46415-1-1.html

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
方案一、在学校给的子网里,强行给自己划一个更小的子网

注1:来自我以前的帖子 https://koolshare.cn/thread-24920-1-1.html ,稍有改动

注2:建议对Linux和网络有一定了解。由于楼主精力有限,可能无法解决解决全部提问。请谅解。

本方案的原理和配置文件打包见二楼、三楼。以下是配置方法。

1. 允许获取IPv6地址、设计子网地址

左边高级设置->IPv6->IPv6联机类型->Native

启动Router Advertisement->关闭 (因为我们要自己配置)
(图0. 在固件中打开IPv6支持)

去SSH中用ifconfig查看得到的IP地址,把前缀记下来。例如得到了2001:250:ffff:8000:e6f4:feff:fe00:1122:3344/64,则前缀是2001:250:ffff:8000::/64.
可以在后面添加任意十六进制字符作为你的子网地址。如我选择将2001:250:ffff:8000:2333:dead:beef::/112作为我的子网。请记住你的子网前缀和前缀长度,后面将多次使用。(我还没见过EUI-64或者隐私扩展产生出2333:dead:beef开头的这样巧合的地址,不用担心冲突)
(图1. 路由自动获取的WAN口地址)


2. 为LAN配置IPv6地址

在以上选定的子网范围内随便选择一个地址作为路由器LAN的地址,如2001:250:ffff:8000:2333:dead:beef:babe/112. 使用
ip -6 addr add 2001:250:ffff:8000:2333:dead:beef:babe/112 dev br0
复制代码
添加到LAN口。
(图2. 手动配置的LAN口地址)


3. 配置RA和DHCPv6

为了减少对其他程序的依赖,这里使用dnsmasq来做DHCPv6服务器,radvd做RA(经测试,dnsmasq的RA功能不稳定,不知道是我的配置有问题还是怎么回事)。radvd我用的是自己编译的版本,放在三楼。解压放在/jffs/bin/radvd,加执行权限。dnsmasq用自带的即可。

dnsmasq的配置如下:
在/jffs/configs/dnsmasq.d/ipv6.conf.add(此路径限X6.6及以后使用,否则请使用原帖中的路径。此文件没有就新建)加入如下一行打开DHCPv6(前缀和前缀长度都要是前面设计好的。主机号的范围是1000到ffff,可修改。):
dhcp-range=2001:250:ffff:8000:2333:dead:beef:1000,2001:250:ffff:8000:2333:dead:beef:ffff,112
复制代码
(图3. dnsmasq.conf示例)

radvd的配置如下:
在/jffs/etc/radvd.conf(自行建立,这个路径可任意改,一会儿启动radvd的时候写好就是了)注意替换LAN设备名和前缀、前缀长度,写入
interface br0
{
AdvSendAdvert on;
# 下面这个用来要求客户端使用DHCPv6地址
AdvManagedFlag on;

#
# These settings cause advertisements to be sent every 3-10 seconds. This
# range is good for 6to4 with a dynamic IPv4 address, but can be greatly
# increased when not using 6to4 prefixes.
# 意思是这两个数值是RA发送的最短和最长时间间隔,可以自己改。

MinRtrAdvInterval 3;
MaxRtrAdvInterval 10;


prefix 2001:250:ffff:8000:2333:dead:beef:1/112
{
AdvOnLink on;
# 禁止使用此前缀自动配置地址(然而112的前缀长度并不能配置成功)
AdvAutonomous off;
AdvRouterAddr on;
};
};
复制代码

4. 配置NS回应

将ndppd上传至/jffs/bin/ndppd,加执行权限。
在/jffs/etc/ndppd.conf(说明同radvd)注意替换WAN设备名、前缀、前缀长度,写入
route-ttl 30000
proxy vlan2 {
router yes
timeout 500
ttl 30000

# rule <ip>[/<mask>]
# This is a rule that the target address is to match against. If no netmask
# is provided, /128 is assumed. You may have several rule sections, and the
# addresses may or may not overlap.
rule 2001:250:ffff:8000:2333:dead:beef::/112 {
# Only one of 'static', 'auto' and 'interface' may be specified. Please
# read 'ndppd.conf' manpage for details about the methods below.

# 'auto' should work in most cases.

# static (NEW)
# 'ndppd' will immediately answer any Neighbor Solicitation Messages
# (if they match the IP rule).

# iface <interface>
# 'ndppd' will forward the Neighbor Solicitation Message through the
# specified interface - and only respond if a matching Neighbor
# Advertisement Message is received.

# auto (NEW)
# Same as above, but instead of manually specifying the outgoing
# interface, 'ndppd' will check for a matching route in /proc/net/ipv6_route.
# 这个auto我自己测试无效,因此改成static,各位可自行测试auto
static
}
}
复制代码
(图4. radvd和ndppd的配置文件)


5. 允许内核进行IPv6转发、清除多余的IPv6防火墙规则、启动相关程序

由于系统并不知道我们已经为IPv6付出了这么多努力来使IPv6变得可用,因此我们需要手动清除系统的“保护”。
我这里直接把ip6tables清空了,因为本身校园网就是有保护的,我懒得再加规则了……

shell下直接执行,注意替换LAN和WAN设备名,以及上述两个配置文件的位置
BASE_DIR=/jffs
LAN_DEVICE=br0
WAN_DEVICE=vlan2
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
echo 0 > /proc/sys/net/ipv6/conf/$WAN_DEVICE/forwarding
echo 2 > /proc/sys/net/ipv6/conf/$WAN_DEVICE/accept_ra

ip6tables -P FORWARD ACCEPT
ip6tables -P INPUT ACCEPT
ip6tables -F
$BASE_DIR/bin/radvd -C $BASE_DIR/etc/radvd.conf -d 1
$BASE_DIR/bin/ndppd -c $BASE_DIR/etc/ndppd.conf -d

service restart_dnsmasq
复制代码

如果这一步结束以后WAN口上的IPv6地址消失,可以用/jffs/bin/rdisc6 vlan2来重新获取。

没有错误的话子网内设备应该可以得到IPv6默认路由了。稍候即可得到IPv6地址。此时可在电脑ping6测试。

其实没有必要划分一个比学校更小的子网。学校是 /64 内网就用 /64,不需要在内网搞什么 DHCPv6。。。

配置过程大致和上面相同,有以下变动

  • 上面所有 /112 改为 /64
  • 修改 radvd 配置: AdvAutonomous on; AdvManagedFlag off;
  • 无需配置 DHCPv6
  • 配置路由表

添加到学校网关 2001:xxx::1/128 的路由。

ip -6 route add 2001:xxx::1/128 dev vlan2 metric 1

添加内网的路由,注意调整 metric 覆盖自动获取的路由。

ip -6 route add 2001:xxx::/64 dev br0 metric 2

虽然这样无法连接学校子网内的设备,但是学校子网内一般没什么东西,代价可以忽略。

这样配置就可以在内网通过 Stateless RA 稳定获取公网 ipv6 了喵~


本博客所有文章除特别声明外,均采用 CC BY-NC-SA 许可协议。
本文链接:
https://nekoquq.github.io/posts/0005.html