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