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

49 Commits

Author SHA1 Message Date
1f31d943ca add DynDNS2 support for noip.com 2021-11-03 23:24:39 +01:00
c712ec5654 minor: 🔃 update .gitchangelog.rc 2021-11-03 18:09:52 +01:00
9cc26d737f feat: validate ip address respons from ip check web service 2021-11-03 18:09:51 +01:00
e6af29dcd4 feat: check internet connection for selected ip versions 2021-11-03 18:09:51 +01:00
b3eb045cc7 doc: 📝 add labels to Dockerfile 2021-11-03 18:09:51 +01:00
4b68ca837d feat: 🎨 colorful info, debug and error messages 2021-11-03 18:09:50 +01:00
eedb0623ac refactor: ♻️ remove unused argbash fragment 2021-11-03 18:09:50 +01:00
b5d300a86e doc: 📝 update CHANGELOG.md 2021-11-03 18:09:50 +01:00
a95effb00d dev: 🔥 remove md-toc from pre-commit 2021-11-03 18:09:49 +01:00
a5dc7ea9b3 doc: 📝 document docker parameters 2021-11-03 18:09:49 +01:00
63cbce3568 feat: enable parameter extensions for docker run --interactive 2021-11-03 18:09:49 +01:00
73d2a7ac44 dev: add pre-commit hooks for markdown 2021-11-03 18:09:49 +01:00
cad6d47cd2 cosmetic: 🎨 lint README.md 2021-11-03 18:09:48 +01:00
06c35d99af doc: 📝 change default dns server setting 2021-11-03 18:09:48 +01:00
9da624b163 dev: 🎨 add shfmt params to pre-commit check 2021-11-03 18:09:47 +01:00
c01bea615e cosmetic: 🎨 fix shell style 2021-11-03 18:09:47 +01:00
046a728f22 change: handle dns server selection 2021-11-03 18:09:47 +01:00
3ded7fc883 refactor: ♻️ seperate parsing logic 2021-11-03 18:09:46 +01:00
f942a4495d dev:️ change git hooks and add shfmt 2021-11-03 18:09:46 +01:00
32404f2957 doc: 📝 update CHANGELOG 2021-11-03 18:09:46 +01:00
3cdcdbc8bf cosmetic: ♻️ normalizing pre-commit configuration to a top-level map 2021-11-03 18:09:45 +01:00
226537b2b0 refactor: ♻️ something 2021-11-03 18:09:45 +01:00
976ea673f8 dev: add pre-commit git hook for shellcheck 2021-11-03 18:09:45 +01:00
9ed30f2bee refactor: ♻️ remove unused help message 2021-11-03 18:09:44 +01:00
3ab88e5993 doc: 📝 update README.md 2021-11-03 18:09:44 +01:00
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
15 changed files with 1413 additions and 395 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

View File

@@ -82,24 +82,34 @@ ignore_regexps = [
## whenever you are tweaking this variable. ## whenever you are tweaking this variable.
## ##
section_regexps = [ section_regexps = [
('New', [ ('Features', [
r'^:sparkles\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$', r'^[fF]eat\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]), ]),
('Changes', [ ('Added', [
r'^:wrench\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$', r'^[aA]dd\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('Changed', [
r'^[cC]hange\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('Deprecated', [
r'^[dD]epricated\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('Removed', [
r'^[rR]emove\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]), ]),
('Fix', [ ('Fix', [
r'^:bug\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$', r'^[fF]ix\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('Security', [
r'^[sS]ec\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]), ]),
('Documentation', [ ('Documentation', [
r'^:memo\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$', r'^[dD]oc\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('Remove', [
r'^:fire\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]), ]),
('Other', None ## Match all lines
), #('Other', None ## Match all lines
# ),
] ]

1
.gitignore vendored
View File

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

17
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,17 @@
repos:
- repo: https://github.com/syntaqx/git-hooks
rev: v0.0.17
hooks:
- id: shellcheck
- id: shfmt
args:
- "-l" # list files whose formatting differs from shfmt's
- "-i 2" # indent: 0 for tabs (default), >0 for number of spaces
- "-ci" # switch cases will be indented
- "-w" # write result to file instead of stdout
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.9
hooks:
- id: mdformat
additional_dependencies:
- mdformat-gfm # GitHub Flavored Markdown support

View File

@@ -1,10 +1,89 @@
# Changelog # Changelog
## (unreleased) ## 0.2.0 (2021-09-24)
### New ### New
* :sparkles: enable parameter extensions for `docker run --interactive` [Eduard Veit]
* :sparkles: add pre-commit hooks for markdown. [Eduard Veit]
* :sparkles: change git hooks and add shfmt. [Eduard Veit]
* :sparkles: add pre-commit git hook for shellcheck. [Eduard Veit]
### Changes
* :wrench: remove md-toc from pre-commit. [Eduard Veit]
* :wrench: handle dns server selection. [Eduard Veit]
### Documentation
* :memo: update CHANGELOG.md. [Eduard Veit]
* :memo: document docker parameters. [Eduard Veit]
* :memo: change default dns server setting. [Eduard Veit]
* :memo: update CHANGELOG. [Eduard Veit]
* :memo: update README.md. [Eduard Veit]
### Other
* :art: lint README.md. [Eduard Veit]
* :art: add shfmt params to pre-commit check. [Eduard Veit]
* :art: fix shell style. [Eduard Veit]
* :recycle: seperate parsing logic. [Eduard Veit]
* :recycle: normalizing pre-commit configuration to a top-level map. [Eduard Veit]
* :recycle: refactorings. [Eduard Veit]
* Refactor: :recycle: remove unused help message. [Eduard Veit]
## 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
* :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 deSEC as DynDNS2 provider. [Eduard Veit]
* :sparkles: add completion. [Eduard Veit]
:sparkles: add man page
* :sparkles: replace getopt with argbash. [Eduard Veit]
* :sparkles: add interpretaton of status codes and act accordingly. [Eduard Veit] * :sparkles: add interpretaton of status codes and act accordingly. [Eduard Veit]
* :sparkles: make network interface configurable. [Eduard Veit] * :sparkles: make network interface configurable. [Eduard Veit]
@@ -13,7 +92,7 @@
* :sparkles: add .gitchangelog.rc. [Eduard Veit] * :sparkles: add .gitchangelog.rc. [Eduard Veit]
* :sparkles: add dynb. [Eduard Veit] * :sparkles: add dynb.sh. [Eduard Veit]
### Fix ### Fix
@@ -23,14 +102,26 @@
### 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 .env.example. [Eduard Veit] * :memo: add example.env. [Eduard Veit]
* :memo: write README.md. [Eduard Veit] * :memo: write README.md. [Eduard Veit]
### Other ### Other
* :recycle: refactor: rename environment variables. [Eduard Veit]
* :recycle: refactor, fix and debug error handling. [Eduard Veit]
* :recycle: refactor main code. [Eduard Veit]
* Initial commit. [EV21] * Initial commit. [EV21]

20
Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM alpine:latest
RUN \
apk update \
&& \
apk add \
bash \
curl \
jq \
bind-tools
WORKDIR /usr/src/app
COPY . .
ENTRYPOINT ["/bin/bash", "/usr/src/app/dynb.sh"]
LABEL org.opencontainers.image.source="https://github.com/EV21/dynb"
LABEL org.opencontainers.image.description="DynB - dynamic DNS update client."
LABEL org.opencontainers.image.licenses="MIT"

136
README.md
View File

@@ -1,8 +1,11 @@
# 🔃 DynB # 🔃 DynB
DynB - dynamic DNS update script, written in bash DynB - dynamic DNS update script, written in bash
IPv4 (A) and IPv6 (AAAA) record updates are supported. IPv4 (A) and IPv6 (AAAA) record updates are supported.
<!-- TOC --> <!-- TOC -->
- [✨ Update Methods](#-update-methods) - [✨ Update Methods](#-update-methods)
- [APIs](#apis) - [APIs](#apis)
- [DynDNS2](#dyndns2) - [DynDNS2](#dyndns2)
@@ -11,100 +14,173 @@ IPv4 (A) and IPv6 (AAAA) record updates are supported.
- [⚙ Configuration](#-configuration) - [⚙ Configuration](#-configuration)
- [🏃 Run](#-run) - [🏃 Run](#-run)
- [⏰ Cron](#-cron) - [⏰ Cron](#-cron)
- [loop mode](#loop-mode)
- [crontab](#crontab)
- [🐟 docker](#-docker)
- [environment variables](#environment-variables)
<!-- /TOC --> <!-- /TOC -->
## ✨ Update Methods ## ✨ Update Methods
The following update methods are currently implemented: The following update methods are currently implemented:
### APIs ### APIs
* INWX.com JSON-RPC-API - INWX.com Domrobot JSON-RPC-API\
Limitations: Limitations:
- minimum TTL is 300 (5 minutes) - minimum TTL is 300 (5 minutes)
### DynDNS2 ### DynDNS2
* INWX.com - INWX.com
* dynv6.com - deSEC.io (dedyn.io)
- DuckDNS.org
- dynv6.com
## 📦 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)
essential for APIs: also essential if you are using other APIs:
* `jq` - Command-line JSON processor - `jq` - Command-line JSON processor
optional requirement:
* `getopt` for CLI parameter handling from [util-linux](https://pkgs.org/download/util-linux)
## 🚀 Installation ## 🚀 Installation
Download the latest release Download the latest release
or simply clone this repo or simply clone this repo
```
```shell
git clone https://github.com/EV21/dynb.git git clone https://github.com/EV21/dynb.git
``` ```
If you want to add the script to you PATH, run :point_down: If you want to add the script to you PATH, run :point_down:
```
```shell
bash dynb.sh --link bash dynb.sh --link
``` ```
This convenience function only works if `util-linux` is installed on your system.
## ⚙ Configuration ## ⚙ Configuration
You can use a config in form of an `.env` file. You can use a config in form of an `.env` file.
Or if your system meets the relevant requirements you can use CLI parameters. 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
## service provider could be inwx ```bash
_serviceProvider=inwx DYNB_DYN_DOMAIN=dyndns.example.com
## service provider could be deSEC, duckdns, dynv6, 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
If you have a config file just run :point_down: If you have a config file just run :point_down:
```
```bash
dynb dynb
``` ```
Alternatively you can use parameters if your system meets the relevant requirements. This example shows the long form parameter, there are also short ones.
Alternatively you can use parameters if your system meets the relevant requirements. This example shows the long form parameter, there are also short ones.\
Call the help function :point_down: Call the help function :point_down:
```
```bash
dynb --help dynb --help
``` ```
```
```bash
dynb --ip-mode dualstack --update-method domrobot --domain dyndns.example.com --username user42 --password SuperSecretPassword dynb --ip-mode dualstack --update-method domrobot --domain dyndns.example.com --username user42 --password SuperSecretPassword
``` ```
```
```bash
dynb --ip-mode dualstack --update-method dyndns --provider inwx --domain dyndns.example.com --username user42 --password SuperSecretPassword dynb --ip-mode dualstack --update-method dyndns --provider inwx --domain dyndns.example.com --username user42 --password SuperSecretPassword
``` ```
## ⏰ 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:
```
```bash
crontab -e crontab -e
``` ```
then enter :point_down: to run dynb every five minutes. then enter :point_down: to run dynb every five minutes.
```
```bash
*/5 * * * * $HOME/.local/bin/dynb >> $HOME/.local/share/dynb/dynb-cron.log */5 * * * * $HOME/.local/bin/dynb >> $HOME/.local/share/dynb/dynb-cron.log
``` ```
alternative with docker and parameters::
```bash
*/5 * * * * docker run --interactive --tty --rm --network host ev21/dynb:latest --ip-mode 64 --update-method domrobot --domain dyndns.example.com --username user42 --password SuperSecretPassword
```
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. Note: [IPv6 networking](https://docs.docker.com/config/daemon/ipv6/) is only supported on Docker daemons running on Linux hosts.
```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; `dyndns.example.com` |
| DYNB_SERVICE_PROVIDER | undefined | required; `deSEC`, `duckdns`, `dynv6`, `inwx` |
| DYNB_UPDATE_METHOD | undefined | required; `dyndns` or `domrobot` (with inwx) |
| DYNB_IP_MODE | undefined | required; `4`, `6` or `64` for both |
| 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 | undefined | If you are using a local DNS Resolver/Server make sure it answers with the public answer or set another server |

41
_dynb.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
# Put this file to /etc/bash_completion.d/dynb.sh
# needed because of Argbash --> m4_ignore([
### START OF CODE GENERATED BY Argbash v2.10.0 one line above ###
# Argbash is a bash code generator used to get arguments parsing right.
# Argbash is FREE SOFTWARE, see https://argbash.io for more info
_dynb_sh ()
{
local cur prev opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
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 "
case "$prev" in
--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}") )
return 0
;;
*)
case "$cur" in
--*)
COMPREPLY=( $(compgen -W "${all_long_opts}" -- "${cur}") )
return 0
;;
-*)
COMPREPLY=( $(compgen -W "${all_short_opts}" -- "${cur}") )
return 0
;;
*)
COMPREPLY=( $(compgen -o bashdefault -o default -- "${cur}") )
return 0
;;
esac
esac
}
complete -F _dynb_sh dynb.sh
### END OF CODE GENERATED BY Argbash (sortof) ### ])

24
dynb-parsing-template.m4 Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
# m4_ignore(
echo "This is just a script template for argbash, not the script." >&2
exit 11 #)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.
# ARG_OPTIONAL_BOOLEAN([version],[v],[outputs the client version],[off])
# ARG_OPTIONAL_BOOLEAN([link],[l],[links to your script at ~/.local/bin/dynb],[off])
# ARG_OPTIONAL_BOOLEAN([reset],[r],[deletes the client blocking status file],[off])
# ARG_OPTIONAL_BOOLEAN([debug],[],[enables debug mode],[off])
# ARG_OPTIONAL_SINGLE([update-method],[m],[choose if you want to use DynDNS2 or the DomRobot RPC-API],[])
# ARG_OPTIONAL_SINGLE([ip-mode],[i],[updates type A (IPv4) and AAAA (IPv6) records],[])
# ARG_OPTIONAL_SINGLE([domain],[d],[set the domain you want to update],[])
# ARG_OPTIONAL_SINGLE([service-provider],[s],[set your provider in case you are using DynDNS2],[])
# 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([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])
# ARGBASH_GO
# [ <-- needed because of Argbash
# ] <-- needed because of Argbash

297
dynb-parsing.sh Normal file
View File

@@ -0,0 +1,297 @@
#!/bin/bash
# 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.
# ARG_OPTIONAL_BOOLEAN([version],[v],[outputs the client version],[off])
# ARG_OPTIONAL_BOOLEAN([link],[l],[links to your script at ~/.local/bin/dynb],[off])
# ARG_OPTIONAL_BOOLEAN([reset],[r],[deletes the client blocking status file],[off])
# ARG_OPTIONAL_BOOLEAN([debug],[],[enables debug mode],[off])
# ARG_OPTIONAL_SINGLE([update-method],[m],[choose if you want to use DynDNS2 or the DomRobot RPC-API],[])
# ARG_OPTIONAL_SINGLE([ip-mode],[i],[updates type A (IPv4) and AAAA (IPv6) records],[])
# ARG_OPTIONAL_SINGLE([domain],[d],[set the domain you want to update],[])
# ARG_OPTIONAL_SINGLE([service-provider],[s],[set your provider in case you are using DynDNS2],[])
# 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([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])
# ARGBASH_GO()
# needed because of Argbash --> m4_ignore([
### START OF CODE GENERATED BY Argbash v2.10.0 one line above ###
# Argbash is a bash code generator used to get arguments parsing right.
# Argbash is FREE SOFTWARE, see https://argbash.io for more info
# # When called, the process ends.
# Args:
# $1: The exit message (print to stderr)
# $2: The exit code (default is 1)
# if env var _PRINT_HELP is set to 'yes', the usage is print to stderr (prior to $1)
# Example:
# test -f "$_arg_infile" || _PRINT_HELP=yes die "Can't continue, have to supply file as an argument, got '$_arg_infile'" 4
die()
{
local _ret="${2:-1}"
test "${_PRINT_HELP:-no}" = yes && print_help >&2
echo "$1" >&2
exit "${_ret}"
}
# Function that evaluates whether a value passed to it begins by a character
# that is a short option of an argument the script knows about.
# This is required in order to support getopts-like short options grouping.
begins_with_short_option()
{
local first_option all_short_options='vlrmidsupth'
first_option="${1:0:1}"
test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0
}
# THE DEFAULTS INITIALIZATION - OPTIONALS
_arg_version="off"
_arg_link="off"
_arg_reset="off"
_arg_debug="off"
_arg_update_method=
_arg_ip_mode=
_arg_domain=
_arg_service_provider=
_arg_username=
_arg_password=
_arg_token=
_arg_interval=
# Function that prints general usage of the script.
# This is useful if users asks for it, or if there is an argument parsing error (unexpected / spurious arguments)
# and it makes sense to remind the user how the script is supposed to be called.
print_help()
{
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>] [--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' "-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' "--debug, --no-debug: enables debug mode (off by default)"
printf '\t%s\n' "-m, --update-method: choose if you want to use DynDNS2 or the DomRobot RPC-API (no default)"
printf '\t%s\n' "-i, --ip-mode: updates type A (IPv4) and AAAA (IPv6) records (no default)"
printf '\t%s\n' "-d, --domain: set the domain you want to update (no default)"
printf '\t%s\n' "-s, --service-provider: set your provider in case you are using DynDNS2 (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' "-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"
}
# The parsing of the command-line
parse_commandline()
{
while test $# -gt 0
do
_key="$1"
case "$_key" in
# The version argurment doesn't accept a value,
# we expect the --version or -v, so we watch for them.
-v|--no-version|--version)
_arg_version="on"
test "${1:0:5}" = "--no-" && _arg_version="off"
;;
# We support getopts-style short arguments clustering,
# so as -v doesn't accept value, other short options may be appended to it, so we watch for -v*.
# After stripping the leading -v from the argument, we have to make sure
# that the first character that follows coresponds to a short option.
-v*)
_arg_version="on"
_next="${_key##-v}"
if test -n "$_next" -a "$_next" != "$_key"
then
{ begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option."
fi
;;
# See the comment of option '--version' to see what's going on here - principle is the same.
-l|--no-link|--link)
_arg_link="on"
test "${1:0:5}" = "--no-" && _arg_link="off"
;;
# See the comment of option '-v' to see what's going on here - principle is the same.
-l*)
_arg_link="on"
_next="${_key##-l}"
if test -n "$_next" -a "$_next" != "$_key"
then
{ begins_with_short_option "$_next" && shift && set -- "-l" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option."
fi
;;
# See the comment of option '--version' to see what's going on here - principle is the same.
-r|--no-reset|--reset)
_arg_reset="on"
test "${1:0:5}" = "--no-" && _arg_reset="off"
;;
# See the comment of option '-v' to see what's going on here - principle is the same.
-r*)
_arg_reset="on"
_next="${_key##-r}"
if test -n "$_next" -a "$_next" != "$_key"
then
{ begins_with_short_option "$_next" && shift && set -- "-r" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option."
fi
;;
# See the comment of option '--version' to see what's going on here - principle is the same.
--no-debug|--debug)
_arg_debug="on"
test "${1:0:5}" = "--no-" && _arg_debug="off"
;;
# We support whitespace as a delimiter between option argument and its value.
# Therefore, we expect the --update-method or -m value.
# so we watch for --update-method and -m.
# Since we know that we got the long or short option,
# we just reach out for the next argument to get the value.
-m|--update-method)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_update_method="$2"
shift
;;
# We support the = as a delimiter between option argument and its value.
# Therefore, we expect --update-method=value, so we watch for --update-method=*
# For whatever we get, we strip '--update-method=' using the ${var##--update-method=} notation
# to get the argument value
--update-method=*)
_arg_update_method="${_key##--update-method=}"
;;
# We support getopts-style short arguments grouping,
# so as -m accepts value, we allow it to be appended to it, so we watch for -m*
# and we strip the leading -m from the argument string using the ${var##-m} notation.
-m*)
_arg_update_method="${_key##-m}"
;;
# See the comment of option '--update-method' to see what's going on here - principle is the same.
-i|--ip-mode)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_ip_mode="$2"
shift
;;
# See the comment of option '--update-method=' to see what's going on here - principle is the same.
--ip-mode=*)
_arg_ip_mode="${_key##--ip-mode=}"
;;
# See the comment of option '-m' to see what's going on here - principle is the same.
-i*)
_arg_ip_mode="${_key##-i}"
;;
# See the comment of option '--update-method' to see what's going on here - principle is the same.
-d|--domain)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_domain="$2"
shift
;;
# See the comment of option '--update-method=' to see what's going on here - principle is the same.
--domain=*)
_arg_domain="${_key##--domain=}"
;;
# See the comment of option '-m' to see what's going on here - principle is the same.
-d*)
_arg_domain="${_key##-d}"
;;
# See the comment of option '--update-method' to see what's going on here - principle is the same.
-s|--service-provider)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_service_provider="$2"
shift
;;
# See the comment of option '--update-method=' to see what's going on here - principle is the same.
--service-provider=*)
_arg_service_provider="${_key##--service-provider=}"
;;
# See the comment of option '-m' to see what's going on here - principle is the same.
-s*)
_arg_service_provider="${_key##-s}"
;;
# See the comment of option '--update-method' to see what's going on here - principle is the same.
-u|--username)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_username="$2"
shift
;;
# See the comment of option '--update-method=' to see what's going on here - principle is the same.
--username=*)
_arg_username="${_key##--username=}"
;;
# See the comment of option '-m' to see what's going on here - principle is the same.
-u*)
_arg_username="${_key##-u}"
;;
# See the comment of option '--update-method' to see what's going on here - principle is the same.
-p|--password)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_password="$2"
shift
;;
# See the comment of option '--update-method=' to see what's going on here - principle is the same.
--password=*)
_arg_password="${_key##--password=}"
;;
# See the comment of option '-m' to see what's going on here - principle is the same.
-p*)
_arg_password="${_key##-p}"
;;
# See the comment of option '--update-method' to see what's going on here - principle is the same.
-t|--token)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_token="$2"
shift
;;
# See the comment of option '--update-method=' to see what's going on here - principle is the same.
--token=*)
_arg_token="${_key##--token=}"
;;
# See the comment of option '-m' to see what's going on here - principle is the same.
-t*)
_arg_token="${_key##-t}"
;;
# See the comment of option '--update-method' to see what's going on here - principle is the same.
--interval)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_interval="$2"
shift
;;
# See the comment of option '--update-method=' to see what's going on here - principle is the same.
--interval=*)
_arg_interval="${_key##--interval=}"
;;
# See the comment of option '--version' to see what's going on here - principle is the same.
-h|--help)
print_help
exit 0
;;
# See the comment of option '-v' to see what's going on here - principle is the same.
-h*)
print_help
exit 0
;;
*)
_PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1
;;
esac
shift
done
}
# Now call all the functions defined above that are needed to get the job done
parse_commandline "$@"
# OTHER STUFF GENERATED BY Argbash
### END OF CODE GENERATED BY Argbash (sortof) ### ])
# [ <-- needed because of Argbash
# vvv PLACE YOUR CODE HERE vvv
# PUT YOUR CODE HERE
# ^^^ TERMINATE YOUR CODE BEFORE THE BOTTOM ARGBASH MARKER ^^^
# ] <-- needed because of Argbash

689
dynb.sh
View File

@@ -10,23 +10,23 @@
## Configuration ## ## Configuration ##
################### ###################
_dyn_domain= #DYNB_DYN_DOMAIN=
## service provider could be 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!)
@@ -36,12 +36,12 @@ 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
## An exernal DNS check server prevents wrong info from local DNS servers/resolvers ## An exernal DNS check server prevents wrong info from local DNS servers/resolvers
_DNS_checkServer=1.1.1.1 _DNS_checkServer=
## if you are actively using multiple network interfaces you might want to specify this ## if you are actively using multiple network interfaces you might want to specify this
## normally the default value is okay ## normally the default value is okay
@@ -51,11 +51,11 @@ _network_interface=
###################################################### ######################################################
## You don't need to change the following variables ## ## You don't need to change the following variables ##
_INWX_JSON_API_URL=https://api.domrobot.com/jsonrpc/ _INWX_JSON_API_URL=https://api.domrobot.com/jsonrpc/
_internet_connectivity_test_server=https://www.google.de
_new_IPv4= _new_IPv4=
_new_IPv6= _new_IPv6=
_dns_records= _dns_records=
_main_domain= _main_domain=
_has_getopt=
_is_IPv4_enabled=false _is_IPv4_enabled=false
_is_IPv6_enabled=false _is_IPv6_enabled=false
_interface_str= _interface_str=
@@ -66,39 +66,46 @@ _response=
_statusHostname= _statusHostname=
_statusUsername= _statusUsername=
_statusPassword= _statusPassword=
_version=0.0.1 _version=0.3.0
_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=1 _debug=0
_minimum_looptime=60
_loopMode=0
_help_message="$(cat << 'EOF' # Ansi color code variables
dynb - dynamic DNS update script for bash yellow_color="\e[0;33m"
green_color="\e[0;92m"
expand_bg="\e[K"
red_color_bg="\e[0;101m${expand_bg}"
bold="\e[1m"
reset_color_modification="\e[0m"
Usage REGEX_IPv4="^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"
===== REGEX_IPv6="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
dynb [options]
-h, --help displays this help message function is_IPv4_address() {
--version outputs the client version if [[ $1 =~ $REGEX_IPv4 ]]
--link links to your script at ~/.local/bin/dynb then return 0
--reset deletes the client blocking status file else return 1
fi
}
Configuration options function is_IPv6_address() {
--------------------- if [[ $1 =~ $REGEX_IPv6 ]]
-i | --ip-mode [ 4 | 6 | dual ] updates type A (IPv4) and AAAA (IPv6) records then return 0
-m | --update-method [dyndns | domrobot] choose if you want to use DynDNS2 or the DomRobot RPC-API else return 1
-s | --service-provider inwx set your provider in case you are using DynDNS2 fi
-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
-t | --token "YourProviderGivenToken" depends on your selected update method and your provider
##### examples ##### function loopMode() {
dynb --ip-mode dual --update-method domrobot --domain dyndns.example.com --username user42 --password SuperSecretPassword if [[ $_loopMode -eq 1 ]]; then
dynb --ip-mode dual --update-method dyndns --service-provider inwx --domain dyndns.example.com --username user42 --password SuperSecretPassword return 0
EOF else
)" return 1
fi
}
function debugMode() { function debugMode() {
if [[ $_debug -eq 1 ]]; then if [[ $_debug -eq 1 ]]; then
@@ -108,42 +115,57 @@ function debugMode() {
fi fi
} }
function infoMessage() {
echo -e "${green_color}$(logtime) INFO: $*${reset_color_modification}"
}
function debugMessage() { function debugMessage() {
if debugMode; then if debugMode; then
echo "Debug: ${1}" echo -e "${yellow_color}$(logtime) DEBUG: ${*}${reset_color_modification}"
fi fi
} }
function echoerr() { printf "%s\n" "$*" >&2; } function errorMessage() {
echo -e "${red_color_bg}${bold}$(logtime) ERROR: $*${reset_color_modification}" >&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=$(
jq '(.method="nameserver.list")' | \ echo "{}" |
jq "(.params.user=\"$_username\")" | \ jq '(.method="nameserver.list")' |
jq "(.params.pass=\"$_password\")" jq "(.params.user=\"$DYNB_USERNAME\")" |
jq "(.params.pass=\"$DYNB_PASSWORD\")"
) )
_response=$(curl --silent \ _response=$(
curl --silent \
"$_interface_str" \ "$_interface_str" \
--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')
} }
function fetchDNSRecords() { function fetchDNSRecords() {
request=$( echo "{}" | \ request=$(
jq '(.method="'nameserver.info'")' | \ echo "{}" |
jq "(.params.user=\"$_username\")" | \ jq '(.method="'nameserver.info'")' |
jq "(.params.pass=\"$_password\")" | \ jq "(.params.user=\"$DYNB_USERNAME\")" |
jq "(.params.domain=\"$_main_domain\")" | \ jq "(.params.pass=\"$DYNB_PASSWORD\")" |
jq "(.params.name=\"$_dyn_domain\")" jq "(.params.domain=\"$_main_domain\")" |
jq "(.params.name=\"$DYNB_DYN_DOMAIN\")"
) )
_response=$( curl --silent \ _response=$(
curl --silent \
"$_interface_str" \ "$_interface_str" \
--user-agent "$_userAgent" \ --user-agent "$_userAgent" \
--header "Content-Type: application/json" \ --header "Content-Type: application/json" \
@@ -171,8 +193,18 @@ function getDNSIP() {
# 2. param: IP check server address # 2. param: IP check server address
# result to stdout # result to stdout
function getRemoteIP() { function getRemoteIP() {
if [[ -n $_DNS_checkServer ]]; then
curl --silent "$_interface_str" --user-agent "$_userAgent" \ curl --silent "$_interface_str" --user-agent "$_userAgent" \
--ipv"${1}" --dns-servers 1.1.1.1 --location "${2}" --ipv"${1}" --dns-servers "$_DNS_checkServer" --location "${2}"
else
curl --silent "$_interface_str" --user-agent "$_userAgent" \
--ipv"${1}" --location "${2}"
fi
# shellcheck disable=2181
if [[ $? -gt 0 ]]; then
errorMessage "IPCheck (getRemoteIP ${1}) request failed"
exit 1
fi
} }
# requires parameter # requires parameter
@@ -187,23 +219,25 @@ function updateRecord() {
IP=$_new_IPv6 IP=$_new_IPv6
fi fi
if [[ $IP != "" ]]; then if [[ $IP != "" ]]; then
request=$( echo "{}" | \ request=$(
jq '(.method="nameserver.updateRecord")' | \ echo "{}" |
jq "(.params.user=\"$_username\")" | \ jq '(.method="nameserver.updateRecord")' |
jq "(.params.pass=\"$_password\")" | \ jq "(.params.user=\"$DYNB_USERNAME\")" |
jq "(.params.id=\"$ID\")" | \ jq "(.params.pass=\"$DYNB_PASSWORD\")" |
jq "(.params.content=\"$IP\")" | \ jq "(.params.id=\"$ID\")" |
jq "(.params.content=\"$IP\")" |
jq "(.params.ttl=\"$TTL\")" jq "(.params.ttl=\"$TTL\")"
) )
_response=$(curl --silent \ _response=$(
curl --silent \
"$_interface_str" \ "$_interface_str" \
--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" --data "$request"
) )
echo -e "$(echo "$_response" | jq --raw-output '.msg')\n Domain: $_dyn_domain\n new IPv${1}: $IP" infoMessage "$(echo "$_response" | jq --raw-output '.msg')\n Domain: $DYNB_DYN_DOMAIN\n New IPv${1}: $IP"
fi fi
} }
@@ -214,21 +248,38 @@ function dynupdate() {
myipv6_str=myipv6 myipv6_str=myipv6
INWX_DYNDNS_UPDATE_URL="https://dyndns.inwx.com/nic/update?" INWX_DYNDNS_UPDATE_URL="https://dyndns.inwx.com/nic/update?"
NOIP_DYNDNS_UPDATE_URL="https://dynupdate.no-ip.com/nic/update?hostname=$_dyn_domain&" DESEC_DYNDNS_UPDATE_URL="https://update.dedyn.io/?"
DYNV6_DYNDNS_UPDATE_URL="https://dynv6.com/api/update?zone=$_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=$DYNB_DYN_DOMAIN&token=$DYNB_TOKEN&"
NOIP_DYNDNS_UPDATE_URL="https://dynupdate.no-ip.com/nic/update?hostname=$DYNB_DYN_DOMAIN&"
if [[ $_serviceProvider == "inwx" ]]; then case $DYNB_SERVICE_PROVIDER in
inwx* | INWX*)
dyndns_update_url=$INWX_DYNDNS_UPDATE_URL dyndns_update_url=$INWX_DYNDNS_UPDATE_URL
fi ;;
if [[ $_serviceProvider == "noip" ]] || [[ $_serviceProvider == "no-ip" ]]; then deSEC* | desec* | dedyn*)
dyndns_update_url=$NOIP_DYNDNS_UPDATE_URL dyndns_update_url="${DESEC_DYNDNS_UPDATE_URL}"
fi ;;
if [[ $_serviceProvider == "dynv6" ]]; then noip* | no-ip*)
dyndns_update_url="$NOIP_DYNDNS_UPDATE_URL"
;;
dynv6*)
dyndns_update_url="${DYNV6_DYNDNS_UPDATE_URL}" dyndns_update_url="${DYNV6_DYNDNS_UPDATE_URL}"
myip_str=ipv4 myip_str=ipv4
myipv6_str=ipv6 myipv6_str=ipv6
fi ;;
DuckDNS* | duckdns*)
dyndns_update_url="${DUCKDNS_DYNDNS_UPDATE_URL}"
myip_str=ipv4
myipv6_str=ipv6
;;
*)
errorMessage "$DYNB_SERVICE_PROVIDER is not supported"
exit 1
;;
esac
# pre encode ip parameters
if [[ $_is_IPv4_enabled == true ]] && [[ $_is_IPv6_enabled == true ]]; then if [[ $_is_IPv4_enabled == true ]] && [[ $_is_IPv6_enabled == true ]]; then
dyndns_update_url="${dyndns_update_url}${myip_str}=${_new_IPv4}&${myipv6_str}=${_new_IPv6}" dyndns_update_url="${dyndns_update_url}${myip_str}=${_new_IPv4}&${myipv6_str}=${_new_IPv6}"
fi fi
@@ -239,81 +290,93 @@ function dynupdate() {
dyndns_update_url="${dyndns_update_url}${myipv6_str}=${_new_IPv6}" dyndns_update_url="${dyndns_update_url}${myipv6_str}=${_new_IPv6}"
fi fi
debugMessage "Update URL was: $dyndns_update_url" debugMessage "Update URL was: $dyndns_update_url"
## request ## ## request ##
if [[ $_serviceProvider == "dynv6" ]]; then case $DYNB_SERVICE_PROVIDER in
inwx* | INWX* | noip* | no-ip*)
_response=$(curl --silent "$_interface_str" \ _response=$(curl --silent "$_interface_str" \
--user-agent "$_userAgent" \
--user "$DYNB_USERNAME":"$DYNB_PASSWORD" \
"${dyndns_update_url}")
;;
deSEC* | desec* | dedyn*)
_response=$(curl --silent "$_interface_str" \
--user-agent "$_userAgent" \
--header "Authorization: Token $DYNB_TOKEN" \
--get --data-urlencode "hostname=$DYNB_DYN_DOMAIN" \
"${dyndns_update_url}")
;;
dynv6* | duckDNS* | duckdns*)
_response=$(
curl --silent "$_interface_str" \
--user-agent "$_userAgent" \ --user-agent "$_userAgent" \
"${dyndns_update_url}" "${dyndns_update_url}"
) )
fi ;;
if [[ $_serviceProvider == "inwx" || $_serviceProvider == "noip" ]]; then esac
_response=$(curl --silent "$_interface_str" \
--user-agent "$_userAgent" \
--user "$_username":"$_password" \
"${dyndns_update_url}" )
fi
case $_response in case $_response in
good* ) 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
;; ;;
@@ -329,14 +392,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"
@@ -344,8 +407,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"
@@ -353,19 +416,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
@@ -373,7 +436,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"
@@ -382,7 +445,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
@@ -394,101 +457,167 @@ function checkStatus() {
# requires parameter # requires parameter
# 1. param: 4 or 6 for IP version # 1. param: 4 or 6 for IP version
function ipHasChanged() { function ipHasChanged() {
if [[ ${1} == 4 ]]; then case ${1} in
4)
remote_ip=$(getRemoteIP 4 $_ipv4_checker) remote_ip=$(getRemoteIP 4 $_ipv4_checker)
if [[ $_update_method == domrobot ]]; then if ! is_IPv4_address "$remote_ip"
then
errorMessage "The response from the IP check server is not an IPv4 address: $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") if [[ -n $_DNS_checkServer ]]; then
dig_response=$(dig @"${_DNS_checkServer}" in a +short "$DYNB_DYN_DOMAIN")
else
dig_response=$(dig in a +short "$DYNB_DYN_DOMAIN")
fi fi
if [[ $dig_response == ";; connection timed out; no servers could be reached" ]]; then
errorMessage "DNS request failed $dig_response"
return 0
fi fi
if [[ ${1} == 6 ]]; then # If the dns resolver lists multiple records in the answer section we filter the first line
# using short option "-n" and not "--lines" because of alpines limited BusyBox head command
dns_ip=$(echo "$dig_response" | head -n 1)
fi
_new_IPv4=$remote_ip
debugMessage "IPv4 from remote IP check server: $_new_IPv4, IPv4 from DNS: $dns_ip"
;;
6)
remote_ip=$(getRemoteIP 6 $_ipv6_checker) remote_ip=$(getRemoteIP 6 $_ipv6_checker)
if [[ $_update_method == domrobot ]]; then if ! is_IPv6_address "$remote_ip"
then
errorMessage "The response from the IP check server is not an IPv6 address: $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") if [[ -n $_DNS_checkServer ]]; then
fi dig_response=$(dig @"${_DNS_checkServer}" in aaaa +short "$DYNB_DYN_DOMAIN")
fi
if [[ ${1} == 4 ]]; then
_new_IPv4=$remote_ip
#echo "New IPv4: $_new_IPv4 old was: $dns_ip"
else else
_new_IPv6=$remote_ip dig_response=$(dig in aaaa +short "$DYNB_DYN_DOMAIN")
#echo "New IPv6: $_new_IPv6 old was: $dns_ip"
fi fi
if [[ $dig_response == ";; connection timed out; no servers could be reached" ]]; then
errorMessage "DNS request failed $dig_response"
return 0
fi
# If the dns server lists multiple records in the answer section we filter the first line
dns_ip=$(echo "$dig_response" | head -n 1)
fi
_new_IPv6=$remote_ip
debugMessage "IPv6 from remote IP check server: $_new_IPv6, IPv4 from DNS: $dns_ip"
;;
*) ;;
esac
if [[ "$remote_ip" == "$dns_ip" ]]; then if [[ "$remote_ip" == "$dns_ip" ]]; then
return 0 return 0
else else
case ${1} in
4) infoMessage "New IPv4: $_new_IPv4 old was: $dns_ip";;
6) infoMessage "New IPv6: $_new_IPv6 old was: $dns_ip";;
esac
return 1 return 1
fi fi
} }
############### ################
## arguments ## ## parameters ##
############### ################
ARGS= function handleParameters() {
if [[ $_has_getopt == "" ]] && [[ $(uname) == Linux ]]; then # shellcheck disable=SC2154
ARGS=$(getopt --options "hvi:,d:,m:,s:,u:,p:,t:" --longoptions "help,version,link,ip-mode:,domain:,update-method:,service-provider:,username:,password:,token:,reset" -- "$@"); if [[ $_arg_version == "on" ]]; then
echo $_version
exit 0
fi fi
eval set -- "$ARGS"; # shellcheck disable=SC2154
unset ARGS if [[ $_arg_link == "on" ]]; then
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" ln --verbose --symbolic "$(realpath "$0")" "$HOME/.local/bin/dynb"
exit 0 exit 0
;; fi
-i | --ip-mode ) # shellcheck disable=SC2154
_ip_mode=$2 if [[ $_arg_reset == "on" ]]; then
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
;;
-t | --token )
_token=$2
shift 2
;;
--reset )
rm --verbose "$_statusFile" rm --verbose "$_statusFile"
exit 0 exit 0
;; fi
--) # shellcheck disable=SC2154
shift if [[ $_arg_debug == "on" ]]; then
break _debug=1
esac fi
done # shellcheck disable=SC2154
if [[ $_arg_update_method != "" ]]; then
DYNB_UPDATE_METHOD=$_arg_update_method
fi
# shellcheck disable=SC2154
if [[ $_arg_ip_mode != "" ]]; then
DYNB_IP_MODE=$_arg_ip_mode
fi
# shellcheck disable=SC2154
if [[ $_arg_domain != "" ]]; then
DYNB_DYN_DOMAIN=$_arg_domain
fi
# shellcheck disable=SC2154
if [[ $_arg_service_provider != "" ]]; then
DYNB_SERVICE_PROVIDER=$_arg_service_provider
fi
# shellcheck disable=SC2154
if [[ $_arg_username != "" ]]; then
DYNB_USERNAME=$_arg_username
fi
# shellcheck disable=SC2154
if [[ $_arg_password != "" ]]; then
DYNB_PASSWORD=$_arg_password
fi
# shellcheck disable=SC2154
if [[ $_arg_token != "" ]]; then
DYNB_TOKEN=$_arg_token
fi
# shellcheck disable=SC2154
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
# shellcheck disable=SC2154
if [[ -n $DYNB_IPv4_CHECK_SITE ]]; then
_ipv4_checker=$DYNB_IPv4_CHECK_SITE
fi
# shellcheck disable=SC2154
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
return 0
} }
################## ##################
@@ -496,34 +625,31 @@ function processParameters() {
################## ##################
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
} }
# maybe replace this with matejak/argbash if [[ failCounter -gt 0 ]]; then
[[ -x $(command -v getopt 2> /dev/null) ]] || { exit 1
_has_getopt=false 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
@@ -531,18 +657,121 @@ 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
}
function ipv6_is_not_working() {
curl --ipv6 --head --silent --max-time 1 "$_internet_connectivity_test_server" > /dev/null
status_code=$?
if [[ $status_code -gt 0 ]]
then return 0
else return 1
fi
}
function ipv4_is_not_working() {
curl --ipv4 --head --silent --max-time 1 "$_internet_connectivity_test_server" > /dev/null
status_code=$?
if [[ $status_code -gt 0 ]]
then return 0
else return 1
fi
}
function check_internet_connection() {
if [[ $_is_IPv4_enabled == true ]]
then
if ipv4_is_not_working
then
_is_IPv4_enabled="false"
errorMessage "Your IPv4 internet connection does not work."
fi
fi
if [[ $_is_IPv6_enabled == true ]]
then
if ipv6_is_not_working
then
_is_IPv6_enabled="false"
errorMessage "Your IPv6 internet connection does not work."
fi
fi
} }
################# #################
## MAIN method ## ## MAIN method ##
################# #################
function dynb() { function dynb() {
## parameters and checks # shellcheck disable=SC1091,SC1090
checkDependencies source "$(dirname "$(realpath "$0")")/dynb-parsing.sh"
# shellcheck source=.env # shellcheck source=.env
if test -f "$_configFile"; then if test -f "$_configFile"; then
@@ -561,68 +790,20 @@ function dynb() {
source "$_statusFile" source "$_statusFile"
fi fi
if [[ $_has_getopt == "" ]] && [[ $(uname) == Linux ]]; then ## parameters and checks
processParameters "$@" handleParameters
fi checkDependencies
check_internet_connection
if [[ $_network_interface != "" ]]; then if loopMode; then
_interface_str="--interface $_network_interface" while :; do
fi doUpdates
sleep $DYNB_INTERVAL
if [[ $_ip_mode == d* ]]; then done
_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"
if dynupdate; then
debugMessage "DynDNS2 update success"
else else
debugMessage "Save new status after dynupdate has failed" doUpdates
setStatus "$_response" "$(date +%s)" $(( _errorCounter += 1 )) "$_dyn_domain" "${_username}${_token}"
fi
else
debugMessage "Skip DynDNS2 update, checkStatus fetched previous error."
fi
fi
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=

114
man/dynb.1 Normal file
View File

@@ -0,0 +1,114 @@
.\" Man page generated from reStructuredText.
.
.TH MAN 1 "2021-04-21" "" ""
.SH NAME
man \- DynB - dynamic DNS update script for bash
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.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] [\-\-interval INTERVAL] [\-\-help]\fP
.SH DESCRIPTION
.sp
IPv4 (A) and IPv6 (AAAA) record updates are supported.
.SH ARGUMENTS
.INDENT 0.0
.TP
.B \-v\fP,\fB \-\-version
outputs the client version.
[Default: off]
.sp
.TP
.B \-l\fP,\fB \-\-link
links to your script at ~/.local/bin/dynb.
[Default: off]
.sp
.TP
.B \-r\fP,\fB \-\-reset
deletes the client blocking status file.
[Default: off]
.sp
.TP
.B \-\-debug
enables debug mode.
[Default: off]
.sp
.TP
.BI \-m \ UPDATE\-METHOD\fR,\fB \ \-\-update\-method \ UPDATE\-METHOD
choose if you want to use DynDNS2 or the DomRobot RPC\-API.
.sp
dyndns | domrobot
.TP
.BI \-i \ IP\-MODE\fR,\fB \ \-\-ip\-mode \ IP\-MODE
updates type A (IPv4) and AAAA (IPv6) records.
.sp
4 | 6 | dual
.TP
.BI \-d \ DOMAIN\fR,\fB \ \-\-domain \ DOMAIN
set the domain you want to update.
.sp
dyndns.example.com
.TP
.BI \-s \ SERVICE\-PROVIDER\fR,\fB \ \-\-service\-provider \ SERVICE\-PROVIDER
set your provider in case you are using DynDNS2.
.sp
deSEC | duckdns | dynv6 | inwx
.TP
.BI \-u \ USERNAME\fR,\fB \ \-\-username \ USERNAME
depends on your selected update method and your provider.
.sp
e.g. user42
.TP
.BI \-p \ PASSWORD\fR,\fB \ \-\-password \ PASSWORD
depends on your selected update method and your provider.
.sp
e.g. SuperSecretPassword
.TP
.BI \-t \ TOKEN\fR,\fB \ \-\-token \ TOKEN
depends on your selected update method and your provider.
.sp
YourProviderGivenToken
.TP
.BI \-\-interval \ INTERVAL
choose the seconds interval to run the script in a loop, minimum is 60.
.sp
.TP
.B \-h\fP,\fB \-\-help
Prints help.
.sp
.UNINDENT
.SH AUTHOR
Eduard Veit
.\" Generated by docutils manpage writer.
.

35
man/man-defs.rst Normal file
View File

@@ -0,0 +1,35 @@
.. |AUTHOR| replace:: Eduard Veit
.. |VERSION| replace:: \
.. |MAN_SECTION| replace:: 1
.. |DESCRIPTION| replace::
IPv4 (A) and IPv6 (AAAA) record updates are supported.
.. |OPTION_VERSION| replace:: \
.. |OPTION_LINK| replace:: \
.. |OPTION_RESET| replace:: \
.. |OPTION_DEBUG| replace:: \
.. |OPTION_UPDATE_METHOD| replace:: dyndns | domrobot
.. |OPTION_IP_MODE| replace:: 4 | 6 | dual
.. |OPTION_DOMAIN| replace:: dyndns.example.com
.. |OPTION_SERVICE_PROVIDER| replace:: deSEC | duckdns | dynv6 | inwx
.. |OPTION_USERNAME| replace:: e.g. user42
.. |OPTION_PASSWORD| replace:: e.g. SuperSecretPassword
.. |OPTION_TOKEN| replace:: YourProviderGivenToken
.. |OPTION_INTERVAL| replace:: \
.. |OPTION_HELP| replace:: \

88
man/man.rst Normal file
View File

@@ -0,0 +1,88 @@
.. include:: man-defs.rst
===
man
===
-----------------------------------------
DynB - dynamic DNS update script for bash
-----------------------------------------
:Author: |AUTHOR|
:Date: 2021-04-21
:Version: |VERSION|
:Manual section: |MAN_SECTION|
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] [--interval INTERVAL] [--help]``
DESCRIPTION
===========
|DESCRIPTION|
ARGUMENTS
=========
-v, --version outputs the client version.
[Default: off]
|OPTION_VERSION|
-l, --link links to your script at ~/.local/bin/dynb.
[Default: off]
|OPTION_LINK|
-r, --reset deletes the client blocking status file.
[Default: off]
|OPTION_RESET|
--debug enables debug mode.
[Default: off]
|OPTION_DEBUG|
-m UPDATE-METHOD, --update-method UPDATE-METHOD choose if you want to use DynDNS2 or the DomRobot RPC-API.
|OPTION_UPDATE_METHOD|
-i IP-MODE, --ip-mode IP-MODE updates type A (IPv4) and AAAA (IPv6) records.
|OPTION_IP_MODE|
-d DOMAIN, --domain DOMAIN set the domain you want to update.
|OPTION_DOMAIN|
-s SERVICE-PROVIDER, --service-provider SERVICE-PROVIDER set your provider in case you are using DynDNS2.
|OPTION_SERVICE_PROVIDER|
-u USERNAME, --username USERNAME depends on your selected update method and your provider.
|OPTION_USERNAME|
-p PASSWORD, --password PASSWORD depends on your selected update method and your provider.
|OPTION_PASSWORD|
-t TOKEN, --token TOKEN depends on your selected update method and your provider.
|OPTION_TOKEN|
--interval INTERVAL choose the seconds interval to run the script in a loop, minimum is 60.
|OPTION_INTERVAL|
-h, --help Prints help.
|OPTION_HELP|