2 import ipaddress, subprocess, sys, getopt,dbm
3 from configparser import ConfigParser
4 class DyndnsNetwork(object):
6 This class represents dynamic DNS server and network.
7 It has attributes hostname network server user and password
9 def __init__(self,config_section):
10 self.hostname = config_section['hostname']
11 self.network = ipaddress.ip_network(config_section['network'])
12 self.server = config_section['server']
13 if user in config_section:
14 self.user=config_section["user"]
15 self.password=config_section["password"]
18 def contains(self,address):
19 if self.network.prefixlen==0 and address.is_private:
21 if self.network.version != address.version:
23 return address in self.network
24 def nsupdate(self, address):
25 raise NotImplementedError
27 def get_current_addresses():
29 for line in subprocess.run(['ip','-o','addr','show'],check=True,stdout=subprocess.PIPE).stdout.decode('utf-8').split("\n"):
32 (no,iface,family,addr,rest)=line.split(maxsplit=4)
33 address=ipaddress.ip_address(addr.split('/')[0])
34 if address.is_loopback or address.is_link_local:
36 result.append(address)
38 def check_for_update():
39 addrlist=get_current_addresses()
40 for name,net in networks.items():
46 old_addr=ipaddress.ip_address(database[name].decode("utf-8"))
48 # Nothing changed go, to next net
60 config['dyngo']={'interval':'60','database','/var/lib/dyngo/dyngo.db'}
61 options=dict(getopt.getopt(sys.argv,"f:")[0])
62 if not '-f' in options:
63 options["-f"]="/etc/dyngo.conf"
64 if len(config.read(options["-f"]))!=1:
65 print("Cannot read config %s"%options["-f"],file=sys.stderr)
69 interval=int(conf['interval'])
70 database=dbm.open(conf['database'],"c")
71 # Convert all other config sections to DyndnsNetwork objects
73 for sect in config.sections():
74 if sect == 'dyngo' or sect= 'DEFAULT':
76 networks[sect]=DyndnsNetwork(config[sect])
77 # Remove stale items from persistent database, which are no more
78 # mentioned in the config file
79 for i in set([x.decode("utf-8") for x database.keys()])-set(network.keys()):