1
0
mirror of https://github.com/EV21/dynb.git synced 2025-12-26 16:39:32 +01:00
Files
dynb/dynb.sh

442 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
## Copyright (c) 2021 Eduard Veit
## All rights reserved. This program and the accompanying materials
## are made available under the terms of the MIT license
## which accompanies this distribution, and is available at
## https://opensource.org/licenses/MIT
_version=0.1.0
###################
## Configuration ##
###################
_dyn_domain=dyndns.example.com
## service provider could be inwx
_serviceProvider=inwx
## update method options: domrobot, dyndns
_update_method=domrobot
## ip mode could be either: 4, 6 or dual for dualstack
_ip_mode=dual
## If you are using the DomRobot RPC-API enter your credentials for the web interface login here
## If you are using the DynDNS2 protocol enter your credentials here
_username=
_password=
## TTL (time to live) minimum allowed value by inwx is 300 (5 minutes)
TTL=300
## The IP-Check sites (some sites have different urls for v4 and v6)
## pro tip: use your own ip check server for privacy
## it could be as simple as that...
## create an index.php with <?php echo $_SERVER['REMOTE_ADDR']; ?>
_ipv4_checker=api64.ipify.org
_ipv6_checker=api64.ipify.org
_DNS_checkServer=1.1.1.1
######################################################
## You don't need to change the following variables ##
_INWX_JSON_API_URL=https://api.domrobot.com/jsonrpc/
_new_IPv4=
_new_IPv6=
_dns_records=
_main_domain=
_has_getopt=
_is_IPv4_enabled=false
_is_IPv6_enabled=false
[[ -x $(command -v jq 2> /dev/null) ]] || {
echo "This script depends on jq and it is not available." >&2
exit 1
}
[[ -x $(command -v curl 2> /dev/null) ]] || {
echo "This script depends on curl and it is not available." >&2
exit 1
}
[[ -x $(command -v getopt 2> /dev/null) ]] || {
_has_getopt=false
}
_help_message="$(cat << 'EOF'
dynb - dynamic DNS update script for bash
Usage
-------
dynb [options]
-h, --help displays this help message
-i | --ip-mode [ 4 | 6 | dual ] updates type A (IPv4) and AAAA (IPv6) records
-m | --update-method [dyndns | domrobot] choose if you want to use DynDNS2 or the DomRobot RPC-API
-s | --service-provider inwx set your provider in case you are using DynDNS2
-d | --domain "dyndns.example.com" set the domain you want to update
-u | --username "user42" depends on your selected update method and your provider
-p | --password "SuperSecretPassword" depends on your selected update method and your provider
##### examples #####
dynb --ip-mode dualstack --update-method domrobot --domain dyndns.example.com --username user42 --password SuperSecretPassword
dynb --ip-mode dualstack --update-method dyndns --service-provider inwx --domain dyndns.example.com --username user42 --password SuperSecretPassword
EOF
)"
# The main domain or another identifier for the zone is required for the updateRecord call
function getMainDomain() {
request=$( echo "{}" | \
jq '(.method="'nameserver.list'")' | \
jq '(.params.user="'$_username'")' | \
jq '(.params.pass="'$_password'")'
)
response=$(curl --silent \
--request POST $_INWX_JSON_API_URL \
--header "Content-Type: application/json" \
--data "$request" | jq '.resData.domains[] | select(inside(.domain="'"$_dyn_domain"'"))'
)
_main_domain=$( echo "$response" | jq --raw-output '.domain' )
}
function fetchDNSRecords() {
request=$( echo "{}" | \
jq '(.method="'nameserver.info'")' | \
jq '(.params.user="'$_username'")' | \
jq '(.params.pass="'$_password'")' | \
jq '(.params.domain="'"$_main_domain"'")' | \
jq '(.params.name="'"$_dyn_domain"'")'
)
response=$( curl --silent \
--request POST $_INWX_JSON_API_URL \
--header "Content-Type: application/json" \
--data "$request"
)
_dns_records=$( echo $response | jq '.resData.record[]' )
}
# requires parameter A or AAAA
# result to stdout
function getRecordID() {
echo $_dns_records | jq 'select(.type == "'${1}'") | .id'
}
# requires parameter A or AAAA
# result to stdout
function getDNSIP() {
echo $_dns_records | jq --raw-output 'select(.type == "'${1}'") | .content'
}
# requires parameter
# 1. param: 4 or 6 for ip version
# 2. param: IP check server address
# result to stdout
function getRemoteIP() {
curl --silent --ipv${1} --dns-servers 1.1.1.1 --location ${2}
}
# requires parameter
# 1. param: 4 or 6 as ip version
function updateRecord() {
if [[ ${1} == 4 ]]; then
ID=$(getRecordID A)
IP=$_new_IPv4
fi
if [[ ${1} == 6 ]]; then
ID=$(getRecordID AAAA)
IP=$_new_IPv6
fi
if [[ $IP != "" ]]; then
request=$( echo "{}" | \
jq '(.method="'nameserver.updateRecord'")' | \
jq '(.params.user="'$_username'")' | \
jq '(.params.pass="'$_password'")' | \
jq '(.params.id="'$ID'")' | \
jq '(.params.content="'$IP'")' | \
jq '(.params.ttl="'$TTL'")'
)
response=$(curl --silent \
--request POST $_INWX_JSON_API_URL \
--header "Content-Type: application/json" \
--data "$request"
)
echo -e "$(echo "$response" | jq --raw-output '.msg')\n Domain: $_dyn_domain\n new IPv${1}: $IP"
fi
}
# using DynDNS2 protocol
function dynupdate() {
myip_str=
myipv6_str=
INWX_DYNDNS_UPDATE_URL="https://dyndns.inwx.com/nic/update?"
DYNV6_DYNDNS_UPDATE_URL="https://dynv6.com/api/update?zone=$_dyn_domain&token=$_password&"
if [[ $_serviceProvider == "inwx" ]]; then
dyndns_update_url=$INWX_DYNDNS_UPDATE_URL
myip_str=myip
myipv6_str=myipv6
fi
if [[ $_serviceProvider == "dynv6" ]]; then
dyndns_update_url="${DYNV6_DYNDNS_UPDATE_URL}"
myip_str=ipv4
myipv6_str=ipv6
fi
if [[ $_is_IPv4_enabled == true ]] && [[ $_is_IPv6_enabled == true ]]; then
dyndns_update_url="${dyndns_update_url}${myip_str}=${_new_IPv4}&${myipv6_str}=${_new_IPv6}"
fi
if [[ $_is_IPv4_enabled == true ]] && [[ $_is_IPv6_enabled == false ]]; then
dyndns_update_url="${dyndns_update_url}${myip_str}=${_new_IPv4}"
fi
if [[ $_is_IPv4_enabled == false ]] && [[ $_is_IPv6_enabled == true ]]; then
dyndns_update_url="${dyndns_update_url}${myipv6_str}=${_new_IPv6}"
fi
## request ##
if [[ $_serviceProvider == "dynv6" ]]; then
response=$(curl --silent "${dyndns_update_url}" )
#echo $dyndns_update_url
fi
if [[ $_serviceProvider == "inwx" ]]; then
response=$(curl --silent --user "$_username":"$_password" "${dyndns_update_url}" )
fi
case $response in
good )
echo "The DynDNS update has been executed."
return
;;
nochg )
echo "Nothing has changed, IP addresses are still up to date."
return
;;
abuse )
echo "You are not allowed to run this command more than once in 60 seconds."
return
;;
badauth )
echo "Your username and/or password is wrong."
return
;;
!yours )
echo "The domain does not belong to your user account"
return
;;
notfqdn )
echo "Hostname $_dyn_domain is invalid"
return
;;
nohost )
echo "No hostname has been specified"
return
;;
numhost )
echo "Too many hostnames have been specified for this update"
return
;;
dnserr )
echo "There is an internal error in the dyndns update system"
return
;;
* )
echo "$response"
return
;;
esac
}
# requires parameter
# 1. param: 4 or 6 for IP version
function ipHasChanged() {
if [[ ${1} == 4 ]]; then
remote_ip=$(getRemoteIP 4 $_ipv4_checker)
if [[ $_update_method == domrobot ]]; then
dns_ip=$(getDNSIP A)
else
dns_ip=$(dig @${_DNS_checkServer} in a +short "$_dyn_domain")
fi
fi
if [[ ${1} == 6 ]]; then
remote_ip=$(getRemoteIP 6 $_ipv6_checker)
if [[ $_update_method == domrobot ]]; then
dns_ip=$(getDNSIP AAAA)
else
dns_ip=$(dig @${_DNS_checkServer} in aaaa +short "$_dyn_domain")
fi
fi
if [[ "$remote_ip" == "$dns_ip" ]]; then
return 0
else
if [[ ${1} == 4 ]]; then
_new_IPv4=$remote_ip
#echo "New IPv4: $_new_IPv4 old was: $dns_ip"
else
_new_IPv6=$remote_ip
#echo "New IPv6: $_new_IPv6 old was: $dns_ip"
fi
return 1
fi
}
###############
## arguments ##
###############
ARGS=
if [[ $_has_getopt == "" ]] && [[ $(uname) == Linux ]]; then
ARGS=$(getopt --options "hvi:,d:,m:,s:,u:,p:" --longoptions "help,version,link,ip-mode:,domain:,update-method:,service-provider:,username:,password:" -- "$@");
fi
eval set -- "$ARGS";
unset ARGS
function processParameters() {
while true; do
case $1 in
-h | --help )
echo "$_help_message"
exit 0
;;
-v | --version )
echo $_version
exit 0
;;
--link )
ln --verbose --symbolic "$(realpath "$0")" "$HOME/.local/bin/dynb"
exit 0
;;
-i | --ip-mode )
_ip_mode=$2
shift 2
;;
-d | --domain )
_dyn_domain=$2
shift 2
;;
-m | --update-method )
_update_method=$2
shift 2
;;
-s | --service-provider )
_serviceProvider=$2
shift 2
;;
-u | --username )
_username=$2
shift 2
;;
-p | --password )
_password=$2
shift 2
;;
--)
shift
break
esac
done
}
##################
## dependencies ##
##################
function checkDependencies() {
[[ -x $(command -v curl 2> /dev/null) ]] || {
echo "This script depends on curl and it is not available." >&2
exit 1
}
[[ -x $(command -v jq 2> /dev/null) ]] || {
if [[ $_update_method != dyndns* ]]; then
echo "This script depends on jq and it is not available." >&2
exit 1
fi
}
[[ -x $(command -v getopt 2> /dev/null) ]] || {
_has_getopt=false
}
}
##################
## MAIN section ##
##################
FILE=$(dirname "$0")/.env
if test -f "$FILE"; then
# shellcheck source=.env
# shellcheck disable=SC1091
source "$FILE"
fi
if [[ $_has_getopt == "" ]] && [[ $(uname) == Linux ]]; then
processParameters "$@"
fi
checkDependencies
if [[ $_ip_mode == d* ]]; then
_is_IPv4_enabled=true
_is_IPv6_enabled=true
fi
if [[ $_ip_mode == *4* ]]; then
_is_IPv4_enabled=true
fi
if [[ $_ip_mode == *6* ]]; then
_is_IPv6_enabled=true
fi
if [[ $_update_method == "domrobot" ]]; then
getMainDomain
fetchDNSRecords
if [[ $_is_IPv4_enabled == true ]]; then
ipHasChanged 4
if [[ $? == 1 ]]; then
updateRecord 4
fi
fi
if [[ $_is_IPv6_enabled == true ]]; then
ipHasChanged 6
if [[ $? == 1 ]]; then
updateRecord 6
fi
fi
fi
if [[ $_update_method == "dyndns" ]]; then
changed=0
if [[ $_is_IPv4_enabled == true ]]; then
ipHasChanged 4
(( changed += $? ))
fi
if [[ $_is_IPv6_enabled == true ]]; then
ipHasChanged 6
(( changed += $? ))
fi
if [[ $changed -gt 0 ]]; then
dynupdate
fi
fi
unset _DNS_checkServer
unset _dns_records
unset _dyn_domain
unset _has_getopt
unset _help_message
unset _INWX_JSON_API_URL
unset _ip_mode
unset _ipv4_checker
unset _ipv6_checker
unset _is_IPv4_enabled
unset _is_IPv6_enabled
unset _main_domain
unset _new_IPv4
unset _new_IPv6
unset _password
unset _username
unset _serviceProvider
unset _version
exit 0