mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-02-25 08:43:36 +00:00
dynamicdns: Replace ez-ipupdate
Add Python implementation of GnuDIP client. Tests: - In testing container, configure Dynamic DNS with a (previously offlined) freedombox.rocks account. FreedomBox interface shows that the address has been updated. GnuDIP server also shows the correct IP address. - Running "gnudip update" and "dynamicdns update" actions produce the expected results.
This commit is contained in:
parent
bfbb5ac62b
commit
84a7323b42
@ -31,7 +31,7 @@ UPDATEMINUTES=5
|
||||
# a "blind" update
|
||||
UPDATEMINUTESUNKNOWN=3600
|
||||
TOOLNAME=ez-ipupdate
|
||||
UPDATE_TOOL=$(which ${TOOLNAME})
|
||||
GNUDIP_ACTION=/usr/share/plinth/actions/gnudip
|
||||
DISABLED_STRING='disabled'
|
||||
ENABLED_STRING='enabled'
|
||||
|
||||
@ -157,13 +157,6 @@ doWriteCFG()
|
||||
else
|
||||
# we are directly connected
|
||||
echo "NAT no" >> ${HELPERCFG}
|
||||
# if this file is added ez-ipupdate will take ip form this interface
|
||||
{
|
||||
echo "interface=${default_interface}"
|
||||
# if this line is added to config file, ez-ipupdate will be launched on startup via init.d
|
||||
echo "daemon"
|
||||
echo "execute=${0} success"
|
||||
} >> ${out_file}
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@ -296,7 +289,7 @@ doGetWANIP()
|
||||
fi
|
||||
}
|
||||
|
||||
# actualy do the update (using wget or ez-ipupdate or even both)
|
||||
# actualy do the update (using wget or gnudip action or even both)
|
||||
# this function is called via cronjob
|
||||
doUpdate()
|
||||
{
|
||||
@ -309,7 +302,11 @@ doUpdate()
|
||||
return
|
||||
fi
|
||||
if [ ! -z "${server}" ];then
|
||||
start-stop-daemon -S -x "${UPDATE_TOOL}" -m -p "${PIDFILE}" -- -c "${cfgfile}"
|
||||
if "${GNUDIP_ACTION}" update; then
|
||||
${0} success ${wanip}
|
||||
else
|
||||
${0} failed
|
||||
fi
|
||||
fi
|
||||
if [ ! -z "${updateurl}" ];then
|
||||
doReplaceVars
|
||||
@ -351,24 +348,14 @@ case ${cmd} in
|
||||
;;
|
||||
start)
|
||||
doGetWANIP
|
||||
if [ "$(grep ^NAT ${HELPERCFG} | awk '{print $2}')" = "no" ];then
|
||||
#if we are not behind a NAT device and we use gnudip, start the daemon tool
|
||||
gnudipServer=$(grep ^server= ${cfgfile} 2> /dev/null | cut -d = -f 2- |grep -v ^\'\')
|
||||
if [ ! -f ${CFG} -a ! -z "${gnudipServer}" ];then
|
||||
mv ${CFG_disabled} ${CFG}
|
||||
/etc/init.d/${TOOLNAME} start
|
||||
fi
|
||||
# if we are not behind a NAT device and we use update-URL, add a cronjob
|
||||
# (daemon tool does not support update-URL feature)
|
||||
if [ ! -z "$(grep ^POSTURL $HELPERCFG | awk '{print $2}')" ];then
|
||||
echo "*/${UPDATEMINUTES} * * * * root ${0} update" > ${CRONJOB}
|
||||
$0 update
|
||||
fi
|
||||
else
|
||||
# if we are behind a NAT device, add a cronjob (daemon tool cannot monitor WAN IP changes)
|
||||
echo "*/${UPDATEMINUTES} * * * * root ${0} update" > $CRONJOB
|
||||
$0 update
|
||||
# if we use gnudip, enable gnudip.
|
||||
gnudipServer=$(grep ^server= ${cfgfile} 2> /dev/null | cut -d = -f 2- |grep -v ^\'\')
|
||||
if [ ! -f ${CFG} -a ! -z "${gnudipServer}" ];then
|
||||
mv ${CFG_disabled} ${CFG}
|
||||
fi
|
||||
# add a cronjob
|
||||
echo "*/${UPDATEMINUTES} * * * * root ${0} update" > $CRONJOB
|
||||
$0 update
|
||||
;;
|
||||
get-nat)
|
||||
NAT=$(grep ^NAT $HELPERCFG 2> /dev/null | awk '{print $2}')
|
||||
|
||||
77
actions/gnudip
Executable file
77
actions/gnudip
Executable file
@ -0,0 +1,77 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- mode: python -*-
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""
|
||||
GnuDIP client for updating Dynamic DNS records.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
from plinth.modules.dynamicdns import gnudip
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CONFIG_FILE = pathlib.Path('/etc/ez-ipupdate/ez-ipupdate.conf')
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
"""Return parsed command line arguments as dictionary."""
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
|
||||
|
||||
subparsers.add_parser('update', help='Update Dynamic DNS record')
|
||||
|
||||
subparsers.required = True
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def subcommand_update(_):
|
||||
"""Update Dynamic DNS record.
|
||||
|
||||
Uses settings from ez-ipupdate config file.
|
||||
"""
|
||||
if not CONFIG_FILE.is_file():
|
||||
logger.info('GnuDIP configuration not found.')
|
||||
return
|
||||
|
||||
config = {}
|
||||
with CONFIG_FILE.open() as cf:
|
||||
lines = cf.readlines()
|
||||
for line in lines:
|
||||
if '=' in line:
|
||||
items = line.split('=')
|
||||
key = items[0].strip()
|
||||
value = items[1].strip()
|
||||
else:
|
||||
key = line.strip()
|
||||
value = True
|
||||
|
||||
config[key] = value
|
||||
|
||||
if not all(['host' in config, 'server' in config, 'user' in config]):
|
||||
logger.warn('GnuDIP configuration is not complete.')
|
||||
return
|
||||
|
||||
username, password = config['user'].split(':')
|
||||
result, new_ip = gnudip.update(config['server'], config['host'], username,
|
||||
password)
|
||||
if result == 0 and new_ip:
|
||||
print(new_ip)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse arguments and perform all duties."""
|
||||
arguments = parse_arguments()
|
||||
|
||||
subcommand = arguments.subcommand.replace('-', '_')
|
||||
subcommand_method = globals()['subcommand_' + subcommand]
|
||||
sys.exit(subcommand_method(arguments))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@ -11,7 +11,6 @@ from plinth import cfg, menu
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.names.components import DomainType
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.package import Packages
|
||||
from plinth.signals import domain_added
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
@ -58,9 +57,6 @@ class DynamicDNSApp(app_module.App):
|
||||
'dynamicdns:index', parent_url_name='system')
|
||||
self.add(menu_item)
|
||||
|
||||
packages = Packages('packages-dynamicdns', ['ez-ipupdate'])
|
||||
self.add(packages)
|
||||
|
||||
domain_type = DomainType('domain-type-dynamic',
|
||||
_('Dynamic Domain Name'), 'dynamicdns:index',
|
||||
can_have_certificate=True)
|
||||
|
||||
39
plinth/modules/dynamicdns/gnudip.py
Normal file
39
plinth/modules/dynamicdns/gnudip.py
Normal file
@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""
|
||||
GnuDIP client for updating Dynamic DNS records.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import socket
|
||||
|
||||
BUF_SIZE = 50
|
||||
GNUDIP_PORT = 3495
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def update(server, domain, username, password):
|
||||
"""Update Dynamic DNS record."""
|
||||
domain = domain.removeprefix(username + '.')
|
||||
password_digest = hashlib.md5(password.encode()).hexdigest()
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
logger.debug('Connecting to %s:%d', server, GNUDIP_PORT)
|
||||
s.connect((server, GNUDIP_PORT))
|
||||
salt = s.recv(BUF_SIZE).decode().strip()
|
||||
salted_digest = password_digest + '.' + salt
|
||||
final_digest = hashlib.md5(salted_digest.encode()).hexdigest()
|
||||
|
||||
update_request = username + ':' + final_digest + ':' + domain + ':2\n'
|
||||
s.sendall(update_request.encode())
|
||||
|
||||
response = s.recv(BUF_SIZE).decode().strip()
|
||||
result, new_ip = response.split(':')
|
||||
result = int(result)
|
||||
if result == 0:
|
||||
logger.info('GnuDIP update success: %s', new_ip)
|
||||
else:
|
||||
logger.warn('GnuDIP update error: %s', response)
|
||||
|
||||
return result, new_ip
|
||||
Loading…
x
Reference in New Issue
Block a user