HNU 新校园网使用 OpenWRT 配置 IPv6 指南

2025年11月4日

目录
目录

配置前须知: 本教程适用于 2025 年 9 月更新后的湖南大学新校园网,未来校园网络依然有更新可能,本教程可能也失效,其他高校的网络也有可能适用 or 不适用。
且在新的校园网情况下,配置 IPv6 并不一定能提高网速,而且也不一定能省钱

接续 cyp 学长的 HNU 校园网 IPv6 免流教程 2.0,写一下自己配置 HNU 新校园网的 IPv6 教程,对校园网账号和电信宽带账号都适用。 参考了这位知乎大佬的指南: 校园网环境下 Openwrt 配置 ipv6教程——以 nat6为例,这篇指南对 HNU 新校园网同样适用,我只是做了一点小修改。 你也可以结合我的一篇旧文章:使用小米 AX3000T 配置 Openwrt 接入 HNU 新校园网食用~

不过配置前须注意,在我所在的天马园区的宿舍楼,校园网 IPv6 比较不稳定,获取都有点看运气……

且在当今 HNU 的网络环境下,你很难保证教育网 IPv6 的高可用性,也许它在宿舍的效果可能网速比 IPv4 网络还差,且访问一些网站丢包卡顿高延迟 (至少在我的宿舍里是这样……)。 经个人测试,在研究生楼,HNU 的校园网络表现最好,且教育网 IPv6 也发挥了不限速的实力,网速甚至达到过 300Mbps 的速度!(比宿舍100兆限速好太多……) 不过这也是看运气的事情,没准在你的宿舍网络更好呢🤔。 当然,如果你想要更好的内网穿透,有一个 IPv6 地址可以有巨大的提升,不过这也是后话了。


IPV6 接口设置

wan6 接口配置 DHCPv6

当你刷好了路由器的 openwrt 配置好了 wan 和 lan 基本上设置,或者桥接的 wwan 的设置,打开接口→wan6,设置设备为 @wwan,协议选择 DHCPv6 客户端,如图配置请求 IPv6 地址请求 IPv6 前缀。基本配置如图: image.png

然后我们需要前往高级设置,配置一下IPv6分配长度设定为64。如图配置。 image.png

lan 接口分配 IPv6

我们需要前往高级选项,将 IPv6分配长度设定为64,然后前往 DHCP 服务器进行一些配置。 image.png

然后选择 DHCP 服务器,勾选动态 DHCP,以及强制image.png

然后前往 IPv6 配置,如图勾选指定的主接口,然后 RA 服务 DHCPv6服务 选择为服务器模式,禁用 NDP 代理不要选指定的主接口。 image.png 然后在 RA 设置里,如图配置: image.png 然后前往接口→全局网络选项,修改一下 IPv6 ULA 前缀,我这里直接跟随教程修改为fd34:fe56:7891:2f3a::/64。可以照抄。 这是内网 IPv6 地址,只要不冲突就无伤大雅。 如果想要更规范,可以用默认的。 image.png

这样,下面的设备就可以拿到 ip 为 fd34开头的 inet6地址。

防火墙配置

前往网络→防火墙,如图配置,把各种入站数据出站数据区域内转发都改为接受,然后 wan 那里配置勾选 IP 动态伪装。 image.png


内网 NAT6的配置

这是我自己使用 HNU 网络情况修改的脚本版本,增加了一些鲁棒性:

#!/bin/sh /etc/rc.common
# NAT6 init script for OpenWrt // Depends on package: kmod-ipt-nat6

# edited by Sad Pencil at 2020-02-09
# replace route command with ip command to solve issues on new OpenWRT


# edited by Sad Pencil at 2021-11-29
# update line WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.device" || uci get "network.$WAN6_NAME.ifname")


START=55

# Options
# -------

# Use temporary addresses (IPv6 privacy extensions) for outgoing connections? Yes: 1 / No: 0
PRIVACY=1

# Maximum number of attempts before this script will stop in case no IPv6 route is available
# This limits the execution time of the IPv6 route lookup to (MAX_TRIES+1)*(MAX_TRIES/2) seconds. The default (15) equals 120 seconds.
MAX_TRIES=15

# An initial delay (in seconds) helps to avoid looking for the IPv6 network too early. Ideally, the first probe is successful.
# This would be the case if the time passed between the system log messages "Probing IPv6 route" and "Setting up NAT6" is 1 second.
DELAY=5

# Logical interface name of outbound IPv6 connection
# There should be no need to modify this, unless you changed the default network interface names
# Edit by Vincent: I never changed my default network interface names, but still I have to change the WAN6_NAME to "wan" instead of "wan6"
WAN6_NAME="wan6"

# ---------------------------------------------------
# Options end here - no need to change anything below

boot() {
        [ $DELAY -gt 0 ] && sleep $DELAY
                # --- 第一步:获取 WAN6_INTERFACE ---

        WAN6_DEVICE_REF=$(uci get "network.$WAN6_NAME.device" 2>/dev/null)

        if [ -n "$WAN6_DEVICE_REF" ]; then
        # 存在 device 选项,检查是否为引用
        if [[ "$WAN6_DEVICE_REF" == @* ]]; then
                REFERENCED_IFACE=${WAN6_DEVICE_REF:1}
                # 获取被引用接口的实际 device 名称 (例如:phy0-sta0)
                WAN6_INTERFACE=$(uci get "network.$REFERENCED_IFACE.device" 2>/dev/null)
        else
                # 直接使用 device 名称
                WAN6_INTERFACE=$WAN6_DEVICE_REF
        fi
        else
        # 原作者的逻辑:如果 device 找不到,尝试 ifname
        WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.ifname" 2>/dev/null)
        fi

        # 确保 WAN6_INTERFACE 最终被设置 (如果 uci 找不到,OpenWrt 接口名称可能就是 wan6)
        if [ -z "$WAN6_INTERFACE" ]; then
        WAN6_INTERFACE=$WAN6_NAME
        fi

        # 注意:上面这段代码替换了您原脚本中获取 WAN6_INTERFACE 的部分
        PROBE=0
        COUNT=1
        while [ $PROBE -eq 0 ]
        do
                if [ $COUNT -gt $MAX_TRIES ]
                then
                        logger -t NAT6 "Fatal error: No IPv6 route found (reached retry limit)" && exit 1
                fi
                sleep $COUNT
                COUNT=$((COUNT+1))
                PROBE=$(ip -6 route | grep -i '^default.*via' | grep -i -F "dev $WAN6_INTERFACE" | grep -i -o 'via.*' | wc -l)
        done

        logger -t NAT6 "Setting up NAT6"

        if [ -z "$WAN6_INTERFACE" ] || [ ! -e "/sys/class/net/$WAN6_INTERFACE/" ] ; then
                logger -t NAT6 "Fatal error: Lookup of $WAN6_NAME interface failed. Were the default interface names changed?" && exit 1
        fi
        # 替换原作者的硬编码:
        # WAN6_GATEWAY=$(ip -6 route |grep -o '2001.*1102'|sed s'/1102/1101::1/g')
        

        # 尝试获取接口上的全局 IPv6 地址
        MY_IPV6_ADDR=$(ip -6 addr show dev $WAN6_INTERFACE | grep -oP 'scope global\s+\K[^/]+' 2>/dev/null)

        if [ -n "$MY_IPV6_ADDR" ]; then
            # 提取前缀(前四个字段),例如 2001:250:4402:1119
            IPV6_PREFIX=$(echo $MY_IPV6_ADDR | cut -d: -f-4)
            # 构造推算的全局网关:前缀 + ::1
            WAN6_GATEWAY="${IPV6_PREFIX}::1"
        else
            # 如果没有找到全局地址,则 WAN6_GATEWAY 保持为空
            WAN6_GATEWAY=""
        fi

        # 检查是否推算成功
        if [ -z "$WAN6_GATEWAY" ] ; then
                logger -t NAT6 "Fatal error: Cannot derive global IPv6 gateway for $WAN6_INTERFACE. Check if a global IPv6 address is assigned." && exit 1
        fi
        LAN_ULA_PREFIX=$(uci get network.globals.ula_prefix)
        if [ $(echo "$LAN_ULA_PREFIX" | grep -c -E "^([0-9a-fA-F]{4}):([0-9a-fA-F]{0,4}):") -ne 1 ] ; then
                logger -t NAT6 "Fatal error: IPv6 ULA prefix $LAN_ULA_PREFIX seems invalid. Please verify that a prefix is set and valid." && exit 1
        fi

        ip6tables -t nat -I POSTROUTING -s "$LAN_ULA_PREFIX" -o "$WAN6_INTERFACE" -j MASQUERADE
        if [ $? -eq 0 ] ; then
                logger -t NAT6 "Added IPv6 masquerading rule to the firewall (Src: $LAN_ULA_PREFIX - Dst: $WAN6_INTERFACE)"
        else
                logger -t NAT6 "Fatal error: Failed to add IPv6 masquerading rule to the firewall (Src: $LAN_ULA_PREFIX - Dst: $WAN6_INTERFACE)" && exit 1
        fi

        ip -6 route add 2000::/3 via "$WAN6_GATEWAY" dev "$WAN6_INTERFACE"
        if [ $? -eq 0 ] ; then
                logger -t NAT6 "Added $WAN6_GATEWAY to routing table as gateway on $WAN6_INTERFACE for outgoing connections"
        else
                logger -t NAT6 "Error: Failed to add $WAN6_GATEWAY to routing table as gateway on $WAN6_INTERFACE for outgoing connections"
        fi

        if [ $PRIVACY -eq 1 ] ; then
                echo 2 > "/proc/sys/net/ipv6/conf/$WAN6_INTERFACE/accept_ra"
                if [ $? -eq 0 ] ; then
                        logger -t NAT6 "Accepting router advertisements on $WAN6_INTERFACE even if forwarding is enabled (required for temporary addresses)"
                else
                        logger -t NAT6 "Error: Failed to change router advertisements accept policy on $WAN6_INTERFACE (required for temporary addresses)"
                fi
                echo 2 > "/proc/sys/net/ipv6/conf/$WAN6_INTERFACE/use_tempaddr"
                if [ $? -eq 0 ] ; then
                        logger -t NAT6 "Using temporary addresses for outgoing connections on interface $WAN6_INTERFACE"
                else
                        logger -t NAT6 "Error: Failed to enable temporary addresses for outgoing connections on interface $WAN6_INTERFACE"
                fi
        fi

        exit 0
}

复制完毕后去 ssh 上去路由器,然后 vi /etc/init.d/nat6, I 后复制到脚本里再 :wq 退出,然后设定权限:

chmod +x /etc/init.d/nat6
/etc/init.d/nat6 enable

然后用 vim 继续 vi /etc/sysctl.conf 在最后又添加:

net.ipv6.conf.default.forwarding=2
net.ipv6.conf.all.forwarding=2
net.ipv6.conf.default.accept_ra=2
net.ipv6.conf.all.accept_ra=2

保存退出,最后:

ip6tables -t nat -A POSTROUTING -o $(uci get network.wan6.ifname) -j MASQUERADE

https://ipv6ready.me/ 看到这个就基本成功了: image.png

如果修改路由器任意配置后 IPv6 消失了,可以 ssh 上去路由器,然后继续 /etc/init.d/nat6 restart 试试,一般有效果。

你也可以去往网络->网络诊断,进行 IPv6 ping 确认路由器的 IPv6 获取情况。 image.png


LAN 侧内网分布配置 odhcpd

这里是配置 NAT6 时候,可能出现 IPv6 不稳定的情况,导致路由器有 IPv6 而下拉设备虽有 IPv6 认证但无法正常连通 IPv6 地址的解决方法。

使用的是 odhcpd,配置也很简单:

opkg update
opkg install odhcpd-ipv6only      # 已装会提示已安装

我的 odhcpd 配置如图,可供参考:

root@OpenWrt:~# cat /etc/config/odhcpd

config odhcpd 'odhcpd'

        option maindhcp     '0'                     # 只负责 IPv6

        option leasefile    '/tmp/hosts/odhcpd'

        option leasetrigger '/usr/sbin/odhcpd-update'

        option loglevel     '4'

root@OpenWrt:~#

然后进行:

/etc/init.d/odhcpd enable
/etc/init.d/odhcpd start
service odhcpd status             # running
netstat -lnp | grep odhcpd        # 应看到 UDP 546/547 监听 br-lan

应该看到:

root@OpenWrt:~# netstat -lnp | grep odhcpd

udp        0      0 :::547                  :::*                                12552/odhcpd

raw        0      0 ::%168:58               :::*                    58          12552/odhcpd

root@OpenWrt:~#

如果设备端拿到 ULA 前缀的 IPv6 地址,但无法 ping 通 IPv6 地址,那么进入路由器端,使用:

# 给 lan 段显式声明默认路由标志
uci set dhcp.lan.ra_default='1'
uci commit dhcp
/etc/init.d/odhcpd restart

即可恢复正常。


dadfailed 问题

当然部署 IPv6也会有很多困难,比如出现 DADFAILED 问题,你可能在系统日志看见这个问题:

Tue Nov 4 20:55:13 2025 kern.info kernel: [768787.360836] IPv6: phy0-sta0: IPv6 duplicate address fe80::92fb:5dff:fef1:2fb8 used by 00:ad:d5:4b:16:ee detected! image.png

同时,你 ip a 可能会看见这个:
inet6 fe80::92fb:5dff:fef1:2fb8/64 scope link dadfailed tentative proto kernel_ll

这个时候就比较麻烦了,涉及到 MAC 地址冲突问题,出现这个问题往往是在校园网内有一个有缘人连接 HNU,网络 MAC 地址和你相同,当然作为 OpenWrt,我们可以直接改掉我们的 MAC 地址(改掉后需要重新进入 web.hnu.edu.cn 进行验证)。

修改方法也很简单,我的做法很暴力,直接关闭 DAD 认证,避免 00:ad:d5:4b:16:ee 这个内网设备的追击。 自己必须在 phy0-sta0 接口上永久禁用 DAD 检查。

vi /etc/sysctl.conf ,然后添加:

net.ipv6.conf.phy0-sta0.dad_transmits = 0

应用更改并重启网络:

sysctl -p
/etc/init.d/network restart

等待一会后,重新认证校园网登录,应该成功。 去服务器 ssh,使用 ip a,应该可以看到:

11: phy0-sta0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000

    link/ether ae:2e:9d:1a:d7:15 brd ff:ff:ff:ff:ff:ff

    inet 10.68.157.83/15 brd 10.69.255.255 scope global phy0-sta0

       valid_lft forever preferred_lft forever

    inet6 2001:250:4402:1119:ac2e:9dff:fe1a:d715/64 scope global dynamic mngtmpaddr proto kernel_ra 

       valid_lft 258906sec preferred_lft 172506sec

    inet6 fe80::ac2e:9dff:fe1a:d715/64 scope link proto kernel_ll 

       valid_lft forever preferred_lft forever

dadfailed 错误消失~


IPv6 优先

前往 https://ipw.cn/ipv6/ 可以更快速地看到自己的 IPv6地址,同时你也可以看到自己的网络是 IPV4 优先还是 IPV6 优先。

一般使用 IPV6 优先比较好,毕竟不限速+不计费流量(教育网 IPv6的好处)。如果你的 IPv6 配置正常,浏览器会为你默认配置 IPv6 优先。

但是我这里有一个奇怪的配置问题,使用测速网站可能无法测出正常的网速,但正常使用无碍,能正常使用就可以了。


一个校园网登录脚本

听说 HNU 校园网更新后经常断连,需要重新登录连接,虽然我自己还没有遇到这个问题,但是维持稳定的网络环境,我自己用 BurpSuite 抓包分析了一下 HNU 的校园网验证,写了一个用于电信宽带验证的小脚本。
这个 HNU 校园网的登录脚本,挂在自己的 openwrt 路由器上,定时 30min 一次运行,仅供参考。
这个脚本的使用前提是你的 DNS 配置正确,为校园的内网 DNS,可以访问 web.hnu.edu.cn 进入验证页面。

自己抓包看了看,如果你不使用电信宽带使用校园网,那么你的 USER_ACCOUNT 改为 USER_ACCOUNT=",0,你的学号" 即可,把@telecom去掉。
然后注意修改 phy0-sta0 为你自己的网络接口,比如 wan 啊,phy1-sta0 之类。

#!/bin/sh

# 用户信息配置 
USER_ACCOUNT=",0,你的学号@telecom"
USER_PASSWORD="你的个人门户密码"
# -------------------

# 从物理设备名 phy0-sta0 获取IP
WLAN_USER_IP=$(ifconfig phy0-sta0 | grep 'inet addr' | cut -d ':' -f 2 | cut -d ' ' -f 1)

if [ -z "$WLAN_USER_IP" ]; then
    logger "HNU Login: [失败] 未能从物理设备(phy0-sta0)获取到IP地址,脚本退出。"
    exit 1
fi

# 使用域名,因为我们确认了DNS是好的
AUTH_URL="http://web.hnu.edu.cn:801/eportal/portal/login?callback=dr1003&login_method=1&user_account=${USER_ACCOUNT}&user_password=${USER_PASSWORD}&wlan_user_ip=${WLAN_USER_IP}&wlan_user_ipv6=&wlan_user_mac=000000000000&wlan_ac_ip=&wlan_ac_name=&jsVersion=4.2.1&terminal_type=3&lang=zh-cn&v=2485&lang=zh"

# 【V6 终极修正】增加 -L 处理重定向,并增加 --header "Referer: ..." 来模拟浏览器行为
RESPONSE=$(curl -s -L -m 5 --header "Referer: http://web.hnu.edu.cn/" "$AUTH_URL")
logger "HNU Login: [信息] 已发送伪装Referer的登录请求。"

if echo "$RESPONSE" | grep -q '"result":1'; then
    logger "HNU Login: [成功] 服务器返回认证成功!"
else
    logger "HNU Login: [警告] 认证可能失败,服务器返回: $RESPONSE"
fi

exit 0

然后去 vi /etc/login_hnu.sh,复制后 wq 保存,然后 crontab -e,在打开的 vim 编辑器中,添加以下一行内容:

*/30 * * * * /etc/login_hnu.sh

之后 :wq 保存


听 cry 学长说,“HNU 校园网完全是一个黑盒系统”。 在一片漆黑的环境下接几根线的确是很费脑力和时间的。我自己配置 IPv6 也经历了很多让人想要放弃的瞬间……但学长学姐们的指南帮助了我很多很多,我也想接续这份薪火。
我更希望我的教程可以帮到更多未来的 HNU 学子们。
Enjoy the IPv6 world!