968b36f5e23f09d77fde0c0ee0187db2345eb78c
[vlendec/samba-autobuild/.git] / third_party / dnspython / dns / rdtypes / ANY / HIP.py
1 # Copyright (C) 2010, 2011 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 cStringIO
17 import string
18 import struct
19
20 import dns.exception
21 import dns.rdata
22 import dns.rdatatype
23
24 class HIP(dns.rdata.Rdata):
25     """HIP record
26
27     @ivar hit: the host identity tag
28     @type hit: string
29     @ivar algorithm: the public key cryptographic algorithm
30     @type algorithm: int
31     @ivar key: the public key
32     @type key: string
33     @ivar servers: the rendezvous servers
34     @type servers: list of dns.name.Name objects
35     @see: RFC 5205"""
36
37     __slots__ = ['hit', 'algorithm', 'key', 'servers']
38
39     def __init__(self, rdclass, rdtype, hit, algorithm, key, servers):
40         super(HIP, self).__init__(rdclass, rdtype)
41         self.hit = hit
42         self.algorithm = algorithm
43         self.key = key
44         self.servers = servers
45
46     def to_text(self, origin=None, relativize=True, **kw):
47         hit = self.hit.encode('hex-codec')
48         key = self.key.encode('base64-codec').replace('\n', '')
49         text = ''
50         servers = []
51         for server in self.servers:
52             servers.append(str(server.choose_relativity(origin, relativize)))
53         if len(servers) > 0:
54             text += (' ' + ' '.join(servers))
55         return '%u %s %s%s' % (self.algorithm, hit, key, text)
56
57     def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
58         algorithm = tok.get_uint8()
59         hit = tok.get_string().decode('hex-codec')
60         if len(hit) > 255:
61             raise dns.exception.SyntaxError("HIT too long")
62         key = tok.get_string().decode('base64-codec')
63         servers = []
64         while 1:
65             token = tok.get()
66             if token.is_eol_or_eof():
67                 break
68             server = dns.name.from_text(token.value, origin)
69             server.choose_relativity(origin, relativize)
70             servers.append(server)
71         return cls(rdclass, rdtype, hit, algorithm, key, servers)
72
73     from_text = classmethod(from_text)
74
75     def to_wire(self, file, compress = None, origin = None):
76         lh = len(self.hit)
77         lk = len(self.key)
78         file.write(struct.pack("!BBH", lh, self.algorithm, lk))
79         file.write(self.hit)
80         file.write(self.key)
81         for server in self.servers:
82             server.to_wire(file, None, origin)
83
84     def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
85         (lh, algorithm, lk) = struct.unpack('!BBH',
86                                             wire[current : current + 4])
87         current += 4
88         rdlen -= 4
89         hit = wire[current : current + lh].unwrap()
90         current += lh
91         rdlen -= lh
92         key = wire[current : current + lk].unwrap()
93         current += lk
94         rdlen -= lk
95         servers = []
96         while rdlen > 0:
97             (server, cused) = dns.name.from_wire(wire[: current + rdlen],
98                                                  current)
99             current += cused
100             rdlen -= cused
101             if not origin is None:
102                 server = server.relativize(origin)
103             servers.append(server)
104         return cls(rdclass, rdtype, hit, algorithm, key, servers)
105
106     from_wire = classmethod(from_wire)
107
108     def choose_relativity(self, origin = None, relativize = True):
109         servers = []
110         for server in self.servers:
111             server = server.choose_relativity(origin, relativize)
112             servers.append(server)
113         self.servers = servers
114
115     def _cmp(self, other):
116         b1 = cStringIO.StringIO()
117         lh = len(self.hit)
118         lk = len(self.key)
119         b1.write(struct.pack("!BBH", lh, self.algorithm, lk))
120         b1.write(self.hit)
121         b1.write(self.key)
122         b2 = cStringIO.StringIO()
123         lh = len(other.hit)
124         lk = len(other.key)
125         b2.write(struct.pack("!BBH", lh, other.algorithm, lk))
126         b2.write(other.hit)
127         b2.write(other.key)
128         v = cmp(b1.getvalue(), b2.getvalue())
129         if v != 0:
130             return v
131         ls = len(self.servers)
132         lo = len(other.servers)
133         count = min(ls, lo)
134         i = 0
135         while i < count:
136             v = cmp(self.servers[i], other.servers[i])
137             if v != 0:
138                 return v
139             i += 1
140         return ls - lo