L

linux系统下配置阿里DDNS(IPv6)

肉松 笔记 2019-12-14

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运行即可。

计划任务

  1. 群晖,群晖在设置--计划任务里设置即可。
  2. OpenWrt等linux都可以使用crontab执行计划任务,参考https://www.rousongs.com/1262.html

拓展

至于如何实现IPv4,有空再写。

PREV
frp内网穿透的安装和使用(基础篇)
NEXT
【脑洞】一个文言文编程语言

评论(18)

发布评论
  1. leo leo

    可以修改下脚本根据mac地址解析多个设备的ipv6地址吗?这样的话就不需要socat进行转发了。

  2. Ozzy Ozzy

    希望优化对@记录的支持

  3. MR wang MR wang

    裸域有解决办法了吗?

  4. 牛爷爷 牛爷爷

    直接解析主机域名@好像不行啊,试了两次都没有解析

    1. 裸域@不行,必须是二级域名

  5. 云

    使用了一下,发现可以设置ipv6,我设备分配到2个公网v6地址1个内网v6地址。,但是脚本获取到的有两个ipv6地址。经过测试其中一个地址是正常的公网v6地址,另一个地址是以240e开头、80ef结尾,这个地址不能访问,但是脚本更新上去的恰恰是这个不能访问的地址,不知道博主您有没有遇到此类问题。

    1. 240e开头是电信正常的公网ipv6呀?我的黑群也是获取到两个240e开头的ipv6,两个都能正常访问到。

      1. 云

        是的,用ip a命令看到的两个ipv6地址的确都可以访问,但是脚本更新的ip却不是其中的任何一个,也不是fe80的内网ip,出现了这个开头240e结尾80ef的新ip,而且这个ip也无法访问。所以有点懵。环境是ubuntu18.04、华硕路由原生固件。

  6. hanhao hanhao

    运行后能够显示ipv6地址,并且有一个 added record,但是实际域名并没有更新。

  7. 77556 77556

    用了一下发现不能更新原有的记录,造成访问缓慢

    1. 这段代码裸域使用有点问题,显示IP更新成功但实际更新不上去,用子域没有问题。建议IPv6 DNS用阿里的2400:3200::1 / 2400:3200:baba::1, 运营商的IPv6 DNS刷新很慢。

  8. root@omv:/home# ./ddns.sh
    ./ddns.sh:行6: $'r': 未找到命令
    ./ddns.sh:行16: 未预期的符号 `$'{r'' 附近有语法错误
    '/ddns.sh:行16: `die () {

    1. eccb eccb

      同样的问题,请问,怎么解决的??????

      1. 使用dos2unix对脚本转换

  9. 羽露 羽露

    @和*都不能用

    1. 感谢反馈!

      1. Geners Geners

        是个小bug,要将后面的 RR=$aliddnsipv6_name1 改为 RR=$aliddnsipv6_name

        1. Geners Geners

          说错了,这个地方没问题。主要是'@'符号在后面使用时要用编码格式'%40'替换才能够正确解析