]> wagner.pp.ru Git - oss/dyngo.git/commitdiff
Initial commit. Actual dyndns request is not implemented yet
authorVictor Wagner <vitus@wagner.pp.ru>
Wed, 11 Sep 2019 15:17:43 +0000 (18:17 +0300)
committerVictor Wagner <vitus@wagner.pp.ru>
Wed, 11 Sep 2019 15:17:43 +0000 (18:17 +0300)
README.md [new file with mode: 0644]
dyngo [new file with mode: 0644]
dyngo.conf [new file with mode: 0644]
dyngo.md [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..9b5f951
--- /dev/null
+++ b/README.md
@@ -0,0 +1,30 @@
+DYNGO
+=====
+
+I like when I can log into my notebook via ssh using some easily
+remembered name. 
+
+But it is not always a case in the world of NATs and VPNs.
+
+If machine always have public IP address, than using some dynamic DNS
+service may help (short of neccessity to use full domain name. But 
+${HOME}/.ssh/config may help). But what if you log into your office
+workstation via corporate VPN, and want ssh back home?
+
+If you have enough power to run (or persuade system administrator to
+run) dyndns service in your office network, dyndns can help even there.
+
+But your setup need to know different dyndns servers depending on IP
+address.
+
+So, I wrote  DYNGO is dynamic DNS client which can handle lots of
+dynamic DNS servers simultaneously. It reads config file, which
+specifies which network ranges correspond to which server, and
+then runs as a daemon, periodically polling IP addresses of all
+interfaces of the machine. If it finds change, it makes http(s) request
+to specified URL.
+
+See [manual page](dyngo.md) for more info.
+
+
+
diff --git a/dyngo b/dyngo
new file mode 100644 (file)
index 0000000..431e8cf
--- /dev/null
+++ b/dyngo
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+import ipaddress, subprocess, sys, getopt,dbm
+from configparser import ConfigParser
+class DyndnsNetwork(object):
+    """
+    This class represents dynamic DNS server and network.
+    It has attributes hostname network server user and password
+    """
+    def __init__(self,config_section):
+        self.hostname = config_section['hostname']
+        self.network = ipaddress.ip_network(config_section['network'])
+        self.server = config_section['server']
+        if user in config_section:
+            self.user=config_section["user"]
+            self.password=config_section["password"]
+
+
+    def contains(self,address):
+        if self.network.prefixlen==0 and address.is_private:
+            return False
+        if self.network.version != address.version:
+            return False
+        return address in self.network
+   def nsupdate(self, address):
+        raise NotImplementedError
+
+def get_current_addresses():
+    result=[]    
+    for line in subprocess.run(['ip','-o','addr','show'],check=True,stdout=subprocess.PIPE).stdout.decode('utf-8').split("\n"):
+        if not len(line): 
+            continue
+        (no,iface,family,addr,rest)=line.split(maxsplit=4)
+        address=ipaddress.ip_address(addr.split('/')[0])
+        if address.is_loopback or address.is_link_local:
+            continue
+        result.append(address)
+    return result
+def check_for_update():
+    addrlist=get_current_addresses()
+    for name,net in networks.items():
+        found=False
+        for a in addrlist:
+            if net.contains(a):
+                found =True
+                if name in database:
+                    old_addr=ipaddress.ip_address(database[name].decode("utf-8"))
+                    if old_addr==a:
+                        # Nothing changed go, to next net
+                        break
+                # address changed
+                net.nsupdate(a)
+                database[name]=str(a)
+        if not found:
+            del data[name]
+
+            
+
+
+config=ConfigPaser()
+config['dyngo']={'interval':'60','database','/var/lib/dyngo/dyngo.db'}
+options=dict(getopt.getopt(sys.argv,"f:")[0])
+if not '-f' in options:
+    options["-f"]="/etc/dyngo.conf"
+if len(config.read(options["-f"]))!=1:
+    print("Cannot read config %s"%options["-f"],file=sys.stderr)
+    sys.exit(1)
+    
+conf=config['dyngo']
+interval=int(conf['interval'])
+database=dbm.open(conf['database'],"c")
+# Convert all other config sections to DyndnsNetwork objects
+networks={}
+for sect in config.sections():
+    if sect == 'dyngo' or sect= 'DEFAULT':
+        continue
+    networks[sect]=DyndnsNetwork(config[sect])
+# Remove stale items from persistent database, which are no more
+# mentioned in the config file
+for i in set([x.decode("utf-8") for x database.keys()])-set(network.keys()):
+    del database[i]
+
+
+while True:
+    check_for_update()
+    time.sleep(interval)
+
diff --git a/dyngo.conf b/dyngo.conf
new file mode 100644 (file)
index 0000000..d8c7aba
--- /dev/null
@@ -0,0 +1,18 @@
+# Config file for dingo dyndns client
+# Section name can be anything - it is for your convinience
+# parameters - hostname - name to send to server
+# network - IP network where this name belonks to
+# server - url of dyndns server
+[dingo]
+interval=60
+database=/var/lib/dingo/dingo.db
+[public ipv6]
+hostname=antares.wagner.pp.ru
+network=::/0   
+server=http://www.wagner.pp.ru/cgi-bin/dyndns.cgi
+user=
+[postgrespro local]
+hostname=antares.local.vm 
+network=192.168.24.0/21
+server=http://fafnir.l.posgrespro.ru/dyndns
+
diff --git a/dyngo.md b/dyngo.md
new file mode 100644 (file)
index 0000000..d7ed659
--- /dev/null
+++ b/dyngo.md
@@ -0,0 +1,45 @@
+% dingo(8)
+% Victor Wagner <vitus@wagner.pp.ru>
+% September 2019
+
+NAME
+====
+
+dingo - multi-network dynamic DNS client
+
+SYNOPSIS
+========
+
+**dyngo** [ **-f** *configuration-file* ]
+
+DESCRIPTION
+===========
+
+**dyngo** is dynamic DNS client which periodically tries to check if
+some of IP addresses of the current machine change and report to
+appropriate dynamic DNS server if so.
+
+It is primarily intended to let machine be visible in the local DNS 
+of office or home local networks, VPNs and so on. So it expects that
+there could be private dynamic dns servers. Couple of dynamic DNS
+scripts is included into distribution to make it easier to set up
+dynamic dns.
+
+But nothing prevent user from defining some of networks as global
+ones and put URL of public dyndns server into it.
+
+If network is defined as global, i.e have netmask /0, private ip ranges
+wouldn't be reported to corresponding DNS server.
+
+CONFIGURATION FILE
+==================
+
+Configuration file **dyngo.conf** is ini-style file. It contains section
+**dyngo** with global service parameters and section per dyndns server.
+
+Names of server-description sections are arbitrary, but should be
+unique, because they are used as keys into persistent database.
+
+
+
+