Refactor the madness

This commit is contained in:
Alexandre Aubin 2021-03-28 22:08:20 +02:00
parent dfd8c0a412
commit ab8e0423fc
4 changed files with 91 additions and 106 deletions

View file

@ -1,15 +1,12 @@
YunoHost DynDNS Server YunoHost DynDNS Server
====================== ======================
**Note: Tested on Debian wheezy and YunoHost 2.4 (should work on Ubuntu)**
Setup quickly Setup quickly
------------------------------- -------------------------------
You can use the dynette_ynh package for YunoHost You can use the dynette_ynh package for YunoHost
https://github.com/YunoHost-Apps/dynette_ynh https://github.com/YunoHost-Apps/dynette_ynh
Web subscribe server deployment Web subscribe server deployment
------------------------------- -------------------------------

View file

@ -1,9 +1,21 @@
{ {
"database_url" : "postgres://{{ db_user }}:{{ db_password }}@localhost/{{ db_name }}", "database_url" : "postgres://{{ db_user }}:{{ db_password }}@localhost/{{ db_name }}",
"domains" : [ {{ subdomains }} ], "dyndns_domains" : [ {{ subdomains }} ],
"subs_url" : [ https://{{ dynette_domain }} ], "base_url" : "https://{{ dynette_domain }}",
"ns0" : {{ ns0 }}, "ns0" : "{{ ns0 }}",
"ns1" : {{ ns1 }}, "ns1" : "{{ ns1 }}",
"rname" : {{ rname }}, "rname" : "{{ rname }}",
"master_key" : {{ master_key }} "master_key" : "{{ master_key }}",
"allowed_operations": {
"." : ["A", "AAAA", "TXT", "MX", "CAA"],
"*." : ["A", "AAAA"],
"pubsub." : ["A", "AAAA", "CNAME"],
"muc." : ["A", "AAAA", "CNAME"],
"vjud." : ["A", "AAAA", "CNAME"],
"xmpp-upload." : ["A", "AAAA", "CNAME"],
"_xmpp-client._tcp." : ["SRV"],
"_xmpp-server._tcp." : ["SRV"],
"mail._domainkey." : ["TXT"],
"_dmarc." : ["TXT"]
}
} }

View file

@ -1,48 +1,26 @@
#!/usr/bin/python #!/usr/bin/python3
### Configuration ###
import json
with open('config.json') as config_file:
config = json.load(config_file)
postgresql_dsn = "dbname=dynette user=dynette password=myPassword"
conf_file = '/etc/bind/named.conf.local' # Include this filename in '/etc/bind/named.conf'
zone_dir = '/var/lib/bind/' # Do not forget the trailing '/'
subs_urls = config_file["subs_urls"] # 127.0.0.1 if you install subscribe server locally
ns0 = config_file["ns0"] # Name servers
ns1 = config_file["ns1"]
rname = config_file["rname"] # Responsible person (https://tools.ietf.org/html/rfc1035#section-3.3.13)
master_key = config_file["master_key"]
allowed_operations = {
'.' : ['A', 'AAAA', 'TXT', 'MX', 'CAA'],
'*.' : ['A', 'AAAA'],
'pubsub.' : ['A', 'AAAA', 'CNAME'],
'muc.' : ['A', 'AAAA', 'CNAME'],
'vjud.' : ['A', 'AAAA', 'CNAME'],
'xmpp-upload.' : ['A', 'AAAA', 'CNAME'],
'_xmpp-client._tcp.' : ['SRV'],
'_xmpp-server._tcp.' : ['SRV'],
'mail._domainkey.' : ['TXT'],
'_dmarc.' : ['TXT']
}
### Script ###
import os import os
import sys import sys
import psycopg2 import psycopg2
from urllib import urlopen from urllib import urlopen
import json
with open('config.json') as config_file:
config = json.load(config_file)
conf_file = '/etc/bind/named.conf.local' # Include this filename in '/etc/bind/named.conf'
zone_dir = '/var/lib/bind/' # Do not forget the trailing '/'
database = config_file["dabase_url"]
base_url = config_file["base_url"]
ns0 = config_file["ns0"]
ns1 = config_file["ns1"]
rname = config_file["rname"] # Responsible person (https://tools.ietf.org/html/rfc1035#section-3.3.13)
master_key = config_file["master_key"]
dyndns_domains = config_file['dyndns_domains']
allowed_operations = config_files["allowed_operations"]
# Bind configuration with psycopg2.connect(database) as postgresql_connection:
lines = ['// Generated by Dynette CRON']
with psycopg2.connect(postgresql_dsn) as postgresql_connection:
with postgresql_connection.cursor() as psql: with postgresql_connection.cursor() as psql:
# look in the job queue if we have tasks to handle # look in the job queue if we have tasks to handle
need_rewrite = False need_rewrite = False
@ -69,70 +47,68 @@ with psycopg2.connect(postgresql_dsn) as postgresql_connection:
# job could be added just after we read them all # job could be added just after we read them all
psql.execute("DELETE FROM jobqueues;") psql.execute("DELETE FROM jobqueues;")
# Loop through Dynette servers # Init zone for dyndns domains that don't already exists
for url in subs_urls: for domain in dyndns_domains:
if os.path.exists(zone_dir + domain +'.db'):
continue
lines.extend([ db_lines = f"""
'key dynette. {', $ORIGIN .
' algorithm hmac-md5;', $TTL 10 ; 10 seconds
' secret "'+ master_key +'";', {domain}. IN SOA {ns0}. {rname}. (
'};', 18 ; serial
]) 10800 ; refresh (3 hours)
3600 ; retry (1 hour)
604800 ; expire (1 week)
10 ; minimum (10 seconds)
# Get available DynDNS domains $TTL 3600 ; 1 hour
domains = json.loads(str(urlopen(url +'/domains').read())) NS {ns0}.
for domain in domains: NS {ns1}.
# Create zone database if not present $ORIGIN {domain}.
if not os.path.exists(zone_dir + domain +'.db'): """
db_lines = [
'$ORIGIN .',
'$TTL 10 ; 10 seconds',
domain+'. IN SOA '+ ns0 +'. '+ rname +'. (',
' 18 ; serial',
' 10800 ; refresh (3 hours)',
' 3600 ; retry (1 hour)',
' 604800 ; expire (1 week)',
' 10 ; minimum (10 seconds)',
' )',
'$TTL 3600 ; 1 hour',
' NS '+ ns0 +'.',
' NS '+ ns1 +'.',
'',
'$ORIGIN '+ domain +'.',
]
with open(zone_dir + domain +'.db', 'w') as zone: with open(zone_dir + domain +'.db', 'w') as zone:
for line in db_lines: zone.write(db_lines)
zone.write(line + '\n')
lines.extend([ # Update /etc/bind/named.conf.local
'zone "'+ domain +'" {', # that provide permissions for all regirested subdomains on allowed zone file elements
' type master;', # and registers the key for bind9, later used to authenticate nsupdate from the clients
' file "'+ zone_dir + domain +'.db"; ', lines = ['// Generated by Dynette CRON']
' update-policy {', lines.append(f"""
' grant dynette. wildcard *.'+ domain +'. ANY;', key dynette. {
]) algorithm hmac-md5;
secret "{master_key}";
};
""")
for domain in dyndns_domains:
lines.append(f"""
zone "{domain}" {
type master;
file {zone_dir}{domain}.db;
update-policy {
grant dynette. wildcard *.{domain}. ANY;""")
# Get registered sub-domains # Get registered sub-domains
result = json.loads(str(urlopen(url +'/all/'+ domain).read())) registered_subdomains = json.loads(str(urlopen(base_url +'/all/'+ domain).read()))
for entry in result: for entry in registered_subdomains:
for subd, type in allowed_operations.items(): for subd, types in allowed_operations.items():
if subd == '.': subd = '' if subd == '.':
lines.append(' grant '+ entry['subdomain'] +'. name '+ subd + entry['subdomain'] +'. ' + ' '.join(type) +';') subd = ''
all_types = ' '.join(types)
lines.append(f" grant {entry['subdomain']}. name {subd}{entry['subdomain']}. {all_types};")
lines.extend([ lines.append(f"""
' };', };
'};' };""")
'',
])
for entry in result: for entry in registered_subdomains:
lines.extend([ lines.append(f"""
'key '+ entry['subdomain'] +'. {', key {entry['subdomain']}. {
' algorithm ' + entry['key_algo'] + ';', algorithm {entry['key_algo']};
' secret "'+ entry['public_key'] +'";', secret {entry['public_key']};
'};', };
]) """
# update bind9 zone # update bind9 zone
if need_rewrite: if need_rewrite:

View file

@ -21,7 +21,7 @@ rescue => err
end end
DataMapper.setup(:default, ENV['DATABASE_URL'] || config['database_url']) DataMapper.setup(:default, ENV['DATABASE_URL'] || config['database_url'])
DOMAINS = config['domains'] DOMAINS = config['dyndns_domains']
ALLOWED_IP = ["127.0.0.1"] ALLOWED_IP = ["127.0.0.1"]
############### ###############