IPv6日渐完善,家里的宽带和手机也都分配了ipv6全球单播地址,手机分到了/64,宽带更是分到了/56。测试了一下运营商内外的连通性也都还可以,基本能跑满带宽,IPv6终于可以用起来了,个个都是公网,不用再渴求ipv4和搞内网穿透了。
适用
此教程适用于基于linux的各种系统,ubuntu、centos、openwrt、群晖 等等,本文只介绍IPv6,不涉及IPv4。
代码
aliddnsipv6_ak="阿里AccessKey ID"
aliddnsipv6_sk="阿里Access Key Secret"
aliddnsipv6_name1='二级域名前缀,比如使用nas.rousongs.com,此处填写nas'
aliddnsipv6_domain='主域名,此处填写rousongs.com'
aliddnsipv6_ttl="600"
if [ "$aliddnsipv6_name1" = "@" ]
then
aliddnsipv6_name=$aliddnsipv6_domain
else
aliddnsipv6_name=$aliddnsipv6_name1.$aliddnsipv6_domain
fi
now=`date`
die () {
echo $1
}
ipv6s=`ip addr show eth0 | grep "inet6.*global" | awk '{print $2}' | awk -F"/" '{print $1}'` || die "$ipv6"
for ipv6 in $ipv6s
do
#ipv6 = $ipv6
break
done
echo $ipv6
current_ipv6=`nslookup -query=AAAA $aliddnsipv6_name 2>&1`
#echo $current_ipv6
current_ipv6=`echo "$current_ipv6" | grep 'Address: ' | tail -n1 | awk '{print $NF}'`
echo $current_ipv6
if [ "$?" -eq "0" ]
then
current_ipv6=`echo "$current_ipv6" | grep 'Address: ' | tail -n1 | awk '{print $NF}'`
echo $current_ipv6
if [ "$ipv6" = "$current_ipv6" ]
then
echo "skipping"
fi
# fix when A record removed by manual dns is always update error
else
unset aliddnsipv6_record_id
fi
timestamp=`date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ"`
urlencode() {
# urlencode <string>
out=""
while read -n1 c
do
case $c in
[a-zA-Z0-9._-]) out="$out$c" ;;
*) out="$out`printf '%%%02X' "'$c"`" ;;
esac
done
echo -n $out
}
enc() {
echo -n "$1" | urlencode
}
send_request() {
local args="AccessKeyId=$aliddnsipv6_ak&Action=$1&Format=json&$2&Version=2015-01-09"
local hash=$(echo -n "GET&%2F&$(enc "$args")" | openssl dgst -sha1 -hmac "$aliddnsipv6_sk&" -binary | openssl base64)
curl -s "http://alidns.aliyuncs.com/?$args&Signature=$(enc "$hash")"
}
get_recordid() {
grep -Eo '"RecordId":"[0-9]+"' | cut -d':' -f2 | tr -d '"'
}
query_recordid() {
send_request "DescribeSubDomainRecords" "SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&SubDomain=$aliddnsipv6_name&Timestamp=$timestamp&Type=AAAA"
}
update_record() {
send_request "UpdateDomainRecord" "RR=$aliddnsipv6_name1&RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&TTL=$aliddnsipv6_ttl&Timestamp=$timestamp&Type=AAAA&Value=$(enc $ipv6)"
}
add_record() {
send_request "AddDomainRecord&DomainName=$aliddnsipv6_domain" "RR=$aliddnsipv6_name1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&TTL=$aliddnsipv6_ttl&Timestamp=$timestamp&Type=AAAA&Value=$(enc $ipv6)"
}
#add support */%2A and @/%40 record
if [ "$aliddnsipv6_record_id" = "" ]
then
aliddnsipv6_record_id=`query_recordid | get_recordid`
#echo '-----------------' $aliddnsipv6_record_id
fi
if [ "$aliddnsipv6_record_id" = "" ]
then
aliddnsipv6_record_id=`add_record | get_recordid`
echo "added record $aliddnsipv6_record_id"
else
update_record $aliddnsipv6_record_id
echo "updated record $aliddnsipv6_record_id"
fi
配置
将以上代码保存为aliddns.sh,需要修改的项有以下几处:
aliddnsipv6_ak="阿里AccessKey ID"
aliddnsipv6_sk="阿里Access Key Secret"
aliddnsipv6_name1='二级域名前缀,比如使用nas.rousongs.com,此处填写nas'
aliddnsipv6_domain='主域名'
第19行左右ipv6s=
ip addr show eth0`,eth0为网卡名称,修改成对应网卡名称。
然后将此文件放于任意位置,在当前目录输入./aliddns.sh
运行即可。
计划任务
- 群晖,群晖在
设置--计划任务
里设置即可。 - OpenWrt等linux都可以使用crontab执行计划任务,参考https://www.rousongs.com/1262.html
拓展
至于如何实现IPv4,有空再写。
可以修改下脚本根据mac地址解析多个设备的ipv6地址吗?这样的话就不需要socat进行转发了。
希望优化对@记录的支持
裸域有解决办法了吗?
直接解析主机域名@好像不行啊,试了两次都没有解析
裸域@不行,必须是二级域名
使用了一下,发现可以设置ipv6,我设备分配到2个公网v6地址1个内网v6地址。,但是脚本获取到的有两个ipv6地址。经过测试其中一个地址是正常的公网v6地址,另一个地址是以240e开头、80ef结尾,这个地址不能访问,但是脚本更新上去的恰恰是这个不能访问的地址,不知道博主您有没有遇到此类问题。
240e开头是电信正常的公网ipv6呀?我的黑群也是获取到两个240e开头的ipv6,两个都能正常访问到。
是的,用ip a命令看到的两个ipv6地址的确都可以访问,但是脚本更新的ip却不是其中的任何一个,也不是fe80的内网ip,出现了这个开头240e结尾80ef的新ip,而且这个ip也无法访问。所以有点懵。环境是ubuntu18.04、华硕路由原生固件。
运行后能够显示ipv6地址,并且有一个 added record,但是实际域名并没有更新。
用了一下发现不能更新原有的记录,造成访问缓慢
这段代码裸域使用有点问题,显示IP更新成功但实际更新不上去,用子域没有问题。建议IPv6 DNS用阿里的2400:3200::1 / 2400:3200:baba::1, 运营商的IPv6 DNS刷新很慢。
root@omv:/home# ./ddns.sh
./ddns.sh:行6: $'r': 未找到命令
./ddns.sh:行16: 未预期的符号 `$'{r'' 附近有语法错误
'/ddns.sh:行16: `die () {
同样的问题,请问,怎么解决的??????
使用dos2unix对脚本转换
@和*都不能用
感谢反馈!
是个小bug,要将后面的 RR=$aliddnsipv6_name1 改为 RR=$aliddnsipv6_name
说错了,这个地方没问题。主要是'@'符号在后面使用时要用编码格式'%40'替换才能够正确解析