mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
Merge remote-tracking branch 'steglicd/dynamicdns'
This commit is contained in:
commit
af94194b7a
443
actions/dynamicdns
Executable file
443
actions/dynamicdns
Executable file
@ -0,0 +1,443 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# #
|
||||
# This file is part of Plinth. #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Affero General Public License as #
|
||||
# published by the Free Software Foundation, either version 3 of the #
|
||||
# License, or (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU Affero General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Affero General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# #
|
||||
# This script is a wrapper around ez-ipupdate and/or wget #
|
||||
# to update a Dynamic DNS account. The script is used as an #
|
||||
# interface between plinth and ez-ipupdate #
|
||||
# the script will store configuration, return configuration #
|
||||
# to plinth UI and do a dynamic DNS update. The script will #
|
||||
# also determe if we are behind a NAT device, if we can use #
|
||||
# ez-ipupdate tool or if we need to do some wget magic #
|
||||
# #
|
||||
# Todo: IPv6 #
|
||||
# Todo: GET WAN IP from Router via UPnP if supported #
|
||||
# Todo: licence string? #
|
||||
# author: Daniel Steglich <steglich@datasystems24.de> #
|
||||
# #
|
||||
############################################################################
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
|
||||
# static values
|
||||
WGET=$(which wget)
|
||||
WGETOPTIONS="-4 -o /dev/null -t 3 -T 3"
|
||||
EMPTYSTRING="none"
|
||||
NOIP="0.0.0.0"
|
||||
# how often do we poll for IP changes if we are behind a NAT?
|
||||
UPDATEMINUTES=5
|
||||
# if we do not have a IP check URL, how often should we do a "blind" update
|
||||
UPDATEMINUTESUNKNOWN=3600
|
||||
TOOLNAME=ez-ipupdate
|
||||
UPDATE_TOOL=$(which ${TOOLNAME})
|
||||
DISABLED_STRING='disabled'
|
||||
ENABLED_STRING='enabled'
|
||||
|
||||
# Dirs and filenames
|
||||
CFGDIR="/etc/${TOOLNAME}/"
|
||||
CFG="${CFGDIR}${TOOLNAME}.conf"
|
||||
CFG_disabled="${CFGDIR}${TOOLNAME}.inactive"
|
||||
IPFILE="${CFGDIR}${TOOLNAME}.currentIP"
|
||||
STATUSFILE="${CFGDIR}${TOOLNAME}.status"
|
||||
LASTUPDATE="${CFGDIR}/last-update"
|
||||
HELPERCFG="${CFGDIR}${TOOLNAME}-plinth.cfg"
|
||||
CRONJOB="/etc/cron.d/${TOOLNAME}"
|
||||
PIDFILE="/var/run/ez-ipupdate.pid"
|
||||
|
||||
# this function will parse commandline options
|
||||
doGetOpt()
|
||||
{
|
||||
basicauth=0
|
||||
ignoreCertError=0
|
||||
|
||||
while getopts ":s:d:u:p:I:U:c:b:" opt; do
|
||||
case ${opt} in
|
||||
s)
|
||||
if [ "${OPTARG}" != "${EMPTYSTRING}" ];then
|
||||
server=${OPTARG}
|
||||
else
|
||||
server=""
|
||||
fi
|
||||
;;
|
||||
d)
|
||||
host=${OPTARG}
|
||||
;;
|
||||
u)
|
||||
user=${OPTARG}
|
||||
;;
|
||||
p)
|
||||
pass=${OPTARG}
|
||||
;;
|
||||
I)
|
||||
if [ "${OPTARG}" != "${EMPTYSTRING}" ];then
|
||||
ipurl=${OPTARG}
|
||||
else
|
||||
ipurl=""
|
||||
fi
|
||||
;;
|
||||
U)
|
||||
if [ "${OPTARG}" != "${EMPTYSTRING}" ];then
|
||||
updateurl=${OPTARG}
|
||||
else
|
||||
updateurl=""
|
||||
fi
|
||||
;;
|
||||
b)
|
||||
basicauth=${OPTARG}
|
||||
;;
|
||||
c)
|
||||
ignoreCertError=${OPTARG}
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -${OPTARG}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# this function will write a persistent config file to disk
|
||||
doWriteCFG()
|
||||
{
|
||||
mkdir ${CFGDIR} 2> /dev/null
|
||||
# always write to the inactive config - needs to be enabled via "start" command later
|
||||
local out_file=${CFG_disabled}
|
||||
|
||||
# reset the last update time
|
||||
echo 0 > ${LASTUPDATE}
|
||||
|
||||
# reset the last updated IP
|
||||
echo "0.0.0.0" > ${IPFILE}
|
||||
|
||||
# reset last update (if there is one)
|
||||
rm ${STATUSFILE} 2> /dev/null
|
||||
|
||||
# find the interface (always the default gateway interface)
|
||||
default_interface=$(ip route |grep default |awk '{print $5}')
|
||||
|
||||
# store the given options in ez-ipupdate compatible config file
|
||||
{
|
||||
echo "host=${host}"
|
||||
echo "server=${server}"
|
||||
echo "user=${user}:${pass}"
|
||||
echo "service-type=gnudip"
|
||||
echo "retrys=3"
|
||||
echo "wildcard"
|
||||
} > ${out_file}
|
||||
|
||||
# store UPDATE URL params
|
||||
{
|
||||
echo "POSTURL ${updateurl}"
|
||||
echo "POSTAUTH ${basicauth}"
|
||||
echo "POSTSSLIGNORE ${ignoreCertError}"
|
||||
} > ${HELPERCFG}
|
||||
|
||||
# check if we are behind a NAT Router
|
||||
echo "IPURL ${ipurl}" >> ${HELPERCFG}
|
||||
if [ -z ${ipurl} ];then
|
||||
echo "NAT unknown" >> ${HELPERCFG}
|
||||
else
|
||||
doGetWANIP
|
||||
ISGLOBAL=$(ip addr ls "${default_interface}" | grep "${wanip}")
|
||||
if [ -z "${ISGLOBAL}" ];then
|
||||
# we are behind NAT
|
||||
echo "NAT yes" >> ${HELPERCFG}
|
||||
else
|
||||
# we are directly connected
|
||||
echo "NAT no" >> ${HELPERCFG}
|
||||
# if this file is added ez-ipupdate will take ip form this interface
|
||||
{
|
||||
"interface=${default_interface}"
|
||||
# if this line is added to config file, ez-ipupdate will be launched on startup via init.d
|
||||
"daemon"
|
||||
"execute=${0} success"
|
||||
} > ${out_file}
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# this function will read the config file from disk
|
||||
# special treatment for empty strings is done here:
|
||||
# plinth will give empty strings like: ''
|
||||
# but we don't want this single quotes to be used
|
||||
doReadCFG()
|
||||
{
|
||||
host=""
|
||||
server=""
|
||||
user=""
|
||||
pass=""
|
||||
ipurl=""
|
||||
|
||||
if [ ! -z "${cfgfile}" ];then
|
||||
host=$(grep host "${cfgfile}" 2> /dev/null |cut -d = -f 2)
|
||||
server=$(grep server "${cfgfile}" 2> /dev/null |cut -d = -f 2 |grep -v ^\'\')
|
||||
user=$(grep user "${cfgfile}" 2> /dev/null |cut -d = -f 2 |cut -d : -f 1 )
|
||||
pass=$(grep user "${cfgfile}" 2> /dev/null |cut -d = -f 2 |cut -d : -f 2)
|
||||
fi
|
||||
|
||||
if [ ! -z ${HELPERCFG} ];then
|
||||
ipurl=$(grep ^IPURL "${HELPERCFG}" 2> /dev/null |awk '{print $2}' |grep -v ^\'\')
|
||||
updateurl=$(grep POSTURL "${HELPERCFG}" 2> /dev/null |awk '{print $2}' |grep -v ^\'\')
|
||||
basicauth=$(grep POSTAUTH "${HELPERCFG}" 2> /dev/null |awk '{print $2}' |grep -v ^\'\')
|
||||
ignoreCertError=$(grep POSTSSLIGNORE "${HELPERCFG}" 2> /dev/null |awk '{print $2}' |grep -v ^\'\')
|
||||
fi
|
||||
}
|
||||
|
||||
# replace vars from url: i.e.:
|
||||
# https://example.com/update.php?domain=<Domain>&User=<User>&Pass=<Pass>
|
||||
# also this function will remove the surounding single quotes from the URL string
|
||||
# as plinth will add them
|
||||
doReplaceVars()
|
||||
{
|
||||
local url=$(echo "${updateurl}" | sed "s/<Ip>/${wanip}/g")
|
||||
url=$(echo "${url}" | sed "s/<Domain>/${host}/g")
|
||||
url=$(echo "${url}" | sed "s/<User>/${user}/g")
|
||||
url=$(echo "${url}" | sed "s/<Pass>/${pass}/g")
|
||||
url=$(echo "${url}" | sed "s/'//g")
|
||||
updateurl=${url}
|
||||
logger "expanded update URL as ${url}"
|
||||
}
|
||||
|
||||
# doReadCFG() needs to be run before this
|
||||
# this function will return all configured parameters in a way that
|
||||
# plinth will understand (plinth know the order of
|
||||
# parameters this function will return)
|
||||
doStatus()
|
||||
{
|
||||
PROC=$(pgrep ${TOOLNAME})
|
||||
if [ -f "${CRONJOB}" ];then
|
||||
echo "${ENABLED_STRING}"
|
||||
elif [ ! -z "${PROC}" ];then
|
||||
echo "${ENABLED_STRING}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${server}" ];then
|
||||
echo "${server}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${host}" ];then
|
||||
echo "${host}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${user}" ];then
|
||||
echo "${user}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${pass}" ];then
|
||||
echo "${pass}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${ipurl}" ];then
|
||||
echo "${ipurl}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${updateurl}" ];then
|
||||
echo "${updateurl}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${basicauth}" ];then
|
||||
echo "${basicauth}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
if [ ! -z "${ignoreCertError}" ];then
|
||||
echo "${ignoreCertError}"
|
||||
else
|
||||
echo "${DISABLED_STRING}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ask a public WEB Server for the WAN IP we are comming from
|
||||
# and store this ip within $wanip
|
||||
doGetWANIP()
|
||||
{
|
||||
if [ ! -z "${ipurl}" ];then
|
||||
outfile=$(mktemp)
|
||||
local cmd="${WGET} ${WGETOPTIONS} -O ${outfile} ${ipurl}"
|
||||
$cmd
|
||||
wanip=$(sed s/[^0-9.]//g "${outfile}")
|
||||
rm "${outfile}"
|
||||
[ -z "${wanip}" ] && wanip=${NOIP}
|
||||
else
|
||||
# no WAN IP found because of missing check URL
|
||||
wanip=${NOIP}
|
||||
fi
|
||||
}
|
||||
|
||||
# actualy do the update (using wget or ez-ipupdate or even both)
|
||||
# this function is called via cronjob
|
||||
doUpdate()
|
||||
{
|
||||
local dnsentry=$(nslookup "${host}"|tail -n2|grep A|sed s/[^0-9.]//g)
|
||||
if [ "${dnsentry}" = "${wanip}" ];then
|
||||
return
|
||||
fi
|
||||
if [ ! -z "${server}" ];then
|
||||
start-stop-daemon -S -x "${UPDATE_TOOL}" -m -p "${PIDFILE}" -- -c "${cfgfile}"
|
||||
fi
|
||||
if [ ! -z "${updateurl}" ];then
|
||||
doReplaceVars
|
||||
if [ "${basicauth}" = "enabled" ];then
|
||||
WGETOPTIONS="${WGETOPTIONS} --user ${user} --password ${pass} "
|
||||
fi
|
||||
if [ "${ignoreCertError}" = "enabled" ];then
|
||||
WGETOPTIONS="${WGETOPTIONS} --no-check-certificate "
|
||||
fi
|
||||
local cmd="${WGET} ${WGETOPTIONS} ${updateurl}"
|
||||
$cmd
|
||||
# ToDo: check the returning text from WEB Server. User need to give expected string.
|
||||
if [ ${?} -eq 0 ];then
|
||||
${0} success ${wanip}
|
||||
else
|
||||
${0} failed
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
cmd=${1}
|
||||
shift
|
||||
# decide which config to use
|
||||
cfgfile="/tmp/none"
|
||||
[ -f ${CFG_disabled} ] && cfgfile=${CFG_disabled}
|
||||
[ -f ${CFG} ] && cfgfile=${CFG}
|
||||
|
||||
# check what action is requested
|
||||
case ${cmd} in
|
||||
configure)
|
||||
doGetOpt "${@}"
|
||||
doWriteCFG
|
||||
;;
|
||||
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
|
||||
local 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
|
||||
fi
|
||||
;;
|
||||
get-nat)
|
||||
NAT=$(grep ^NAT $HELPERCFG 2> /dev/null | awk '{print $2}')
|
||||
[ -z "${NAT}" ] && NAT="unknown"
|
||||
echo ${NAT}
|
||||
;;
|
||||
update)
|
||||
doReadCFG
|
||||
dnsentry=$(nslookup "${host}"|tail -n2|grep A|sed s/[^0-9.]//g)
|
||||
doGetWANIP
|
||||
echo ${wanip} > ${IPFILE}
|
||||
grep -v execute ${cfgfile} > ${cfgfile}.tmp
|
||||
mv ${cfgfile}.tmp ${cfgfile}
|
||||
echo "execute=${0} success ${wanip}" >> ${cfgfile}
|
||||
# if we know our WAN IP, only update if IP changes
|
||||
if [ "${dnsentry}" != "${wanip}" -a "${wanip}" != ${NOIP} ];then
|
||||
doUpdate
|
||||
fi
|
||||
# if we don't know our WAN IP do a blind update once a hour
|
||||
if [ "${wanip}" = ${NOIP} ];then
|
||||
uptime=$(cut -d . -f 1 /proc/uptime)
|
||||
LAST=0
|
||||
[ -f ${LASTUPDATE} ] && LAST=$(cat ${LASTUPDATE})
|
||||
diff=$((uptime - LAST))
|
||||
if [ ${diff} -gt ${UPDATEMINUTESUNKNOWN} ];then
|
||||
doUpdate
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
rm ${CRONJOB} 2> /dev/null
|
||||
/etc/init.d/${TOOLNAME} stop
|
||||
kill "$(cat ${PIDFILE})" 2> /dev/null
|
||||
mv ${CFG} ${CFG_disabled}
|
||||
;;
|
||||
success)
|
||||
date=$(date)
|
||||
echo "last update done (${date})" > ${STATUSFILE}
|
||||
awk '{print $1}' /proc/uptime |cut -d . -f 1 > ${LASTUPDATE}
|
||||
# if called from cronjob, the current IP is given as parameter
|
||||
if [ $# -eq 1 ];then
|
||||
echo "${1}" > ${IPFILE}
|
||||
else
|
||||
# if called from ez-ipupdate daemon, no WAN IP is given as parameter
|
||||
doGetWANIP
|
||||
echo ${wanip} > ${IPFILE}
|
||||
fi
|
||||
;;
|
||||
failed)
|
||||
date=$(date)
|
||||
echo "last update failed (${date})" > ${STATUSFILE}
|
||||
;;
|
||||
get-last-success)
|
||||
if [ -f ${STATUSFILE} ];then
|
||||
cat ${STATUSFILE}
|
||||
else
|
||||
echo "no successful update recorded since last config change"
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
doReadCFG
|
||||
doStatus
|
||||
;;
|
||||
get-timer)
|
||||
echo ${UPDATEMINUTES}
|
||||
;;
|
||||
clean)
|
||||
rm ${CFGDIR}/*
|
||||
rm ${CRONJOB}
|
||||
;;
|
||||
*)
|
||||
echo "usage: status|configure <options>|start|stop|update|get-nat|clean|success [updated IP]|failed|get-last-success"
|
||||
echo ""
|
||||
echo "options are:"
|
||||
echo "-s <server> Gnudip Server address"
|
||||
echo "-d <domain> Domain to be updated"
|
||||
echo "-u <user> Account username"
|
||||
echo "-p <password> Account Password"
|
||||
echo "-I <IP check URL> A URL which returns the IP of the client who is requesting"
|
||||
echo "-U <update URL> The update URL (a HTTP GET on this URL will be done)"
|
||||
echo "-c <1|0> disable SSL check on Update URL"
|
||||
echo "-b <1|0> use HTTP basic auth on Update URL"
|
||||
echo ""
|
||||
echo "update do a one time update"
|
||||
echo "clean delete configuration"
|
||||
echo "success store update success and optional the updated IP"
|
||||
echo "failed store update failure"
|
||||
echo "get-nat return the detected nat type"
|
||||
echo "get-last-success return date of last successful update"
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
1
data/etc/plinth/modules-enabled/dynamicdns
Normal file
1
data/etc/plinth/modules-enabled/dynamicdns
Normal file
@ -0,0 +1 @@
|
||||
plinth.modules.dynamicdns
|
||||
27
plinth/modules/dynamicdns/__init__.py
Normal file
27
plinth/modules/dynamicdns/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# This file is part of Plinth.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""
|
||||
Plinth module to configure ez-ipupdate client
|
||||
"""
|
||||
|
||||
from . import dynamicdns
|
||||
from .dynamicdns import init
|
||||
|
||||
__all__ = ['dynamicdns', 'init']
|
||||
|
||||
depends = ['plinth.modules.apps']
|
||||
392
plinth/modules/dynamicdns/dynamicdns.py
Normal file
392
plinth/modules/dynamicdns/dynamicdns.py
Normal file
@ -0,0 +1,392 @@
|
||||
#
|
||||
# This file is part of Plinth.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core import validators
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.template.response import TemplateResponse
|
||||
from gettext import gettext as _
|
||||
import logging
|
||||
|
||||
from plinth import actions
|
||||
from plinth import cfg
|
||||
from plinth import package
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
EMPTYSTRING = 'none'
|
||||
|
||||
subsubmenu = [{'url': reverse_lazy('dynamicdns:index'),
|
||||
'text': _('About')},
|
||||
{'url': reverse_lazy('dynamicdns:configure'),
|
||||
'text': _('Configure')},
|
||||
{'url': reverse_lazy('dynamicdns:statuspage'),
|
||||
'text': _('Status')}
|
||||
]
|
||||
|
||||
|
||||
def init():
|
||||
"""Initialize the dynamicdns module"""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname('Dynamic DNS', 'glyphicon-refresh',
|
||||
'dynamicdns:index', 40)
|
||||
|
||||
|
||||
@login_required
|
||||
@package.required('ez-ipupdate')
|
||||
def index(request):
|
||||
"""Serve dynamic DNS page"""
|
||||
|
||||
return TemplateResponse(request, 'dynamicdns.html',
|
||||
{'title': _('dynamicdns'),
|
||||
'subsubmenu': subsubmenu})
|
||||
|
||||
|
||||
class TrimmedCharField(forms.CharField):
|
||||
"""Trim the contents of a CharField"""
|
||||
def clean(self, value):
|
||||
"""Clean and validate the field value"""
|
||||
if value:
|
||||
value = value.strip()
|
||||
|
||||
return super(TrimmedCharField, self).clean(value)
|
||||
|
||||
|
||||
class ConfigureForm(forms.Form):
|
||||
"""Form to configure the dynamic DNS client"""
|
||||
|
||||
hlp_updt_url = 'The Variables <User>, <Pass>, <Ip>, \
|
||||
<Domain> may be used within the URL. For details\
|
||||
see the update URL templates of the example providers.'
|
||||
|
||||
hlp_services = 'Please choose an update protocol according to your \
|
||||
provider. If your provider does not support the GnudIP \
|
||||
protocol or your provider is not listed you may use \
|
||||
the update URL of your provider.'
|
||||
|
||||
hlp_server = 'Please do not enter a URL here (like "https://example.com/")\
|
||||
but only the hostname of the GnuDIP server (like \
|
||||
"example.com").'
|
||||
|
||||
hlp_domain = 'The public domain name you want use to reach your box.'
|
||||
|
||||
hlp_disable_ssl = 'Use this option if your provider uses self signed \
|
||||
certificates.'
|
||||
|
||||
hlp_http_auth = 'If this option is selected, your username and \
|
||||
password will be used for HTTP basic authentication.'
|
||||
|
||||
hlp_secret = 'Leave this field empty \
|
||||
if you want to keep your previous configured password.'
|
||||
|
||||
hlp_ipurl = 'Optional Value. If your FreedomBox is not connected \
|
||||
directly to the Internet (i.e. connected to a NAT \
|
||||
router) this URL is used to figure out the real Internet \
|
||||
IP. The URL should simply return the IP where the \
|
||||
client comes from. Example: \
|
||||
http://myip.datasystems24.de'
|
||||
|
||||
hlp_user = 'You should have been requested to select a username \
|
||||
when you created the account.'
|
||||
|
||||
"""ToDo: sync this list with the html template file"""
|
||||
provider_choices = (
|
||||
('GnuDIP', 'GnuDIP'),
|
||||
('noip', 'noip.com'),
|
||||
('selfhost', 'selfhost.bz'),
|
||||
('freedns', 'freedns.afraid.org'),
|
||||
('other', 'other update URL'))
|
||||
|
||||
enabled = forms.BooleanField(label=_('Enable Dynamic DNS'),
|
||||
required=False)
|
||||
|
||||
service_type = forms.ChoiceField(label=_('Service type'),
|
||||
help_text=_(hlp_services),
|
||||
choices=provider_choices)
|
||||
|
||||
dynamicdns_server = TrimmedCharField(
|
||||
label=_('GnudIP Server Address'),
|
||||
required=False,
|
||||
help_text=_(hlp_server),
|
||||
validators=[
|
||||
validators.RegexValidator(r'^[\w-]{1,63}(\.[\w-]{1,63})*$',
|
||||
_('Invalid server name'))])
|
||||
|
||||
dynamicdns_update_url = TrimmedCharField(label=_('Update URL'),
|
||||
required=False,
|
||||
help_text=_(hlp_updt_url))
|
||||
|
||||
disable_SSL_cert_check = forms.BooleanField(label=_('accept all SSL \
|
||||
certificates'),
|
||||
help_text=_(hlp_disable_ssl),
|
||||
required=False)
|
||||
|
||||
use_http_basic_auth = forms.BooleanField(label=_('use HTTP basic \
|
||||
authentication'),
|
||||
help_text=_(hlp_http_auth),
|
||||
required=False)
|
||||
|
||||
dynamicdns_domain = TrimmedCharField(
|
||||
label=_('Domain Name'),
|
||||
help_text=_(hlp_domain),
|
||||
required=False,
|
||||
validators=[
|
||||
validators.RegexValidator(r'^[\w-]{1,63}(\.[\w-]{1,63})*$',
|
||||
_('Invalid domain name'))])
|
||||
|
||||
dynamicdns_user = TrimmedCharField(
|
||||
label=_('Username'),
|
||||
required=False,
|
||||
help_text=_(hlp_user))
|
||||
|
||||
dynamicdns_secret = TrimmedCharField(
|
||||
label=_('Password'), widget=forms.PasswordInput(),
|
||||
required=False,
|
||||
help_text=_(hlp_secret))
|
||||
|
||||
showpw = forms.BooleanField(label=_('show password'),
|
||||
required=False)
|
||||
|
||||
dynamicdns_ipurl = TrimmedCharField(
|
||||
label=_('IP check URL'),
|
||||
required=False,
|
||||
help_text=_(hlp_ipurl),
|
||||
validators=[
|
||||
validators.URLValidator(schemes=['http', 'https', 'ftp'])])
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(ConfigureForm, self).clean()
|
||||
dynamicdns_secret = cleaned_data.get('dynamicdns_secret')
|
||||
dynamicdns_update_url = cleaned_data.get('dynamicdns_update_url')
|
||||
dynamicdns_user = cleaned_data.get('dynamicdns_user')
|
||||
dynamicdns_domain = cleaned_data.get('dynamicdns_domain')
|
||||
dynamicdns_server = cleaned_data.get('dynamicdns_server')
|
||||
service_type = cleaned_data.get('service_type')
|
||||
old_dynamicdns_secret = self.initial['dynamicdns_secret']
|
||||
|
||||
"""clear the fields which are not in use"""
|
||||
if service_type == 'GnuDIP':
|
||||
dynamicdns_update_url = ""
|
||||
else:
|
||||
dynamicdns_server = ""
|
||||
|
||||
if cleaned_data.get('enabled'):
|
||||
"""check if gnudip server or update URL is filled"""
|
||||
if not dynamicdns_update_url and not dynamicdns_server:
|
||||
raise forms.ValidationError('please give update URL or \
|
||||
a GnuDIP Server')
|
||||
LOGGER.info('no server address given')
|
||||
|
||||
if dynamicdns_server and not dynamicdns_user:
|
||||
raise forms.ValidationError('please give GnuDIP username')
|
||||
|
||||
if dynamicdns_server and not dynamicdns_domain:
|
||||
raise forms.ValidationError('please give GnuDIP domain')
|
||||
|
||||
"""check if a password was set before or a password is set now"""
|
||||
if (dynamicdns_server and not dynamicdns_secret
|
||||
and not old_dynamicdns_secret):
|
||||
raise forms.ValidationError('please give a password')
|
||||
LOGGER.info('no password given')
|
||||
|
||||
|
||||
@login_required
|
||||
@package.required('ez-ipupdate')
|
||||
def configure(request):
|
||||
"""Serve the configuration form"""
|
||||
status = get_status()
|
||||
form = None
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ConfigureForm(request.POST, initial=status)
|
||||
if form.is_valid():
|
||||
_apply_changes(request, status, form.cleaned_data)
|
||||
status = get_status()
|
||||
form = ConfigureForm(initial=status)
|
||||
else:
|
||||
form = ConfigureForm(initial=status)
|
||||
|
||||
return TemplateResponse(request, 'dynamicdns_configure.html',
|
||||
{'title': _('Configure dynamicdns Client'),
|
||||
'form': form,
|
||||
'subsubmenu': subsubmenu})
|
||||
|
||||
|
||||
@login_required
|
||||
@package.required('ez-ipupdate')
|
||||
def statuspage(request):
|
||||
"""Serve the status page """
|
||||
check_nat = actions.run('dynamicdns', ['get-nat'])
|
||||
last_update = actions.run('dynamicdns', ['get-last-success'])
|
||||
|
||||
no_nat = check_nat.strip() == 'no'
|
||||
nat_unchecked = check_nat.strip() == 'unknown'
|
||||
timer = actions.run('dynamicdns', ['get-timer'])
|
||||
|
||||
if no_nat:
|
||||
LOGGER.info('we are not behind a NAT')
|
||||
|
||||
if nat_unchecked:
|
||||
LOGGER.info('we did not checked if we are behind a NAT')
|
||||
|
||||
return TemplateResponse(request, 'dynamicdns_status.html',
|
||||
{'title': _('Status of dynamicdns Client'),
|
||||
'no_nat': no_nat,
|
||||
'nat_unchecked': nat_unchecked,
|
||||
'timer': timer,
|
||||
'last_update': last_update,
|
||||
'subsubmenu': subsubmenu})
|
||||
|
||||
|
||||
def get_status():
|
||||
"""Return the current status"""
|
||||
"""ToDo: use key/value instead of hard coded value list"""
|
||||
status = {}
|
||||
output = actions.run('dynamicdns', 'status')
|
||||
details = output.split()
|
||||
status['enabled'] = (output.split()[0] == 'enabled')
|
||||
|
||||
if len(details) > 1:
|
||||
if details[1] == 'disabled':
|
||||
status['dynamicdns_server'] = ''
|
||||
else:
|
||||
status['dynamicdns_server'] = details[1].replace("'", "")
|
||||
else:
|
||||
status['dynamicdns_server'] = ''
|
||||
|
||||
if len(details) > 2:
|
||||
if details[2] == 'disabled':
|
||||
status['dynamicdns_domain'] = ''
|
||||
else:
|
||||
status['dynamicdns_domain'] = details[2]
|
||||
status['dynamicdns_domain'] = details[2].replace("'", "")
|
||||
else:
|
||||
status['dynamicdns_domain'] = ''
|
||||
|
||||
if len(details) > 3:
|
||||
if details[3] == 'disabled':
|
||||
status['dynamicdns_user'] = ''
|
||||
else:
|
||||
status['dynamicdns_user'] = details[3].replace("'", "")
|
||||
else:
|
||||
status['dynamicdns_user'] = ''
|
||||
|
||||
if len(details) > 4:
|
||||
if details[4] == 'disabled':
|
||||
status['dynamicdns_secret'] = ''
|
||||
else:
|
||||
status['dynamicdns_secret'] = details[4].replace("'", "")
|
||||
else:
|
||||
status['dynamicdns_secret'] = ''
|
||||
|
||||
if len(details) > 5:
|
||||
if details[5] == 'disabled':
|
||||
status['dynamicdns_ipurl'] = ''
|
||||
else:
|
||||
status['dynamicdns_ipurl'] = details[5].replace("'", "")
|
||||
else:
|
||||
status['dynamicdns_ipurl'] = ''
|
||||
|
||||
if len(details) > 6:
|
||||
if details[6] == 'disabled':
|
||||
status['dynamicdns_update_url'] = ''
|
||||
else:
|
||||
status['dynamicdns_update_url'] = details[6].replace("'", "")
|
||||
else:
|
||||
status['dynamicdns_update_url'] = ''
|
||||
|
||||
if len(details) > 7:
|
||||
status['disable_SSL_cert_check'] = (output.split()[7] == 'enabled')
|
||||
else:
|
||||
status['disable_SSL_cert_check'] = False
|
||||
|
||||
if len(details) > 8:
|
||||
status['use_http_basic_auth'] = (output.split()[8] == 'enabled')
|
||||
else:
|
||||
status['use_http_basic_auth'] = False
|
||||
|
||||
if not status['dynamicdns_server'] and not status['dynamicdns_update_url']:
|
||||
status['service_type'] = 'GnuDIP'
|
||||
elif not status['dynamicdns_server'] and status['dynamicdns_update_url']:
|
||||
status['service_type'] = 'other'
|
||||
else:
|
||||
status['service_type'] = 'GnuDIP'
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def _apply_changes(request, old_status, new_status):
|
||||
"""Apply the changes to Dynamic DNS client"""
|
||||
LOGGER.info('New status is - %s', new_status)
|
||||
LOGGER.info('Old status was - %s', old_status)
|
||||
|
||||
if new_status['dynamicdns_secret'] == '':
|
||||
new_status['dynamicdns_secret'] = old_status['dynamicdns_secret']
|
||||
|
||||
if new_status['dynamicdns_ipurl'] == '':
|
||||
new_status['dynamicdns_ipurl'] = EMPTYSTRING
|
||||
|
||||
if new_status['dynamicdns_update_url'] == '':
|
||||
new_status['dynamicdns_update_url'] = EMPTYSTRING
|
||||
|
||||
if new_status['dynamicdns_server'] == '':
|
||||
new_status['dynamicdns_server'] = EMPTYSTRING
|
||||
|
||||
if new_status['service_type'] == 'GnuDIP':
|
||||
new_status['dynamicdns_update_url'] = EMPTYSTRING
|
||||
else:
|
||||
new_status['dynamicdns_server'] = EMPTYSTRING
|
||||
|
||||
if old_status != new_status:
|
||||
disable_ssl_check = "disabled"
|
||||
use_http_basic_auth = "disabled"
|
||||
|
||||
if new_status['disable_SSL_cert_check']:
|
||||
disable_ssl_check = "enabled"
|
||||
|
||||
if new_status['use_http_basic_auth']:
|
||||
use_http_basic_auth = "enabled"
|
||||
|
||||
_run(['configure', '-s', new_status['dynamicdns_server'],
|
||||
'-d', new_status['dynamicdns_domain'],
|
||||
'-u', new_status['dynamicdns_user'],
|
||||
'-p', new_status['dynamicdns_secret'],
|
||||
'-I', new_status['dynamicdns_ipurl'],
|
||||
'-U', new_status['dynamicdns_update_url'],
|
||||
'-c', disable_ssl_check,
|
||||
'-b', use_http_basic_auth])
|
||||
|
||||
if old_status['enabled']:
|
||||
_run(['stop'])
|
||||
if new_status['enabled']:
|
||||
_run(['start'])
|
||||
|
||||
messages.success(request,
|
||||
_('Dynamic DNS configuration is updated!'))
|
||||
else:
|
||||
LOGGER.info('nothing changed')
|
||||
|
||||
|
||||
def _run(arguments, superuser=False):
|
||||
"""Run a given command and raise exception if there was an error"""
|
||||
command = 'dynamicdns'
|
||||
|
||||
if superuser:
|
||||
return actions.superuser_run(command, arguments)
|
||||
else:
|
||||
return actions.run(command, arguments)
|
||||
46
plinth/modules/dynamicdns/templates/dynamicdns.html
Normal file
46
plinth/modules/dynamicdns/templates/dynamicdns.html
Normal file
@ -0,0 +1,46 @@
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
#
|
||||
# This file is part of Plinth.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
{% endcomment %}
|
||||
|
||||
{% block content %}
|
||||
<h2>DynamicDNS client</h2>
|
||||
<p>If your internet provider changes your IP address periodic (i.e. every 24h)
|
||||
it may be hard for others to find you in the WEB. And for this reason nobody
|
||||
may find the services which are provided by FreedomBox (like your ownCloud).
|
||||
</br> </br>
|
||||
The solution is to assign a DNS name to your IP address and update the DNS
|
||||
name every time your IP is changed by your Internet provider. Dynamic DNS
|
||||
allows you to push your current public IP address to an
|
||||
<a href='http://gnudip2.sourceforge.net/' target='_blank'> gnudip </a>
|
||||
server. Afterwards the Server will assign your DNS name with the new IP
|
||||
and if someone from the internet asks for your DNS name he will get your
|
||||
current IP answered.
|
||||
</br> </br>
|
||||
If you are looking for a free dynamic DNS account, you may find a free
|
||||
GnuDIP service at <a href='http://gnudip.datasystems24.net'
|
||||
target='_blank'>gnudip.datasystems24.net</a> or you may find free update
|
||||
URL based services on
|
||||
<a href='http://freedns.afraid.org/' target='_blank'>
|
||||
freedns.afraid.org</a>
|
||||
</br> </br>
|
||||
If your freedombox is connected behind some NAT router, don't forget
|
||||
to add portforwarding (i.e. forward some standard ports like 80 and 443)
|
||||
to your freedombox device.
|
||||
</p>
|
||||
{% endblock %}
|
||||
164
plinth/modules/dynamicdns/templates/dynamicdns_configure.html
Normal file
164
plinth/modules/dynamicdns/templates/dynamicdns_configure.html
Normal file
@ -0,0 +1,164 @@
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
#
|
||||
# This file is part of Plinth.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
#
|
||||
{% endcomment %}
|
||||
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form class="form" method="post">
|
||||
{% csrf_token %}
|
||||
<noscript>
|
||||
You have disabled Javascript. Dynamic form mode is disabled and
|
||||
some helper functions may not work <br>
|
||||
(but the main functionality should work)
|
||||
<br><hr>
|
||||
</noscript>
|
||||
|
||||
{{ form|bootstrap }}
|
||||
|
||||
<input type="submit" class="btn btn-primary" value="Update setup"/>
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block page_js %}
|
||||
<script type="text/javascript">
|
||||
|
||||
(function($) {
|
||||
var SELFHOST = 'https://carol.selfhost.de/update?username=<User>&' +
|
||||
'password=<Pass>&myip=<Ip>'
|
||||
var NOIP = 'http://dynupdate.no-ip.com/nic/update?hostname=' +
|
||||
'<Domain>&myip=<Ip>'
|
||||
var FREEDNS = 'https://freedns.afraid.org/dynamic/update.php?' +
|
||||
'_YOURAPIKEYHERE_'
|
||||
|
||||
//hide ALL form fields
|
||||
$('.form-group').hide();
|
||||
//show the enable checkbox
|
||||
$('#id_enabled').closest('.form-group').show();
|
||||
if ($('#id_enabled').prop('checked')) {
|
||||
//show all form fields
|
||||
show_all();
|
||||
//set the selectbox to the last configured value
|
||||
select_service();
|
||||
}
|
||||
|
||||
$('#id_enabled').change(function() {
|
||||
if ($('#id_enabled').prop('checked')) {
|
||||
show_all();
|
||||
if ($("#id_service_type option:selected").text() == "GnuDIP") {
|
||||
set_gnudip_mode()
|
||||
} else {
|
||||
set_update_url_mode();
|
||||
}
|
||||
} else {
|
||||
$('.form-group').hide();
|
||||
$('#id_enabled').closest('.form-group').show();
|
||||
}
|
||||
});
|
||||
|
||||
$('#id_service_type').change(function() {
|
||||
var service_type = $("#id_service_type option:selected").text();
|
||||
if ( service_type == "GnuDIP" ) {
|
||||
set_gnudip_mode()
|
||||
} else {
|
||||
set_update_url_mode();
|
||||
if ( service_type == "noip.com" ) {
|
||||
$( '#id_dynamicdns_update_url' ).val( NOIP );
|
||||
$( '#id_use_http_basic_auth' ).prop( 'checked', true);
|
||||
} else {
|
||||
$( '#id_use_http_basic_auth' ).prop( 'checked', false);
|
||||
}
|
||||
if ( service_type == "selfhost.bz" ) {
|
||||
$( '#id_dynamicdns_update_url' ).val(SELFHOST);
|
||||
}
|
||||
if ( service_type == "freedns.afraid.org" ) {
|
||||
$('#id_dynamicdns_update_url').val(FREEDNS);
|
||||
}
|
||||
if ( service_type == "other update URL" ) {
|
||||
$('#id_dynamicdns_update_url').val('');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#id_showpw').change(function() {
|
||||
//changing type attribute from password to text is prevented by
|
||||
//most browsers make a new form field works for me
|
||||
if ($('#id_showpw').prop('checked')) {
|
||||
$('#id_dynamicdns_secret').replaceWith(
|
||||
$('#id_dynamicdns_secret').clone().attr(
|
||||
'type', 'text'));
|
||||
} else {
|
||||
$('#id_dynamicdns_secret').replaceWith(
|
||||
$('#id_dynamicdns_secret').clone().attr(
|
||||
'type', 'password'));
|
||||
}
|
||||
});
|
||||
|
||||
function select_service() {
|
||||
var update_url = $("#id_dynamicdns_update_url").val()
|
||||
if ( $("#id_dynamicdns_server").val().length == 0 ) {
|
||||
set_update_url_mode()
|
||||
if ( update_url == NOIP) {
|
||||
$("#id_service_type").val("noip");
|
||||
} else if ( update_url == SELFHOST) {
|
||||
$("#id_service_type").val("selfhost");
|
||||
} else if ( update_url == FREEDNS) {
|
||||
$("#id_service_type").val("freedns");
|
||||
} else {
|
||||
$("#id_service_type").val("other");
|
||||
}
|
||||
} else {
|
||||
$("#id_service_type").val("GnuDIP");
|
||||
set_gnudip_mode();
|
||||
}
|
||||
}
|
||||
|
||||
function set_gnudip_mode() {
|
||||
$('#id_dynamicdns_update_url').closest('.form-group').hide();
|
||||
$('#id_disable_SSL_cert_check').closest('.form-group').hide();
|
||||
$('#id_use_http_basic_auth').closest('.form-group').hide();
|
||||
$('#id_dynamicdns_server').closest('.form-group').show();
|
||||
}
|
||||
|
||||
function set_update_url_mode() {
|
||||
$('#id_dynamicdns_update_url').closest('.form-group').show();
|
||||
$('#id_disable_SSL_cert_check').closest('.form-group').show();
|
||||
$('#id_use_http_basic_auth').closest('.form-group').show();
|
||||
$('#id_dynamicdns_server').closest('.form-group').hide();
|
||||
}
|
||||
|
||||
function show_all() {
|
||||
$('#id_enabled').closest('.form-group').show();
|
||||
$('#id_service_type').closest('.form-group').show();
|
||||
$('#id_dynamicdns_server').closest('.form-group').show();
|
||||
$('#id_dynamicdns_update_url').closest('.form-group').show();
|
||||
$('#id_disable_SSL_cert_check').closest('.form-group').show();
|
||||
$('#id_use_http_basic_auth').closest('.form-group').show();
|
||||
$('#id_dynamicdns_domain').closest('.form-group').show();
|
||||
$('#id_dynamicdns_user').closest('.form-group').show();
|
||||
$('#id_dynamicdns_secret').closest('.form-group').show();
|
||||
$('#id_showpw').closest('.form-group').show();
|
||||
$('#id_dynamicdns_ipurl').closest('.form-group').show();
|
||||
}
|
||||
})(jQuery);
|
||||
</script>
|
||||
{% endblock %}
|
||||
42
plinth/modules/dynamicdns/templates/dynamicdns_status.html
Normal file
42
plinth/modules/dynamicdns/templates/dynamicdns_status.html
Normal file
@ -0,0 +1,42 @@
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
#
|
||||
# This file is part of Plinth.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
{% endcomment %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<h3>NAT type</h3>
|
||||
{% if nat_unchecked %}
|
||||
NAT type not detected yet, if you do not provide a "IP check URL" we will
|
||||
not detect a NAT type.
|
||||
{% else %}
|
||||
{% if no_nat %}
|
||||
Direct connection to the internet.
|
||||
{% else %}
|
||||
Behind NAT, this means that dynamic DNS service will poll the
|
||||
"IP check URL" for changes (we need the "IP check URL" for this reason
|
||||
- otherwise we will not detect IP changes).
|
||||
It may take up to {{ timer }} minutes until we update your DNS entry in
|
||||
case of WAN IP change.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<h3>Last update</h3>
|
||||
{{ last_update }}
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
||||
30
plinth/modules/dynamicdns/urls.py
Normal file
30
plinth/modules/dynamicdns/urls.py
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# This file is part of Plinth.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""
|
||||
URLs for the dynamicdns module
|
||||
"""
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
|
||||
urlpatterns = patterns(
|
||||
'plinth.modules.dynamicdns.dynamicdns',
|
||||
url(r'^apps/dynamicdns/$', 'index', name='index'),
|
||||
url(r'^apps/dynamicdns/configure/$', 'configure', name='configure'),
|
||||
url(r'^apps/dynamicdns/statuspage/$', 'statuspage', name='statuspage')
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user