1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import base64
17 import binascii
18 import string
19 import struct
20
21 import dns.exception
22 import dns.rdata
23 import dns.rdatatype
24 from dns._compat import xrange, text_type
25
26 try:
27 b32_hex_to_normal = string.maketrans('0123456789ABCDEFGHIJKLMNOPQRSTUV',
28 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')
29 b32_normal_to_hex = string.maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
30 '0123456789ABCDEFGHIJKLMNOPQRSTUV')
31 except AttributeError:
32 b32_hex_to_normal = bytes.maketrans(b'0123456789ABCDEFGHIJKLMNOPQRSTUV',
33 b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')
34 b32_normal_to_hex = bytes.maketrans(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
35 b'0123456789ABCDEFGHIJKLMNOPQRSTUV')
36
37
38 SHA1 = 1
39
40
41 OPTOUT = 1
42
43
44 -class NSEC3(dns.rdata.Rdata):
45
46 """NSEC3 record
47
48 @ivar algorithm: the hash algorithm number
49 @type algorithm: int
50 @ivar flags: the flags
51 @type flags: int
52 @ivar iterations: the number of iterations
53 @type iterations: int
54 @ivar salt: the salt
55 @type salt: string
56 @ivar next: the next name hash
57 @type next: string
58 @ivar windows: the windowed bitmap list
59 @type windows: list of (window number, string) tuples"""
60
61 __slots__ = ['algorithm', 'flags', 'iterations', 'salt', 'next', 'windows']
62
63 - def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt,
64 next, windows):
75
76 - def to_text(self, origin=None, relativize=True, **kw):
77 next = base64.b32encode(self.next).translate(
78 b32_normal_to_hex).lower().decode()
79 if self.salt == b'':
80 salt = '-'
81 else:
82 salt = binascii.hexlify(self.salt).decode()
83 text = u''
84 for (window, bitmap) in self.windows:
85 bits = []
86 for i in xrange(0, len(bitmap)):
87 byte = bitmap[i]
88 for j in xrange(0, 8):
89 if byte & (0x80 >> j):
90 bits.append(dns.rdatatype.to_text(window * 256 +
91 i * 8 + j))
92 text += (u' ' + u' '.join(bits))
93 return u'%u %u %u %s %s%s' % (self.algorithm, self.flags,
94 self.iterations, salt, next, text)
95
96 @classmethod
97 - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
98 algorithm = tok.get_uint8()
99 flags = tok.get_uint8()
100 iterations = tok.get_uint16()
101 salt = tok.get_string()
102 if salt == u'-':
103 salt = b''
104 else:
105 salt = binascii.unhexlify(salt.encode('ascii'))
106 next = tok.get_string().encode(
107 'ascii').upper().translate(b32_hex_to_normal)
108 next = base64.b32decode(next)
109 rdtypes = []
110 while 1:
111 token = tok.get().unescape()
112 if token.is_eol_or_eof():
113 break
114 nrdtype = dns.rdatatype.from_text(token.value)
115 if nrdtype == 0:
116 raise dns.exception.SyntaxError("NSEC3 with bit 0")
117 if nrdtype > 65535:
118 raise dns.exception.SyntaxError("NSEC3 with bit > 65535")
119 rdtypes.append(nrdtype)
120 rdtypes.sort()
121 window = 0
122 octets = 0
123 prior_rdtype = 0
124 bitmap = bytearray(b'\0' * 32)
125 windows = []
126 for nrdtype in rdtypes:
127 if nrdtype == prior_rdtype:
128 continue
129 prior_rdtype = nrdtype
130 new_window = nrdtype // 256
131 if new_window != window:
132 if octets != 0:
133 windows.append((window, ''.join(bitmap[0:octets])))
134 bitmap = bytearray(b'\0' * 32)
135 window = new_window
136 offset = nrdtype % 256
137 byte = offset // 8
138 bit = offset % 8
139 octets = byte + 1
140 bitmap[byte] = bitmap[byte] | (0x80 >> bit)
141 if octets != 0:
142 windows.append((window, bitmap[0:octets]))
143 return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
144 windows)
145
146 - def to_wire(self, file, compress=None, origin=None):
147 l = len(self.salt)
148 file.write(struct.pack("!BBHB", self.algorithm, self.flags,
149 self.iterations, l))
150 file.write(self.salt)
151 l = len(self.next)
152 file.write(struct.pack("!B", l))
153 file.write(self.next)
154 for (window, bitmap) in self.windows:
155 file.write(struct.pack("!BB", window, len(bitmap)))
156 file.write(bitmap)
157
158 @classmethod
159 - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
160 (algorithm, flags, iterations, slen) = \
161 struct.unpack('!BBHB', wire[current: current + 5])
162
163 current += 5
164 rdlen -= 5
165 salt = wire[current: current + slen].unwrap()
166 current += slen
167 rdlen -= slen
168 nlen = wire[current]
169 current += 1
170 rdlen -= 1
171 next = wire[current: current + nlen].unwrap()
172 current += nlen
173 rdlen -= nlen
174 windows = []
175 while rdlen > 0:
176 if rdlen < 3:
177 raise dns.exception.FormError("NSEC3 too short")
178 window = wire[current]
179 octets = wire[current + 1]
180 if octets == 0 or octets > 32:
181 raise dns.exception.FormError("bad NSEC3 octets")
182 current += 2
183 rdlen -= 2
184 if rdlen < octets:
185 raise dns.exception.FormError("bad NSEC3 bitmap length")
186 bitmap = bytearray(wire[current: current + octets].unwrap())
187 current += octets
188 rdlen -= octets
189 windows.append((window, bitmap))
190 return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
191 windows)
192