validate hostnames
[zonemaker.git] / zonemaker / zone.py
1 import ipaddress, re
2
3 second = 1
4 minute = 60*second
5 hour = 60*minute
6 day = 24*hour
7
8 def hostname(name):
9     # check hostname for validity
10     label = r'[a-zA-Z90-9]([a-zA-Z90-9-]{0,61}[a-zA-Z90-9])?' # must not start or end with hyphen
11     pattern = r'^{0}(\.{0})*\.?'.format(label)
12     print(pattern)
13     if re.match(pattern, name):
14         return name
15     raise Exception(name+" is not a valid hostname")
16
17 class Address:
18     def __init__(self, IPv4 = None, IPv6 = None):
19         self._IPv4 = None if IPv4 is None else ipaddress.IPv4Address(IPv4)
20         self._IPv6 = None if IPv6 is None else ipaddress.IPv6Address(IPv6)
21     
22     def IPv4(self):
23         return Address(IPv4 = self._IPv4)
24     
25     def IPv6(self):
26         return Address(IPv6 = self._IPv6)
27
28 class Name:
29     def __init__(self, address = None, MX = None, TCP = None, UDP = None):
30         self._address = address
31
32 class Service:
33     def __init__(self, SRV = None, TLSA=None):
34         self._SRV = SRV
35         self._TLSA = TLSA
36
37 class CName:
38     def __init__(self, name):
39         self._name = name
40
41 class Delegation():
42     def __init__(self, NS, DS = None):
43         pass
44
45 class Zone:
46     def __init__(self, name, mail, NS,
47                  secondary_refresh, secondary_retry, secondary_discard,
48                  NX_TTL = None, A_TTL = None, other_TTL = None,
49                  domains = []):
50         self._name = hostname(name)
51         assert mail.endswith('.'), "Mail must be absolute, end with a dot"
52         atpos = mail.find('@')
53         assert atpos >= 0 and atpos < mail.find('.'), "Mail must contain an @ before the first dot"
54         self._mail = hostname(mail.replace('@', '.', 1))
55         self._NS = list(map(hostname, NS))
56         
57         self._secondary_refresh = secondary_refresh
58         self._secondary_retry = secondary_retry
59         self._secondary_discard = secondary_discard
60         
61         assert other_TTL is not None
62         self._NX_TTL = other_TTL if NX_TTL is None else NX_TTL
63         self._A_TTL = other_TTL if A_TTL is None else A_TTL
64         self._other_TTL = other_TTL
65     
66     def write(self, file):
67         raise NotImplementedError()