梅林固件使用自定义DDNS更新aliyun DDNS的ipv6地址

移动宽带分配的ipv4是内网ip,但是可以分配ipv6地址。梅林固件默认不支持ipv6地址,只能使用自定义shell来实现。参考koolshare的aliyun ddns shell,修改为支持对aliyun ddns的ipv6地址进行更新。

移动光猫如何分配ipv6地址请自行google。

梅林固件webgui界面配置

菜单:外部网络(WAN)-> DDNS

  1. 启用 DDNS 客户端 - 选 “是”。
  2. Method to retrieve WAN IP - 选 “Internal” 。如果用光猫拔号,选哪个都是一样的,路由器传给 ddns-start 的ip是内网ip。
  3. 服务器 - 选 “Custom”。
  4. 主机名称 - 填 “自定义的域名”。
  5. Forced update interval (in days) - 填“72” 。每天更新72次,即每20分钟更新一次DDNS。

新建shell /jffs/scripts/ddns-start

固件的自定义DDNS shell是 /jffs/scripts/ddns-start ,需要先检查是否启用了 jffs 的script功能。

#!/bin/sh

aliddns_ak="your aliyun ak"  #aliyun accessKey ID
aliddns_sk="your aliyun sk"  #aliyun access Key

aliddns_name="your host name"
aliddns_domain="your-domain.net"

alias echo_date='echo [$(TZ=UTC-8 date -R +%Y%m%d\ %X)]'
now=`echo_date`

die () {
        echo $1
        # dbus set aliddns_last_act="$now: failed($1)"
}

# whatismyip.akamai.com for ipv4
[ "$aliddns_curl" = "" ] && aliddns_curl="curl -s --interface vlan2 ipv6.whatismyip.akamai.com"
[ "$aliddns_dns" = "" ] && aliddns_dns="223.5.5.5"
[ "$aliddns_ttl" = "" ] && aliddns_ttl="600"

ip=`$aliddns_curl 2>&1` || die "$ip"

#support @ record nslookup
if [ "$aliddns_name" = "@" ];then
        current_ip=`nslookup $aliddns_domain $aliddns_dns 2>&1`
else
        current_ip=`nslookup $aliddns_name.$aliddns_domain $aliddns_dns 2>&1`
fi

if [ "$?" -eq "0" ];then
        current_ip=`echo "$current_ip" | grep 'Address 1' | tail -n1 | awk '{print $NF}'`
        if [ "$ip" = "$current_ip" ]
        then
                echo "aliyunddns: skipping ${aliddns_name}.${aliddns_domain} $ip $now" |tee /tmp/aliyun_ddns_ipv6.log
                #web ui show without @.
                if [ "$aliddns_name" = "@" ] ;then
                        nvram set ddns_hostname_x="$aliddns_domain"
                else
                        # nvram set ddns_hostname_x="$aliddns_name"."$aliddns_domain"
                        ddns_custom_updated 1
                        exit 0
                fi
        fi 
else
        # fix when A record removed by manual dns is always update error
        unset aliddns_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=$aliddns_ak&Action=$1&Format=json&$2&Version=2015-01-09"
        local hash=$(echo -n "GET&%2F&$(enc "$args")" | openssl dgst -sha1 -hmac "$aliddns_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=$aliddns_name1.$aliddns_domain&Timestamp=$timestamp"
}

update_record() {
        # Type=AAAA for ipv6
        send_request "UpdateDomainRecord" "RR=$aliddns_name1&RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&TTL=$aliddns_ttl&Timestamp=$timestamp&Type=AAAA&Value=$ip"
}

add_record() {
        # Type=AAAA for ipv6
        send_request "AddDomainRecord&DomainName=$aliddns_domain" "RR=$aliddns_name1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&TTL=$aliddns_ttl&Timestamp=$timestamp&Type=AAAA&Value=$ip"
}

#add support */%2A and @/%40 record
case "$aliddns_name" in
        \*)
                aliddns_name1=%2A
        ;;
        \@)
                aliddns_name1=%40
        ;;
        *)
                aliddns_name1="$aliddns_name"
        ;;
esac

if [ -z "$aliddns_record_id" ];then
        aliddns_record_id=`query_recordid | get_recordid`
fi

if [ -z "$aliddns_record_id" ];then
        aliddns_record_id=`add_record | get_recordid`
        echo "aliyunddns: added record $aliddns_record_id"
else
        update_record "$aliddns_record_id"
        echo "aliyunddns: updated record $aliddns_record_id"
fi

# save to file
if [ -z "$aliddns_record_id" ]; then
        # failed
        # dbus set aliddns_last_act="$now: failed"
        # nvram set ddns_hostname_x=`nvram get ddns_hostname_old`
        echo "aliyun ddns update failed"
else
        # dbus set aliddns_record_id="$aliddns_record_id"
        # dbus set aliddns_last_act="$now: success($ip)"
        # nvram set ddns_enable_x=1
        # web ui show without @.
        if [ "$aliddns_name" = "@" ] ;then
                # nvram set ddns_hostname_x="$aliddns_domain"
                ddns_custom_updated 1
        else
                # nvram set ddns_hostname_x="$aliddns_name"."$aliddns_domain"
                ddns_custom_updated 1
        fi
fi

测试DDNS是否正常

更新DDNS后,可以从 /tmp/syslog.log 看到DDNS的log。

正常的log如下:

Mar 12 10:34:05 start_ddns: update CUSTOM , wan_unit 0
Mar 12 10:34:05 custom_script: Running /jffs/scripts/ddns-start (args: 192.168.11.78)
Mar 12 10:34:07 ddns: Completed custom ddns update

参考