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

24 Commits

Author SHA1 Message Date
317abdbcec doc: 📝 document environment variables 2021-11-03 18:09:44 +01:00
4faba4e600 refactor: ♻️ method extractions and other beautifications 2021-11-03 18:09:43 +01:00
84784248c3 fix: 🐛 fix loop and error handling in case of connection issues 2021-11-03 18:09:43 +01:00
b083080c9d doc: 📝 document example of an docker-compose.yml file 2021-11-03 18:09:42 +01:00
48df7c7646 feat: add Dockerfile 2021-11-03 18:09:42 +01:00
b1f6c5a0fd doc: 📝 document loop mode and mention dig as requirement 2021-11-03 18:09:42 +01:00
17e23e7623 feat: add loop mode 2021-11-03 18:09:41 +01:00
bb1e0db9bf doc: 📝 update example of .env in README.md 2021-11-03 18:09:41 +01:00
29c2f62292 change: 🔃 rename environment variables 2021-11-03 18:09:41 +01:00
c85d5eaaee feat: add support for Duck DNS as DynDNS2 provider 2021-11-03 18:09:40 +01:00
3221f29d71 feat: add support for deSEC as DynDNS2 provider 2021-11-03 18:09:40 +01:00
706b6d84c1 feat: add completion
 add man page
2021-11-03 18:09:39 +01:00
6d9bf8a2ae feat: 🔃 replace getopt with argbash 2021-11-03 18:09:39 +01:00
6a14d00256 fix: 🐛 fix error handling 2021-11-03 18:09:39 +01:00
dff0c1c178 refactor: ♻️ main code 2021-11-03 18:09:38 +01:00
9bac611ddf feat: add interpretaton of status codes and act accordingly 2021-11-03 18:09:38 +01:00
1bb0f44d28 feat: make network interface configurable 2021-11-03 18:09:38 +01:00
730858344c fix: 🐛 fix sourcing of config file
♻️ do some shellcheck fixes
2021-11-03 18:09:02 +01:00
e3781a87bb feat: add DynDNS2 support for dynv6.com 2021-11-03 17:00:44 +01:00
fa5086f197 doc: 📝 CHANGELOG.md 2021-11-03 17:00:21 +01:00
3fa15b4d9d minor: 📝 .gitchangelog.rc 2021-11-03 16:59:05 +01:00
2c90e74bf5 doc: 📝 add example.env 2021-11-03 16:57:53 +01:00
cddcd9cfca add: 📝 README.md 2021-11-03 16:56:55 +01:00
616c1d47c1 add: dynb.sh 2021-11-03 16:56:39 +01:00
11 changed files with 395 additions and 168 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
**/.env
**/.dockerignore
**/.docker-compose.debug.yml
**/.docker-compose.yml
**/.git
**/.gitignore
**/.gitchangelog.rc
man/man.rst
man/man-defs.rst

3
.gitignore vendored
View File

@@ -1 +1,2 @@
.env* .env*
docker-compose*

View File

@@ -1,10 +1,32 @@
# Changelog # Changelog
## (unreleased) ## 0.1.2 (2021-04-23)
### Documentation
* :memo: document environment variables. [Eduard Veit]
### Other
* :recycle: refactor: method extractions and other beautifications. [Eduard Veit]
## 0.1.1 (2021-04-23)
### Fix
* :bug: fix loop and error handling in case of connection issues. [Eduard Veit]
## 0.1.0 (2021-04-22)
### New ### New
* :sparkles: add Dockerfile. [Eduard Veit]
* :sparkles: add loop mode. [Eduard Veit]
* :sparkles: add support for Duck DNS as DynDNS2 provider. [Eduard Veit] * :sparkles: add support for Duck DNS as DynDNS2 provider. [Eduard Veit]
* :sparkles: add support for deSEC as DynDNS2 provider. [Eduard Veit] * :sparkles: add support for deSEC as DynDNS2 provider. [Eduard Veit]
@@ -33,6 +55,12 @@
### Documentation ### Documentation
* :memo: document example of an docker-compose.yml file. [Eduard Veit]
* :memo: document loop mode and dig as requirement. [Eduard Veit]
* :memo: update example of .env in README.md. [Eduard Veit]
* :memo: add CHANGELOG.md. [Eduard Veit] * :memo: add CHANGELOG.md. [Eduard Veit]
* :memo: add example.env. [Eduard Veit] * :memo: add example.env. [Eduard Veit]
@@ -41,6 +69,8 @@
### Other ### Other
* :recycle: refactor: rename environment variables. [Eduard Veit]
* :recycle: refactor, fix and debug error handling. [Eduard Veit] * :recycle: refactor, fix and debug error handling. [Eduard Veit]
* :recycle: refactor main code. [Eduard Veit] * :recycle: refactor main code. [Eduard Veit]

5
Dockerfile Normal file
View File

@@ -0,0 +1,5 @@
FROM alpine:latest
RUN apk update && apk add bash curl jq bind-tools
WORKDIR /usr/src/app
COPY . .
CMD /bin/bash /usr/src/app/dynb.sh

View File

@@ -11,6 +11,7 @@ IPv4 (A) and IPv6 (AAAA) record updates are supported.
- [⚙ Configuration](#-configuration) - [⚙ Configuration](#-configuration)
- [🏃 Run](#-run) - [🏃 Run](#-run)
- [⏰ Cron](#-cron) - [⏰ Cron](#-cron)
- [🐟 docker](#-docker)
<!-- /TOC --> <!-- /TOC -->
## ✨ Update Methods ## ✨ Update Methods
@@ -31,7 +32,8 @@ The following update methods are currently implemented:
## 📦 Requirements ## 📦 Requirements
* `curl` - The minimum requirement for running DynDNS2 operations * `curl` - The minimum requirement for all API requests.
* `dig` - You can get it by installing `dnsutils` (debian/ubuntu/ArchLinux), `bind-utils` (CentOS/RHEL), `bind-tools` (Alpine)
also essential if you are using other APIs: also essential if you are using other APIs:
@@ -50,7 +52,6 @@ If you want to add the script to you PATH, run :point_down:
``` ```
bash dynb.sh --link bash dynb.sh --link
``` ```
This convenience function only works if `util-linux` is installed on your system.
## ⚙ Configuration ## ⚙ Configuration
@@ -59,21 +60,23 @@ Or you can just use CLI parameters.
Create `.env` in the app root directory or at `~/.local/share/dynb/.env`. Create `.env` in the app root directory or at `~/.local/share/dynb/.env`.
``` ```
_dyn_domain=dyndns.example.com DYNB_DYN_DOMAIN=dyndns.example.com
## service provider could be inwx ## service provider could be deSEC, duckdns, dynv6, inwx
_serviceProvider=inwx DYNB_SERVICE_PROVIDER=inwx
## update method options: domrobot, dyndns ## update method options: domrobot, dyndns
_update_method=domrobot DYNB_UPDATE_METHOD=domrobot
## ip mode could be either: 4, 6 or dual for dualstack ## ip mode could be either: 4, 6 or dual for dualstack
_ip_mode=dual DYNB_IP_MODE=64
## If you are using the DomRobot RPC-API enter your credentials for the web interface login here ## 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 ## If you are using the DynDNS2 protocol enter your credentials here
_username= DYNB_USERNAME=User42
_password= DYNB_PASSWORD=SuperSecretPassword
## or use a token
DYNB_TOKEN=
``` ```
## 🏃 Run ## 🏃 Run
@@ -95,7 +98,14 @@ dynb --ip-mode dualstack --update-method dyndns --provider inwx --domain dyndns.
``` ```
## ⏰ Cron ## ⏰ Cron
To automatically call the script you can use cron.
To automatically call the script you can use either crontab or the script can also run in a loop mode.
### loop mode
Just use the parameter `--interval 60` or the environment variable `DYNB_INTERVAL=60` so the script will check every 60 seconds if it needs to do an update.
### crontab
execute :point_down: execute :point_down:
``` ```
@@ -106,3 +116,42 @@ then enter :point_down: to run dynb every five minutes.
*/5 * * * * $HOME/.local/bin/dynb >> $HOME/.local/share/dynb/dynb-cron.log */5 * * * * $HOME/.local/bin/dynb >> $HOME/.local/share/dynb/dynb-cron.log
``` ```
Note, cron typically does not use the users PATH variable. Note, cron typically does not use the users PATH variable.
## 🐟 docker
This is an example of a `docker-compose.yml` file. If you are using IPv6 make sure the routing works properly with your docker container.
```yaml
version: '3.4'
services:
dynb:
image: ev21/dynb
container_name: dynb
network_mode: host
build:
context: .
dockerfile: ./Dockerfile
environment:
- DYNB_DYN_DOMAIN=dyndns.example.com
- DYNB_SERVICE_PROVIDER=inwx
- DYNB_UPDATE_METHOD=dyndns
- DYNB_IP_MODE=64
- DYNB_USERNAME=User42
- DYNB_PASSWORD=SuperSecretPassword
- DYNB_INTERVAL=60
```
## environment variables
| variable | default value | description |
| --------------------- | --------------- | ----------- |
| DYNB_DYN_DOMAIN | undefined | required |
| DYNB_SERVICE_PROVIDER | undefined | required |
| DYNB_UPDATE_METHOD | undefined | required |
| DYNB_IP_MODE | undefined | required |
| DYNB_USERNAME | undefined | the requirement depends on your provider and the update method |
| DYNB_PASSWORD | undefined | the requirement depends on your provider and the update method |
| DYNB_TOKEN | undefined | the requirement depends on your provider and the update method |
| DYNB_INTERVAL | undefined | without this setting the script/docker container will run one time and exits |
| DYNB_DEBUG | undefined | more console outputs |
| DYNB_IPv4_CHECK_SITE | api64.ipify.org | You need a website or Web-API that outputs your remote IP |
| DYNB_IPv6_CHECK_SITE | api64.ipify.org | You need a website or Web-API that outputs your remote IP |
| DYNB_DNS_CHECK_SERVER | 1.1.1.1 | If you are using a local DNS Resolver/Server make sure it answers with the public answer |

View File

@@ -12,10 +12,10 @@ _dynb_sh ()
COMPREPLY=() COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}" cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
all_long_opts="--version --link --reset --debug --update-method --ip-mode --domain --service-provider --username --password --token --help " all_long_opts="--version --link --reset --debug --update-method --ip-mode --domain --service-provider --username --password --token --interval --help "
all_short_opts="-v -l -r -m -i -d -s -u -p -t -h " all_short_opts="-v -l -r -m -i -d -s -u -p -t -h "
case "$prev" in case "$prev" in
--update-method|-m|--ip-mode|-i|--domain|-d|--service-provider|-s|--username|-u|--password|-p|--token|-t) --update-method|-m|--ip-mode|-i|--domain|-d|--service-provider|-s|--username|-u|--password|-p|--token|-t|--interval)
COMPREPLY=( $(compgen -o bashdefault -o default -- "${cur}") ) COMPREPLY=( $(compgen -o bashdefault -o default -- "${cur}") )
return 0 return 0
;; ;;
@@ -37,5 +37,5 @@ _dynb_sh ()
esac esac
} }
complete -F _dynb_sh dynb.sh dynb complete -F _dynb_sh dynb.sh
### END OF CODE GENERATED BY Argbash (sortof) ### ]) ### END OF CODE GENERATED BY Argbash (sortof) ### ])

392
dynb.sh
View File

@@ -10,33 +10,33 @@
## Configuration ## ## Configuration ##
################### ###################
_dyn_domain= #DYNB_DYN_DOMAIN=
## service provider could be deSEC, duckdns, dynv6, inwx ## service provider could be deSEC, duckdns, dynv6, inwx
_serviceProvider= #DYNB_SERVICE_PROVIDER=
## update method options: domrobot, dyndns ## update method options: domrobot, dyndns
_update_method= #DYNB_UPDATE_METHOD=
## ip mode could be either: 4, 6 or dual for dualstack ## ip mode could be either: 4, 6 or dual for dualstack
_ip_mode= #DYNB_IP_MODE=
## If you are using the DomRobot RPC-API enter your credentials for the web interface login here ## 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 ## If you are using the DynDNS2 protocol enter your credentials here
_username= #DYNB_USERNAME=
_password= #DYNB_PASSWORD=
## or use a token ## or use a token
_token= #DYNB_TOKEN=
## TTL (time to live) for the DNS record ## TTL (time to live) for the DNS record
## This setting is only relevant for API based record updates (not DnyDNS2!) ## This setting is only relevant for API based record updates (not DnyDNS2!)
## minimum allowed TTL value by inwx is 300 (5 minutes) ## minimum allowed TTL value by inwx is 300 (5 minutes)
TTL=300 TTL=300
## The IP-Check sites (some sites have different urls for v4 and v6) ## The IP-Check sites (some sites have different urls for v4 and v6)
## Pro tip: use your own ip check server for privacy ## Pro tip: use your own ip check server for privacy
## it could be as simple as that... ## it could be as simple as that...
## create an index.php with <?php echo $_SERVER['REMOTE_ADDR']; ?> ## create an index.php with <?php echo $_SERVER'REMOTE_ADDR'; ?>
_ipv4_checker=api64.ipify.org _ipv4_checker=api64.ipify.org
_ipv6_checker=api64.ipify.org _ipv6_checker=api64.ipify.org
@@ -65,11 +65,13 @@ _response=
_statusHostname= _statusHostname=
_statusUsername= _statusUsername=
_statusPassword= _statusPassword=
_version=0.0.1 _version=0.1.2
_userAgent="DynB/$_version github.com/EV21/dynb" _userAgent="DynB/$_version github.com/EV21/dynb"
_configFile=$HOME/.local/share/dynb/.env _configFile=$HOME/.local/share/dynb/.env
_statusFile=/tmp/dynb.status _statusFile=/tmp/dynb.status
_debug=0 _debug=0
_minimum_looptime=60
_loopMode=0
# Created by argbash-init v2.10.0 # Created by argbash-init v2.10.0
# Rearrange the order of options below according to what you would like to see in the help message. # Rearrange the order of options below according to what you would like to see in the help message.
@@ -84,6 +86,7 @@ _debug=0
# ARG_OPTIONAL_SINGLE([username],[u],[depends on your selected update method and your provider],[]) # ARG_OPTIONAL_SINGLE([username],[u],[depends on your selected update method and your provider],[])
# ARG_OPTIONAL_SINGLE([password],[p],[depends on your selected update method and your provider],[]) # ARG_OPTIONAL_SINGLE([password],[p],[depends on your selected update method and your provider],[])
# ARG_OPTIONAL_SINGLE([token],[t],[depends on your selected update method and your provider],[]) # ARG_OPTIONAL_SINGLE([token],[t],[depends on your selected update method and your provider],[])
# ARG_OPTIONAL_SINGLE([interval],[],[choose the seconds interval to run the script in a loop, minimum is 60],[])
# ARG_HELP([DynB - dynamic DNS update script for bash]) # ARG_HELP([DynB - dynamic DNS update script for bash])
# ARGBASH_GO() # ARGBASH_GO()
# needed because of Argbash --> m4_ignore([ # needed because of Argbash --> m4_ignore([
@@ -120,12 +123,13 @@ _arg_service_provider=
_arg_username= _arg_username=
_arg_password= _arg_password=
_arg_token= _arg_token=
_arg_interval=
print_help() print_help()
{ {
printf '%s\n' "DynB - dynamic DNS update script for bash" printf '%s\n' "DynB - dynamic DNS update script for bash"
printf 'Usage: %s [-v|--(no-)version] [-l|--(no-)link] [-r|--(no-)reset] [--(no-)debug] [-m|--update-method <arg>] [-i|--ip-mode <arg>] [-d|--domain <arg>] [-s|--service-provider <arg>] [-u|--username <arg>] [-p|--password <arg>] [-t|--token <arg>] [-h|--help]\n' "$0" printf 'Usage: %s [-v|--(no-)version] [-l|--(no-)link] [-r|--(no-)reset] [--(no-)debug] [-m|--update-method <arg>] [-i|--ip-mode <arg>] [-d|--domain <arg>] [-s|--service-provider <arg>] [-u|--username <arg>] [-p|--password <arg>] [-t|--token <arg>] [--interval <arg>] [-h|--help]\n' "$0"
printf '\t%s\n' "-v, --version, --no-version: outputs the client version (off by default)" printf '\t%s\n' "-v, --version, --no-version: outputs the client version (off by default)"
printf '\t%s\n' "-l, --link, --no-link: links to your script at ~/.local/bin/dynb (off by default)" printf '\t%s\n' "-l, --link, --no-link: links to your script at ~/.local/bin/dynb (off by default)"
printf '\t%s\n' "-r, --reset, --no-reset: deletes the client blocking status file (off by default)" printf '\t%s\n' "-r, --reset, --no-reset: deletes the client blocking status file (off by default)"
@@ -137,6 +141,7 @@ print_help()
printf '\t%s\n' "-u, --username: depends on your selected update method and your provider (no default)" printf '\t%s\n' "-u, --username: depends on your selected update method and your provider (no default)"
printf '\t%s\n' "-p, --password: depends on your selected update method and your provider (no default)" printf '\t%s\n' "-p, --password: depends on your selected update method and your provider (no default)"
printf '\t%s\n' "-t, --token: depends on your selected update method and your provider (no default)" printf '\t%s\n' "-t, --token: depends on your selected update method and your provider (no default)"
printf '\t%s\n' "--interval: choose the seconds interval to run the script in a loop, minimum is 60 (no default)"
printf '\t%s\n' "-h, --help: Prints help" printf '\t%s\n' "-h, --help: Prints help"
} }
@@ -264,6 +269,14 @@ parse_commandline()
-t*) -t*)
_arg_token="${_key##-t}" _arg_token="${_key##-t}"
;; ;;
--interval)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_interval="$2"
shift
;;
--interval=*)
_arg_interval="${_key##--interval=}"
;;
-h|--help) -h|--help)
print_help print_help
exit 0 exit 0
@@ -316,6 +329,14 @@ dynb --ip-mode dual --update-method dyndns --service-provider inwx --domain dynd
EOF EOF
)" )"
function loopMode() {
if [[ $_loopMode -eq 1 ]]; then
return 0
else
return 1
fi
}
function debugMode() { function debugMode() {
if [[ $_debug -eq 1 ]]; then if [[ $_debug -eq 1 ]]; then
return 0 return 0
@@ -324,20 +345,29 @@ function debugMode() {
fi fi
} }
function infoMessage() {
echo "$(logtime) INFO: $*"
}
function debugMessage() { function debugMessage() {
if debugMode; then if debugMode; then
echo "Debug: $*" echo "$(logtime) DEBUG: $*"
fi fi
} }
function echoerr() { printf "%s\n" "$*" >&2; } function errorMessage() { printf "$(logtime) ERROR: %s\n" "$*" >&2; }
function logtime() {
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$LOGTIME]"
}
# The main domain as an identifier for the dns zone is required for the updateRecord call # The main domain as an identifier for the dns zone is required for the updateRecord call
function getMainDomain() { function getMainDomain() {
request=$( echo "{}" | \ request=$( echo "{}" | \
jq '(.method="nameserver.list")' | \ jq '(.method="nameserver.list")' | \
jq "(.params.user=\"$_username\")" | \ jq "(.params.user=\"$DYNB_USERNAME\")" | \
jq "(.params.pass=\"$_password\")" jq "(.params.pass=\"$DYNB_PASSWORD\")"
) )
_response=$(curl --silent \ _response=$(curl --silent \
@@ -345,7 +375,7 @@ function getMainDomain() {
--user-agent "$_userAgent" \ --user-agent "$_userAgent" \
--header "Content-Type: application/json" \ --header "Content-Type: application/json" \
--request POST $_INWX_JSON_API_URL \ --request POST $_INWX_JSON_API_URL \
--data "$request" | jq ".resData.domains[] | select(inside(.domain=\"$_dyn_domain\"))" --data "$request" | jq ".resData.domains[] | select(inside(.domain=\"$DYNB_DYN_DOMAIN\"))"
) )
_main_domain=$( echo "$_response" | jq --raw-output '.domain' ) _main_domain=$( echo "$_response" | jq --raw-output '.domain' )
} }
@@ -353,10 +383,10 @@ function getMainDomain() {
function fetchDNSRecords() { function fetchDNSRecords() {
request=$( echo "{}" | \ request=$( echo "{}" | \
jq '(.method="'nameserver.info'")' | \ jq '(.method="'nameserver.info'")' | \
jq "(.params.user=\"$_username\")" | \ jq "(.params.user=\"$DYNB_USERNAME\")" | \
jq "(.params.pass=\"$_password\")" | \ jq "(.params.pass=\"$DYNB_PASSWORD\")" | \
jq "(.params.domain=\"$_main_domain\")" | \ jq "(.params.domain=\"$_main_domain\")" | \
jq "(.params.name=\"$_dyn_domain\")" jq "(.params.name=\"$DYNB_DYN_DOMAIN\")"
) )
_response=$( curl --silent \ _response=$( curl --silent \
@@ -405,8 +435,8 @@ function updateRecord() {
if [[ $IP != "" ]]; then if [[ $IP != "" ]]; then
request=$( echo "{}" | \ request=$( echo "{}" | \
jq '(.method="nameserver.updateRecord")' | \ jq '(.method="nameserver.updateRecord")' | \
jq "(.params.user=\"$_username\")" | \ jq "(.params.user=\"$DYNB_USERNAME\")" | \
jq "(.params.pass=\"$_password\")" | \ jq "(.params.pass=\"$DYNB_PASSWORD\")" | \
jq "(.params.id=\"$ID\")" | \ jq "(.params.id=\"$ID\")" | \
jq "(.params.content=\"$IP\")" | \ jq "(.params.content=\"$IP\")" | \
jq "(.params.ttl=\"$TTL\")" jq "(.params.ttl=\"$TTL\")"
@@ -419,7 +449,7 @@ function updateRecord() {
--request POST $_INWX_JSON_API_URL \ --request POST $_INWX_JSON_API_URL \
--data "$request" --data "$request"
) )
echo -e "$(echo "$_response" | jq --raw-output '.msg')\n Domain: $_dyn_domain\n new IPv${1}: $IP" echo -e "$(echo "$_response" | jq --raw-output '.msg')\n Domain: $DYNB_DYN_DOMAIN\n new IPv${1}: $IP"
fi fi
} }
@@ -431,10 +461,10 @@ function dynupdate() {
INWX_DYNDNS_UPDATE_URL="https://dyndns.inwx.com/nic/update?" INWX_DYNDNS_UPDATE_URL="https://dyndns.inwx.com/nic/update?"
DESEC_DYNDNS_UPDATE_URL="https://update.dedyn.io/?" DESEC_DYNDNS_UPDATE_URL="https://update.dedyn.io/?"
DUCKDNS_DYNDNS_UPDATE_URL="https://www.duckdns.org/update?domains=$_dyn_domain&token=$_token&" DUCKDNS_DYNDNS_UPDATE_URL="https://www.duckdns.org/update?domains=$DYNB_DYN_DOMAIN&token=$DYNB_TOKEN&"
DYNV6_DYNDNS_UPDATE_URL="https://dynv6.com/api/update?zone=$_dyn_domain&token=$_token&" DYNV6_DYNDNS_UPDATE_URL="https://dynv6.com/api/update?zone=$DYNB_DYN_DOMAIN&token=$DYNB_TOKEN&"
case $_serviceProvider in case $DYNB_SERVICE_PROVIDER in
inwx* | INWX* ) inwx* | INWX* )
dyndns_update_url=$INWX_DYNDNS_UPDATE_URL dyndns_update_url=$INWX_DYNDNS_UPDATE_URL
;; ;;
@@ -452,7 +482,7 @@ function dynupdate() {
myipv6_str=ipv6 myipv6_str=ipv6
;; ;;
* ) * )
echoerr "$_serviceProvider is not supported" errorMessage "$DYNB_SERVICE_PROVIDER is not supported"
exit 1 exit 1
;; ;;
esac esac
@@ -470,18 +500,18 @@ function dynupdate() {
debugMessage "Update URL was: $dyndns_update_url" debugMessage "Update URL was: $dyndns_update_url"
## request ## ## request ##
case $_serviceProvider in case $DYNB_SERVICE_PROVIDER in
inwx* | INWX* ) inwx* | INWX* )
_response=$(curl --silent "$_interface_str" \ _response=$(curl --silent "$_interface_str" \
--user-agent "$_userAgent" \ --user-agent "$_userAgent" \
--user "$_username":"$_password" \ --user "$DYNB_USERNAME":"$DYNB_PASSWORD" \
"${dyndns_update_url}" ) "${dyndns_update_url}" )
;; ;;
deSEC* | desec* | dedyn* ) deSEC* | desec* | dedyn* )
_response=$(curl --silent "$_interface_str" \ _response=$(curl --silent "$_interface_str" \
--user-agent "$_userAgent" \ --user-agent "$_userAgent" \
--header "Authorization: Token $_token" \ --header "Authorization: Token $DYNB_TOKEN" \
--get --data-urlencode "hostname=$_dyn_domain" \ --get --data-urlencode "hostname=$DYNB_DYN_DOMAIN" \
"${dyndns_update_url}" ) "${dyndns_update_url}" )
;; ;;
dynv6* | duckDNS* | duckdns* ) dynv6* | duckDNS* | duckdns* )
@@ -493,66 +523,66 @@ function dynupdate() {
esac esac
case $_response in case $_response in
good* | OK* ) good* | OK* | "addresses updated" )
if [[ $_response == "good 127.0.0.1" ]]; then if [[ $_response == "good 127.0.0.1" ]]; then
echoerr "Error: $_response: Request ignored." errorMessage "$_response: Request ignored."
return 1 return 1
else else
echo "$_response: The DynDNS update has been executed." infoMessage "$_response: The DynDNS update has been executed."
_errorCounter=0 _errorCounter=0
return 0 return 0
fi fi
;; ;;
nochg* ) nochg* )
echo "$_response: Nothing has changed, IP addresses are still up to date." infoMessage "$_response: Nothing has changed, IP addresses are still up to date."
return 1 return 1
;; ;;
abuse ) abuse )
echoerr "Error: $_response: Username is blocked due to abuse." errorMessage "$_response: Username is blocked due to abuse."
return 1 return 1
;; ;;
badauth | 401 ) badauth | 401 )
echoerr "Error: $_response: Invalid username password combination." errorMessage "$_response: Invalid username password combination."
return 1 return 1
;; ;;
badagent ) badagent )
echoerr "Error: $_response: Client disabled. Something is very wrong!" errorMessage "$_response: Client disabled. Something is very wrong!"
return 1 return 1
;; ;;
!donator ) !donator )
echoerr "Error: $_response: An update request was sent, including a feature that is not available to that particular user such as offline options." errorMessage "$_response: An update request was sent, including a feature that is not available to that particular user such as offline options."
return 1 return 1
;; ;;
!yours ) !yours )
echoerr "Error: $_response: The domain does not belong to your user account" errorMessage "$_response: The domain does not belong to your user account"
return 1 return 1
;; ;;
notfqdn ) notfqdn )
echoerr "Error: $_response: Hostname $_dyn_domain is invalid" errorMessage "$_response: Hostname $DYNB_DYN_DOMAIN is invalid"
return 1 return 1
;; ;;
nohost ) nohost )
echoerr "Error: $_response: Hostname supplied does not exist under specified account, enter new login credentials before performing an additional request." errorMessage "$_response: Hostname supplied does not exist under specified account, enter new login credentials before performing an additional request."
return 1 return 1
;; ;;
numhost ) numhost )
echoerr "Error: $_response: Too many hostnames have been specified for this update" errorMessage "$_response: Too many hostnames have been specified for this update"
return 1 return 1
;; ;;
dnserr ) dnserr )
echoerr "Error: $_response: There is an internal error in the dyndns update system. Retry update no sooner than 30 minutes." errorMessage "$_response: There is an internal error in the dyndns update system. Retry update no sooner than 30 minutes."
return 1 return 1
;; ;;
911 | 5* ) 911 | 5* )
echoerr "Error: $_response: A fatal error on provider side such as a database outage. Retry update no sooner than 30 minutes." errorMessage "$_response: A fatal error on provider side such as a database outage. Retry update no sooner than 30 minutes."
return 1 return 1
;; ;;
* ) * )
if [[ "$_response" == "$_status" ]]; then if [[ "$_response" == "$_status" ]]; then
echoerr "Error: An unknown response code has been received. $_response" errorMessage "An unknown response code has been received. $_response"
return 1 return 1
else else
echoerr "Error: unknown respnse code: $_response" errorMessage "unknown respnse code: $_response"
return 0 return 0
fi fi
;; ;;
@@ -568,14 +598,14 @@ function checkStatus() {
case $_status in case $_status in
nochg* ) nochg* )
if [[ _errorCounter -gt 1 ]]; then if [[ _errorCounter -gt 1 ]]; then
echoerr "Error: The update client was spamming unnecessary update requests, something might be wrong with your IP-Check site." errorMessage "The update client was spamming unnecessary update requests, something might be wrong with your IP-Check site."
echoerr "Fix your config an then delete $_statusFile" errorMessage "Fix your config an then delete $_statusFile or restart your docker container"
return 1 return 1
fi fi
;; ;;
nohost | !yours ) nohost | !yours )
if [[ "$_statusHostname" == "$_dyn_domain" && ( "$_statusUsername" == "$_username" || $_statusUsername == "$_token" ) ]]; then if [[ "$_statusHostname" == "$DYNB_DYN_DOMAIN" && ( "$_statusUsername" == "$DYNB_USERNAME" || $_statusUsername == "$DYNB_TOKEN" ) ]]; then
echoerr "Error: Hostname supplied does not exist under specified account, enter new login credentials before performing an additional request." errorMessage "Hostname supplied does not exist under specified account, enter new login credentials before performing an additional request."
return 1 return 1
else else
rm "$_statusFile" rm "$_statusFile"
@@ -583,8 +613,8 @@ function checkStatus() {
return 0 return 0
;; ;;
badauth | 401 ) badauth | 401 )
if [[ "$_statusUsername" == "$_username" && "$_statusPassword" == "$_password" ]]; then if [[ "$_statusUsername" == "$DYNB_USERNAME" && "$_statusPassword" == "$DYNB_PASSWORD" ]]; then
echoerr "Error: Invalid username password combination." errorMessage "Invalid username password combination."
return 1 return 1
else else
rm "$_statusFile" rm "$_statusFile"
@@ -592,19 +622,19 @@ function checkStatus() {
return 0 return 0
;; ;;
badagent ) badagent )
echoerr "Error: Client is deactivated by provider." errorMessage "Client is deactivated by provider."
echo "Fix your config and then manually remove $_statusFile to reset the client blockade." echo "Fix your config and then manually remove $_statusFile to reset the client blockade."
echo "If it still fails file an issue at github or try another client :)" echo "If it still fails file an issue at github or try another client :)"
return 1 return 1
;; ;;
!donator ) !donator )
echoerr "Error: An update request was sent, including a feature that is not available to that particular user such as offline options." errorMessage "An update request was sent, including a feature that is not available to that particular user such as offline options."
echo "Fix your config and then manually remove $_statusFile to reset the client blockade" echo "Fix your config and then manually remove $_statusFile to reset the client blockade"
echo "If it still fails file an issue at github or try another client :)" echo "If it still fails file an issue at github or try another client :)"
return 1 return 1
;; ;;
abuse ) abuse )
echoerr "Error: Username is blocked due to abuse." errorMessage "Username is blocked due to abuse."
echo "Fix your config and then manually remove $_statusFile to reset the client blockade" echo "Fix your config and then manually remove $_statusFile to reset the client blockade"
echo "If it still fails file an issue at github or try another client :)" echo "If it still fails file an issue at github or try another client :)"
return 1 return 1
@@ -612,7 +642,7 @@ function checkStatus() {
911 | 5* ) 911 | 5* )
delta=$(( $(date +%s) - _eventTime )) delta=$(( $(date +%s) - _eventTime ))
if [[ $delta -lt 1800 ]]; then if [[ $delta -lt 1800 ]]; then
echoerr "$_status: The provider currently has an fatal error. DynB will wait for next update until 30 minutes have passed since last request, $(date --date=@$delta -u +%M) minutes already passed." errorMessage "$_status: The provider currently has an fatal error. DynB will wait for next update until 30 minutes have passed since last request, $(date --date=@$delta -u +%M) minutes already passed."
return 1 return 1
else else
rm "$_statusFile" rm "$_statusFile"
@@ -621,7 +651,7 @@ function checkStatus() {
;; ;;
* ) * )
if [[ _errorCounter -gt 1 ]]; then if [[ _errorCounter -gt 1 ]]; then
echoerr "Error: An unknown response code has repeatedly been received. $_response" errorMessage "An unknown response code has repeatedly been received. $_response"
return 1 return 1
else else
return 0 return 0
@@ -635,18 +665,40 @@ function checkStatus() {
function ipHasChanged() { function ipHasChanged() {
if [[ ${1} == 4 ]]; then if [[ ${1} == 4 ]]; then
remote_ip=$(getRemoteIP 4 $_ipv4_checker) remote_ip=$(getRemoteIP 4 $_ipv4_checker)
if [[ $_update_method == domrobot ]]; then #TODO: this is duplicated code, refactor this.
if [[ $? -gt 0 ]]; then
errorMessage "IPCheck (getRemoteIP 4) request failed $remote_ip"
return 0
fi
if [[ $DYNB_UPDATE_METHOD == domrobot ]]; then
dns_ip=$(getDNSIP A) dns_ip=$(getDNSIP A)
else else
dns_ip=$(dig @${_DNS_checkServer} in a +short "$_dyn_domain") dig_response=$(dig @${_DNS_checkServer} in a +short "$DYNB_DYN_DOMAIN")
#TODO: this is duplicated code, refactor this.
if [[ $dig_response == ";; connection timed out; no servers could be reached" ]]; then
errorMessage "DNS request failed $dig_response"
return 0
fi
dns_ip=$dig_response
fi fi
fi fi
if [[ ${1} == 6 ]]; then if [[ ${1} == 6 ]]; then
remote_ip=$(getRemoteIP 6 $_ipv6_checker) remote_ip=$(getRemoteIP 6 $_ipv6_checker)
if [[ $_update_method == domrobot ]]; then #TODO: this is duplicated code, refactor this.
if [[ $? -gt 0 ]]; then
errorMessage "IPCheck (getRemoteIP 6) request failed $remote_ip"
return 0
fi
if [[ $DYNB_UPDATE_METHOD == domrobot ]]; then
dns_ip=$(getDNSIP AAAA) dns_ip=$(getDNSIP AAAA)
else else
dns_ip=$(dig @${_DNS_checkServer} in aaaa +short "$_dyn_domain") dig_response=$(dig @${_DNS_checkServer} in aaaa +short "$DYNB_DYN_DOMAIN")
#TODO: this is duplicated code, refactor this.
if [[ $dig_response == ";; connection timed out; no servers could be reached" ]]; then
errorMessage "DNS request failed $dig_response"
return 0
fi
dns_ip=$dig_response
fi fi
fi fi
@@ -686,25 +738,64 @@ function handleParameters() {
_debug=1 _debug=1
fi fi
if [[ $_arg_update_method != "" ]]; then if [[ $_arg_update_method != "" ]]; then
_update_method=$_arg_update_method DYNB_UPDATE_METHOD=$_arg_update_method
fi fi
if [[ $_arg_ip_mode != "" ]]; then if [[ $_arg_ip_mode != "" ]]; then
_ip_mode=$_arg_ip_mode DYNB_IP_MODE=$_arg_ip_mode
fi fi
if [[ $_arg_domain != "" ]]; then if [[ $_arg_domain != "" ]]; then
_dyn_domain=$_arg_domain DYNB_DYN_DOMAIN=$_arg_domain
fi fi
if [[ $_arg_service_provider != "" ]]; then if [[ $_arg_service_provider != "" ]]; then
_serviceProvider=$_arg_service_provider DYNB_SERVICE_PROVIDER=$_arg_service_provider
fi fi
if [[ $_arg_username != "" ]]; then if [[ $_arg_username != "" ]]; then
_username=$_arg_username DYNB_USERNAME=$_arg_username
fi fi
if [[ $_arg_password != "" ]]; then if [[ $_arg_password != "" ]]; then
_password=$_arg_password DYNB_PASSWORD=$_arg_password
fi fi
if [[ $_arg_token != "" ]]; then if [[ $_arg_token != "" ]]; then
_token=$_arg_token DYNB_TOKEN=$_arg_token
fi
if [[ $_arg_interval != "" ]]; then
DYNB_INTERVAL=$_arg_interval
fi
if [[ -z $DYNB_INTERVAL ]]; then
_loopMode=0
elif [[ $DYNB_INTERVAL -lt _minimum_looptime ]]; then
DYNB_INTERVAL=$_minimum_looptime
_loopMode=1
else
_loopMode=1
fi
if [[ $_network_interface != "" ]]; then
_interface_str="--interface $_network_interface"
fi
if [[ $DYNB_IP_MODE == d* ]]; then
_is_IPv4_enabled=true
_is_IPv6_enabled=true
fi
if [[ $DYNB_IP_MODE == *4* ]]; then
_is_IPv4_enabled=true
fi
if [[ $DYNB_IP_MODE == *6* ]]; then
_is_IPv6_enabled=true
fi
if [[ $DYNB_DEBUG == true ]]; then
_debug=1
fi
if [[ -n $DYNB_IPv4_CHECK_SITE ]]; then
_ipv4_checker=$DYNB_IPv4_CHECK_SITE
fi
if [[ -n $DYNB_IPv6_CHECK_SITE ]]; then
_ipv6_checker=$DYNB_IPv6_CHECK_SITE
fi
if [[ -n $DYNB_DNS_CHECK_SERVER ]]; then
_DNS_checkServer=$DYNB_DNS_CHECK_SERVER
fi fi
return 0 return 0
} }
@@ -714,30 +805,31 @@ function handleParameters() {
################## ##################
function checkDependencies() { function checkDependencies() {
## If there will be more general dependencies use a loop failCounter=0
# for i in curl and some other stuff; do for i in curl dig; do
# if ! command -v $i >/dev/null 2>&1; then if ! command -v $i >/dev/null 2>&1; then
# echoerr "Error: could not find \"$i\", DynB depends on it. " errorMessage "could not find \"$i\", DynB depends on it. "
# exit 1 (( failCounter++ ))
# fi fi
# done done
[[ -x $(command -v jq 2> /dev/null) ]] || { [[ -x $(command -v jq 2> /dev/null) ]] || {
if [[ $_update_method != dyndns* ]]; then if [[ $DYNB_UPDATE_METHOD != dyndns* ]]; then
echo "This script depends on jq and it is not available." >&2 echo "This script depends on jq and it is not available." >&2
exit 1 (( failCounter++ ))
fi fi
} }
if [[ failCounter -gt 0 ]]; then
exit 1
fi
} }
function doUnsets() { function doUnsets() {
unset _network_interface unset _network_interface
unset _DNS_checkServer unset _DNS_checkServer
unset _dns_records unset _dns_records
unset _dyn_domain
unset _has_getopt unset _has_getopt
unset _help_message unset _help_message
unset _INWX_JSON_API_URL unset _INWX_JSON_API_URL
unset _ip_mode
unset _ipv4_checker unset _ipv4_checker
unset _ipv6_checker unset _ipv6_checker
unset _is_IPv4_enabled unset _is_IPv4_enabled
@@ -745,10 +837,76 @@ function doUnsets() {
unset _main_domain unset _main_domain
unset _new_IPv4 unset _new_IPv4
unset _new_IPv6 unset _new_IPv6
unset _password
unset _username
unset _serviceProvider
unset _version unset _version
unset DYNB_DYN_DOMAIN
unset DYNB_USERNAME
unset DYNB_PASSWORD
unset DYNB_TOKEN
unset DYNB_SERVICE_PROVIDER
unset DYNB_IP_MODE
unset DYNB_INTERVAL
unset DYNB_IPv4_CHECK_SITE
unset DYNB_IPv6_CHECK_SITE
unset DYNB_DNS_CHECK_SERVER
unset DYNB_DEBUG
}
function doDomrobotUpdates() {
getMainDomain
fetchDNSRecords
if [[ $_is_IPv4_enabled == true ]]; then
ipHasChanged 4
if [[ $? == 1 ]]; then
updateRecord 4
else
debugMessage "Skip IPv4 record update, it is already up to date"
fi
fi
if [[ $_is_IPv6_enabled == true ]]; then
ipHasChanged 6
if [[ $? == 1 ]]; then
updateRecord 6
else
debugMessage "Skip IPv6 record update, it is already up to date"
fi
fi
}
function doDynDNS2Updates() {
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
if checkStatus; then
debugMessage "checkStatus has no errors, try update"
if dynupdate; then
debugMessage "DynDNS2 update success"
else
debugMessage "Save new status after dynupdate has failed"
setStatus "$_response" "$(date +%s)" $(( _errorCounter += 1 )) "$DYNB_DYN_DOMAIN" "${DYNB_USERNAME}" "${DYNB_PASSWORD}${DYNB_TOKEN}"
fi
else
debugMessage "Skip DynDNS2 update, checkStatus fetched previous error."
fi
else
debugMessage "Skip DynDNS2 update, IPs are up to date or there is a connection problem"
fi
}
function doUpdates() {
if [[ $DYNB_UPDATE_METHOD == "domrobot" ]]; then
doDomrobotUpdates
fi
if [[ $DYNB_UPDATE_METHOD == "dyndns" ]]; then
doDynDNS2Updates
fi
} }
################# #################
@@ -777,66 +935,16 @@ function dynb() {
handleParameters handleParameters
if [[ $_network_interface != "" ]]; then if loopMode; then
_interface_str="--interface $_network_interface" while :
do
doUpdates
sleep $DYNB_INTERVAL
done
else
doUpdates
fi fi
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
## execute operations
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
if checkStatus; then
debugMessage "checkStatus has no errors, try update"
if dynupdate; then
debugMessage "DynDNS2 update success"
else
debugMessage "Save new status after dynupdate has failed"
setStatus "$_response" "$(date +%s)" $(( _errorCounter += 1 )) "$_dyn_domain" "${_username}" "${_password}${_token}"
fi
else
debugMessage "Skip DynDNS2 update, checkStatus fetched previous error."
fi
else
debugMessage "Skip DynDNS2 update, IPs are up to date"
fi
fi
doUnsets doUnsets
return 0 return 0
} }

View File

@@ -1,7 +1,21 @@
_dyn_domain=dyndns.example.com ###################
_serviceProvider=inwx ## Configuration ##
_update_method=domrobot ###################
_ip_mode=dual
_username=User42 DYNB_DYN_DOMAIN=dyndns.example.com
_password=SuperSecretPassword
_token= ## service provider could be deSEC, duckdns, dynv6, inwx
DYNB_SERVICE_PROVIDER=inwx
## update method options: domrobot, dyndns
DYNB_UPDATE_METHOD=domrobot
## ip mode could be either: 4, 6 or dual for dualstack
DYNB_IP_MODE=64
## 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
DYNB_USERNAME=User42
DYNB_PASSWORD=SuperSecretPassword
## or use a token
DYNB_TOKEN=

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH MAN 1 "2021-04-03" "" "" .TH MAN 1 "2021-04-21" "" ""
.SH NAME .SH NAME
man \- DynB - dynamic DNS update script for bash man \- DynB - dynamic DNS update script for bash
. .
@@ -32,7 +32,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.. ..
.SH SYNOPSIS .SH SYNOPSIS
.sp .sp
\fBman [\-\-version] [\-\-link] [\-\-reset] [\-\-debug] [\-\-update\-method UPDATE\-METHOD] [\-\-ip\-mode IP\-MODE] [\-\-domain DOMAIN] [\-\-service\-provider SERVICE\-PROVIDER] [\-\-username USERNAME] [\-\-password PASSWORD] [\-\-token TOKEN] [\-\-help]\fP \fBman [\-\-version] [\-\-link] [\-\-reset] [\-\-debug] [\-\-update\-method UPDATE\-METHOD] [\-\-ip\-mode IP\-MODE] [\-\-domain DOMAIN] [\-\-service\-provider SERVICE\-PROVIDER] [\-\-username USERNAME] [\-\-password PASSWORD] [\-\-token TOKEN] [\-\-interval INTERVAL] [\-\-help]\fP
.SH DESCRIPTION .SH DESCRIPTION
.sp .sp
IPv4 (A) and IPv6 (AAAA) record updates are supported. IPv4 (A) and IPv6 (AAAA) record updates are supported.
@@ -97,6 +97,11 @@ e.g. SuperSecretPassword
depends on your selected update method and your provider. depends on your selected update method and your provider.
.sp .sp
YourProviderGivenToken YourProviderGivenToken
.TP
.BI \-\-interval \ INTERVAL
choose the seconds interval to run the script in a loop, minimum is 60.
.sp
.TP .TP
.B \-h\fP,\fB \-\-help .B \-h\fP,\fB \-\-help
Prints help. Prints help.

View File

@@ -30,4 +30,6 @@
.. |OPTION_TOKEN| replace:: YourProviderGivenToken .. |OPTION_TOKEN| replace:: YourProviderGivenToken
.. |OPTION_INTERVAL| replace:: \
.. |OPTION_HELP| replace:: \ .. |OPTION_HELP| replace:: \

View File

@@ -11,7 +11,7 @@ DynB - dynamic DNS update script for bash
----------------------------------------- -----------------------------------------
:Author: |AUTHOR| :Author: |AUTHOR|
:Date: 2021-04-03 :Date: 2021-04-21
:Version: |VERSION| :Version: |VERSION|
:Manual section: |MAN_SECTION| :Manual section: |MAN_SECTION|
@@ -19,7 +19,7 @@ DynB - dynamic DNS update script for bash
SYNOPSIS SYNOPSIS
======== ========
``man [--version] [--link] [--reset] [--debug] [--update-method UPDATE-METHOD] [--ip-mode IP-MODE] [--domain DOMAIN] [--service-provider SERVICE-PROVIDER] [--username USERNAME] [--password PASSWORD] [--token TOKEN] [--help]`` ``man [--version] [--link] [--reset] [--debug] [--update-method UPDATE-METHOD] [--ip-mode IP-MODE] [--domain DOMAIN] [--service-provider SERVICE-PROVIDER] [--username USERNAME] [--password PASSWORD] [--token TOKEN] [--interval INTERVAL] [--help]``
DESCRIPTION DESCRIPTION
@@ -79,6 +79,10 @@ ARGUMENTS
|OPTION_TOKEN| |OPTION_TOKEN|
--interval INTERVAL choose the seconds interval to run the script in a loop, minimum is 60.
|OPTION_INTERVAL|
-h, --help Prints help. -h, --help Prints help.
|OPTION_HELP| |OPTION_HELP|