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