业务需要搭建一个 DHCPv6 测试环境,因为手上资源有限,于是决定使用 OpenWrt 的路由器来操作。
测试环境的目标是针对 Android 设备连接 WiFi 的情况下,验证 DHCPv6 的工作情况。
本文提到的 OpenWrt 代指所有运行 OpenWrt 的 24.10.4 版本固件的路由器。
软件包准备
OpenWrt 默认情况下使用 odhcpd 作为 DHCP 服务器。
odhcpd 的功能满足 OpenWrt 的基本要求,但是不满足需要的测试场景,比如不能自定义控制 DHCPv6 的地址范围等参数。
所以需要搭配一个强劲的 DHCPv6 服务器软件。
在 OpenWrt 中安装以下软件包:
- dnsmasq-dhcpv6
- isc-dhcp-server-ipv6
这个包包含了isc-dhcp-server-ipv4的功能。
通过界面配置
修改 lan 接口的 IPV4 地址
- 网络 -> 接口 -> lan -> 常规设置 -> IPv4 地址 -> 192.168.10.1
这个步骤对
DHCPv6测试没有直接关系,如果不关注DHCPv4,可以不修改。
配置 lan 接口的 odhcpd 服务,禁用 DHCPv4、DHCPv6 以及 RA中关闭SLAAC并开启M+O
- 网络 -> 接口 -> lan -> DHCP服务器 -> 常规设置 -> 忽略此接口 -> 勾选
禁用 odhcpd 对 br-lan 开启的 DHCPv4 服务。如果不关注DHCPv4,可以不修改。 - 网络 -> 接口 -> lan -> DHCP服务器 -> IPv6设置 -> RA服务 -> 服务器模式
控制 RA 来源。 - 网络 -> 接口 -> lan -> DHCP服务器 -> IPv6设置 -> DHCPv6服务 -> 已禁用
禁用 odhcpd 对 br-lan 开启的 DHCPv6 服务。 - 网络 -> 接口 -> lan -> DHCP服务器 -> IPv6 RA 设置 -> 默认路由器 -> 强制通告
控制 Android 设备无线网卡是否具备默认路由。 - 网络 -> 接口 -> lan -> DHCP服务器 -> IPv6 RA 设置 -> 启用SLAAC -> 取消勾选
模拟没有 SLAAC 或具有无效 SLAAC 的情况。 - 网络 -> 接口 -> lan -> DHCP服务器 -> IPv6 RA 设置 -> RA标记 -> MO
开启 MO 模式,告知客户端启动 DHCPv6 流程。
Android设备AOSP原生实现默认不会检查M&O&P的配置,而是根据是否具有默认路由来判断是否启动DHCPv6流程。
修改 lan 接口的 IPV6 地址
- 网络 -> 接口 -> 全局网络选项 -> IPv6 ULA 前缀 -> 2001:758:1:1::/64
配置 ULA 前缀,以一个公网前缀开头,模拟公网环境。
通过终端配置
由于 isc-dhcp-server 没有前台界面,所以只能通过终端进行配置。使用终端连接路由器 ssh root@192.168.10.1,密码是路由器后台密码。
初始化 isc-dhcp-server 运行环境
mkdir -p /var/db/
touch /var/db/dhcpd.leases
touch /var/db/dhcpd6.leases
初始化配置文件
由于 isc-dhcp-server 会通过配置文件规划的网段自动匹配网卡,所以这里使用的是和 br-lan 相同的网段。这也是修改全局 IPV6 地址的原因。
关于绑定网卡,还有种说法是新建
/etc/default/isc-dhcp-server文件,可以在其中指定要监听的网卡,不过我这尝试过,发现并不管用,可能还要哪里遗漏了什么:
# Defaults for isc-dhcp-server (sourced by /etc/init.d/isc-dhcp-server)
# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf).
#DHCPDv4_CONF=/etc/dhcp/dhcpd.conf
#DHCPDv6_CONF=/etc/dhcp/dhcpd6.conf
# Path to dhcpd's PID file (default: /var/run/dhcpd.pid).
#DHCPDv4_PID=/var/run/dhcpd.pid
#DHCPDv6_PID=/var/run/dhcpd6.pid
# Additional options to start dhcpd with.
# Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead
#OPTIONS=""
# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
# Separate multiple interfaces with spaces, e.g. "eth0 eth1".
INTERFACESv4="br-lan"
INTERFACESv6="br-lan"
创建 /etc/dhcpd.conf 文件并写入以下内容:
tee /etc/dhcpd.conf <<\EOF
# /etc/dhcpd.conf
subnet 192.168.10.0 netmask 255.255.255.0 {
# Range for clients
range 192.168.10.100 192.168.10.200;
# Additional options
option domain-name-servers 192.168.10.1;
option domain-name "domain.example";
option routers 192.168.10.1;
default-lease-time 600;
max-lease-time 7200;
}
EOF
/etc/dhcpd.conf是负责DHCPv4的配置。如果不关注DHCPv4,可以不创建。
创建 /etc/dhcpd6.conf 文件并写入以下内容:
tee /etc/dhcpd6.conf <<\EOF
# /etc/dhcpd6.conf
authoritative;
default-lease-time 3600;
max-lease-time 86400;
# Enable RFC 5007 support
#allow leasequery;
# Global definitions for name server address(es) and domain search list
#option dhcp6.name-servers 3ffe:501:ffff:100:200:ff:fe00:3f3e;
#option dhcp6.domain-search "test.example.com","example.com";
# Set preference to 255 (maximum) in order to avoid waiting for
# additional servers when there is only one
#option dhcp6.preference 255;
# Server side command to enable rapid-commit (2 packet exchange)
#option dhcp6.rapid-commit;
# The delay before information-request refresh
# (minimum is 10 minutes, maximum one day, default is to not refresh)
# (set to 6 hours)
#option dhcp6.info-refresh-time 3600;
subnet6 2001:758:1:1::/64 {
# Range for clients
range6 2001:758:1:1:1:: 2001:758:1:1:1::ffff;
# Range for clients requesting a temporary address
range6 2001:758:1:1:2:: /112 temporary;
# Prefix range for delegation to sub-routers pd
prefix6 2001:758:1:1:3:: 2001:758:1:1:4:: /80;
# Additional options
option dhcp6.name-servers 2001:758:1:1::1;
option dhcp6.domain-search "domain.example";
}
EOF
调整服务开机自启动顺序
实测发现默认的开机启动时机太早,会导致服务启动后绑定网卡失败。
将 isc-dhcp-server 服务开机启动顺序放到靠后的位置(原理请看 /etc/rc.common & /etc/rc.d/S*):
# 取消设置开机自启
service dhcpd disable
service dhcpd6 disable
# 修改开机自启顺序,原始:dhcp START=25 dhcp6 START=65
sed -i 's/START=\d\+/START=99/g' /etc/init.d/dhcpd
sed -i 's/START=\d\+/START=99/g' /etc/init.d/dhcpd6
# 重新设置开机自启
service dhcpd enable
service dhcpd6 enable
dhcpd是负责DHCPv4的服务。如果不关注DHCPv4,可以不操作。
https://github.com/openwrt/packages/tree/openwrt-22.03/net/isc-dhcp
启动服务
service dhcpd start
service dhcpd6 start
dhcpd是负责DHCPv4的服务。如果不关注DHCPv4,可以不操作。
通过以下命令查看 dhcpd 服务日志:
logread | grep dhcpd
Wed Dec 10 19:25:26 2025 daemon.info dhcpd: Bound to *:547
...
Wed Dec 10 19:25:26 2025 daemon.info dhcpd: Server starting service.
检查一下启动的服务情况:
service
正常结果如下,dhcpd 与 dhcpd6 处于运行状态。
Usage: service <service> [command]
...
/etc/init.d/dhcpd enabled running
/etc/init.d/dhcpd6 enabled stopped
...
这里的
stopped不必理会,是软件包适配问题,可通过netstat命令确认。
检查一下启动的服务网络情况:
netstat -tplnu
正常结果如下,dhcpd 绑定在 0.0.0.0:67(DHCPv4) 和 :::547(DHCPv6)。
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
udp 0 0 0.0.0.0:67 0.0.0.0:* 8087/dhcpd
udp 0 0 :::547 :::* 7582/dhcpd
结果验证
终端验证
- ifconfig
wlan0 Link encap:Ethernet HWaddr d0:a0:d6:1b:3a:e8 Driver wlan inet addr:192.168.10.100 Bcast:192.168.10.255 Mask:255.255.255.0 inet6 addr: fe80::2623:b587:4f56:e6a/64 Scope: Link inet6 addr: 2001:758:1:1:1::fda5/128 Scope: Global UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:19 errors:0 dropped:0 overruns:0 frame:0 TX packets:27 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3000 RX bytes:2865 TX bytes:3163 - ip address show dev wlan0
36: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 3000 link/ether d0:a0:d6:1b:3a:e8 brd ff:ff:ff:ff:ff:ff inet 192.168.10.100/24 brd 192.168.10.255 scope global wlan0 valid_lft forever preferred_lft forever inet6 2001:758:1:1:1::fda5/128 scope global nodad dynamic noprefixroute valid_lft 3095sec preferred_lft 1745sec inet6 fe80::2623:b587:4f56:e6a/64 scope link stable-privacy valid_lft forever preferred_lft forever - ping6 -c 4 2001:758:1:1::1
PING 2001:758:1:1::1(2001:758:1:1::1) 56 data bytes 64 bytes from 2001:758:1:1::1: icmp_seq=1 ttl=64 time=7.94 ms 64 bytes from 2001:758:1:1::1: icmp_seq=2 ttl=64 time=7.89 ms 64 bytes from 2001:758:1:1::1: icmp_seq=3 ttl=64 time=10.2 ms 64 bytes from 2001:758:1:1::1: icmp_seq=4 ttl=64 time=8.42 ms --- 2001:758:1:1::1 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3007ms rtt min/avg/max/mdev = 7.894/8.635/10.287/0.979 ms - ip -6 route show table 0
2001:758:1:1:1::fda5 dev wlan0 table wlan0 proto static metric 1024 pref medium 2001:758:1:1::/64 dev wlan0 table wlan0 proto kernel metric 256 expires 5270sec pref medium 2001:758:1:1::/64 dev wlan0 table wlan0 proto static metric 1024 pref medium fe80::/64 dev wlan0 table wlan0 proto kernel metric 256 pref medium fe80::/64 dev wlan0 table wlan0 proto static metric 1024 pref medium default via fe80::ee88:8fff:febb:9182 dev wlan0 table wlan0 proto ra metric 1024 expires 2570sec hoplimit 64 pref medium 2001:758:1:1:1::fda5 dev wlan0 table wlan0_local proto static metric 1024 pref medium 2001:758:1:1::/64 dev wlan0 table wlan0_local proto static metric 1024 pref medium fe80::/64 dev wlan0 table wlan0_local proto static metric 1024 pref medium fe80::/64 dev dummy0 table dummy0 proto kernel metric 256 pref medium default dev dummy0 table dummy0 proto static metric 1024 pref medium local ::1 dev lo table local proto kernel metric 0 pref medium local 2001:758:1:1:1::fda5 dev wlan0 table local proto kernel metric 0 pref medium local fe80::2623:b587:4f56:e6a dev wlan0 table local proto kernel metric 0 pref medium local fe80::d8b3:36ff:fe3a:3c4c dev dummy0 table local proto kernel metric 0 pref medium multicast ff00::/8 dev dummy0 table local proto kernel metric 256 pref medium multicast ff00::/8 dev wlan0 table local proto kernel metric 256 pref medium