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
======================
**Note: Tested on Debian wheezy and YunoHost 2.4 (should work on Ubuntu)**
Setup quickly
-------------------------------
You can use the dynette_ynh package for YunoHost
https://github.com/YunoHost-Apps/dynette_ynh
Web subscribe server deployment
-------------------------------

View file

@ -1,9 +1,21 @@
{
"database_url": "postgres://{{ db_user }}:{{ db_password }}@localhost/{{ db_name }}",
"domains" : [ {{ subdomains }} ],
"subs_url" : [ https://{{ dynette_domain }} ],
"ns0" : {{ ns0 }},
"ns1" : {{ ns1 }},
"rname" : {{ rname }},
"master_key" : {{ master_key }}
"database_url" : "postgres://{{ db_user }}:{{ db_password }}@localhost/{{ db_name }}",
"dyndns_domains" : [ {{ subdomains }} ],
"base_url" : "https://{{ dynette_domain }}",
"ns0" : "{{ ns0 }}",
"ns1" : "{{ ns1 }}",
"rname" : "{{ rname }}",
"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
### 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 ###
#!/usr/bin/python3
import os
import sys
import psycopg2
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
lines = ['// Generated by Dynette CRON']
with psycopg2.connect(postgresql_dsn) as postgresql_connection:
with psycopg2.connect(database) as postgresql_connection:
with postgresql_connection.cursor() as psql:
# look in the job queue if we have tasks to handle
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
psql.execute("DELETE FROM jobqueues;")
# Loop through Dynette servers
for url in subs_urls:
# Init zone for dyndns domains that don't already exists
for domain in dyndns_domains:
if os.path.exists(zone_dir + domain +'.db'):
continue
lines.extend([
'key dynette. {',
' algorithm hmac-md5;',
' secret "'+ master_key +'";',
'};',
])
db_lines = f"""
$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)
# Get available DynDNS domains
domains = json.loads(str(urlopen(url +'/domains').read()))
for domain in domains:
$TTL 3600 ; 1 hour
NS {ns0}.
NS {ns1}.
# Create zone database if not present
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:
for line in db_lines:
zone.write(line + '\n')
$ORIGIN {domain}.
"""
with open(zone_dir + domain +'.db', 'w') as zone:
zone.write(db_lines)
lines.extend([
'zone "'+ domain +'" {',
' type master;',
' file "'+ zone_dir + domain +'.db"; ',
' update-policy {',
' grant dynette. wildcard *.'+ domain +'. ANY;',
])
# Update /etc/bind/named.conf.local
# that provide permissions for all regirested subdomains on allowed zone file elements
# and registers the key for bind9, later used to authenticate nsupdate from the clients
lines = ['// Generated by Dynette CRON']
lines.append(f"""
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
result = json.loads(str(urlopen(url +'/all/'+ domain).read()))
for entry in result:
for subd, type in allowed_operations.items():
if subd == '.': subd = ''
lines.append(' grant '+ entry['subdomain'] +'. name '+ subd + entry['subdomain'] +'. ' + ' '.join(type) +';')
# Get registered sub-domains
registered_subdomains = json.loads(str(urlopen(base_url +'/all/'+ domain).read()))
for entry in registered_subdomains:
for subd, types in allowed_operations.items():
if subd == '.':
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:
lines.extend([
'key '+ entry['subdomain'] +'. {',
' algorithm ' + entry['key_algo'] + ';',
' secret "'+ entry['public_key'] +'";',
'};',
])
for entry in registered_subdomains:
lines.append(f"""
key {entry['subdomain']}. {
algorithm {entry['key_algo']};
secret {entry['public_key']};
};
"""
# update bind9 zone
if need_rewrite:

View file

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