mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-20 10:34:30 +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
|
# a "blind" update
|
||||||
UPDATEMINUTESUNKNOWN=3600
|
UPDATEMINUTESUNKNOWN=3600
|
||||||
TOOLNAME=ez-ipupdate
|
TOOLNAME=ez-ipupdate
|
||||||
UPDATE_TOOL=$(which ${TOOLNAME})
|
GNUDIP_ACTION=/usr/share/plinth/actions/gnudip
|
||||||
DISABLED_STRING='disabled'
|
DISABLED_STRING='disabled'
|
||||||
ENABLED_STRING='enabled'
|
ENABLED_STRING='enabled'
|
||||||
|
|
||||||
@ -157,13 +157,6 @@ doWriteCFG()
|
|||||||
else
|
else
|
||||||
# we are directly connected
|
# we are directly connected
|
||||||
echo "NAT no" >> ${HELPERCFG}
|
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
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -296,7 +289,7 @@ doGetWANIP()
|
|||||||
fi
|
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
|
# this function is called via cronjob
|
||||||
doUpdate()
|
doUpdate()
|
||||||
{
|
{
|
||||||
@ -309,7 +302,11 @@ doUpdate()
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if [ ! -z "${server}" ];then
|
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
|
fi
|
||||||
if [ ! -z "${updateurl}" ];then
|
if [ ! -z "${updateurl}" ];then
|
||||||
doReplaceVars
|
doReplaceVars
|
||||||
@ -351,24 +348,14 @@ case ${cmd} in
|
|||||||
;;
|
;;
|
||||||
start)
|
start)
|
||||||
doGetWANIP
|
doGetWANIP
|
||||||
if [ "$(grep ^NAT ${HELPERCFG} | awk '{print $2}')" = "no" ];then
|
# if we use gnudip, enable gnudip.
|
||||||
#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 ^\'\')
|
||||||
gnudipServer=$(grep ^server= ${cfgfile} 2> /dev/null | cut -d = -f 2- |grep -v ^\'\')
|
if [ ! -f ${CFG} -a ! -z "${gnudipServer}" ];then
|
||||||
if [ ! -f ${CFG} -a ! -z "${gnudipServer}" ];then
|
mv ${CFG_disabled} ${CFG}
|
||||||
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
|
|
||||||
fi
|
fi
|
||||||
|
# add a cronjob
|
||||||
|
echo "*/${UPDATEMINUTES} * * * * root ${0} update" > $CRONJOB
|
||||||
|
$0 update
|
||||||
;;
|
;;
|
||||||
get-nat)
|
get-nat)
|
||||||
NAT=$(grep ^NAT $HELPERCFG 2> /dev/null | awk '{print $2}')
|
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.backups.components import BackupRestore
|
||||||
from plinth.modules.names.components import DomainType
|
from plinth.modules.names.components import DomainType
|
||||||
from plinth.modules.users.components import UsersAndGroups
|
from plinth.modules.users.components import UsersAndGroups
|
||||||
from plinth.package import Packages
|
|
||||||
from plinth.signals import domain_added
|
from plinth.signals import domain_added
|
||||||
from plinth.utils import format_lazy
|
from plinth.utils import format_lazy
|
||||||
|
|
||||||
@ -58,9 +57,6 @@ class DynamicDNSApp(app_module.App):
|
|||||||
'dynamicdns:index', parent_url_name='system')
|
'dynamicdns:index', parent_url_name='system')
|
||||||
self.add(menu_item)
|
self.add(menu_item)
|
||||||
|
|
||||||
packages = Packages('packages-dynamicdns', ['ez-ipupdate'])
|
|
||||||
self.add(packages)
|
|
||||||
|
|
||||||
domain_type = DomainType('domain-type-dynamic',
|
domain_type = DomainType('domain-type-dynamic',
|
||||||
_('Dynamic Domain Name'), 'dynamicdns:index',
|
_('Dynamic Domain Name'), 'dynamicdns:index',
|
||||||
can_have_certificate=True)
|
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