最近有佬友经常在问:自己的环境有公网但不固定,如何能够将当前的公网IP自动提交到cloudflare进行更新。
针对这个问题咱们就出一个简单的教程,并且花了10分钟手搓了一个shell脚本(完全遵循POSIX规范,理论上没有兼容性问题)。
第一部分:在cloudflare上申请API管理域名的token
1.打开cloudflare面板 https://dash.cloudflare.com/
2.点击右上角个人头像,找到 Profile 并点击
3.点击最左侧 API Tokens,找到 CreateToken 并点击
4.点击文字 Edit zone DNS 右边的 Use template 按钮
5.将 Zone Resources 区域里的第二个下拉框更改为 All zones
6.点击页面最下方 Continue to summary
7.点击 Create Token,稍等片刻就会出现token字符串
最后在成功页面找到token字符串并复制下来。因为这个token仅会出现一次,所以一定要把token保存好。
第二部分:会用到的几个API接口
headers是固定的 "Authorization: Bearer token字符串" "Content-Type:application/json“
查询根域名的zoneid
https://api.cloudflare.com/client/v4/zones?name=根域名
查询子域名的解析记录
https://api.cloudflare.com/client/v4/zones/根域名zoneid/dns_records?name=子域名&type=解析类型(可为空)
新增解析记录
https://api.cloudflare.com/client/v4/zones/根域名zoneid/dns_records 新增解析记录
POST {"type":"记录类型","name":"子域名称","content":"解析记录值","ttl":1,"proxied":是否开启小黄云(true/false)}
修改解析记录
https://api.cloudflare.com/client/v4/zones/根域名zoneid/dns_records/子域ID 修改解析记录
PUT {"id":"根域名zoneid","type":"记录类型","name":"子域名称","content":"解析记录值","ttl":1,"proxied":是否开启小黄云(true/false)}
第三部分:手搓的shell成品 cfddns.sh
#!/bin/bash
get_wan_ip(){
ip4=$(curl -s -m 5 -4 http://api64.ipify.org/)
echo $ip4 | grep -F "." >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo $ip4
else
echo ""
fi
}
get_wan_ip6(){
ip6=$(curl -s -m 5 -6 http://api64.ipify.org/)
echo $ip6 | grep -F ":" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo $ip6
else
echo ""
fi
}
dns_isupdated(){
dns_line=$(nslookup $domain2 lia.ns.cloudflare.com 2>/dev/null)
for line in $dns_line
do
if [ "$line" = "$checkip" ]; then return 1; fi
done
return 0
}
func=$1 ; token=$2 ; domaininfo=$3 ; ip=$4 ; ipv6=$5
echo $domaininfo | grep -F "#" >/dev/null 2>&1
if [ $? -eq 0 ]; then
domain=$(echo $domaininfo | awk -F '#' '{print $NF}')
domain2=$(echo $domaininfo | sed -e 's/#/./gi')
else
domain=${domaininfo#*.}
domain2=$domaininfo
fi
if [ "$func" = "" ]; then echo "wrong parameter (v4v6 token domain2 ip ipv6)" ; exit 1 ; fi
if [ "$ip" = "auto" ]; then ip=""; fi
if [ "$ipv6" = "auto" ]; then ipv6=""; fi
domain2=$(echo $domain2 | sed 's/@.//g')
types=""
proxied=false ; echo $func | grep -F "#" >/dev/null 2>&1
if [ $? -eq 0 ]; then proxied=true; fi
echo $func | grep -F "v4" >/dev/null 2>&1
if [ $? -eq 0 ]; then
htype=1
if [ "$ip" = "" ]; then ip=$(get_wan_ip); fi
if [ "$ip" != "" ]; then
if [ "$proxied" = "true" ];then
types=$types"A "
else
checkip=$ip
if dns_isupdated ; then
types=$types"A "
else
echo "$domain2 A Record is ready"
fi
fi
fi
fi
echo $func | grep -F "v6" >/dev/null 2>&1
if [ $? -eq 0 ]; then
htype=1
if [ "$ipv6" = "" ]; then ipv6=$(get_wan_ip6); fi
if [ "$ipv6" != "" ]; then
if [ "$proxied" = "true" ];then
types=$types"AAAA "
else
checkip=$ipv6
if dns_isupdated ; then
types=$types"AAAA "
else
echo "$domain2 AAAA Record is ready"
fi
fi
fi
fi
if [ "$types" = "" ] && [ "$htype" = "1" ]; then exit 0; fi
if [ "$types" = "" ]; then types=$(echo $func | sed -e 's/#//gi'); fi
html=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$domain" -H "Authorization: Bearer $token" -H "Content-Type:application/json")
zoneid=$(echo $html | sed -e 's/,"status":"/#\n/g' | grep -F "\"$domain\"" | awk -F '"id":"' 'NR==1{print $NF}' | cut -f 1 -d '"')
if [ "$zoneid" = "" ]; then echo "no zoneid" ; exit 2 ; fi
for type in $types
do
newip=$ip;newinfo=""
if [ "$type" = "AAAA" ]; then newip=$ipv6; fi
if [ "$type" = "TXT" ]; then newip="\\\"$newip\\\""; fi
html=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?name=$domain2&type=$type" -H "Authorization: Bearer $token" -H "Content-Type:application/json")
echo $html | grep -F "\"success\":true" | grep -v "grep" >/dev/null 2>&1
if [ $? -ne 0 ]; then echo "no data" ; continue ; fi
domain2id=$(echo $html | awk -F '"id":"' '{print $2}' | cut -f 1 -d '"')
if [ "$domain2id" = "" ]; then
html=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" -H "Authorization: Bearer $token" -H "Content-Type:application/json" --data "{\"type\":\"$type\",\"name\":\"$domain2\",\"content\":\"$newip\",\"ttl\":1,\"proxied\":$proxied}")
else
ready=false
echo $html | grep -F "\"content\":\"$newip\"" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo $html | grep -F "\"proxied\":$proxied" >/dev/null 2>&1
if [ $? -eq 0 ]; then
ready=true
fi
fi
if [ "$ready" = "true" ]; then
html='"success":true' ; newinfo="(ready)"
else
html=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$domain2id" -H "Authorization: Bearer $token" -H "Content-Type:application/json" --data "{\"id\":\"$zoneid\",\"type\":\"$type\",\"name\":\"$domain2\",\"content\":\"$newip\",\"ttl\":1,\"proxied\":$proxied}")
fi
fi
echo $html | grep -F "\"success\":true" | grep -v "grep" >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "$domain2 $type Record $newip update fail"
echo $html
else
echo "$domain2 $type Record $newip update$newinfo success"
fi
done
第四部分:使用shell脚本
如果想要解析根域名那么将 子域名 替换成 @
如果想要解析成固定IP那么将 auto 替换成 你的IP地址
#仅解析ipv4
sh cfddns.sh v4 token字符串 v4name#mydomain.com auto
#仅解析ipv6
sh cfddns.sh v6 token字符串 v6name#mydomain.com auto auto
#同时解析ipv4和ipv6
sh cfddns.sh v4v6 token字符串 v46name#mydomain.com auto auto
#解析CNAME
sh cfddns.sh CNAME token字符串 cname#mydomain.com www.google.com
如果以上解析记录想要开启小黄云,则修改成 v4#、v6#、v4v6#、CNAME#
#解析TXT记录
sh cfddns.sh TXT token字符串 ctxt#mydomain.com "Welcome to my txt record"
寄语:
曾经有佬友问我经常发教程为什么不设置权限(比如回复才可以阅读什么的),不仅可以防止白嫖还能增加回复量。
其实写这些教程的初衷,最重要的还是分享和交流,和佬友们共同进步。
关于回帖这个问题,我相信如果写的好、写的对佬友有用,佬友必定会所回复和反馈的。
我坚信尊重他人也是尊重自己的一种表现。
Good luck to all