Browse Source

Update dns_beget.sh

pull/6509/head
Artem 1 month ago
committed by GitHub
parent
commit
f484eacf40
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 331
      dnsapi/dns_beget.sh

331
dnsapi/dns_beget.sh

@ -12,270 +12,119 @@ Author: ARNik <arnik@arnik.ru>
Beget_Api="https://api.beget.com/api"
#################### Public functions ####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_beget_add() {
fulldomain=$1
txtvalue=$2
_debug "dns_beget_add() $fulldomain $txtvalue"
fulldomain=$(echo "$fulldomain" | _lower_case)
Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
if [ -z "$Beget_Username" ] || [ -z "$Beget_Password" ]; then
Beget_Username=""
Beget_Password=""
_err "You must export variables: Beget_Username, and Beget_Password"
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable Beget_Username "$Beget_Username"
_saveaccountconf_mutable Beget_Password "$Beget_Password"
_info "Prepare subdomain."
if ! _prepare_subdomain "$fulldomain"; then
_err "Can't prepare subdomain."
return 1
fi
_info "Get domain records"
data="{\"fqdn\":\"$fulldomain\"}"
res=$(_api_call "$Beget_Api/dns/getData" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't get domain records."
return 1
fi
_info "Add new TXT record"
data="{\"fqdn\":\"$fulldomain\",\"records\":{"
data=${data}$(_parce_records "$res" "A")
data=${data}$(_parce_records "$res" "AAAA")
data=${data}$(_parce_records "$res" "CAA")
data=${data}$(_parce_records "$res" "MX")
data=${data}$(_parce_records "$res" "SRV")
data=${data}$(_parce_records "$res" "TXT")
data=$(echo "$data" | sed 's/,$//')
data=${data}'}}'
str=$(_txt_to_dns_json "$txtvalue")
data=$(_add_record "$data" "TXT" "$str")
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't change domain records."
return 1
fi
# API call function
_api_call() {
api_url="$1"
input_data="$2"
url="$api_url?login=$Beget_Username&passwd=$Beget_Password&input_format=json&output_format=json"
[ -n "$input_data" ] && url="${url}&input_data=$(echo -n "$input_data" | jq -s -R -r @uri)"
return 0
echo "[DEBUG] _api_call url=$url"
curl -s "$url"
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_beget_rm() {
# Add TXT record (supports multiple additions without overwriting)
dns_beget_add() {
fulldomain=$1
txtvalue=$2
_debug "dns_beget_rm() $fulldomain $txtvalue"
fulldomain=$(echo "$fulldomain" | _lower_case)
Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
_info "Get current domain records"
data="{\"fqdn\":\"$fulldomain\"}"
res=$(_api_call "$Beget_Api/dns/getData" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't get domain records."
return 1
fi
_info "Remove TXT record"
data="{\"fqdn\":\"$fulldomain\",\"records\":{"
data=${data}$(_parce_records "$res" "A")
data=${data}$(_parce_records "$res" "AAAA")
data=${data}$(_parce_records "$res" "CAA")
data=${data}$(_parce_records "$res" "MX")
data=${data}$(_parce_records "$res" "SRV")
data=${data}$(_parce_records "$res" "TXT")
data=$(echo "$data" | sed 's/,$//')
data=${data}'}}'
echo "[DEBUG] Starting dns_beget_add"
echo "[DEBUG] fulldomain=$fulldomain"
echo "[DEBUG] txtvalue=$txtvalue"
str=$(_txt_to_dns_json "$txtvalue")
data=$(_rm_record "$data" "$str")
Beget_Username="${Beget_Username:?Please set Beget_Username}"
Beget_Password="${Beget_Password:?Please set Beget_Password}"
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't change domain records."
return 1
fi
return 0
}
#################### Private functions below ####################
fulldomain=$(echo "$fulldomain" | tr '[:upper:]' '[:lower:]')
echo "[DEBUG] fulldomain (lowercase)=$fulldomain"
# Create subdomain if needed
# Usage: _prepare_subdomain [fulldomain]
_prepare_subdomain() {
fulldomain=$1
_info "Detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
# Get current DNS records
res=$(_api_call "$Beget_Api/dns/getData" "{\"fqdn\":\"$fulldomain\"}") || {
echo "[ERROR] API getData did not return a response"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
if [ -z "$_sub_domain" ]; then
_debug "$fulldomain is a root domain."
return 0
fi
}
echo "[DEBUG] API getData response: $res"
status=$(echo "$res" | jq -r '.answer.status' 2>/dev/null || echo "error")
if [ "$status" = "success" ]; then
old_txts=$(echo "$res" | jq -c '.answer.result.records.TXT // []')
echo "[DEBUG] Existing TXT records from API: $old_txts"
else
echo "[WARN] Beget API error (status=$status). Try fallback with dig polling."
old_txts="[]"
i=1
while [ $i -le 6 ]; do # 6 раз по 20 секунд = максимум 120
dig_txts=$(dig TXT +short "${fulldomain}" \
@ns1.beget.com @ns2.beget.com | sed 's/^"//;s/"$//' | jq -R . | jq -s .)
if [ "$dig_txts" != "[]" ]; then
old_txts="$dig_txts"
echo "[DEBUG] dig found TXT records on attempt $i: $old_txts"
break
else
echo "[DEBUG] dig attempt $i: no TXT yet, waiting 20s..."
if [ $i -gt 3 ]; then
sleep 40
else
sleep 20
fi
fi
_info "Get subdomain list"
res=$(_api_call "$Beget_Api/domain/getSubdomainList")
if ! _is_api_reply_ok "$res"; then
_err "Can't get subdomain list."
return 1
fi
i=$((i+1))
done
if _contains "$res" "\"fqdn\":\"$fulldomain\""; then
_debug "Subdomain $fulldomain already exist."
return 0
if [ "$old_txts" = "[]" ]; then
echo "[DEBUG] dig found no TXT records after 120s. old_txts empty."
fi
fi
# Prepare new TXT record
new_txt="{\"priority\":10,\"value\":\"$txtvalue\"}"
echo "[DEBUG] New TXT record: $new_txt"
# Merge with existing TXT records
if [ "$old_txts" = "[]" ]; then
txt_records="[$new_txt]"
else
old_objs=$(jq -c --argjson p 10 '[.[] | {priority: ($p|tonumber), value: .}]' <<< "$old_txts")
txt_records=$(jq -c --argjson new "$new_txt" '. + [$new]' <<< "$old_objs")
fi
echo "[DEBUG] Final TXT records set: $txt_records"
data="{\"fqdn\":\"$fulldomain\",\"records\":{\"TXT\":$txt_records}}"
echo "[DEBUG] Sending data to changeRecords: $data"
_info "Subdomain $fulldomain does not exist. Let's create one."
data="{\"subdomain\":\"$_sub_domain\",\"domain_id\":$_domain_id}"
res=$(_api_call "$Beget_Api/domain/addSubdomainVirtual" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't create subdomain."
_api_call "$Beget_Api/dns/changeRecords" "$data" || {
echo "[ERROR] Error calling changeRecords"
return 1
fi
_debug "Cleanup subdomen records"
data="{\"fqdn\":\"$fulldomain\",\"records\":{}}"
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_debug "Can't cleanup $fulldomain records."
fi
data="{\"fqdn\":\"www.$fulldomain\",\"records\":{}}"
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_debug "Can't cleanup www.$fulldomain records."
fi
}
return 0
echo "[INFO] TXT record successfully added for $fulldomain"
}
# Usage: _get_root _acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=32436365
_get_root() {
# Remove all _acme-challenge TXT records
dns_beget_rm() {
fulldomain=$1
i=1
p=1
_debug "Get domain list"
res=$(_api_call "$Beget_Api/domain/getList")
if ! _is_api_reply_ok "$res"; then
_err "Can't get domain list."
return 1
fi
echo "[DEBUG] Starting dns_beget_rm"
echo "[DEBUG] fulldomain=$fulldomain"
while true; do
h=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100)
_debug h "$h"
Beget_Username="${Beget_Username:?Please set Beget_Username}"
Beget_Password="${Beget_Password:?Please set Beget_Password}"
if [ -z "$h" ]; then
return 1
fi
fulldomain=$(echo "$fulldomain" | tr '[:upper:]' '[:lower:]')
echo "[DEBUG] fulldomain (lowercase)=$fulldomain"
if _contains "$res" "$h"; then
_domain_id=$(echo "$res" | _egrep_o "\"id\":[0-9]*,\"fqdn\":\"$h\"" | cut -d , -f1 | cut -d : -f2)
if [ "$_domain_id" ]; then
if [ "$h" != "$fulldomain" ]; then
_sub_domain=$(echo "$fulldomain" | cut -d . -f 1-"$p")
else
_sub_domain=""
fi
_domain=$h
return 0
fi
return 1
fi
p="$i"
i=$(_math "$i" + 1)
done
return 1
}
# Remove all TXT records by sending empty array
data="{\"fqdn\":\"$fulldomain\",\"records\":{\"TXT\": []}}"
echo "[DEBUG] Sending data to changeRecords: $data"
# Parce DNS records from json string
# Usage: _parce_records [j_str] [record_name]
_parce_records() {
j_str=$1
record_name=$2
res="\"$record_name\":["
res=${res}$(echo "$j_str" | _egrep_o "\"$record_name\":\[.*" | cut -d '[' -f2 | cut -d ']' -f1)
res=${res}"],"
echo "$res"
}
# Usage: _add_record [data] [record_name] [record_data]
_add_record() {
data=$1
record_name=$2
record_data=$3
echo "$data" | sed "s/\"$record_name\":\[/\"$record_name\":\[$record_data,/" | sed "s/,\]/\]/"
}
# Usage: _rm_record [data] [record_data]
_rm_record() {
data=$1
record_data=$2
echo "$data" | sed "s/$record_data//g" | sed "s/,\+/,/g" |
sed "s/{,/{/g" | sed "s/,}/}/g" |
sed "s/\[,/\[/g" | sed "s/,\]/\]/g"
}
_txt_to_dns_json() {
echo "{\"ttl\":600,\"txtdata\":\"$1\"}"
}
# Usage: _api_call [api_url] [input_data]
_api_call() {
api_url="$1"
input_data="$2"
_debug "_api_call $api_url"
_debug "Request: $input_data"
# res=$(curl -s -L -D ./http.header \
# "$api_url" \
# --data-urlencode login=$Beget_Username \
# --data-urlencode passwd=$Beget_Password \
# --data-urlencode input_format=json \
# --data-urlencode output_format=json \
# --data-urlencode "input_data=$input_data")
url="$api_url?login=$Beget_Username&passwd=$Beget_Password&input_format=json&output_format=json"
if [ -n "$input_data" ]; then
url=${url}"&input_data="
url=${url}$(echo "$input_data" | _url_encode)
fi
res=$(_get "$url")
_debug "Reply: $res"
echo "$res"
}
_api_call "$Beget_Api/dns/changeRecords" "$data" || {
echo "[ERROR] Error calling changeRecords"
return 1
}
# Usage: _is_api_reply_ok [api_reply]
_is_api_reply_ok() {
_contains "$1" '^{"status":"success","answer":{"status":"success","result":.*}}$'
echo "[INFO] All _acme-challenge TXT records removed for $fulldomain"
}
Loading…
Cancel
Save