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

55 Commits

Author SHA1 Message Date
05120c25e4 feat: add tzdata to Dockerfile for timezone config
You can now set your timezone with the environment variable
`TZ="Europe/Berlin"`
2022-05-26 16:10:47 +02:00
dcb3d7436b fix: 🐛 curl/libcurl doesn't support dns-server option
the latest alpine we are using for the docker image
does also drops the support for that option like debian/ubuntu/etc
2022-05-26 13:30:23 +02:00
fa60312c0d minor: 📝 update CHANGELOG.md 2022-05-26 10:35:03 +02:00
ba6e91bbd6 dev: 🔃 strip more prefix variants from commits for changelog 2022-05-26 10:27:03 +02:00
756c17d117 fix: abort on all dig errors 2022-04-12 20:23:52 +02:00
3d1b27aaed minor: 🎨 change code style 2022-01-31 20:40:29 +01:00
8721af229d dev: add github action with shellcheck for PRs 2021-11-05 20:58:17 +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
7 changed files with 422 additions and 268 deletions

View File

@@ -82,24 +82,34 @@ ignore_regexps = [
## whenever you are tweaking this variable.
##
section_regexps = [
('New', [
r'^:sparkles\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
('Features', [
r'^[fF]eat\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('Changes', [
r'^:wrench\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
('Added', [
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', [
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', [
r'^:memo\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]*)$',
r'^[dD]oc\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('Other', None ## Match all lines
),
#('Other', None ## Match all lines
# ),
]
@@ -148,7 +158,7 @@ body_process = ReSub(r'((^|\n)[A-Z]\w+(-\w+)*: .*(\n\s+.*)*)+$', r'') | strip
##
## Available constructs are those listed in ``body_process`` doc.
subject_process = (strip |
ReSub(r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n@]*)(@[a-z]+\s+)*$', r'\4') |
ReSub(r'^([cC]hg|[fF]ix|[nN]ew|[dD]oc|[fF]eat|[aA]dd|[cC]hange)\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n@]*)(@[a-z]+\s+)*$', r'\4') |
SetIfEmpty("No commit message.") | ucfirst | final_dot)

16
.github/workflows/shellcheck.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Run shellcheck with reviewdog
on: [pull_request]
jobs:
shellcheck:
name: runner / shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: shellcheck
uses: reviewdog/action-shellcheck@v1.9.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-review
path: "."
pattern: "*.sh"
exclude: "./.git/*"

View File

@@ -15,11 +15,3 @@ repos:
- id: mdformat
additional_dependencies:
- mdformat-gfm # GitHub Flavored Markdown support
- repo: https://codeberg.org/frnmst/md-toc
rev: 8.0.1 # or a specific git tag from md-toc
hooks:
- id: md-toc
args:
- "--in-place"
- "github"
- "--header-levels 6"

View File

@@ -1,97 +1,114 @@
# Changelog
## (unreleased)
## 0.3.0 (2022-05-26)
### Features
* ✨ validate ip address respons from ip check web service. [Eduard Veit]
* ✨ check internet connection for selected ip versions. [Eduard Veit]
* 🎨 colorful info, debug and error messages. [Eduard Veit]
### Fix
* Abort on all dig errors. [Eduard Veit]
### Documentation
* :memo: update README.md. [Eduard Veit]
* 📝 add labels to Dockerfile. [Eduard Veit]
### Other
* :recycle: normalizing pre-commit configuration to a top-level map. [Eduard Veit]
## 0.2.0 (2021-09-24)
* :recycle: refactorings. [Eduard Veit]
### Features
* Feature: :sparkles: add pre-commit git hook for shellcheck. [Eduard Veit]
* ✨ enable parameter extensions for `docker run --interactive` [Eduard Veit]
* Refactor: :recycle: remove unused help message. [Eduard Veit]
### Changed
* Handle dns server selection. [Eduard Veit]
### Documentation
* 📝 update CHANGELOG.md. [Eduard Veit]
* 📝 document docker parameters. [Eduard Veit]
* 📝 change default dns server setting. [Eduard Veit]
* 📝 update CHANGELOG. [Eduard Veit]
* 📝 update README.md. [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]
* 📝 document environment variables. [Eduard Veit]
## 0.1.1 (2021-04-23)
### Fix
* :bug: fix loop and error handling in case of connection issues. [Eduard Veit]
* 🐛 fix loop and error handling in case of connection issues. [Eduard Veit]
## 0.1.0 (2021-04-22)
### New
### Features
* :sparkles: add Dockerfile. [Eduard Veit]
* add Dockerfile. [Eduard Veit]
* :sparkles: add loop mode. [Eduard Veit]
* add loop mode. [Eduard Veit]
* :sparkles: add support for Duck DNS as DynDNS2 provider. [Eduard Veit]
* add support for Duck DNS as DynDNS2 provider. [Eduard Veit]
* :sparkles: add support for deSEC as DynDNS2 provider. [Eduard Veit]
* add support for deSEC as DynDNS2 provider. [Eduard Veit]
* :sparkles: add completion. [Eduard Veit]
* add completion. [Eduard Veit]
:sparkles: add man page
add man page
* :sparkles: replace getopt with argbash. [Eduard Veit]
* 🔃 replace getopt with argbash. [Eduard Veit]
* :sparkles: add interpretaton of status codes and act accordingly. [Eduard Veit]
* add interpretaton of status codes and act accordingly. [Eduard Veit]
* :sparkles: make network interface configurable. [Eduard Veit]
* make network interface configurable. [Eduard Veit]
* :sparkles: add DynDNS2 support for dynv6.com. [Eduard Veit]
* add DynDNS2 support for dynv6.com. [Eduard Veit]
* :sparkles: add .gitchangelog.rc. [Eduard Veit]
### Added
* :sparkles: add dynb.sh. [Eduard Veit]
* 📝 README.md. [Eduard Veit]
* ✨ dynb.sh. [Eduard Veit]
### Changed
* 🔃 rename environment variables. [Eduard Veit]
### Fix
* :bug: fix sourcing of config file. [Eduard Veit]
* 🐛 fix error handling. [Eduard Veit]
:recycle: do some shellcheck fixes
* 🐛 fix sourcing of config file. [Eduard Veit]
♻️ do some shellcheck fixes
### Documentation
* :memo: document example of an docker-compose.yml file. [Eduard Veit]
* 📝 document example of an docker-compose.yml file. [Eduard Veit]
* :memo: document loop mode and dig as requirement. [Eduard Veit]
* 📝 document `loop mode` and mention `dig` as requirement. [Eduard Veit]
* :memo: update example of .env in README.md. [Eduard Veit]
* 📝 update example of .env in README.md. [Eduard Veit]
* :memo: add CHANGELOG.md. [Eduard Veit]
* 📝 CHANGELOG.md. [Eduard Veit]
* :memo: add example.env. [Eduard Veit]
* :memo: write README.md. [Eduard Veit]
### 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]
* 📝 add example.env. [Eduard Veit]

View File

@@ -1,5 +1,21 @@
FROM alpine:latest
RUN apk update && apk add bash curl jq bind-tools
RUN \
apk update \
&& \
apk add \
bash \
curl \
jq \
bind-tools \
tzdata
WORKDIR /usr/src/app
COPY . .
CMD /bin/bash /usr/src/app/dynb.sh
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"

View File

@@ -14,7 +14,10 @@ IPv4 (A) and IPv6 (AAAA) record updates are supported.
- [⚙ Configuration](#-configuration)
- [🏃 Run](#-run)
- [⏰ Cron](#-cron)
- [loop mode](#loop-mode)
- [crontab](#crontab)
- [🐟 docker](#-docker)
- [environment variables](#environment-variables)
<!-- /TOC -->
@@ -132,11 +135,17 @@ then enter :point_down: to run dynb every five minutes.
*/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.
## 🐟 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.
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'
@@ -146,17 +155,15 @@ services:
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_SERVICE_PROVIDER=desec
- DYNB_UPDATE_METHOD=dyndns
- DYNB_IP_MODE=64
- DYNB_USERNAME=User42
- DYNB_PASSWORD=SuperSecretPassword
- DYNB_INTERVAL=60
- TZ=Europe/Berlin
```
## environment variables

502
dynb.sh
View File

@@ -51,6 +51,7 @@ _network_interface=
######################################################
## You don't need to change the following variables ##
_INWX_JSON_API_URL=https://api.domrobot.com/jsonrpc/
_internet_connectivity_test_server=https://www.google.de
_new_IPv4=
_new_IPv6=
_dns_records=
@@ -65,7 +66,7 @@ _response=
_statusHostname=
_statusUsername=
_statusPassword=
_version=0.1.2
_version=0.3.2
_userAgent="DynB/$_version github.com/EV21/dynb"
_configFile=$HOME/.local/share/dynb/.env
_statusFile=/tmp/dynb.status
@@ -73,41 +74,77 @@ _debug=0
_minimum_looptime=60
_loopMode=0
function loopMode() {
if [[ $_loopMode -eq 1 ]]; then
return 0
else
return 1
# Ansi color code variables
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"
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]))$"
function is_IPv4_address
{
local ip=$1
if [[ $ip =~ $REGEX_IPv4 ]]
then return 0
else return 1
fi
}
function debugMode() {
if [[ $_debug -eq 1 ]]; then
return 0
else
return 1
function is_IPv6_address
{
local ip=$1
if [[ $ip =~ $REGEX_IPv6 ]]
then return 0
else return 1
fi
}
function infoMessage() {
echo "$(logtime) INFO: $*"
}
function debugMessage() {
if debugMode; then
echo "$(logtime) DEBUG: $*"
function loopMode
{
if [[ $_loopMode -eq 1 ]]
then return 0
else return 1
fi
}
function errorMessage() { printf "$(logtime) ERROR: %s\n" "$*" >&2; }
function debugMode
{
if [[ $_debug -eq 1 ]]
then return 0
else return 1
fi
}
function logtime() {
function infoMessage
{
echo -e "${green_color}$(logtime) INFO: $*${reset_color_modification}"
}
function debugMessage
{
if debugMode
then echo -e "${yellow_color}$(logtime) DEBUG: ${*}${reset_color_modification}"
fi
}
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
function getMainDomain() {
function getMainDomain
{
request=$(
echo "{}" |
jq '(.method="nameserver.list")' |
@@ -126,7 +163,8 @@ function getMainDomain() {
_main_domain=$(echo "$_response" | jq --raw-output '.domain')
}
function fetchDNSRecords() {
function fetchDNSRecords
{
request=$(
echo "{}" |
jq '(.method="'nameserver.info'")' |
@@ -150,47 +188,54 @@ function fetchDNSRecords() {
# requires parameter A or AAAA
# result to stdout
function getRecordID() {
echo "$_dns_records" | jq "select(.type == \"${1}\") | .id"
function getRecordID
{
echo "$_dns_records" |
jq "select(.type == \"${1}\") | .id"
}
# requires parameter A or AAAA
# result to stdout
function getDNSIP() {
echo "$_dns_records" | jq --raw-output "select(.type == \"${1}\") | .content"
echo "$_dns_records" |
jq --raw-output "select(.type == \"${1}\") | .content"
}
# requires parameter
# 1. param: 4 or 6 for ip version
# 2. param: IP check server address
# result to stdout
function getRemoteIP() {
if [[ -n $_DNS_checkServer ]]; then
function getRemoteIP
{
local ip_version=$1
local ip_check_server=$2
curl --silent "$_interface_str" --user-agent "$_userAgent" \
--ipv"${1}" --dns-servers "$_DNS_checkServer" --location "${2}"
else
curl --silent "$_interface_str" --user-agent "$_userAgent" \
--ipv"${1}" --location "${2}"
fi
--ipv"${ip_version}" --location "${ip_check_server}"
local curls_status_code=$?
# shellcheck disable=2181
if [[ $? -gt 0 ]]; then
errorMessage "IPCheck (getRemoteIP ${1}) request failed"
if [[ $curls_status_code -gt 0 ]]; then
errorMessage "IPCheck (getRemoteIP $ip_version) request failed"
exit 1
fi
}
# requires parameter
# 1. param: 4 or 6 as ip version
function updateRecord() {
if [[ ${1} == 4 ]]; then
function updateRecord
{
local ip_version=$1
if [[ ${ip_version} == 4 ]]
then
ID=$(getRecordID A)
IP=$_new_IPv4
fi
if [[ ${1} == 6 ]]; then
if [[ ${ip_version} == 6 ]]
then
ID=$(getRecordID AAAA)
IP=$_new_IPv6
fi
if [[ $IP != "" ]]; then
if [[ $IP != "" ]]
then
request=$(
echo "{}" |
jq '(.method="nameserver.updateRecord")' |
@@ -209,12 +254,13 @@ function updateRecord() {
--request POST $_INWX_JSON_API_URL \
--data "$request"
)
echo -e "$(echo "$_response" | jq --raw-output '.msg')\n Domain: $DYNB_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
}
# using DynDNS2 protocol
function dynupdate() {
function dynupdate
{
# default parameter values
myip_str=myip
myipv6_str=myipv6
@@ -350,12 +396,14 @@ function dynupdate() {
esac
}
function setStatus() {
function setStatus
{
echo "_status=$1; _eventTime=$2; _errorCounter=$3; _statusHostname=$4; _statusUsername=$5; _statusPassword=$6" >/tmp/dynb.status
}
# handle errors from past update requests
function checkStatus() {
function checkStatus
{
case $_status in
nochg*)
if [[ _errorCounter -gt 1 ]]; then
@@ -368,8 +416,7 @@ function checkStatus() {
if [[ "$_statusHostname" == "$DYNB_DYN_DOMAIN" && ("$_statusUsername" == "$DYNB_USERNAME" || $_statusUsername == "$DYNB_TOKEN") ]]; then
errorMessage "Hostname supplied does not exist under specified account, enter new login credentials before performing an additional request."
return 1
else
rm "$_statusFile"
else rm "$_statusFile"
fi
return 0
;;
@@ -377,8 +424,7 @@ function checkStatus() {
if [[ "$_statusUsername" == "$DYNB_USERNAME" && "$_statusPassword" == "$DYNB_PASSWORD" ]]; then
errorMessage "Invalid username password combination."
return 1
else
rm "$_statusFile"
else rm "$_statusFile"
fi
return 0
;;
@@ -402,20 +448,20 @@ function checkStatus() {
;;
911 | 5*)
delta=$(($(date +%s) - _eventTime))
if [[ $delta -lt 1800 ]]; then
if [[ $delta -lt 1800 ]]
then
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
else
rm "$_statusFile"
else rm "$_statusFile"
fi
return 0
;;
*)
if [[ _errorCounter -gt 1 ]]; then
if [[ _errorCounter -gt 1 ]]
then
errorMessage "An unknown response code has repeatedly been received. $_response"
return 1
else
return 0
else return 0
fi
;;
esac
@@ -423,178 +469,192 @@ function checkStatus() {
# requires parameter
# 1. param: 4 or 6 for IP version
function ipHasChanged() {
case ${1} in
function ipHasChanged
{
local ip_version=$1
case ${ip_version} in
4)
remote_ip=$(getRemoteIP 4 $_ipv4_checker)
if [[ $DYNB_UPDATE_METHOD == domrobot ]]; then
dns_ip=$(getDNSIP A)
else
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")
if ! is_IPv4_address "$remote_ip"
then
errorMessage "The response from the IP check server is not an IPv4 address: $remote_ip"
return 1
fi
if [[ $dig_response == ";; connection timed out; no servers could be reached" ]]; then
if [[ $DYNB_UPDATE_METHOD == domrobot ]]
then dns_ip=$(getDNSIP A)
else
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
if [[ $dig_response == ";; connection timed out; no servers could be reached" ]]
then
errorMessage "DNS request failed $dig_response"
return 0
return 1
fi
dns_ip=$dig_response
# 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 "New IPv4: $_new_IPv4 old was: $dns_ip"
debugMessage "IPv4 from remote IP check server: $_new_IPv4, IPv4 from DNS: $dns_ip"
;;
6)
remote_ip=$(getRemoteIP 6 $_ipv6_checker)
if [[ $DYNB_UPDATE_METHOD == domrobot ]]; then
dns_ip=$(getDNSIP AAAA)
else
if [[ -n $_DNS_checkServer ]]; then
dig_response=$(dig @"${_DNS_checkServer}" in aaaa +short "$DYNB_DYN_DOMAIN")
else
dig_response=$(dig in aaaa +short "$DYNB_DYN_DOMAIN")
fi
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
_new_IPv6=$remote_ip
debugMessage "New IPv6: $_new_IPv6 old was: $dns_ip"
;;
*) ;;
esac
if [[ "$remote_ip" == "$dns_ip" ]]; then
return 0
else
if ! is_IPv6_address "$remote_ip"
then
errorMessage "The response from the IP check server is not an IPv6 address: $remote_ip"
return 1
fi
if [[ $DYNB_UPDATE_METHOD == domrobot ]]
then dns_ip=$(getDNSIP AAAA)
else
if [[ -n $_DNS_checkServer ]]
then dig_response=$(dig @"${_DNS_checkServer}" in aaaa +short "$DYNB_DYN_DOMAIN")
else dig_response=$(dig in aaaa +short "$DYNB_DYN_DOMAIN")
fi
exitcode=$?
if [[ $exitcode -gt 0 ]]
then
errorMessage "DNS request failed with exit code: $exitcode $dig_response"
return 1
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 return 1
else
case ${ip_version} in
4) infoMessage "New IPv4: $_new_IPv4 old was: $dns_ip";;
6) infoMessage "New IPv6: $_new_IPv6 old was: $dns_ip";;
esac
return 0
fi
}
################
## parameters ##
################
function handleParameters() {
function handleParameters
{
# shellcheck disable=SC2154
if [[ $_arg_version == "on" ]]; then
echo $_version
exit 0
if [[ $_arg_version == "on" ]]
then echo $_version; exit 0
fi
# shellcheck disable=SC2154
if [[ $_arg_link == "on" ]]; then
ln --verbose --symbolic "$(realpath "$0")" "$HOME/.local/bin/dynb"
exit 0
if [[ $_arg_link == "on" ]]
then ln --verbose --symbolic "$(realpath "$0")" "$HOME/.local/bin/dynb"; exit 0
fi
# shellcheck disable=SC2154
if [[ $_arg_reset == "on" ]]; then
rm --verbose "$_statusFile"
exit 0
if [[ $_arg_reset == "on" ]] && test -f "$_statusFile"
then rm --verbose "$_statusFile"; exit 0
fi
# shellcheck disable=SC2154
if [[ $_arg_debug == "on" ]]; then
_debug=1
if [[ $_arg_debug == "on" ]]
then _debug=1
fi
# shellcheck disable=SC2154
if [[ $_arg_update_method != "" ]]; then
DYNB_UPDATE_METHOD=$_arg_update_method
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
if [[ $_arg_ip_mode != "" ]]
then DYNB_IP_MODE=$_arg_ip_mode
fi
# shellcheck disable=SC2154
if [[ $_arg_domain != "" ]]; then
DYNB_DYN_DOMAIN=$_arg_domain
if [[ $_arg_domain != "" ]]
then DYNB_DYN_DOMAIN=$_arg_domain
fi
# shellcheck disable=SC2154
if [[ $_arg_service_provider != "" ]]; then
DYNB_SERVICE_PROVIDER=$_arg_service_provider
if [[ $_arg_service_provider != "" ]]
then DYNB_SERVICE_PROVIDER=$_arg_service_provider
fi
# shellcheck disable=SC2154
if [[ $_arg_username != "" ]]; then
DYNB_USERNAME=$_arg_username
if [[ $_arg_username != "" ]]
then DYNB_USERNAME=$_arg_username
fi
# shellcheck disable=SC2154
if [[ $_arg_password != "" ]]; then
DYNB_PASSWORD=$_arg_password
if [[ $_arg_password != "" ]]
then DYNB_PASSWORD=$_arg_password
fi
# shellcheck disable=SC2154
if [[ $_arg_token != "" ]]; then
DYNB_TOKEN=$_arg_token
if [[ $_arg_token != "" ]]
then DYNB_TOKEN=$_arg_token
fi
# shellcheck disable=SC2154
if [[ $_arg_interval != "" ]]; then
DYNB_INTERVAL=$_arg_interval
if [[ $_arg_interval != "" ]]
then DYNB_INTERVAL=$_arg_interval
fi
if [[ -z $DYNB_INTERVAL ]]; then
_loopMode=0
elif [[ $DYNB_INTERVAL -lt _minimum_looptime ]]; then
if [[ -z $DYNB_INTERVAL ]]
then _loopMode=0
elif [[ $DYNB_INTERVAL -lt _minimum_looptime ]]
then
DYNB_INTERVAL=$_minimum_looptime
_loopMode=1
else
_loopMode=1
else _loopMode=1
fi
if [[ $_network_interface != "" ]]; then
_interface_str="--interface $_network_interface"
if [[ $_network_interface != "" ]]
then _interface_str="--interface $_network_interface"
fi
if [[ $DYNB_IP_MODE == d* ]]; then
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
if [[ $DYNB_IP_MODE == *4* ]]
then _is_IPv4_enabled=true
fi
if [[ $DYNB_IP_MODE == *6* ]]; then
_is_IPv6_enabled=true
if [[ $DYNB_IP_MODE == *6* ]]
then _is_IPv6_enabled=true
fi
if [[ $DYNB_DEBUG == true ]]; then
_debug=1
if [[ $DYNB_DEBUG == true ]]
then _debug=1
fi
# shellcheck disable=SC2154
if [[ -n $DYNB_IPv4_CHECK_SITE ]]; then
_ipv4_checker=$DYNB_IPv4_CHECK_SITE
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
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
if [[ -n $DYNB_DNS_CHECK_SERVER ]]
then _DNS_checkServer=$DYNB_DNS_CHECK_SERVER
fi
return 0
}
##################
## dependencies ##
##################
function checkDependencies() {
function checkDependencies
{
failCounter=0
for i in curl dig; do
if ! command -v $i >/dev/null 2>&1; then
if ! command -v $i >/dev/null 2>&1
then
errorMessage "could not find \"$i\", DynB depends on it. "
((failCounter++))
fi
done
[[ -x $(command -v jq 2>/dev/null) ]] || {
if [[ $DYNB_UPDATE_METHOD != dyndns* ]]; then
if [[ $DYNB_UPDATE_METHOD != dyndns* ]]
then
echo "This script depends on jq and it is not available." >&2
((failCounter++))
fi
}
if [[ failCounter -gt 0 ]]; then
exit 1
if [[ failCounter -gt 0 ]]
then exit 1
fi
}
function doUnsets() {
function doUnsets
{
unset _network_interface
unset _DNS_checkServer
unset _dns_records
@@ -622,83 +682,121 @@ function doUnsets() {
unset DYNB_DEBUG
}
function doDomrobotUpdates() {
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"
if [[ $_is_IPv4_enabled == true ]]
then
if ipHasChanged 4
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"
if [[ $_is_IPv6_enabled == true ]]
then
if ipHasChanged 6
then updateRecord 6
else debugMessage "Skip IPv6 record update, it is already up to date"
fi
fi
}
function doDynDNS2Updates() {
function doDynDNS2Updates
{
changed=0
if [[ $_is_IPv4_enabled == true ]]; then
ipHasChanged 4
((changed += $?))
if [[ $_is_IPv4_enabled == true ]] && ipHasChanged 4
then ((changed += 1))
fi
if [[ $_is_IPv6_enabled == true ]]; then
ipHasChanged 6
((changed += $?))
if [[ $_is_IPv6_enabled == true ]] && ipHasChanged 6
then ((changed += 1))
fi
if [[ $changed -gt 0 ]]; then
if checkStatus; then
if [[ $changed -gt 0 ]]
then
if checkStatus
then
debugMessage "checkStatus has no errors, try update"
if dynupdate; then
debugMessage "DynDNS2 update success"
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."
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"
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
function doUpdates
{
if [[ $DYNB_UPDATE_METHOD == "domrobot" ]]
then doDomrobotUpdates
elif [[ $DYNB_UPDATE_METHOD == "dyndns" ]]
then doDynDNS2Updates
fi
}
#################
## MAIN method ##
#################
function dynb() {
function ipv6_is_not_working
{
curl --ipv6 --head --silent --max-time 5 $_internet_connectivity_test_server > /dev/null
status_code=$?
if test $status_code -gt 0
then return 0
else return 1
fi
}
function ipv4_is_not_working
{
curl --ipv4 --head --silent --max-time 5 $_internet_connectivity_test_server > /dev/null
status_code=$?
if test $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
}
function main
{
# shellcheck disable=SC1091,SC1090
source "$(dirname "$(realpath "$0")")/dynb-parsing.sh"
# shellcheck source=.env
if test -f "$_configFile"; then
if test -f "$_configFile"
then
# shellcheck disable=SC1091
source "$_configFile"
else
alternativeConfig="$(dirname "$(realpath "$0")")/.env"
if test -f "$alternativeConfig"; then
if test -f "$alternativeConfig"
then
# shellcheck disable=SC1091
source "$alternativeConfig"
fi
fi
if test -f "$_statusFile"; then
if test -f "$_statusFile"
then
debugMessage "read previous status file"
# shellcheck disable=SC1090
source "$_statusFile"
@@ -707,24 +805,22 @@ function dynb() {
## parameters and checks
handleParameters
checkDependencies
check_internet_connection
if loopMode; then
while :; do
if loopMode
then
while :
do
doUpdates
debugMessage "wait $DYNB_INTERVAL seconds until next check"
sleep $DYNB_INTERVAL
done
else
doUpdates
else doUpdates
fi
doUnsets
return 0
}
######################
## END MAIN section ##
######################
dynb "${@}"
main "${@}"
exit $?
# ] <-- needed because of Argbash