家用NAS利用公网IPV6外网访问
2019/10/20 计算机 次 0 条
通过IPV6从外网访问家里的NAS需要做两件事:一是解决IPV6的DDNS,二是配置路由器的防火墙。
先说DDNS,我用的是群晖的NAS,动态域名用的是Dnspod,但是群晖NAS自带的DDNS不支持Dnspod的IPV6更新。
只能自己写脚本来解决这个问题,直接上代码: 【以下代码在群晖DSM6系统下测试正常,其他设备可能需要做修改】
#!/bin/bash #Dnspod DDNS6 with BashShell #改编自Github:https://github.com/kkkgo/dnspod-ddns-with-bashshell #CONF START #API_ID和API_Token在dnspod的控制台 -> 用户中心 -> 安全设置 -> API Token 中获取 API_ID="12345" API_Token="abcdef123456abcdef123456abcdef123456" domain="yourdomain.com" host="yourhost" DEV="eth0" #CONF END date IPREX="((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))" DEVIP=$(ip -6 addr list scope global $DEV | grep -v " fd" | grep inet6 | awk '{print $2}' | head -n 1) if (echo $DEVIP | grep -qEvo "$IPREX");then echo "Get $DEV inet6 IP Failed." exit else DEVIP=$(echo $DEVIP | grep -Eo "$IPREX" | head -n 1) fi echo "[DEV IP]:$DEVIP" DNSTEST=$(nslookup -q=AAAA $host.$domain) if (echo $DNSTEST | grep -qEvo "$IPREX");then echo "Get $host.$domain DNS Failed." exit else DNSIP=$(echo $DNSTEST | grep -Eo "$IPREX" | tail -n 1) fi echo "[DNS IP]:$DNSIP" if [ "$DNSIP" == "$DEVIP" ];then echo "IP SAME IN DNS,SKIP UPDATE." exit fi token="login_token=${API_ID},${API_Token}&format=json&domain=${domain}&sub_domain=${host}" Record=$(curl -s -k -X POST https://dnsapi.cn/Record.List -d "${token}") iferr=$(echo ${Record#*code} | cut -d'"' -f3) if [ "$iferr" == "1" ];then record_ip=$(echo ${Record#*value} | cut -d'"' -f3) echo "[API IP]:$record_ip" if [ "$record_ip" == "$DEVIP" ];then echo "IP SAME IN API,SKIP UPDATE." exit fi record_id=$(echo ${Record#*\"records\"\:\[\{\"id\"} | cut -d'"' -f2) record_line_id=$(echo ${Record#*line_id} | cut -d'"' -f3) echo Start DDNS update... ddns=$(curl -s -k -X POST https://dnsapi.cn/Record.Modify -d "${token}&record_id=${record_id}&record_line_id=${record_line_id}&value=${DEVIP}&record_type=AAAA") ddns_result="$(echo ${ddns#*message\"} | cut -d'"' -f2)" echo -n "DDNS upadte result:$ddns_result " echo $ddns | grep -Eo "$IPREX" | tail -n 1 else echo -n Get $host.$domain error : echo $(echo ${Record#*message\"}) | cut -d'"' -f2 fi
将以上代码保存为.sh文件,然后在NAS系统里添加一个计划任务:
搞定了DDNS,下一步就是配置路由器的防火墙了。
Openwrt是基于Linux – ip6tables的防火墙。默认情况下,ip6tables只允许了v6子网内的设备被ping,只允许特定类型的ICMPv6报文通过,其他通信报文一律丢弃了。
所以虽然IPv6下每个设备都有公网地址,但是还不至于不安全到每个设备都可让人从外网随便连接。想要能从外网访问你家里的NAS主机,就需要修改一下路由器的防火墙设置。
我用的路由器是Openwrt的系统,直接在防火墙设置里添加几条自定义规则然后重启防火墙就OK了:
简单介绍一下上面几条指令。
不同设备获取的IPv6地址有区别,较为通用的是无状态EUI-64地址,操作系统通过网卡的mac地址生成一个64位固定后缀,以及路由器下发的64位前缀,合成一个固定的IPv6地址。
但是家用宽带ISP提供的IPv6前缀是不定期变化的。所以你家里的NAS虽然能获取公网的IPV6地址,但是这个地址不是固定的,每次你的光猫重新拨号,这个地址都会变化,怎么办呢?
方案一,直接关闭ipv6的防火墙,简单粗暴,但是不安全:
ip6tables -F ip6tables -X ip6tables -P INPUT ACCEPT ip6tables -P OUTPUT ACCEPT ip6tables -P FORWARD ACCEPT
方案二,直接开放所有地址的特定端口,也不太完美:
ip6tables -I FORWARD -p tcp --dport 5000 -j ACCEPT
方案三,因为特定设备的IPV6地址后缀一般是固定的,那么我们可以利用掩码的方式,让IPTABLES匹配设备的EUI-64后缀来放行这个地址的数据包。
ip6tables -I FORWARD -d ::abcd:1234:5678:90ef/::ffff:ffff:ffff:ffff -p tcp --dport 5000 -j ACCEPT
完美解决,再也不怕ISP不提供公网IPV4了。