Beispiel #1
0
def to_address(name):
    """Convert a reverse map domain name into textual address form.
    @param name: an IPv4 or IPv6 address in reverse-map form.
    @type name: thirdparty.dns.name.Name object
    @rtype: str
    """
    if name.is_subdomain(ipv4_reverse_domain):
        name = name.relativize(ipv4_reverse_domain)
        labels = list(name.labels)
        labels.reverse()
        text = b'.'.join(labels)
        # run through inet_aton() to check syntax and make pretty.
        return thirdparty.dns.ipv4.inet_ntoa(
            thirdparty.dns.ipv4.inet_aton(text))
    elif name.is_subdomain(ipv6_reverse_domain):
        name = name.relativize(ipv6_reverse_domain)
        labels = list(name.labels)
        labels.reverse()
        parts = []
        i = 0
        l = len(labels)
        while i < l:
            parts.append(b''.join(labels[i:i + 4]))
            i += 4
        text = b':'.join(parts)
        # run through inet_aton() to check syntax and make pretty.
        return thirdparty.dns.ipv6.inet_ntoa(
            thirdparty.dns.ipv6.inet_aton(text))
    else:
        raise thirdparty.dns.exception.SyntaxError(
            'unknown reverse-map address family')
Beispiel #2
0
def to_e164(name, origin=public_enum_domain, want_plus_prefix=True):
    """Convert an ENUM domain name into an E.164 number.

    Note that dnspython does not have any information about preferred
    number formats within national numbering plans, so all numbers are
    emitted as a simple string of digits, prefixed by a '+' (unless
    *want_plus_prefix* is ``False``).

    *name* is a ``thirdparty.dns.name.Name``, the ENUM domain name.

    *origin* is a ``thirdparty.dns.name.Name``, a domain containing the ENUM
    domain name.  The name is relativized to this domain before being
    converted to text.  If ``None``, no relativization is done.

    *want_plus_prefix* is a ``bool``.  If True, add a '+' to the beginning of
    the returned number.

    Returns a ``str``.

    """
    if origin is not None:
        name = name.relativize(origin)
    dlabels = [d for d in name.labels if d.isdigit() and len(d) == 1]
    if len(dlabels) != len(name.labels):
        raise thirdparty.dns.exception.SyntaxError(
            'non-digit labels in ENUM domain name')
    dlabels.reverse()
    text = b''.join(dlabels)
    if want_plus_prefix:
        text = b'+' + text
    return text.decode()
Beispiel #3
0
 def _validate_name(self, name):
     if isinstance(name, string_types):
         name = thirdparty.dns.name.from_text(name, None)
     elif not isinstance(name, thirdparty.dns.name.Name):
         raise KeyError("name parameter must be convertible to a DNS name")
     if name.is_absolute():
         if not name.is_subdomain(self.origin):
             raise KeyError(
                 "name parameter must be a subdomain of the zone origin")
         if self.relativize:
             name = name.relativize(self.origin)
     return name
Beispiel #4
0
def to_address(name,
               v4_origin=ipv4_reverse_domain,
               v6_origin=ipv6_reverse_domain):
    """Convert a reverse map domain name into textual address form.

    *name*, a ``thirdparty.dns.name.Name``, an IPv4 or IPv6 address in reverse-map name
    form.

    *v4_origin*, a ``thirdparty.dns.name.Name`` representing the top-level domain for
    IPv4 addresses, instead of the default (in-addr.arpa.)

    *v6_origin*, a ``thirdparty.dns.name.Name`` representing the top-level domain for
    IPv4 addresses, instead of the default (ip6.arpa.)

    Raises ``thirdparty.dns.exception.SyntaxError`` if the name does not have a
    reverse-map form.

    Returns a ``str``.
    """

    if name.is_subdomain(v4_origin):
        name = name.relativize(v4_origin)
        text = b'.'.join(reversed(name.labels))
        # run through inet_ntoa() to check syntax and make pretty.
        return thirdparty.dns.ipv4.inet_ntoa(
            thirdparty.dns.ipv4.inet_aton(text))
    elif name.is_subdomain(v6_origin):
        name = name.relativize(v6_origin)
        labels = list(reversed(name.labels))
        parts = []
        for i in range(0, len(labels), 4):
            parts.append(b''.join(labels[i:i + 4]))
        text = b':'.join(parts)
        # run through inet_ntoa() to check syntax and make pretty.
        return thirdparty.dns.ipv6.inet_ntoa(
            thirdparty.dns.ipv6.inet_aton(text))
    else:
        raise thirdparty.dns.exception.SyntaxError(
            'unknown reverse-map address family')
Beispiel #5
0
def to_e164(name, origin=public_enum_domain, want_plus_prefix=True):
    """Convert an ENUM domain name into an E.164 number.
    @param name: the ENUM domain name.
    @type name: thirdparty.dns.name.Name object.
    @param origin: A domain containing the ENUM domain name.  The
    name is relativized to this domain before being converted to text.
    @type origin: thirdparty.dns.name.Name object or None
    @param want_plus_prefix: if True, add a '+' to the beginning of the
    returned number.
    @rtype: str
    """
    if origin is not None:
        name = name.relativize(origin)
    dlabels = [d for d in name.labels if (d.isdigit() and len(d) == 1)]
    if len(dlabels) != len(name.labels):
        raise thirdparty.dns.exception.SyntaxError('non-digit labels in ENUM domain name')
    dlabels.reverse()
    text = b''.join(dlabels)
    if want_plus_prefix:
        text = b'+' + text
    return text
Beispiel #6
0
 def get_name(self, origin=None):
     name = thirdparty.dns.name.from_wire_parser(self)
     if origin:
         name = name.relativize(origin)
     return name
Beispiel #7
0
    def _generate_line(self):
        # range lhs [ttl] [class] type rhs [ comment ]
        """Process one line containing the GENERATE statement from a DNS
        master file."""
        if self.current_origin is None:
            raise UnknownOrigin

        token = self.tok.get()
        # Range (required)
        try:
            start, stop, step = thirdparty.dns.grange.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except:
            raise thirdparty.dns.exception.SyntaxError

        # lhs (required)
        try:
            lhs = token.value
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except:
            raise thirdparty.dns.exception.SyntaxError

        # TTL
        try:
            ttl = thirdparty.dns.ttl.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except thirdparty.dns.ttl.BadTTL:
            ttl = self.ttl
        # Class
        try:
            rdclass = thirdparty.dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except thirdparty.dns.exception.SyntaxError:
            raise thirdparty.dns.exception.SyntaxError
        except:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise thirdparty.dns.exception.SyntaxError(
                "RR class is not zone's class")
        # Type
        try:
            rdtype = thirdparty.dns.rdatatype.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except:
            raise thirdparty.dns.exception.SyntaxError(
                "unknown rdatatype '%s'" % token.value)

        # lhs (required)
        try:
            rhs = token.value
        except:
            raise thirdparty.dns.exception.SyntaxError

        lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs)
        rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs)
        for i in range(start, stop + 1, step):
            # +1 because bind is inclusive and python is exclusive

            if lsign == u'+':
                lindex = i + int(loffset)
            elif lsign == u'-':
                lindex = i - int(loffset)

            if rsign == u'-':
                rindex = i - int(roffset)
            elif rsign == u'+':
                rindex = i + int(roffset)

            lzfindex = str(lindex).zfill(int(lwidth))
            rzfindex = str(rindex).zfill(int(rwidth))

            name = lhs.replace(u'$%s' % (lmod), lzfindex)
            rdata = rhs.replace(u'$%s' % (rmod), rzfindex)

            self.last_name = thirdparty.dns.name.from_text(
                name, self.current_origin)
            name = self.last_name
            if not name.is_subdomain(self.zone.origin):
                self._eat_line()
                return
            if self.relativize:
                name = name.relativize(self.zone.origin)

            n = self.zone.nodes.get(name)
            if n is None:
                n = self.zone.node_factory()
                self.zone.nodes[name] = n
            try:
                rd = thirdparty.dns.rdata.from_text(rdclass, rdtype, rdata,
                                                    self.current_origin, False)
            except thirdparty.dns.exception.SyntaxError:
                # Catch and reraise.
                (ty, va) = sys.exc_info()[:2]
                raise va
            except:
                # All exceptions that occur in the processing of rdata
                # are treated as syntax errors.  This is not strictly
                # correct, but it is correct almost all of the time.
                # We convert them to syntax errors so that we can emit
                # helpful filename:line info.
                (ty, va) = sys.exc_info()[:2]
                raise thirdparty.dns.exception.SyntaxError(
                    "caught exception %s: %s" % (str(ty), str(va)))

            rd.choose_relativity(self.zone.origin, self.relativize)
            covers = rd.covers()
            rds = n.find_rdataset(rdclass, rdtype, covers, True)
            rds.add(rd, ttl)
Beispiel #8
0
    def _rr_line(self):
        """Process one line from a DNS master file."""
        # Name
        if self.current_origin is None:
            raise UnknownOrigin
        token = self.tok.get(want_leading=True)
        if not token.is_whitespace():
            self.last_name = thirdparty.dns.name.from_text(
                token.value, self.current_origin)
        else:
            token = self.tok.get()
            if token.is_eol_or_eof():
                # treat leading WS followed by EOL/EOF as if they were EOL/EOF.
                return
            self.tok.unget(token)
        name = self.last_name
        if not name.is_subdomain(self.zone.origin):
            self._eat_line()
            return
        if self.relativize:
            name = name.relativize(self.zone.origin)
        token = self.tok.get()
        if not token.is_identifier():
            raise thirdparty.dns.exception.SyntaxError
        # TTL
        try:
            ttl = thirdparty.dns.ttl.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except thirdparty.dns.ttl.BadTTL:
            ttl = self.ttl
        # Class
        try:
            rdclass = thirdparty.dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except thirdparty.dns.exception.SyntaxError:
            raise thirdparty.dns.exception.SyntaxError
        except:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise thirdparty.dns.exception.SyntaxError(
                "RR class is not zone's class")
        # Type
        try:
            rdtype = thirdparty.dns.rdatatype.from_text(token.value)
        except:
            raise thirdparty.dns.exception.SyntaxError(
                "unknown rdatatype '%s'" % token.value)
        n = self.zone.nodes.get(name)
        if n is None:
            n = self.zone.node_factory()
            self.zone.nodes[name] = n
        try:
            rd = thirdparty.dns.rdata.from_text(rdclass, rdtype, self.tok,
                                                self.current_origin, False)
        except thirdparty.dns.exception.SyntaxError:
            # Catch and reraise.
            (ty, va) = sys.exc_info()[:2]
            raise va
        except:
            # All exceptions that occur in the processing of rdata
            # are treated as syntax errors.  This is not strictly
            # correct, but it is correct almost all of the time.
            # We convert them to syntax errors so that we can emit
            # helpful filename:line info.
            (ty, va) = sys.exc_info()[:2]
            raise thirdparty.dns.exception.SyntaxError(
                "caught exception %s: %s" % (str(ty), str(va)))

        rd.choose_relativity(self.zone.origin, self.relativize)
        covers = rd.covers()
        rds = n.find_rdataset(rdclass, rdtype, covers, True)
        rds.add(rd, ttl)
Beispiel #9
0
    def _rr_line(self):
        """Process one line from a DNS master file."""
        # Name
        if self.current_origin is None:
            raise UnknownOrigin
        token = self.tok.get(want_leading=True)
        if not token.is_whitespace():
            self.last_name = self.tok.as_name(token, self.current_origin)
        else:
            token = self.tok.get()
            if token.is_eol_or_eof():
                # treat leading WS followed by EOL/EOF as if they were EOL/EOF.
                return
            self.tok.unget(token)
        name = self.last_name
        if not name.is_subdomain(self.zone.origin):
            self._eat_line()
            return
        if self.relativize:
            name = name.relativize(self.zone.origin)
        token = self.tok.get()
        if not token.is_identifier():
            raise thirdparty.dns.exception.SyntaxError

        # TTL
        ttl = None
        try:
            ttl = thirdparty.dns.ttl.from_text(token.value)
            self.last_ttl = ttl
            self.last_ttl_known = True
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except thirdparty.dns.ttl.BadTTL:
            if self.default_ttl_known:
                ttl = self.default_ttl
            elif self.last_ttl_known:
                ttl = self.last_ttl

        # Class
        try:
            rdclass = thirdparty.dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise thirdparty.dns.exception.SyntaxError
        except thirdparty.dns.exception.SyntaxError:
            raise
        except Exception:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise thirdparty.dns.exception.SyntaxError(
                "RR class is not zone's class")
        # Type
        try:
            rdtype = thirdparty.dns.rdatatype.from_text(token.value)
        except Exception:
            raise thirdparty.dns.exception.SyntaxError(
                "unknown rdatatype '%s'" % token.value)
        n = self.zone.nodes.get(name)
        if n is None:
            n = self.zone.node_factory()
            self.zone.nodes[name] = n
        try:
            rd = thirdparty.dns.rdata.from_text(rdclass, rdtype, self.tok,
                                                self.current_origin,
                                                self.relativize,
                                                self.zone.origin)
        except thirdparty.dns.exception.SyntaxError:
            # Catch and reraise.
            raise
        except Exception:
            # All exceptions that occur in the processing of rdata
            # are treated as syntax errors.  This is not strictly
            # correct, but it is correct almost all of the time.
            # We convert them to syntax errors so that we can emit
            # helpful filename:line info.
            (ty, va) = sys.exc_info()[:2]
            raise thirdparty.dns.exception.SyntaxError(
                "caught exception {}: {}".format(str(ty), str(va)))

        if not self.default_ttl_known and rdtype == thirdparty.dns.rdatatype.SOA:
            # The pre-RFC2308 and pre-BIND9 behavior inherits the zone default
            # TTL from the SOA minttl if no $TTL statement is present before the
            # SOA is parsed.
            self.default_ttl = rd.minimum
            self.default_ttl_known = True
            if ttl is None:
                # if we didn't have a TTL on the SOA, set it!
                ttl = rd.minimum

        # TTL check.  We had to wait until now to do this as the SOA RR's
        # own TTL can be inferred from its minimum.
        if ttl is None:
            raise thirdparty.dns.exception.SyntaxError(
                "Missing default TTL value")

        covers = rd.covers()
        rds = n.find_rdataset(rdclass, rdtype, covers, True)
        rds.add(rd, ttl)
Beispiel #10
0
    def _get_section(self, section, count):
        """Read the next I{count} records from the wire data and add them to
        the specified section.
        @param section: the section of the message to which to add records
        @type section: list of thirdparty.dns.rrset.RRset objects
        @param count: the number of records to read
        @type count: int"""

        if self.updating or self.one_rr_per_rrset:
            force_unique = True
        else:
            force_unique = False
        seen_opt = False
        for i in xrange(0, count):
            rr_start = self.current
            (name, used) = thirdparty.dns.name.from_wire(self.wire, self.current)
            absolute_name = name
            if self.message.origin is not None:
                name = name.relativize(self.message.origin)
            self.current = self.current + used
            (rdtype, rdclass, ttl, rdlen) = \
                struct.unpack('!HHIH',
                              self.wire[self.current:self.current + 10])
            self.current = self.current + 10
            if rdtype == thirdparty.dns.rdatatype.OPT:
                if section is not self.message.additional or seen_opt:
                    raise BadEDNS
                self.message.payload = rdclass
                self.message.ednsflags = ttl
                self.message.edns = (ttl & 0xff0000) >> 16
                self.message.options = []
                current = self.current
                optslen = rdlen
                while optslen > 0:
                    (otype, olen) = \
                        struct.unpack('!HH',
                                      self.wire[current:current + 4])
                    current = current + 4
                    opt = thirdparty.dns.ethirdparty.dns.option_from_wire(
                        otype, self.wire, current, olen)
                    self.message.options.append(opt)
                    current = current + olen
                    optslen = optslen - 4 - olen
                seen_opt = True
            elif rdtype == thirdparty.dns.rdatatype.TSIG:
                if not (section is self.message.additional and
                        i == (count - 1)):
                    raise BadTSIG
                if self.message.keyring is None:
                    raise UnknownTSIGKey('got signed message without keyring')
                secret = self.message.keyring.get(absolute_name)
                if secret is None:
                    raise UnknownTSIGKey("key '%s' unknown" % name)
                self.message.keyname = absolute_name
                (self.message.keyalgorithm, self.message.mac) = \
                    thirdparty.dns.tsig.get_algorithm_and_mac(self.wire, self.current,
                                                   rdlen)
                self.message.tsig_ctx = \
                    thirdparty.dns.tsig.validate(self.wire,
                                      absolute_name,
                                      secret,
                                      int(time.time()),
                                      self.message.request_mac,
                                      rr_start,
                                      self.current,
                                      rdlen,
                                      self.message.tsig_ctx,
                                      self.message.multi,
                                      self.message.first)
                self.message.had_tsig = True
            else:
                if ttl < 0:
                    ttl = 0
                if self.updating and \
                   (rdclass == thirdparty.dns.rdataclass.ANY or
                        rdclass == thirdparty.dns.rdataclass.NONE):
                    deleting = rdclass
                    rdclass = self.zone_rdclass
                else:
                    deleting = None
                if deleting == thirdparty.dns.rdataclass.ANY or \
                   (deleting == thirdparty.dns.rdataclass.NONE and
                        section is self.message.answer):
                    covers = thirdparty.dns.rdatatype.NONE
                    rd = None
                else:
                    rd = thirdparty.dns.rdata.from_wire(rdclass, rdtype, self.wire,
                                             self.current, rdlen,
                                             self.message.origin)
                    covers = rd.covers()
                if self.message.xfr and rdtype == thirdparty.dns.rdatatype.SOA:
                    force_unique = True
                rrset = self.message.find_rrset(section, name,
                                                rdclass, rdtype, covers,
                                                deleting, True, force_unique)
                if rd is not None:
                    rrset.add(rd, ttl)
            self.current = self.current + rdlen