133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright (C) 2004-2007, 2009, 2010 Nominum, Inc.
233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck#
333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Permission to use, copy, modify, and distribute this software and its
433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# documentation for any purpose with or without fee is hereby granted,
533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# provided that the above copyright notice and this permission notice
633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# appear in all copies.
733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck#
833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport cStringIO
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.exception
1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdata
2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdatatype
2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.name
2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass NSEC(dns.rdata.Rdata):
2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """NSEC record
2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar next: the next name
2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type next: dns.name.Name object
2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar windows: the windowed bitmap list
2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type windows: list of (window number, string) tuples"""
3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    __slots__ = ['next', 'windows']
3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __init__(self, rdclass, rdtype, next, windows):
3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(NSEC, self).__init__(rdclass, rdtype)
3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.next = next
3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.windows = windows
3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_text(self, origin=None, relativize=True, **kw):
3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        next = self.next.choose_relativity(origin, relativize)
4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        text = ''
4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for (window, bitmap) in self.windows:
4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            bits = []
4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            for i in xrange(0, len(bitmap)):
4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                byte = ord(bitmap[i])
4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                for j in xrange(0, 8):
4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if byte & (0x80 >> j):
4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        bits.append(dns.rdatatype.to_text(window * 256 + \
4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                                          i * 8 + j))
4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            text += (' ' + ' '.join(bits))
5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return '%s%s' % (next, text)
5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        next = tok.get_name()
5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        next = next.choose_relativity(origin, relativize)
5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        rdtypes = []
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        while 1:
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            token = tok.get().unescape()
5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if token.is_eol_or_eof():
5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                break
6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            nrdtype = dns.rdatatype.from_text(token.value)
6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if nrdtype == 0:
6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise dns.exception.SyntaxError("NSEC with bit 0")
6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if nrdtype > 65535:
6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise dns.exception.SyntaxError("NSEC with bit > 65535")
6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdtypes.append(nrdtype)
6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        rdtypes.sort()
6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        window = 0
6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        octets = 0
6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        prior_rdtype = 0
7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        bitmap = ['\0'] * 32
7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        windows = []
7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for nrdtype in rdtypes:
7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if nrdtype == prior_rdtype:
7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                continue
7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            prior_rdtype = nrdtype
7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            new_window = nrdtype // 256
7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if new_window != window:
7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                windows.append((window, ''.join(bitmap[0:octets])))
7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                bitmap = ['\0'] * 32
8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                window = new_window
8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            offset = nrdtype % 256
8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            byte = offset / 8
8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            bit = offset % 8
8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            octets = byte + 1
8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit))
8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        windows.append((window, ''.join(bitmap[0:octets])))
8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return cls(rdclass, rdtype, next, windows)
8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    from_text = classmethod(from_text)
9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_wire(self, file, compress = None, origin = None):
9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.next.to_wire(file, None, origin)
9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for (window, bitmap) in self.windows:
9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            file.write(chr(window))
9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            file.write(chr(len(bitmap)))
9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            file.write(bitmap)
9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        (next, cused) = dns.name.from_wire(wire[: current + rdlen], current)
10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        current += cused
10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        rdlen -= cused
10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        windows = []
10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        while rdlen > 0:
10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if rdlen < 3:
10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise dns.exception.FormError("NSEC too short")
10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            window = ord(wire[current])
10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            octets = ord(wire[current + 1])
10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if octets == 0 or octets > 32:
10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise dns.exception.FormError("bad NSEC octets")
11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            current += 2
11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdlen -= 2
11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if rdlen < octets:
11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise dns.exception.FormError("bad NSEC bitmap length")
11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            bitmap = wire[current : current + octets]
11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            current += octets
11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdlen -= octets
11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            windows.append((window, bitmap))
11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not origin is None:
11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            next = next.relativize(origin)
12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return cls(rdclass, rdtype, next, windows)
12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    from_wire = classmethod(from_wire)
12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def choose_relativity(self, origin = None, relativize = True):
12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.next = self.next.choose_relativity(origin, relativize)
12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def _cmp(self, other):
12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        v = cmp(self.next, other.next)
12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if v == 0:
13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            b1 = cStringIO.StringIO()
13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            for (window, bitmap) in self.windows:
13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                b1.write(chr(window))
13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                b1.write(chr(len(bitmap)))
13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                b1.write(bitmap)
13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            b2 = cStringIO.StringIO()
13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            for (window, bitmap) in other.windows:
13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                b2.write(chr(window))
13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                b2.write(chr(len(bitmap)))
13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                b2.write(bitmap)
14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            v = cmp(b1.getvalue(), b2.getvalue())
14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return v
142