932d7b40327553a83e5f8c971f6558a4b94d8a11
[samba.git] / source4 / scripting / python / samba_external / dnspython / dns / rdtypes / ANY / NSEC3.py
1 # Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc.
2 #
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose with or without fee is hereby granted,
5 # provided that the above copyright notice and this permission notice
6 # appear in all copies.
7 #
8 # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
9 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
11 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
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 # hash algorithm constants
31 SHA1 = 1
32
33 # flag constants
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):
56         super(NSEC3, self).__init__(rdclass, rdtype)
57         self.algorithm = algorithm
58         self.flags = flags
59         self.iterations = iterations
60         self.salt = salt
61         self.next = next
62         self.windows = 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]
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]
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]
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())