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