133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright (C) 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 Reckimport string 1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport struct 1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.exception 2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdata 2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdatatype 2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass HIP(dns.rdata.Rdata): 2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """HIP record 2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @ivar hit: the host identity tag 2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @type hit: string 2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @ivar algorithm: the public key cryptographic algorithm 3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @type algorithm: int 3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @ivar key: the public key 3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @type key: string 3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @ivar servers: the rendezvous servers 3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @type servers: list of dns.name.Name objects 3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @see: RFC 5205""" 3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck __slots__ = ['hit', 'algorithm', 'key', 'servers'] 3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def __init__(self, rdclass, rdtype, hit, algorithm, key, servers): 4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck super(HIP, self).__init__(rdclass, rdtype) 4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.hit = hit 4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.algorithm = algorithm 4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.key = key 4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.servers = servers 4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def to_text(self, origin=None, relativize=True, **kw): 4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck hit = self.hit.encode('hex-codec') 4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck key = self.key.encode('base64-codec').replace('\n', '') 4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck text = '' 5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers = [] 5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for server in self.servers: 5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers.append(str(server.choose_relativity(origin, relativize))) 5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if len(servers) > 0: 5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck text += (' ' + ' '.join(servers)) 5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return '%u %s %s%s' % (self.algorithm, hit, key, text) 5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): 5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck algorithm = tok.get_uint8() 5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck hit = tok.get_string().decode('hex-codec') 6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if len(hit) > 255: 6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise dns.exception.SyntaxError("HIT too long") 6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck key = tok.get_string().decode('base64-codec') 6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers = [] 6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck while 1: 6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck token = tok.get() 6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if token.is_eol_or_eof(): 6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck break 6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server = dns.name.from_text(token.value, origin) 6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server.choose_relativity(origin, relativize) 7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers.append(server) 7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return cls(rdclass, rdtype, hit, algorithm, key, servers) 7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck from_text = classmethod(from_text) 7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def to_wire(self, file, compress = None, origin = None): 7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lh = len(self.hit) 7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lk = len(self.key) 7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck file.write(struct.pack("!BBH", lh, self.algorithm, lk)) 7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck file.write(self.hit) 8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck file.write(self.key) 8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for server in self.servers: 8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server.to_wire(file, None, origin) 8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): 8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck (lh, algorithm, lk) = struct.unpack('!BBH', 8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck wire[current : current + 4]) 8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck current += 4 8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck rdlen -= 4 8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck hit = wire[current : current + lh] 9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck current += lh 9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck rdlen -= lh 9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck key = wire[current : current + lk] 9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck current += lk 9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck rdlen -= lk 9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers = [] 9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck while rdlen > 0: 9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck (server, cused) = dns.name.from_wire(wire[: current + rdlen], 9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck current) 9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck current += cused 10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck rdlen -= cused 10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not origin is None: 10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server = server.relativize(origin) 10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers.append(server) 10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return cls(rdclass, rdtype, hit, algorithm, key, servers) 10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck from_wire = classmethod(from_wire) 10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def choose_relativity(self, origin = None, relativize = True): 10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers = [] 11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for server in self.servers: 11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server = server.choose_relativity(origin, relativize) 11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck servers.append(server) 11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.servers = servers 11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def _cmp(self, other): 11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b1 = cStringIO.StringIO() 11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lh = len(self.hit) 11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lk = len(self.key) 11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b1.write(struct.pack("!BBH", lh, self.algorithm, lk)) 12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b1.write(self.hit) 12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b1.write(self.key) 12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b2 = cStringIO.StringIO() 12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lh = len(other.hit) 12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lk = len(other.key) 12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b2.write(struct.pack("!BBH", lh, other.algorithm, lk)) 12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b2.write(other.hit) 12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck b2.write(other.key) 12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck v = cmp(b1.getvalue(), b2.getvalue()) 12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if v != 0: 13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return v 13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ls = len(self.servers) 13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lo = len(other.servers) 13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck count = min(ls, lo) 13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck i = 0 13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck while i < count: 13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck v = cmp(self.servers[i], other.servers[i]) 13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if v != 0: 13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return v 13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck i += 1 14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return ls - lo 141