133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright (C) 2003-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 struct
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.exception
1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.name
2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdata
2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef _write_string(file, s):
2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    l = len(s)
2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    assert l < 256
2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    byte = chr(l)
2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    file.write(byte)
2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    file.write(s)
2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass NAPTR(dns.rdata.Rdata):
3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """NAPTR record
3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar order: order
3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type order: int
3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar preference: preference
3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type preference: int
3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar flags: flags
3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type flags: string
3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar service: service
3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type service: string
4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar regexp: regular expression
4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type regexp: string
4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar replacement: replacement name
4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type replacement: dns.name.Name object
4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @see: RFC 3403"""
4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    __slots__ = ['order', 'preference', 'flags', 'service', 'regexp',
4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                 'replacement']
4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __init__(self, rdclass, rdtype, order, preference, flags, service,
5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                 regexp, replacement):
5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(NAPTR, self).__init__(rdclass, rdtype)
5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.order = order
5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.preference = preference
5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.flags = flags
5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.service = service
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.regexp = regexp
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.replacement = replacement
5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_text(self, origin=None, relativize=True, **kw):
6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        replacement = self.replacement.choose_relativity(origin, relativize)
6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return '%d %d "%s" "%s" "%s" %s' % \
6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck               (self.order, self.preference,
6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                dns.rdata._escapify(self.flags),
6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                dns.rdata._escapify(self.service),
6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                dns.rdata._escapify(self.regexp),
6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                self.replacement)
6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        order = tok.get_uint16()
7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        preference = tok.get_uint16()
7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        flags = tok.get_string()
7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        service = tok.get_string()
7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        regexp = tok.get_string()
7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        replacement = tok.get_name()
7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        replacement = replacement.choose_relativity(origin, relativize)
7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        tok.get_eol()
7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return cls(rdclass, rdtype, order, preference, flags, service,
7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                   regexp, replacement)
7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    from_text = classmethod(from_text)
8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_wire(self, file, compress = None, origin = None):
8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        two_ints = struct.pack("!HH", self.order, self.preference)
8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        file.write(two_ints)
8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        _write_string(file, self.flags)
8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        _write_string(file, self.service)
8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        _write_string(file, self.regexp)
8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.replacement.to_wire(file, compress, origin)
8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        (order, preference) = struct.unpack('!HH', wire[current : current + 4])
9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        current += 4
9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        rdlen -= 4
9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        strings = []
9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for i in xrange(3):
9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l = ord(wire[current])
9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            current += 1
9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdlen -= 1
9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if l > rdlen or rdlen < 0:
10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise dns.exception.FormError
10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            s = wire[current : current + l]
10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            current += l
10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdlen -= l
10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            strings.append(s)
10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        (replacement, cused) = dns.name.from_wire(wire[: current + rdlen],
10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                                  current)
10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if cused != rdlen:
10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise dns.exception.FormError
10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not origin is None:
11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            replacement = replacement.relativize(origin)
11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return cls(rdclass, rdtype, order, preference, strings[0], strings[1],
11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                   strings[2], replacement)
11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    from_wire = classmethod(from_wire)
11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def choose_relativity(self, origin = None, relativize = True):
11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.replacement = self.replacement.choose_relativity(origin,
11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                                              relativize)
11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def _cmp(self, other):
12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        sp = struct.pack("!HH", self.order, self.preference)
12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        op = struct.pack("!HH", other.order, other.preference)
12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        v = cmp(sp, op)
12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if v == 0:
12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            v = cmp(self.flags, other.flags)
12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if v == 0:
12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                v = cmp(self.service, other.service)
12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if v == 0:
12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    v = cmp(self.regexp, other.regexp)
13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if v == 0:
13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        v = cmp(self.replacement, other.replacement)
13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return v
133