cloudflare ddns 更新 脚本 shell

2021年6月20日 0 条评论 972 次阅读 0 人点赞
#!/bin/bash
#完善授权信息之后的几个变量内容
#用法: bash cfddns.sh 二级域名

which jq >/dev/null 2>&1 || yum install jq -y >/dev/null 2>&1
which jq >/dev/null 2>&1 || yum install jq -y >/dev/null 2>&1

path0="/cfddns"
function messageSend() {
	message=$1
	#your messageSend code
}
######################  监测日志格式 ########################
# 监测日志保存位置
log_file="$path0/cloudflare.log"
#日志开关,touch这个文件以打开日志查看脚本执行反馈
logSwitch="$path0/logon"
if [ ! -f "$log_file" ];then touch  "$log_file";fi
log() {
    if [ -f "$logSwitch" ];then
        if [ "$1" ]; then
            echo -e "[$(date)] - $1" >> $log_file
        fi
    fi
}
# 告警文件位置
# 连续多少次失败后发送告警,每分钟检测就是30分钟连续失败则告警一次
alertTime=30
alert_file="$path0/alert"
if [ ! -f "$alert_file" ];then touch "$alert_file";fi
function AlertLog(){
    alertMessage=$1
    echo -e "[$(date)] - $1" >> "${alert_file}"
    if [ "$(grep -w "$alertMessage" "${alert_file}" | wc -l)" == "${alertTime}" ];then
        messageSend "$HOSTNAME #cfddns $alertMessage 已经连续30分钟出现!"
        log "ALERT !!!!!!!!!! $alertMessage 已经连续30分钟出现!!!!!!!!!!!"
    fi
}
function AlertClear(){
    alertMessage=$1
    if [ "$alertMessage" != "" ];then sed -i "/$alertMessage/d;/^$/d" "${alert_file}";fi
}
#获取结果ip
function printResult(){
    if $(grep -q total_count "${tmpFile}");then
        jq .result[].$1 "${tmpFile}" | sed 's#"##g'
    else
        jq .result.$1 "${tmpFile}" | sed 's#"##g'
    fi
}

###############  授权信息(需修改成你自己的) ################
#APIurl
APIurl="https://api.cloudflare.com/client/v4/zones"
# CloudFlare 注册邮箱
auth_email=""
if [ 123"$auth_email" == 123 ];then
    AlertLog '脚本内置参数 auth_email :注册邮箱未填入'
    exit 1
fi
AlertClear '脚本内置参数 auth_email'
# CloudFlare Global API Key,
auth_key=""
if [ 123"$auth_key" == 123 ];then
    AlertLog '脚本内置参数 auth_key :Global API Key未填入'
    exit 1
fi
AlertClear '脚本内置参数 auth_key'
# 做 DDNS 的根域名
zone_name=""
if [ 123"$zone_name" == 123 ];then
    AlertLog '脚本内置参数 zone_name :根域名未填入'
    exit 1
fi
AlertClear '脚本内置参数 zone_name'
# 根域名id
zone_identifier=""
if [ 123"$zone_identifier" == 123 ];then
    AlertLog '脚本内置参数 zone_identifier :根域名id未填入'
    exit 1
fi
AlertClear '脚本内置参数 zone_identifier'
# 做 DDNS 的域名,二级域名,比如 www.cloudflare.com 的 www
record_name="$1"
if [ 123"$record_name" == 123 ];then
    AlertLog '脚本参数1:二级域名缺失'
    exit 1
fi
AlertClear '脚本参数1'
# 域名类型,IPv4 为 A,IPv6 则是 AAAA
record_type="A"
#二级域名id
record_identifier_file="$path0/record_identifier.ids"


######################  修改配置信息 #######################
# IPv6 检测服务,本站检测服务仅在大陆提供
#ip=$(curl -s https://ipv6.vircloud.net)
# IPv4 检测服务 curl -s http://ipv4.icanhazip.com
ipAPI1="https://ipv4.icanhazip.com"
ipAPI2="http://ifconfig.me"
# 变动前的公网 IP 保存位置
if [ ! -f "$path0" ];then mkdir -p "$path0" ;fi
ip_file="$path0/ip.txt"
if [ ! -f "$ip_file" ];then touch "$ip_file";fi
# api返回信息结果临时文件
tmpFile="$path0/tmp"


log "检测开始……"
ip=$(curl -s "$ipAPI1")
if ! $(echo "${ip}" | egrep -q '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$');then
    log "获取外网ip错误,接口爲 $ipAPI1 ,尝试从服务器获取……"
    ip=$(curl -s "$ipAPI2")
    if ! $(echo "${ip}" | egrep -q '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$');then
        AlertLog "获取外网IP"
        exit 1
    fi
fi
AlertClear "获取外网IP"


function getResult(){
    action=$1
    log "操作类型:$action\tAPI结果处理……"

    #检测结果文件
    if [ ! -f "$tmpFile" ];then log "操作类型:$action\t获取结果文件丢失,等待下次处理";return 1;fi

    #api错误类
    log "操作类型:$action\tAPI结果数据处理1……"
    success=$(jq .success "${tmpFile}" | sed 's#"##g')
    total_count=$(jq .result_info.total_count "${tmpFile}" | sed 's#"##g')
    #检测api返回结果,success 或 total_count 爲空则返回
    if [ "${success}" == "null" ] || [ "${success}" != "true" ];then
        errorCode=$(jq .errors[].code "${tmpFile}" | sed 's#"##g')
        errorMessage=$(jq .errors[].message "${tmpFile}" | sed 's#"##g')
        APIErrors="errors\tcode:${errorCode}\tmessage:${errorMessage}"
        log "操作类型:$action\t获取结果:\t${APIErrors},获取失败,分析错误代码……"
        case "${errorCode}" in
        "81044")
            log "操作类型:$action\t线上不存在记录"
            return 0
            ;;
        *)
            log "操作类型:$action\t${errorMessage}"
            ;;
        esac
        AlertLog "API请求错误 ${APIErrors}"
        return 1
    fi
    AlertClear "API请求错误"

    #检测返回个数
    log "操作类型:$action\tAPI结果数据处理2……"
    if [ "${total_count}" == "0" ];then log "操作类型:$action\t获取结果:\t0,没有查询到信息";return 0;fi
    #超过一个结果
    if [ "${total_count}" != "null" ] && [ "${total_count}" -gt "1" ];then
        if [ "$action" == "recheck" ];then #检测操作 爲cf线上错误,直接返回
            log "操作类型:$action\t获取结果:\t爲CF线上错误,id ${total_count} 个数爲 ${total_count}"
            messageSend "$HOSTNAME #cfddns CF线上错误 id $2 查询到了2个记录!"
            return 1
        elif [ "$action" == "search" ];then #搜索操作 只保留一个
            log "操作类型:$action\t获取结果:查询域名解析个数爲 ${total_count} 个"
            record_id=""
            for record in $(printResult id) ;do
                if [ "$record_id" == "" ];then #获取一个id
                    record_id=$record
                    log "操作类型:$action\t获取结果:保留 id 爲 ${total_count} 的解析"
                else #其馀删除
                    log "操作类型:$action\t获取结果:删除 id 爲 ${total_count} 的解析"
                    curl -s -X DELETE "$APIurl/${zone_identifier}/dns_records/${record}" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" >/dev/null 2>&1
                fi
            done
            echo "$record_id"
            return 0
        fi
    fi

    #返回结果
    log "操作类型:$action\tAPI结果数据处理完成……"
    printResult id
    return 0
}

function getrecord_id(){
    log "本地数据检测……"
    record_identifier=""
    if [ -f "$record_identifier_file" ];then
        #获取本地解析id
        log "尝试获取本地记录id……"
        record_identifier=$(cat "$record_identifier_file")
        record_count=$(echo $record_identifier | sed 's# #\n#g' | wc -l)
        if [ "$record_count" != "1" ];then #本地数据 异常:爲空;多个数值
            log "本地数据错误……"
            log "本地id信息错误,重置本地数据"
            record_identifier="" #重置数据
            cd . > "$record_identifier_file"
        elif [ "$record_identifier" != "" ];then #本地数据 正常
            #验证线上数据
            log "以本地数据检测线上数据……"
            curl -s -X GET "$APIurl/${zone_identifier}/dns_records/${record_identifier}" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" >"${tmpFile}" 2>&1
            #再次获取id
            record_identifier=$(getResult recheck "${record_identifier}")
            if [ $? == 1 ];then
                log "线上数据获取错误,等待下次检测";return 1
            fi
            if [ "$(printResult name)" != "${record_name}.${zone_name}" ];then
                log "本地数据和待处理域名不匹配,重置本地数据……"
                record_identifier="" #重置数据
                cd . > "$record_identifier_file"
            fi
        fi
    fi
    #如果异常
    if [ "${record_identifier}" == "" ];then #本地数据爲空
        log "id爲空,尝试搜索线上是否存在域名解析数据……"
        #搜索线上解析鬱闷
        curl -s -X GET "$APIurl/${zone_identifier}/dns_records?name=${record_name}.${zone_name}&proxied=false&type=$record_type" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" > "${tmpFile}" 2>&1
        record_identifier=$(getResult search)
        if [ $? == 0 ];then
            if [ "$record_identifier" != "" ];then #搜索到了
                log "线上id获取成功!写入本地记录……"
                echo "$record_identifier" > $record_identifier_file
                return 0
            else #没有搜索到记录 则新增
                log "没有查询到记录,尝试新增……"
                curl -s -X POST "$APIurl/$zone_identifier/dns_records" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"type\":\"$record_type\",\"name\":\"${record_name}.${zone_name}\",\"content\":\"$ip\",\"ttl\":120,\"proxied\":false}" > "${tmpFile}" 2>&1
                record_identifier=$(getResult recheck)
                if [ $? == 0 ] && [ "${record_identifier}" != "" ];then
                    log "新增成功!写入本地记录……"
                    messageSend "$HOSTNAME #cfddns $1 新增解析成功,当前IP:$ip!"
                    echo "$record_identifier" > $record_identifier_file
                    return 0
                fi
            fi
        fi
        return 1
    fi
    #如果查询到了
    return 0
}

######################  获取域名授权及新增 ######################
getrecord_id
if [ $? == 1 ];then exit 1;fi
log "数据获取成功……"
if [ "$ipOnline" == "" ];then
    ipOnline=$(printResult content)
fi

######################  判断 IP 是否变化 ####################
if [ -f "$ip_file" ]; then
    old_ip=$(cat "$ip_file")
    #如果查询ip等于本地存储ip
    if [ "$ip" == "$old_ip" ] && [ "$ip" == "$ipOnline" ]; then
        log "IP has not changed."
        exit 0
    fi
    if [ "$ip" == "$ipOnline" ] && [ "$ip" != "$old_ip" ];then
        log "ip正常,修正本地数据……"
        echo "$ip" > "$ip_file"
        exit 0
    fi
fi


######################  更新 DNS 记录 ######################
log "ip变动,修正线上数据……"
curl -s -X PUT "$APIurl/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"type\":\"$record_type\",\"name\":\"${record_name}.${zone_name}\",\"content\":\"$ip\",\"ttl\":120,\"proxied\":false}" >/dev/null 2>&1
record_identifier=$(getResult recheck "${record_identifier}")
if [ $? == 0 ];then
    result_ip=$(printResult content)
    if [ "$ip" == "$result_ip" ];then
        log "修正线上数据成功,写入本地……"
        messageSend "$HOSTNAME #cfddns $1 解析修改成功,当前IP:$ip!"
        echo "$ip" > "$ip_file"
        exit 0
    fi
fi
log "处理完成!"

Sevenfal

这个人太懒什么东西都没留下

文章评论(0)