diff --git a/bundles/pppd/files/check_dyndns_update b/bundles/pppd/files/check_dyndns_update deleted file mode 100644 index eaf8dfe..0000000 --- a/bundles/pppd/files/check_dyndns_update +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -[[ -n "$DEBUG" ]] && set -x - -interface="$(ip link show | awk '/ ppp/ {print substr($2, 1, length($2)-1)}')" -addr="$(ip addr show dev "$interface" | awk '/inet / {print $2}')" -resolved="$(dig +short "${domain}" A)" - -if [[ -z "$addr" ]] || [[ -z "$resolved" ]] -then - echo "Address on '$interface' is '$addr' - resolved '$resolved'" - exit 3 -elif [[ "$addr" == "$resolved" ]] -then - echo "Resolved IP for ${domain} matches current ip on $interface" - exit 0 -else - echo "Resolved $resolved for ${domain}, but got $addr on $interface!" - exit 2 -fi diff --git a/bundles/pppd/files/dyndns b/bundles/pppd/files/dyndns index f1760d8..5058b2f 100644 --- a/bundles/pppd/files/dyndns +++ b/bundles/pppd/files/dyndns @@ -1,24 +1,59 @@ #!/usr/bin/env python3 -from sys import argv +import logging +from ipaddress import ip_address +from json import loads +from subprocess import check_output -import requests +from requests import get -INTERFACE = argv[1] -LOCAL_IP = argv[4] UPDATE_URL = '${url}' USERNAME = '${username}' PASSWORD = '${password}' -r = requests.get( - UPDATE_URL.format( - ip=LOCAL_IP, - ), - auth=( - USERNAME, - PASSWORD, - ) -) +# <%text> +logging.basicConfig(level=logging.INFO) +LOG = logging.getLogger('DynDNS') +try: + ips = set() -print('got status {} when updating dns'.format(r.status_code)) + iproute = loads(check_output(['ip', '-json', 'address', 'show', 'scope', 'global'])) + + for iface in iproute: + if not iface['ifname'].startswith('ppp'): + LOG.debug(f'ignoring {iface["ifname"]}') + continue + + LOG.info(f'working on {iface["ifname"]}') + for ip in iface['addr_info']: + try: + addr = ip_address(ip['local']) + + LOG.info(f'{iface["ifname"]} has ip {addr.compressed}') + ips.add(addr.compressed) + except Exception: + continue + + if ips: + LOG.info('got some addresses!') + break + + url = UPDATE_URL.format( + ips=','.join(sorted(ips)) + ) + + LOG.info(url) + + r = get( + url, + auth=( + USERNAME, + PASSWORD, + ), + ) + r.raise_for_status() +except Exception as e: + logging.exception(e) + +# diff --git a/bundles/pppd/files/dyndns_periodic b/bundles/pppd/files/dyndns_periodic index 3aebb47..236c4fc 100644 --- a/bundles/pppd/files/dyndns_periodic +++ b/bundles/pppd/files/dyndns_periodic @@ -1,17 +1,52 @@ -#!/bin/bash +#!/usr/bin/env python3 -[[ -n "$DEBUG" ]] && set -x +import logging +from ipaddress import ip_address +from json import loads +from subprocess import check_output, run -interface="$(ip link show | awk '/ ppp/ {print substr($2, 1, length($2)-1)}')" -addr="$(ip addr show dev "$interface" | awk '/inet / {print $2}')" -resolved="$(dig +short "${domain}" A)" -if [[ -z "$addr" ]] || [[ -z "$resolved" ]] -then - echo "Something is wrong:" - echo "Address on '$interface' is '$addr'" - echo "Resolved DNS is '$resolved'" -elif [[ "$addr" != "$resolved" ]] -then - /etc/ppp/ip-up.d/dyndns "$interface" "doesnt" "matter" "$addr" -fi +DOMAIN = '${domain}' + +# <%text> +logging.basicConfig(level=logging.INFO) +LOG = logging.getLogger('DynDNS checker') +try: + iproute = loads(check_output(['ip', '-json', 'address', 'show', 'scope', 'global'])) + resolved_ipv4 = check_output(['dig', '+short', DOMAIN, 'A']).decode().strip() + resolved_ipv6 = check_output(['dig', '+short', DOMAIN, 'AAAA']).decode().strip() + + LOG.info(f'resolved ipv4 is "{resolved_ipv4}"') + LOG.info(f'resolved ipv6 is "{resolved_ipv6}"') + + needs_changing = False + + for iface in iproute: + if not iface['ifname'].startswith('ppp'): + LOG.debug(f'ignoring {iface["ifname"]}') + continue + + LOG.info(f'working on {iface["ifname"]}') + for ip in iface['addr_info']: + try: + addr = ip_address(ip['local']) + + LOG.info(f'{iface["ifname"]} has ip {addr.compressed}') + + if ( + (addr.version == 4 and addr.compressed != resolved_ipv4) + or (addr.version == 6 and addr.compressed != resolved_ipv6) + ): + needs_changing = True + except Exception: + continue + + if needs_changing: + LOG.warning('addresses have changed, calling update script!') + run(['/etc/ppp/ip-up.d/dyndns']) + else: + LOG.info('everything is fine') +except Exception as e: + logging.exception(e) + +# diff --git a/bundles/pppd/items.py b/bundles/pppd/items.py index 8d94950..cf21a6f 100644 --- a/bundles/pppd/items.py +++ b/bundles/pppd/items.py @@ -110,11 +110,6 @@ if node.metadata.get('pppd/dyndns', {}): 'context': node.metadata.get('pppd/dyndns'), 'mode': '0755', } - files['/usr/local/share/icinga/plugins/check_dyndns_update'] = { - 'content_type': 'mako', - 'context': node.metadata.get('pppd/dyndns'), - 'mode': '0755', - } files['/usr/local/bin/dyndns_periodic'] = { 'content_type': 'mako', 'context': node.metadata.get('pppd/dyndns'), diff --git a/bundles/pppd/metadata.py b/bundles/pppd/metadata.py index 9d8792b..75274a5 100644 --- a/bundles/pppd/metadata.py +++ b/bundles/pppd/metadata.py @@ -39,24 +39,3 @@ def ignore_interface(metadata): }, }, } - - -@metadata_reactor.provides( - 'icinga2_api/pppd/services', -) -def icinga_dyndns(metadata): - if not metadata.get('pppd/dyndns', {}): - return {} - - return { - 'icinga2_api': { - 'pppd': { - 'services': { - 'DYNDNS UPDATE': { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_dyndns_update', - 'vars.notification.mail': True, - }, - }, - }, - }, - } diff --git a/nodes/home/router.py b/nodes/home/router.py index 480c2ed..e6f9125 100644 --- a/nodes/home/router.py +++ b/nodes/home/router.py @@ -1,5 +1,5 @@ nodes['home.router'] = { - 'hostname': 'router-remote', + 'hostname': '172.19.138.1', 'bundles': { 'bird', 'kea-dhcp-server', @@ -118,7 +118,7 @@ nodes['home.router'] = { 'interface': 'enp1s0.7', 'dyndns': { 'domain': 'franzi-home.kunbox.net', - 'url': 'https://ns-mephisto.kunbox.net/nic/update?hostname=franzi-home.kunbox.net&myip={ip}', + 'url': 'https://ns-mephisto.kunbox.net/nic/update?hostname=franzi-home.kunbox.net&myip={ips}', 'username': vault.decrypt('encrypt$gAAAAABfr8DLAJhmUIhdxLq83I8MnRRvkRgDZcO8Brvw1KpvplC3K8ZGj0jIIWD3Us33vIP6t0ybd_mgD8slpRUk78Kqd3BMoQ=='), 'password': vault.decrypt('encrypt$gAAAAABfr8Cq5M1hweeJTQAl0dLhFntdlw-QnkIYUQpY-_ycODVWOpyeAwjwOgWLSdsdXIUvqcoiXPZPV-BE12p5C42NGnj9r7sKYpoGz8xfuGIk6haMa2g='), },