133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright (C) 2001-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 Reck"""DNS rdatasets (an rdataset is a set of rdatas of a given type and class)"""
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport random
1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport StringIO
2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport struct
2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.exception
2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdatatype
2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdataclass
2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.rdata
2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.set
2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# define SimpleSet here for backwards compatibility
2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckSimpleSet = dns.set.Set
3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass DifferingCovers(dns.exception.DNSException):
3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if an attempt is made to add a SIG/RRSIG whose covered type
3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    is not the same as that of the other rdatas in the rdataset."""
3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass IncompatibleTypes(dns.exception.DNSException):
3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if an attempt is made to add rdata of an incompatible type."""
3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass Rdataset(dns.set.Set):
4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """A DNS rdataset.
4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar rdclass: The class of the rdataset
4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type rdclass: int
4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar rdtype: The type of the rdataset
4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type rdtype: int
4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar covers: The covered type.  Usually this value is
4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    dns.rdatatype.RRSIG, then the covers value will be the rdata
5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    type the SIG/RRSIG covers.  The library treats the SIG and RRSIG
5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    types as if they were a family of
5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).  This makes RRSIGs much
5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    easier to work with than if RRSIGs covering different rdata
5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    types were aggregated into a single RRSIG rdataset.
5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type covers: int
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar ttl: The DNS TTL (Time To Live) value
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type ttl: int
5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    __slots__ = ['rdclass', 'rdtype', 'covers', 'ttl']
6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __init__(self, rdclass, rdtype, covers=dns.rdatatype.NONE):
6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Create a new rdataset of the specified class and type.
6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @see: the description of the class instance variables for the
6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        meaning of I{rdclass} and I{rdtype}"""
6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(Rdataset, self).__init__()
6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.rdclass = rdclass
7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.rdtype = rdtype
7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.covers = covers
7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.ttl = 0
7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def _clone(self):
7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        obj = super(Rdataset, self)._clone()
7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        obj.rdclass = self.rdclass
7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        obj.rdtype = self.rdtype
7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        obj.covers = self.covers
7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        obj.ttl = self.ttl
8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return obj
8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def update_ttl(self, ttl):
8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Set the TTL of the rdataset to be the lesser of the set's current
8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        TTL or the specified TTL.  If the set contains no rdatas, set the TTL
8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        to the specified TTL.
8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param ttl: The TTL
8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type ttl: int"""
8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(self) == 0:
9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            self.ttl = ttl
9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        elif ttl < self.ttl:
9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            self.ttl = ttl
9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def add(self, rd, ttl=None):
9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Add the specified rdata to the rdataset.
9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        If the optional I{ttl} parameter is supplied, then
9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.update_ttl(ttl) will be called prior to adding the rdata.
9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param rd: The rdata
10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type rd: dns.rdata.Rdata object
10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param ttl: The TTL
10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type ttl: int"""
10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        #
10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        # If we're adding a signature, do some special handling to
10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        # check that the signature covers the same type as the
10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        # other rdatas in this rdataset.  If this is the first rdata
10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        # in the set, initialize the covers field.
11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        #
11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if self.rdclass != rd.rdclass or self.rdtype != rd.rdtype:
11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise IncompatibleTypes
11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not ttl is None:
11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            self.update_ttl(ttl)
11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if self.rdtype == dns.rdatatype.RRSIG or \
11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck           self.rdtype == dns.rdatatype.SIG:
11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            covers = rd.covers()
11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if len(self) == 0 and self.covers == dns.rdatatype.NONE:
11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                self.covers = covers
12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            elif self.covers != covers:
12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise DifferingCovers
12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0:
12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            self.clear()
12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(Rdataset, self).add(rd)
12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def union_update(self, other):
12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.update_ttl(other.ttl)
12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(Rdataset, self).union_update(other)
12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def intersection_update(self, other):
13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.update_ttl(other.ttl)
13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(Rdataset, self).intersection_update(other)
13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def update(self, other):
13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Add all rdatas in other to self.
13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param other: The rdataset from which to update
13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type other: dns.rdataset.Rdataset object"""
13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.update_ttl(other.ttl)
14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(Rdataset, self).update(other)
14233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __repr__(self):
14433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if self.covers == 0:
14533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            ctext = ''
14633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
14733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            ctext = '(' + dns.rdatatype.to_text(self.covers) + ')'
14833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return '<DNS ' + dns.rdataclass.to_text(self.rdclass) + ' ' + \
14933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck               dns.rdatatype.to_text(self.rdtype) + ctext + ' rdataset>'
15033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __str__(self):
15233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return self.to_text()
15333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __eq__(self, other):
15533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Two rdatasets are equal if they have the same class, type, and
15633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        covers, and contain the same rdata.
15733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: bool"""
15833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not isinstance(other, Rdataset):
16033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return False
16133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if self.rdclass != other.rdclass or \
16233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck           self.rdtype != other.rdtype or \
16333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck           self.covers != other.covers:
16433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return False
16533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return super(Rdataset, self).__eq__(other)
16633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
16733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __ne__(self, other):
16833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return not self.__eq__(other)
16933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_text(self, name=None, origin=None, relativize=True,
17133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                override_rdclass=None, **kw):
17233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Convert the rdataset into DNS master file format.
17333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @see: L{dns.name.Name.choose_relativity} for more information
17533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        on how I{origin} and I{relativize} determine the way names
17633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        are emitted.
17733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        Any additional keyword arguments are passed on to the rdata
17933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        to_text() method.
18033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
18133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param name: If name is not None, emit a RRs with I{name} as
18233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        the owner name.
18333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type name: dns.name.Name object
18433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param origin: The origin for relative names, or None.
18533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type origin: dns.name.Name object
18633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param relativize: True if names should names be relativized
18733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type relativize: bool"""
18833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not name is None:
18933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            name = name.choose_relativity(origin, relativize)
19033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            ntext = str(name)
19133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            pad = ' '
19233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
19333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            ntext = ''
19433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            pad = ''
19533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        s = StringIO.StringIO()
19633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not override_rdclass is None:
19733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdclass = override_rdclass
19833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
19933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdclass = self.rdclass
20033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(self) == 0:
20133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            #
20233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            # Empty rdatasets are used for the question section, and in
20333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            # some dynamic updates, so we don't need to print out the TTL
20433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            # (which is meaningless anyway).
20533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            #
20633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            print >> s, '%s%s%s %s' % (ntext, pad,
20733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                       dns.rdataclass.to_text(rdclass),
20833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                       dns.rdatatype.to_text(self.rdtype))
20933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
21033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            for rd in self:
21133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                print >> s, '%s%s%d %s %s %s' % \
21233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                      (ntext, pad, self.ttl, dns.rdataclass.to_text(rdclass),
21333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                       dns.rdatatype.to_text(self.rdtype),
21433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                       rd.to_text(origin=origin, relativize=relativize, **kw))
21533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        #
21633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        # We strip off the final \n for the caller's convenience in printing
21733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        #
21833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return s.getvalue()[:-1]
21933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
22033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_wire(self, name, file, compress=None, origin=None,
22133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                override_rdclass=None, want_shuffle=True):
22233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Convert the rdataset to wire format.
22333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
22433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param name: The owner name of the RRset that will be emitted
22533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type name: dns.name.Name object
22633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param file: The file to which the wire format data will be appended
22733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type file: file
22833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param compress: The compression table to use; the default is None.
22933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type compress: dict
23033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param origin: The origin to be appended to any relative names when
23133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        they are emitted.  The default is None.
23233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @returns: the number of records emitted
23333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: int
23433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
23533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
23633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not override_rdclass is None:
23733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdclass =  override_rdclass
23833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            want_shuffle = False
23933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
24033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            rdclass = self.rdclass
24133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        file.seek(0, 2)
24233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(self) == 0:
24333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            name.to_wire(file, compress, origin)
24433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            stuff = struct.pack("!HHIH", self.rdtype, rdclass, 0, 0)
24533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            file.write(stuff)
24633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return 1
24733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
24833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if want_shuffle:
24933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                l = list(self)
25033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                random.shuffle(l)
25133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            else:
25233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                l = self
25333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            for rd in l:
25433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                name.to_wire(file, compress, origin)
25533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                stuff = struct.pack("!HHIH", self.rdtype, rdclass,
25633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                    self.ttl, 0)
25733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                file.write(stuff)
25833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                start = file.tell()
25933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                rd.to_wire(file, compress, origin)
26033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                end = file.tell()
26133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                assert end - start < 65536
26233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                file.seek(start - 2)
26333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                stuff = struct.pack("!H", end - start)
26433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                file.write(stuff)
26533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                file.seek(0, 2)
26633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return len(self)
26733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
26833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def match(self, rdclass, rdtype, covers):
26933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Returns True if this rdataset matches the specified class, type,
27033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        and covers"""
27133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if self.rdclass == rdclass and \
27233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck           self.rdtype == rdtype and \
27333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck           self.covers == covers:
27433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return True
27533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return False
27633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
27733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef from_text_list(rdclass, rdtype, ttl, text_rdatas):
27833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Create an rdataset with the specified class, type, and TTL, and with
27933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    the specified list of rdatas in text format.
28033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
28133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: dns.rdataset.Rdataset object
28233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
28333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
28433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if isinstance(rdclass, str):
28533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        rdclass = dns.rdataclass.from_text(rdclass)
28633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if isinstance(rdtype, str):
28733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        rdtype = dns.rdatatype.from_text(rdtype)
28833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    r = Rdataset(rdclass, rdtype)
28933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    r.update_ttl(ttl)
29033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    for t in text_rdatas:
29133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        rd = dns.rdata.from_text(r.rdclass, r.rdtype, t)
29233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        r.add(rd)
29333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return r
29433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
29533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef from_text(rdclass, rdtype, ttl, *text_rdatas):
29633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Create an rdataset with the specified class, type, and TTL, and with
29733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    the specified rdatas in text format.
29833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
29933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: dns.rdataset.Rdataset object
30033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
30133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
30233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return from_text_list(rdclass, rdtype, ttl, text_rdatas)
30333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
30433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef from_rdata_list(ttl, rdatas):
30533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Create an rdataset with the specified TTL, and with
30633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    the specified list of rdata objects.
30733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
30833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: dns.rdataset.Rdataset object
30933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
31033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
31133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if len(rdatas) == 0:
31233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise ValueError("rdata list must not be empty")
31333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    r = None
31433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    for rd in rdatas:
31533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if r is None:
31633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            r = Rdataset(rd.rdclass, rd.rdtype)
31733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            r.update_ttl(ttl)
31833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            first_time = False
31933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        r.add(rd)
32033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return r
32133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
32233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef from_rdata(ttl, *rdatas):
32333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Create an rdataset with the specified TTL, and with
32433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    the specified rdata objects.
32533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
32633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: dns.rdataset.Rdataset object
32733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
32833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
32933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return from_rdata_list(ttl, rdatas)
330