1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
"""Regexes used in the DNS protocol"""
def grpm(regex):
"""Make a matching group"""
return grp(regex, matching=True)
def grp(regex, matching=False):
"""Make a group"""
return r'(' + (r'' if matching else r'?:') + regex + r')'
def opt(regex):
"""Make an optional group"""
return grp(grp(regex) + r'?')
def regex_opt_r(*regexes):
"""Make a group that matches one of the given regexes"""
return grp(r'|'.join(regexes))
DIGIT = r'\d'
LETTER = r'[a-zA-Z]'
LETDIG = grp(regex_opt_r(DIGIT, LETTER))
LETDIGHYP = grp(regex_opt_r(LETDIG, r'-'))
LDHSTR = grp(LETDIGHYP + r'+')
LABEL = grp(LETTER + opt(opt(LDHSTR) + LETDIG))
SUBDOMAIN = grp(grpm(grp(LABEL + r'\.') + r'*') + grpm(LABEL))
DOMAIN = regex_opt_r(SUBDOMAIN, r' ')
# Fast, non-matching domain
_DOMAIN = r'(?:(?:[a-zA-Z](?:[a-zA-Z\d\-]*[a-zA-Z\d])?\.)*)?'
IP = r'(?:(?:\d{1,3}\.){3}\d{1,3})'
CLASS = regex_opt_r(r'IN', r'CH')
TYPE = regex_opt_r(r'A', r'CNAME', r'HINFO', r'MX', r'NS', r'PTR', r'SOA')
TTL = r'\d+'
RDATA = r'.*?'
RR = regex_opt_r(
grp(grpm(TTL) + r'\s+' + opt(grpm(CLASS))),
grp(grpm(CLASS) + r'\s+' + opt(grpm(TTL)))
) + r'\s+' + grpm(TYPE) + r'\s+' + grpm(RDATA) + r'\s*(?:(?<!\\);)?\s*$'
ZONE_LINE_DOMAIN = r'^' + grpm(_DOMAIN) + r'\s+' + RR
|