温馨提示:
本文所述内容具有依赖性,可能因软硬条件不同而与预期有所差异,故请以实际为准,仅供参考。
不知道什么时候起,宽带变成了 N 级 NAT,花生壳、ORAY、NO-IP 等基于动态公网 IP 的 DDNS 服务全线倒地,虽然 FRP、NGROK 这些内网穿透依然可以实现类 DDNS 功能,但网络严重依赖于中转服务器带宽,不是非常适合有大流量需求的业务,比如监控、云盘、同步等等。
最近发现本地宽带终于支持 IPv6 了,DDNS 就又可以搞起来了,考虑到安全问题,本文将探讨使用 CloudFlare API 来实现 DDNS 功能。
对了,DDNS 是指动态 DNS(英语:Dynamic DNS)是域名系统(DNS)中的一种自动更新名称服务器(Name Server)内容的技术,根据互联网的域名订立规则,域名必须有固定的 IP 地址,动态 DNS 系统就是为动态 IP 提供一个固定的名称服务器(Name Server),通过即时更新,使外界用户能够连上使用动态 IP 用户的网址。
相关文章:《利用华为云 API 实现自动 DDNS 功能|支持IPv4|IPv6》
一、思路
虽然现在上了 IPv6,可以直接与外界通信,但仍然不是静态 IP,即重新拨号或重新联网后,IP 会发生变更,根据 DDNS 原理,可以通过实时监测公网 IP,判断是否发生变更,一旦监测到发生变更,则立即更新 DNS 记录。
二、实现
CloudFlare 以前就有介绍过,是一家功能十分强大的电信服务提供商,今天我们就是通过其 DNS 管理和 API 功能来实现上述思路。
1、SHELL 脚本代码
#!/bin/bash
############### 授权信息(需修改成你自己的) ################
# CloudFlare 注册邮箱
auth_email="vircloud.net"
# CloudFlare Global API Key,下一节会说到
auth_key="vircloud.net"
# 做 DDNS 的根域名
zone_name="vircloud.net"
# 做 DDNS 的域名,创建成功后就是通过该域名访问内网资源
record_name="cu.vircloud.net"
###################### 修改配置信息 #######################
# 域名类型,IPv4 为 A,IPv6 则是 AAAA
record_type="A"
# IPv6 检测服务,本站检测服务仅在大陆提供
#ip=$(curl -s https://ipv6.vircloud.net)
# IPv4 检测服务
ip=$(curl -s https://ipv4.vircloud.net)
# 也可以获取远程主机 IPv4 地址
#ip=`sshpass -p 'password' ssh [email protected] 'curl -s https://ipv4.vircloud.net'`
# IPv4 解析检测
eip=`curl -s -H "accept: application/dns-json" "https://doh.360.cn/resolve?name=$record_name&type=A"| jq -r ".Answer[] | select(.type == 1) | .data"`
# 文件保存地址
#current_dir=$(cd `dirname $0`; pwd)
current_dir="/var/log/ddns-cf"
# 变动前的公网 IP 保存位置
ip_file="$current_dir/ip.txt"
# 域名识别信息保存位置
id_file="$current_dir/cloudflare.ids"
# 监测日志保存位置
log_file="$current_dir/cloudflare.log"
################### 判断日志文件夹是否存在 ##################
if [ ! -d "$current_dir" ]; then
mkdir -p $current_dir
fi
###################### 监测日志格式 ########################
log() {
if [ "$1" ]; then
echo -e "[$(date)] - $1" >> $log_file
fi
}
log "Check Initiated"
###################### 简单判断是否是 IP ####################
if [ "$ip" != "${1#*[0-9].[0-9]}" ]; then
log "IPv4 address detected: $ip"
elif [ "$ip" != "${1#*:[0-9a-fA-F]}" ]; then
log "IPv6 address detected: $ip"
else
log "No valid IP address detected"
log "Check Done"
exit 0
fi
###################### 判断 IP 是否变化 ####################
if [ -f $ip_file ]; then
old_ip=$(cat $ip_file)
else
old_ip=$eip
echo "$eip" > $ip_file
fi
log "Last recorded IP: $old_ip"
if [ "$ip" == "$old_ip" ]; then
echo "IP has not changed."
log "IP has not changed."
log "Check Done"
exit 0
else
echo "IP has changed, updating..."
log "IP has changed, updating..."
fi
###################### 获取域名及授权 ######################
if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
zone_identifier=$(head -1 $id_file)
if [ ! -n "$zone_identifier" ]; then
zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
sed -i '1d' $id_file
sed -i '1i $zone_identifier' $id_file
fi
record_identifier=$(tail -1 $id_file)
if [ ! -n "$zone_identifier" ]; then
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name&type=$record_type" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*')
sed -i '2d' $id_file
echo "$record_identifier" >> $id_file
fi
else
zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name&type=$record_type" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*')
echo "$zone_identifier" > $id_file
echo "$record_identifier" >> $id_file
fi
###################### 更新 DNS 记录 ######################
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"$record_type\",\"name\":\"$record_name\",\"content\":\"$ip\"}")
######################### 更新反馈 #########################
if [[ $update == *"\"success\":false"* ]]; then
result=`echo $update | jq ".errors | .[] | .message"`
message="API UPDATE FAILED. MESSGAE:\n$result"
log "$message"
echo -e "$message"
exit 1
elif [[ $update == *"\"error\""* ]]; then
result=`echo $update | jq ".error"`
message="ERROR ENCOUNTERED. MESSGAE:\n$result"
log "$message"
echo -e "$message"
exit 1
elif [ ! -n "$update" ]; then
message="REQUEST TIMED OUT. CHECK NETWORK CONNECTIVITY."
log "$message"
echo -e "$message"
exit 1
else
message="IP has been updated to: $ip"
echo "$ip" > $ip_file
log "$message"
echo "$message"
fi
log "Check Done"
注意,本脚本使用 jq
来解析 CloudFlare 等响应的内容,所以需先安装 jq
命令:
# Ubuntu
apt install jq -y
#CentOS
yum install jq -y
2、获取授权信息
使用 CloudFlare "DDNS 服务" 需要把域名托管到 CloudFlare,此处不做介绍,自行搜索。
在 DNS 页面,由于我们要达到的是 DDNS 效果,所以 CDN 不要开启,即这朵云保持灰色状态(默认是开启的):
其中 Type 是你要设置的 IP 类型,Name 是要做为连接的域名, Value 第一次可以随便设一个,TTL 2 minutes 或者 Automatic 都可以,再次强调 Status 这朵云不要点亮。
在 个人信息页面 下滑到 API Keys,把 Global API Key 一串字符贴到上述脚本中的 auth_key:
3、执行结果
~# chmod +x ddns.sh
~# ./ddns.sh
IP changed to: ****
~# ./ddns.sh
IP has not changed.
4、定时运行
由于无法得知运营商什么时候会把 IP 变了,所以我们可以设置定时运行脚本来实现实时监控 并更新 IP 的变化。比如通过 crontab 实现:
~# crontab -e
......
0 */1 * * * /root/ddns.sh >/dev/null 2>&1
......
可以通过 cloudflare.log 来查看历史执行记录。
5、错误分析
问题
~# ./ddns.sh
API UPDATE FAILED. DUMPING RESULTS:
{"success":false,"errors":[{"code":6007,"message":"Malformed JSON in request body"}],"messages":[],"result":null}
分析
猜测是网络原因引起的,概率出现这个提示,如若出现忽略再执行一次即可。
问题
~# ./ddns.sh
API UPDATE FAILED. DUMPING RESULTS:
{"success":false,"errors":[{"code":7003,"message":"Could not route to \/zones\/dns_records, perhaps your object identifier is invalid?"},{"code":"7000","message":"No route for that URI"}],"messages":[],"result":null}
分析
再次确认邮箱、域名、KEY 等信息是否正确,不然就是获取 IP 时出现错误(本站 IP 检测服务仅在大陆提供)。
三、总结
自己搭建 DDNS 最大的好处在于可以充分发挥宽带的带宽,不再局限于服务端的限制,其次安全性有了保证,可以不受服务提供者的记录。
其实并不仅仅 CloudFlare 可以实现,其他支持 API 更新 DNS 的 DNS 服务商理论上都支持通过上面的方法来实现 DDNS,而且从网络大环境而言,国内的服务商肯定会比国外的稳定。
参考文章:
1、 《利用CloudFlare设置Dynamic DNS(DDNS)获取动态IP》
2、 《GitHub: benkulbertis/cloudflare-update-record.sh》
3、 《CloudFlare API Documentation》
Windows 10Chrome 114.0.0.0来自 台湾 的大神
大佬,脚本不可通篇复制的么
不建议直接复制,根据实际情况参考