在linux下使用dnspod實現動態域名DDNS

以前的文章的,不知道還能不能用


將dnspodsh複製到/usr/bin下設置成可執行屬性,並在/etc/rc.local中加入下面一行即可實現你自己的免費DDNS:

/usr/bin/dnspodsh dnspod_name dnspod_passwaord &>/dev/null


保存時注意使用LINUX格式和UTF8編碼

設置域名的地方有2個數組,如果只有一個域名的話可以這麼設置:

domainList[0]='baidu.com \* @'

domainList[1]='baidu.com www'


文件名:dnspodsh


內容:


#!/bin/bash

 

##############################

# dnspodsh v0.3

# 基於dnspod api構架的bash ddns客戶端

# 作者:zrong(zengrong.net)

# 詳細介紹:http://zengrong.net/post/1524.htm

# 創建日期:2012-02-13

# 更新日期:2012-03-11

##############################

 

login_email=${1:?'必須提供登錄名'}

login_password=${2:?'必須提供密碼'}

format="json"

lang="en"

userAgent="dnspodsh/0.3([email protected])"

commonPost="login_email=$login_email&login_password=$login_password&format=$format&lang=$lang"

 

apiUrl='https://dnsapi.cn/'

ipUrl='http://members.3322.org/dyndns/getip'

 

# 要處理的域名數組,每個元素代表一個域名的一組記錄

# 在數組的一個元素中,以空格分隔域名和子域名

# 第一個空格前爲主域名,後面用空格分離多個子域名

# 如果使用泛域名,必須用\*轉義

domainList[0]='domain1.com \* @ www'

domainList[1]='domain2.com subdomain subdomain2'

 

# 多長時間比較一次ip地址

delay=300

 

# logfile

logDir='/var/log'

logFile=$logDir'/dnspodsh.log'

traceFile=$logDir'/dnspodshtrace.log'

 

# 檢測ip地址是否符合要求

checkip()

{

# ipv4地址

if [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]];then

return 0

# ipv6地址

elif [[ "$1" =~ ^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}$|^:((:[\da-fA-F]{1,4}){1,6}|:)$|^[\da-fA-F]{1,4}:((:


[\da-fA-F]{1,4}){1,5}|:)$|^([\da-fA-F]{1,4}:){2}((:[\da-fA-F]{1,4}){1,4}|:)$|^([\da-fA-F]{1,4}:){3}((:[\da-fA-F]


{1,4}){1,3}|:)$|^([\da-fA-F]{1,4}:){4}((:[\da-fA-F]{1,4}){1,2}|:)$|^([\da-fA-F]{1,4}:){5}:([\da-fA-F]{1,4})?$|^


([\da-fA-F]{1,4}:){6}:$ ]];then

return 0

fi

return 1

}

 

getUrl()

{

#curl -s -A $userAgent -d $commonPost$2 --trace $traceFile $apiUrl$1

curl -s -A $userAgent -d $commonPost$2 $apiUrl$1

}

 

getVersion()

{

getUrl "Info.Version"

}

 

getUserDetail()

{

getUrl "User.Detail"

}

 

writeLog()

{

if [ -w $logDir ];then

local pre=`date`

for arg in $@;do

pre=$pre'\t'$arg

done

echo -e $pre>>$logFile

fi

echo -e $1

}

 

getDomainList()

{

getUrl "Domain.List" "&type=all&offset=0&length=10"

}

 

# 根據域名id獲取記錄列表

# $1 域名id

getRecordList()

{

getUrl "Record.List" "&domain_id=$1&offset=0&length=20"

}

 

# 設置記錄

setRecord()

{

writeLog "set domain $3.$8 to new ip:$7"

local subDomain=$3

# 由於*會被擴展,在最後一步將轉義的\*替換成*

if [ "$subDomain" = '\*' ];then

subDomain='*'

fi

local request="&domain_id=$1&record_id=$2&sub_domain=$subDomain&record_type=$4&record_line=$5&ttl=


$6&value=$7"

#echo $request

local saveResult=$(getUrl 'Record.Modify' "$request")

# 檢測返回是否正常,但即使不正常也不退出程序

if checkStatusCode "$saveResult" 0;then

writeLog "set record $3.$8 success."

fi

#getUrl 'Record.Modify' "&domain_id=$domainid&record_id=$recordid&sub_domain=$recordName&record_type=


$recordtype&record_line=$recordline&ttl=$recordttl&value=$newip"

}

 

# 設置一批記錄

setRecords()

{

numRecord=${#changedRecords[@]}

for (( i=0; i < $numRecord; i++ ));do

setRecord ${changedRecords[$i]}

done

# 刪除待處理的變量

unset changeRecords

}

 

# 通過key得到找到一個JSON對象字符串中的值

getDataByKey()

{

local s='s/{[^}]*"'$2'":["]*\('$(getRegexp $2)'\)["]*[^}]*}/\1/'

#echo '拼合成的regexp:'$s

echo $1|sed $s

}

 

# 根據key返回要獲取的正則表達式

getRegexp()

{

case $1 in

'value') echo '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}';;

'type') echo '[A-Z]\+';;

'name') echo '[-_.A-Za-z*]\+';;

'ttl'|'id') echo '[0-9]\+';;

'line') echo '[^"]\+';;

esac

}

 

# 通過一個JSON key名稱,獲取一個{}包圍的JSON對象字符串

# $1 要搜索的key名稱

# $2 要搜索的對應值

getJSONObjByKey()

{

grep -o '{[^}{]*"'$1'":"'$2'"[^}]*}'

}

 

# 獲取A記錄類型的域名信息

# 對於其它記錄,同樣的名稱可以對應多條記錄,因此使用getJSONObjByKey可能獲取不到需要的數據

getJSONObjByARecord()

{

grep -o '{[^}{]*"name":"'$1'"[^}]*"type":"A"[^}]*}'

}

 

# 獲取返回代碼是否正確

# $1 要檢測的字符串,該字符串包含{status:{code:1}}形式,代表DNSPodAPI返回正確

# $2 是否要停止程序,因爲dnspod在代碼錯誤過多的情況下會封禁賬號

checkStatusCode()

{

if [[ "$1" =~ \{\"status\":\{[^}{]*\"code\":\"1\"[^}]*\} ]];then

return 0

fi

writeLog "DNSPOD return error:$1"

# 根據參數需求退出程序

if [ -n "$2" ] && [ "$2" -eq 1 ];then

writeLog 'exit dnspodsh'

exit 1

fi

}

 

# 獲取與當前ip不同的,要更新的記錄的數組

getChangedRecords()

{

# 從DNSPod獲取最新的域名列表

local domainListInfo=$(getDomainList)

if [ -z "$domainListInfo" ];then

writeLog 'DNSPOD tell me domain list is null,waiting...'

return 1

fi

checkStatusCode "$domainListInfo" 1

 

# 主域名的id

local domainid

local domainName

# 主域名的JSON信息

local domainInfo

# 主域名的所有記錄列表

local recordList

# 一條記錄的JSON信息

local recordInfo

# 記錄的id

local recordid

local recordName

# 記錄的TTL

local recordTtl

# 記錄的類型

local recordType

# 記錄的線路

local recordLine

local j

 

# 用於記錄被改變的記錄

unset changedRecords

 

local numDomain=${#domainList[@]}

local domainGroup

 

for ((i=0;i<$numDomain;i++));do

domainGroup=${domainList[$i]}

j=0

for domain in ${domainGroup[@]};do

# 列表的第一個項目,是主域名

if ((j==0));then

domainName=$domain

domainInfo=$(echo $domainListInfo|getJSONObjByKey 'name' $domainName) 

domainid=$(getDataByKey "$domainInfo" 'id')

recordList=$(getRecordList $domainid)

if [ -z "$recordList" ];then

writeLog 'DNSPOD tell me record list null,waiting...'

return 1

fi

checkStatusCode "$recordList" 1

else

# 從dnspod獲取要設置的子域名記錄的信息

recordInfo=$(echo $recordList|getJSONObjByARecord $domain)

# 如果取不到記錄,則不處理

if [ -z "$recordInfo" ];then

continue

fi

 

# 從dnspod獲取要設置的子域名的ip

oldip=$(getDataByKey "$recordInfo" 'value')

 

# 檢測獲取到的舊ip地址是否符合ip規則

if ! checkip "$oldip";then

writeLog 'get old ip error!it is "$oldid".waiting...'

continue

fi

 

if [ "$newip" != "$oldip" ];then

recordid=$(getDataByKey "$recordInfo" 'id')

recordName=$(getDataByKey "$recordInfo" 'name')

recordTtl=$(getDataByKey "$recordInfo" 'ttl')

recordType=$(getDataByKey "$recordInfo" 'type')

# 由於從服務器獲取的線路是utf編碼,目前無法知道如何轉換成中文,因此在這裏寫


死。dnspod中免費用戶的默認線路的名稱就是“默認”

#recordLine=$(getDataByKey "$recordInfo" 'line')

recordLine='默認'

# 判斷取值是否正常,如果值爲空就不處理

if [ -n "$recordid" ] && [ -n "$recordTtl" ] && [ -n "$recordType" ]; then

# 使用數組記錄需要修改的子域名的所有值

# 這裏一共有8個參數,與setRecord中的參數對應

changedRecords[${#changedRecords[@]}]="$domainid $recordid $domain 


$recordType $recordLine $recordTtl $newip $domainName"

fi

fi

fi

j=$((j+1))

done

done

}

 

# 執行檢測工作

go()

{

# 由於獲取到的數據多了一些多餘的字符,所以提取ip地址的部分

# 從api中獲取當前的外網ip

newip=$(curl -s $ipUrl|grep -o $(getRegexp 'value'))

# 如果獲取最新ip錯誤,就繼續等待下一次取值

if ! checkip "$newip";then

writeLog 'can not get new ip,waiting...'

sleep $delay

continue

fi

# 獲取需要修改的記錄

getChangedRecords

if (( ${#changedRecords[@]} > 0 ));then

writeLog "ip is changed,new ip is:$newip"

setRecords

fi

}

 

while [ 1 ];do

go

sleep $delay

done


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章