dyndns: accept and validate both A and AAAA records; default to client address

This commit is contained in:
Andreas Oberritter 2019-02-02 13:28:56 +01:00
parent 5b88ec58ec
commit 98f1e96d1a
3 changed files with 63 additions and 31 deletions

View File

@ -2,6 +2,7 @@ import re
import json import json
import requests import requests
import hashlib import hashlib
import ipaddress
from app import app from app import app
from distutils.version import StrictVersion from distutils.version import StrictVersion
@ -291,3 +292,14 @@ def display_setting_state(value):
return "OFF" return "OFF"
else: else:
return "UNKNOWN" return "UNKNOWN"
def validate_ipaddress(address):
try:
ip = ipaddress.ip_address(address)
except ValueError:
pass
else:
if isinstance(ip, (ipaddress.IPv4Address, ipaddress.IPv6Address)):
return [ip]
return []

View File

@ -1666,7 +1666,7 @@ class Record(object):
jrecords = jdata['records'] jrecords = jdata['records']
for jr in jrecords: for jr in jrecords:
if jr['name'] == self.name: if jr['name'] == self.name and jr['type'] == self.type:
self.name = jr['name'] self.name = jr['name']
self.type = jr['type'] self.type = jr['type']
self.status = jr['disabled'] self.status = jr['disabled']

View File

@ -5,6 +5,7 @@ import traceback
import re import re
import datetime import datetime
import json import json
import ipaddress
from distutils.util import strtobool from distutils.util import strtobool
from distutils.version import StrictVersion from distutils.version import StrictVersion
from functools import wraps from functools import wraps
@ -1742,6 +1743,11 @@ def dyndns_update():
hostname = request.args.get('hostname') hostname = request.args.get('hostname')
myip = request.args.get('myip') myip = request.args.get('myip')
if not hostname:
history = History(msg="DynDNS update: missing hostname parameter", created_by=current_user.username)
history.add()
return render_template('dyndns.html', response='nohost'), 200
try: try:
# get all domains owned by the current user # get all domains owned by the current user
domains = User(id=current_user.id).get_domain() domains = User(id=current_user.id).get_domain()
@ -1765,37 +1771,51 @@ def dyndns_update():
history.add() history.add()
return render_template('dyndns.html', response='nohost'), 200 return render_template('dyndns.html', response='nohost'), 200
r = Record() myip_addr = []
r.name = hostname if myip:
for address in myip.split(','):
myip_addr += utils.validate_ipaddress(address)
remote_addr = utils.validate_ipaddress(request.headers.get('X-Forwarded-For', request.remote_addr).split(', ')[:1])
response='nochg'
for ip in myip_addr or remote_addr:
if isinstance(ip, ipaddress.IPv4Address):
rtype='A'
else:
rtype='AAAA'
r = Record(name=hostname,type=rtype)
# check if the user requested record exists within this domain # check if the user requested record exists within this domain
if r.exists(domain.name) and r.is_allowed_edit(): if r.exists(domain.name) and r.is_allowed_edit():
if r.data == myip: if r.data == str(ip):
# record content did not change, return 'nochg' # record content did not change, return 'nochg'
history = History(msg="DynDNS update: attempted update of {0} but record did not change".format(hostname), created_by=current_user.username) history = History(msg="DynDNS update: attempted update of {0} but record did not change".format(hostname), created_by=current_user.username)
history.add() history.add()
return render_template('dyndns.html', response='nochg'), 200
else: else:
oldip = r.data oldip = r.data
result = r.update(domain.name, myip) result = r.update(domain.name, str(ip))
if result['status'] == 'ok': if result['status'] == 'ok':
history = History(msg='DynDNS update: updated record {0} in zone {1}, it changed from {2} to {3}'.format(hostname,domain.name,oldip,myip), detail=str(result), created_by=current_user.username) history = History(msg='DynDNS update: updated {0} record {1} in zone {2}, it changed from {3} to {4}'.format(rtype,hostname,domain.name,oldip,str(ip)), detail=str(result), created_by=current_user.username)
history.add() history.add()
return render_template('dyndns.html', response='good'), 200 response='good'
else: else:
return render_template('dyndns.html', response='911'), 200 response='911'
break
elif r.is_allowed_edit(): elif r.is_allowed_edit():
ondemand_creation = DomainSetting.query.filter(DomainSetting.domain == domain).filter(DomainSetting.setting == 'create_via_dyndns').first() ondemand_creation = DomainSetting.query.filter(DomainSetting.domain == domain).filter(DomainSetting.setting == 'create_via_dyndns').first()
if (ondemand_creation != None) and (strtobool(ondemand_creation.value) == True): if (ondemand_creation is not None) and (strtobool(ondemand_creation.value) == True):
record = Record(name=hostname,type='A',data=myip,status=False,ttl=3600) record = Record(name=hostname,type=rtype,data=str(ip),status=False,ttl=3600)
result = record.add(domain.name) result = record.add(domain.name)
if result['status'] == 'ok': if result['status'] == 'ok':
history = History(msg='DynDNS update: created record {0} in zone {1}, it now represents {2}'.format(hostname,domain.name,myip), detail=str(result), created_by=current_user.username) history = History(msg='DynDNS update: created record {0} in zone {1}, it now represents {2}'.format(hostname,domain.name,str(ip)), detail=str(result), created_by=current_user.username)
history.add() history.add()
return render_template('dyndns.html', response='good'), 200 response='good'
else:
history = History(msg='DynDNS update: attempted update of {0} but it does not exist for this user'.format(hostname), created_by=current_user.username) history = History(msg='DynDNS update: attempted update of {0} but it does not exist for this user'.format(hostname), created_by=current_user.username)
history.add() history.add()
return render_template('dyndns.html', response='nohost'), 200
return render_template('dyndns.html', response=response), 200
@app.route('/', methods=['GET', 'POST']) @app.route('/', methods=['GET', 'POST'])