Example #1
0
def to_address(name):
    """Convert a reverse map domain name into textual address form.

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

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

    Returns a ``text``.
    """

    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 dns.ipv4.inet_ntoa(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 dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text))
    else:
        raise dns.exception.SyntaxError('unknown reverse-map address family')
Example #2
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: 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 = '.'.join(labels)
        # run through inet_aton() to check syntax and make pretty.
        return dns.ipv4.inet_ntoa(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(''.join(labels[i:i+4]))
            i += 4
        text = ':'.join(parts)
        # run through inet_aton() to check syntax and make pretty.
        return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text))
    else:
        raise dns.exception.SyntaxError('unknown reverse-map address family')
Example #3
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: 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 = '.'.join(labels)
        # run through inet_aton() to check syntax and make pretty.
        return dns.ipv4.inet_ntoa(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(''.join(labels[i:i+4]))
            i += 4
        text = ':'.join(parts)
        # run through inet_aton() to check syntax and make pretty.
        return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text))
    else:
        raise dns.exception.SyntaxError, 'unknown reverse-map address family'
Example #4
0
def export_zone(suffix, names, zonefile_dir, server_names, conffile_fh):
    filename = os.path.join(zonefile_dir, 'db._odup.%s' % (suffix.to_text().rstrip('.')))
    conffile_fh.write('zone "_odup.%s" {\n' % suffix.to_text())
    conffile_fh.write('\ttype master;\n')
    conffile_fh.write('\tfile "%s";\n' % filename)
    conffile_fh.write('\tallow-transfer { any; };\n')
    conffile_fh.write('};\n')

    if len(suffix) == 2:
        fetch_str = ' +fetch:axfr://'
    else:
        fetch_str = ''

    with open(filename, 'w+') as fh:
        fh.write('$ORIGIN _odup.%s\n' % (suffix.to_text()))
        fh.write('$TTL 604800\n')
        fh.write('@\tSOA\t%s root.nic.%s 1 1800 900 604800 86400\n' % (server_names[0].to_text(), suffix.to_text()))
        for server_name in server_names:
            fh.write('\tNS\t%s\n' % (server_name.to_text()))
        fh.write('\tTXT\t"v=odup1 +bound%s -all"\n' % fetch_str)

        for name in names:
            name = name.relativize(suffix)
            if name == dns.name.empty:
                continue
            if name[0][0].startswith('!'):
                fh.write('%s\tTXT\t"v=odup1 +org"\n' % (name.to_text().lstrip('!')))
            elif name[0] == '*':
                fh.write('%s\tTXT\t"v=odup1 +bound:%d -all"\n' % (name.to_text(), len(name) - 1))
            else:
                fh.write('%s\tTXT\t"v=odup1 +bound -all"\n' % (name.to_text()))
Example #5
0
 def del_ods_zone(self, name):
     # ods-ksmutil blows up if zone name has period at the end
     name = name.relativize(dns.name.root)
     cmd = ['zone', 'delete', '--zone', str(name)]
     output = self.ksmutil(cmd)
     self.log.info(output)
     self.notify_enforcer()
Example #6
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 ``dns.name.Name``, the ENUM domain name.

    *origin* is a ``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 ``text``.

    """
    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 dns.exception.SyntaxError('non-digit labels in ENUM domain name')
    dlabels.reverse()
    text = b''.join(dlabels)
    if want_plus_prefix:
        text = b'+' + text
    return maybe_decode(text)
Example #7
0
def _hashed_order(names, origin=None, salt='', iterations=0):
    """
    Hash the given names using SHA-1 algorithm, the given salt and the given
    number of iterations. Return list of tuples (name, hash) in hash order.
    Used for NSEC3 records generation. See RFC-5155 for details.
    """

    # Add empty non terminals to the list, see RFC-5155, section 7.1
    nameset = set(names)
    for name in names:
        n = name.relativize(origin)
        while len(n) > 1:
            n = n.parent()
            nameset.add(n.derelativize(origin))
    names = list(nameset)

    ret = []
    for name in names:
        h = name.to_digestable(origin)
        i = iterations
        while i >= 0:
            sha = Crypto.Hash.SHA.new()
            sha.update(h)
            sha.update(salt)
            h = sha.digest()
            i -= 1
        ret.append((name, h))

    # Check for hash collision
    if len(ret) != len(set(ret)):
        raise NSEC3Collision()

    ret = sorted(ret, key=lambda x: x[1])
    return ret
Example #8
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 ``dns.name.Name``, the ENUM domain name.

    *origin* is a ``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 ``text``.

    """
    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 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()
Example #9
0
 def _validate_name(self, name):
     if name.is_absolute():
         if not name.is_subdomain(self.zone.origin):
             raise KeyError("name is not a subdomain of the zone origin")
         if self.zone.relativize:
             name = name.relativize(self.origin)
     return name
Example #10
0
 def _validate_name(self, name):
     if name.is_absolute():
         if not name.is_subdomain(self.zone.origin):
             raise KeyError("name is not a subdomain of the zone origin")
         if self.zone.relativize:
             # XXXRTH should it be an error if self.origin is still None?
             name = name.relativize(self.origin)
     return name
Example #11
0
    def getRdatasetWildcardRecursion(self, name, rdtype, first=True):
        try:
            rdataset = self.data.find_rdataset(
                name,
                rdtype
            )
        except KeyError as e:
            if name.is_wild():
                name = name.parent()
            name.relativize(self.zone)
            if not first:
                name = name.parent()
            name = dns.name.Name(['*']).concatenate(name)

            rdataset = self.getRdatasetWildcardRecursion(name, rdtype, False)

        return rdataset
Example #12
0
 def del_ods_zone(self, name):
     # ods-ksmutil blows up if zone name has period at the end
     name = name.relativize(dns.name.root)
     # detect if name is root zone
     if name == dns.name.empty:
         name = dns.name.root
     cmd = ['zone', 'delete', '--zone', str(name)]
     output = self.ksmutil(cmd)
     self.log.info(output)
     self.notify_enforcer()
Example #13
0
 def _validate_name(self, name):
     if isinstance(name, (str, unicode)):
         name = dns.name.from_text(name, None)
     elif not isinstance(name, dns.name.Name):
         raise KeyError("name parameter must be convertable 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
Example #14
0
 def _validate_name(self, name):
     if isinstance(name, (str, unicode)):
         name = dns.name.from_text(name, None)
     elif not isinstance(name, dns.name.Name):
         raise KeyError("name parameter must be convertable 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
Example #15
0
 def del_ods_zone(self, name):
     # ods-ksmutil blows up if zone name has period at the end
     name = name.relativize(dns.name.root)
     # detect if name is root zone
     if name == dns.name.empty:
         name = dns.name.root
     cmd = ['zone', 'delete', '--zone', str(name)]
     output = self.ksmutil(cmd)
     self.log.info(output)
     self.notify_enforcer()
     self.cleanup_signer(name)
Example #16
0
def to_address(
    name: dns.name.Name,
    v4_origin: dns.name.Name = ipv4_reverse_domain,
    v6_origin: dns.name.Name = ipv6_reverse_domain,
) -> str:
    """Convert a reverse map domain name into textual address form.

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

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

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

    Raises ``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 dns.ipv4.inet_ntoa(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 dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text))
    else:
        raise dns.exception.SyntaxError("unknown reverse-map address family")
Example #17
0
 def _validate_name(self, name):
     if isinstance(name, str):
         name = dns.name.from_text(name, None)
     elif not isinstance(name, 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)
     elif not self.relativize:
         # We have a relative name in a non-relative zone, so derelativize.
         if self.origin is None:
             raise KeyError('no zone origin is defined')
         name = name.derelativize(self.origin)
     return name
Example #18
0
 def add_ods_zone(self, uuid, name):
     zone_path = '%s%s' % (ENTRYUUID_PREFIX, uuid)
     if name != dns.name.root:
         name = name.relativize(dns.name.root)
     cmd = ['zone', 'add', '--zone', str(name), '--input', zone_path]
     output = None
     try:
         output = self.ksmutil(cmd)
     except ipautil.CalledProcessError as e:
         # Zone already exists in HSM
         if e.returncode == 1 \
                 and str(e.output).endswith(str(name) + ' already exists!'):
             # Just return
             return
     if output is not None:
         logger.info('%s', output)
         self.notify_enforcer()
Example #19
0
 def _validate_name(self, name: dns.name.Name) -> dns.name.Name:
     if name.is_absolute():
         if self.origin is None:
             # This should probably never happen as other code (e.g.
             # _rr_line) will notice the lack of an origin before us, but
             # we check just in case!
             raise KeyError("no zone origin is defined")
         if not name.is_subdomain(self.origin):
             raise KeyError("name is not a subdomain of the zone origin")
         if self.zone.relativize:
             name = name.relativize(self.origin)
     elif not self.zone.relativize:
         # We have a relative name in a non-relative zone, so derelativize.
         if self.origin is None:
             raise KeyError("no zone origin is defined")
         name = name.derelativize(self.origin)
     return name
Example #20
0
    def add_record(self, name, rdtype, content, rdclass="IN", ttl=None):
        """
        Add a resource record to the zone.

        :param name: The record's name.
        :type name: string
        :param rdtype: The record's type, e.g. "CNAME".
        :type rdtype: string
        :param content: The record's content.
        :type content: string
        :param rdclass: The record's class.
        :type rdclass: string
        :param ttl: The record's TTL.
        :type ttl: ttl
        :return: :class:`Record <Record>` object
        :rtype: localzone.models.Record
        """
        # TODO: standardize on named params?

        # convert string parameters to dnspython objects
        name = dns.name.from_text(name, self.origin)
        rdclass = dns.rdataclass.from_text(rdclass)
        rdtype = dns.rdatatype.from_text(rdtype)

        # TODO: won't this always be the case?
        if name.is_subdomain(self.origin):
            name = name.relativize(self.origin)

        if not ttl:
            ttl = self.ttl

        # create the record data
        rdata = dns.rdata.from_text(rdclass,
                                    rdtype,
                                    content,
                                    origin=self.origin)

        # get or create the node and rdataset that will conatin the record
        node = self.find_node(name, create=True)
        rdataset = self.find_rdataset(name, rdtype, create=True)

        # add the new rdata to the set
        rdataset.add(rdata, ttl)

        return Record(self.origin, name, node, rdataset, rdata)
Example #21
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: 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: dns.name.Name object or None
    @param want_plus_prefix: if True, add a '+' to the beginning of the
    returned number.
    @rtype: str
    """
    if not origin is 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 dns.exception.SyntaxError('non-digit labels in ENUM domain name')
    dlabels.reverse()
    text = ''.join(dlabels)
    if want_plus_prefix:
        text = '+' + text
    return text
Example #22
0
 def del_ods_zone(self, name):
     # ods-ksmutil blows up if zone name has period at the end
     if name != dns.name.root:
         name = name.relativize(dns.name.root)
     # detect if name is root zone
     if name == dns.name.empty:
         name = dns.name.root
     cmd = ['zone', 'delete', '--zone', str(name)]
     output = None
     try:
         output = self.ksmutil(cmd)
     except ipautil.CalledProcessError as e:
         # Zone already doesn't exist in HSM
         if e.returncode == 1 \
                 and str(e.output).endswith(str(name) + ' not found!'):
             # Just cleanup signer, no need to notify enforcer
             self.cleanup_signer(name)
             return
     if output is not None:
         logger.info('%s', output)
         self.notify_enforcer()
         self.cleanup_signer(name)
Example #23
0
 def _validate_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name:
     if isinstance(name, str):
         name = dns.name.from_text(name, None)
     elif not isinstance(name, dns.name.Name):
         raise KeyError("name parameter must be convertible to a DNS name")
     if name.is_absolute():
         if self.origin is None:
             # This should probably never happen as other code (e.g.
             # _rr_line) will notice the lack of an origin before us, but
             # we check just in case!
             raise KeyError("no zone origin is defined")
         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)
     elif not self.relativize:
         # We have a relative name in a non-relative zone, so derelativize.
         if self.origin is None:
             raise KeyError("no zone origin is defined")
         name = name.derelativize(self.origin)
     return name
Example #24
0
def to_e164(name, origin=public_enum_domain, want_plus_prefix=True):
    """Convert an ENUM domain name into an E.164 number.

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

    *origin* is a ``dns.anme.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 ``text``.
    """
    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 dns.exception.SyntaxError('non-digit labels in ENUM domain name')
    dlabels.reverse()
    text = b''.join(dlabels)
    if want_plus_prefix:
        text = b'+' + text
    return maybe_decode(text)
Example #25
0
    def resolve(self, name, response):
        assert not name.is_absolute() or name.is_subdomain(self.origin)

        _logger = logging.getLogger(__name__)
        #_logger.debug('Enter ODUPPolicyRealm.resolve(): name: %s' % (name))

        # make sure name is relative to origin
        if name.is_absolute():
            name = name.relativize(self.origin)

        if self.origin == dns.name.root:
            origin = ''
        else:
            origin = self.origin.to_text()

        # check for org/bound directives in names in ancestry
        longest_match = None
        longest_match_boundary = None
        existing_labels = 0
        for i in range(len(name) + 1):

            if i == 0:
                test_domain = dns.name.empty
                wildcard_name = None
            else:
                test_domain = dns.name.Name(name[-i:])
                wildcard_name = dns.name.from_text('*', test_domain.parent())

            test_domain_qualified = dns.name.Name(test_domain.labels + ('_odup',) + self.origin.labels)

            policy = None
            # Name exists; check for policy
            if test_domain in self._policies:
                if i > 0:
                    existing_labels += 1
                if self._policies[test_domain] is not None:
                    _logger.debug('%s/TXT: NOERROR (local): %s' % (test_domain_qualified, self._policies[test_domain]))
                    policy = self._policies[test_domain]
                    response.add_query(test_domain_qualified, dns.rcode.NOERROR, policy)
                else:
                    # It's effectively a NODATA response
                    _logger.debug('%s/TXT: NODATA (local)' % (test_domain_qualified))
                    response.add_query(test_domain_qualified, dns.rcode.NOERROR, None)
                    pass

            # Name doesn't exist; check for wildcard
            elif wildcard_name in self._policies and self._policies[wildcard_name] is not None:
                _logger.debug('%s/TXT: NOERROR (wildcard local): %s' % (test_domain_qualified, self._policies[wildcard_name]))
                existing_labels += 1
                policy = self._policies[wildcard_name]
                response.add_query(test_domain_qualified, dns.rcode.NOERROR, policy)

            # Effective NXDOMAIN:
            # An NXDOMAIN result means that no further lookups are
            # necessary, as there is no subtree
            else:
                _logger.debug('%s/TXT: NXDOMAIN (local)' % (test_domain_qualified))
                response.add_query(test_domain_qualified, dns.rcode.NXDOMAIN, None)
                break

            if policy is not None:

                org_match = ORG_RE.search(policy)
                bound_match = BOUND_RE.search(policy)

                # Update longestMatch by giving org and bound highest
                # priority and ignoring policy statements below "bound".
                if org_match is not None or bound_match is not None or \
                        (longest_match is None or BOUND_RE.search(longest_match) is None):
                    longest_match = policy
                    longest_match_boundary = i

                # If this was a organizational domain designation,
                # then don't go any further; the organization will
                # dictate policy
                if org_match is not None:
                    break

                # If this was a boundary designation, and the answer
                # was synthesized from a wildcard, no further
                # lookups must be performed
                if bound_match is not None and \
                        bound_match.group('labels') is not None and \
                        int(bound_match.group('labels')) < i + 1:
                    break

            # Effective NODATA response
            else:
                pass

        if longest_match is not None:
            # If a policy has been found, then look for +org or +bound
            # directives, which will cause org names to be returned.
            # A +org directive indicates that the organizational domain and
            # policy are (at least) one level lower than the value of
            # longestMatchBoundary.
            if ORG_RE.search(longest_match) is not None:
                org_domain = dns.name.Name(name[-(longest_match_boundary+1):]).derelativize(self.origin)
                response.set_policy(None, org_domain, None)
                return response
            # A +bound directive indicates that the organizational domain
            # and policy are (at least) one level lower than the value of
            # longestExistingBoundary.
            if BOUND_RE.search(longest_match) is not None and \
                    existing_labels + 1 <= len(name):
                org_domain = dns.name.Name(name[-(existing_labels+1):]).derelativize(self.origin)
                response.set_policy(None, org_domain, None)
                return response

            # With no +org or +bound directives present, the orgDomain and
            # policy remain as they were looked up, and are returned with
            # the policy domain
            policy_domain = dns.name.Name(name[-(longest_match_boundary+1):]).derelativize(self.origin)
            response.set_policy(policy_domain, self.origin, longest_match)
            return response
        else:
            # Otherwise, return the policy for the orgDomain
            response.set_policy(None, self.origin, None)
            return response
Example #26
0
    def _get_section(self, section, count):
        """Read the next I{count} records from the wire data and add them to
        the specified section.

        section: the section of the message to which to add records
        count: the number of records to read
        """

        if self.updating or self.one_rr_per_rrset:
            force_unique = True
        else:
            force_unique = False
        seen_opt = False
        for i in range(0, count):
            rr_start = self.current
            (name, used) = 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 == 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 = dns.edns.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 == 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) = \
                    dns.tsig.get_algorithm_and_mac(self.wire, self.current,
                                                   rdlen)
                self.message.tsig_ctx = \
                    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 == dns.rdataclass.ANY or
                        rdclass == dns.rdataclass.NONE):
                    deleting = rdclass
                    rdclass = self.zone_rdclass
                else:
                    deleting = None
                if deleting == dns.rdataclass.ANY or \
                   (deleting == dns.rdataclass.NONE and
                        section is self.message.answer):
                    covers = dns.rdatatype.NONE
                    rd = None
                else:
                    rd = dns.rdata.from_wire(rdclass, rdtype, self.wire,
                                             self.current, rdlen,
                                             self.message.origin)
                    covers = rd.covers()
                if self.message.xfr and rdtype == 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
Example #27
0
    def _rr_line(self):
        """Process one line from a DNS zone 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 dns.exception.SyntaxError

        # TTL
        ttl = None
        try:
            ttl = 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 dns.exception.SyntaxError
        except dns.ttl.BadTTL:
            if self.default_ttl_known:
                ttl = self.default_ttl
            elif self.last_ttl_known:
                ttl = self.last_ttl

        # Class
        try:
            rdclass = dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except dns.exception.SyntaxError:
            raise
        except Exception:
            rdclass = self.zone_rdclass
        if rdclass != self.zone_rdclass:
            raise dns.exception.SyntaxError("RR class is not zone's class")
        # Type
        try:
            rdtype = dns.rdatatype.from_text(token.value)
        except Exception:
            raise dns.exception.SyntaxError("unknown rdatatype '%s'" %
                                            token.value)
        try:
            rd = dns.rdata.from_text(rdclass, rdtype, self.tok,
                                     self.current_origin, self.relativize,
                                     self.zone_origin)
        except 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 dns.exception.SyntaxError("caught exception {}: {}".format(
                str(ty), str(va)))

        if not self.default_ttl_known and rdtype == 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 dns.exception.SyntaxError("Missing default TTL value")

        self.txn.add(name, ttl, rd)
Example #28
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 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) = dns.name.from_wire(self.wire, self.current)
            absolute_name = name
            if not self.message.origin is 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 == dns.rdatatype.OPT:
                if not section is 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 = dns.edns.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 == 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.tsig_ctx = \
                                      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 == dns.rdataclass.ANY or
                    rdclass == dns.rdataclass.NONE):
                    deleting = rdclass
                    rdclass = self.zone_rdclass
                else:
                    deleting = None
                if deleting == dns.rdataclass.ANY or \
                   (deleting == dns.rdataclass.NONE and \
                    section is self.message.answer):
                    covers = dns.rdatatype.NONE
                    rd = None
                else:
                    rd = dns.rdata.from_wire(rdclass, rdtype, self.wire,
                                             self.current, rdlen,
                                             self.message.origin)
                    covers = rd.covers()
                if self.message.xfr and rdtype == dns.rdatatype.SOA:
                    force_unique = True
                rrset = self.message.find_rrset(section, name,
                                                rdclass, rdtype, covers,
                                                deleting, True, force_unique)
                if not rd is None:
                    rrset.add(rd, ttl)
            self.current = self.current + rdlen
Example #29
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 = 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 dns.exception.SyntaxError
        # TTL
        try:
            ttl = dns.ttl.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except dns.ttl.BadTTL:
            ttl = self.ttl
        # Class
        try:
            rdclass = dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except dns.exception.SyntaxError:
            raise dns.exception.SyntaxError
        except:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise dns.exception.SyntaxError("RR class is not zone's class")
        # Type
        try:
            rdtype = dns.rdatatype.from_text(token.value)
        except:
            raise 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 = dns.rdata.from_text(rdclass, rdtype, self.tok,
                                     self.current_origin, False)
        except 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 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)
Example #30
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 = dns.grange.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except:
            raise dns.exception.SyntaxError

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

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

        # lhs (required)
        try:
            rhs = token.value
        except:
            raise 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 = 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 = dns.rdata.from_text(rdclass, rdtype, rdata,
                                         self.current_origin, False)
            except 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 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)
Example #31
0
 def get_name(self,
              origin: Optional["dns.name.Name"] = None) -> "dns.name.Name":
     name = dns.name.from_wire_parser(self)
     if origin:
         name = name.relativize(origin)
     return name
Example #32
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 dns.exception.SyntaxError

        # TTL
        ttl = None
        try:
            ttl = 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 dns.exception.SyntaxError
        except dns.ttl.BadTTL:
            if self.default_ttl_known:
                ttl = self.default_ttl
            elif self.last_ttl_known:
                ttl = self.last_ttl

        # Class
        try:
            rdclass = dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except dns.exception.SyntaxError:
            raise dns.exception.SyntaxError
        except Exception:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise dns.exception.SyntaxError("RR class is not zone's class")
        # Type
        try:
            rdtype = dns.rdatatype.from_text(token.value)
        except:
            raise 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 = dns.rdata.from_text(rdclass, rdtype, self.tok,
                                     self.current_origin, self.relativize,
                                     self.zone.origin)
        except 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 dns.exception.SyntaxError("caught exception {}: {}".format(
                str(ty), str(va)))

        if not self.default_ttl_known and isinstance(rd,
                                                     dns.rdtypes.ANY.SOA.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

        # TTL check
        if ttl is None:
            if not (self.last_ttl_known or self.default_ttl_known):
                raise dns.exception.SyntaxError("Missing default TTL value")
            else:
                if self.default_ttl_known:
                    ttl = self.default_ttl
                else:
                    ttl = self.last_ttl

        covers = rd.covers()
        rds = n.find_rdataset(rdclass, rdtype, covers, True)
        rds.add(rd, ttl)
Example #33
0
    def _generate_line(self):
        # range lhs [ttl] [class] type rhs [ comment ]
        """Process one line containing the GENERATE statement from a DNS
        zone file."""
        if self.current_origin is None:
            raise UnknownOrigin

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

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

        # TTL
        try:
            ttl = 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 dns.exception.SyntaxError
        except dns.ttl.BadTTL:
            if not (self.last_ttl_known or self.default_ttl_known):
                raise dns.exception.SyntaxError("Missing default TTL value")
            if self.default_ttl_known:
                ttl = self.default_ttl
            elif self.last_ttl_known:
                ttl = self.last_ttl
        # Class
        try:
            rdclass = dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except dns.exception.SyntaxError:
            raise dns.exception.SyntaxError
        except Exception:
            rdclass = self.zone_rdclass
        if rdclass != self.zone_rdclass:
            raise dns.exception.SyntaxError("RR class is not zone's class")
        # Type
        try:
            rdtype = dns.rdatatype.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except Exception:
            raise dns.exception.SyntaxError("unknown rdatatype '%s'" %
                                            token.value)

        # rhs (required)
        rhs = token.value

        # The code currently only supports base 'd', so the last value
        # in the tuple _parse_modify returns is ignored
        lmod, lsign, loffset, lwidth, _ = self._parse_modify(lhs)
        rmod, rsign, roffset, rwidth, _ = self._parse_modify(rhs)
        for i in range(start, stop + 1, step):
            # +1 because bind is inclusive and python is exclusive

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

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

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

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

            self.last_name = dns.name.from_text(name, self.current_origin,
                                                self.tok.idna_codec)
            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)

            try:
                rd = dns.rdata.from_text(rdclass, rdtype, rdata,
                                         self.current_origin, self.relativize,
                                         self.zone_origin)
            except 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 dns.exception.SyntaxError("caught exception %s: %s" %
                                                (str(ty), str(va)))

            self.txn.add(name, ttl, rd)
Example #34
0
 def get_name(self, origin=None):
     name = dns.name.from_wire_parser(self)
     if origin:
         name = name.relativize(origin)
     return name
Example #35
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 = 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 dns.exception.SyntaxError
        # TTL
        try:
            ttl = dns.ttl.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except dns.ttl.BadTTL:
            ttl = self.ttl
        # Class
        try:
            rdclass = dns.rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except dns.exception.SyntaxError:
            raise dns.exception.SyntaxError
        except:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise dns.exception.SyntaxError("RR class is not zone's class")
        # Type
        try:
            rdtype = dns.rdatatype.from_text(token.value)
        except:
            raise 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 = dns.rdata.from_text(rdclass, rdtype, self.tok,
                                     self.current_origin, False)
        except 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 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)
Example #36
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 = dns.grange.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise dns.exception.SyntaxError
        except:
            raise dns.exception.SyntaxError

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

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

        # lhs (required)
        try:
            rhs = token.value
        except:
            raise 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 == '+':
                lindex = i + int(loffset)
            elif lsign == '-':
                lindex = i - int(loffset)

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

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


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

            self.last_name = 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 = dns.rdata.from_text(rdclass, rdtype, rdata,
                                         self.current_origin, False)
            except 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 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)
Example #37
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 dns.rrset.RRset objects
        @param count: the number of records to read
        @type count: int"""

        if self.updating:
            force_unique = True
        else:
            force_unique = False
        seen_opt = False
        for i in xrange(0, count):
            rr_start = self.current
            (name, used) = dns.name.from_wire(self.wire, self.current)
            if not self.message.origin is 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 == dns.rdatatype.OPT:
                if not section is self.message.additional or seen_opt:
                    raise BadEDNS
                self.message.payload = rdclass
                self.message.ednsflags = ttl
                self.message.edns = (ttl & 0xff0000) >> 16
                seen_opt = True
            elif rdtype == 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(name)
                if secret is None:
                    raise UnknownTSIGKey, "key '%s' unknown" % name
                self.message.tsig_ctx = \
                 dns.tsig.validate(self.wire,
                                          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 == dns.rdataclass.ANY or
                    rdclass == dns.rdataclass.NONE):
                    deleting = rdclass
                    rdclass = self.zone_rdclass
                else:
                    deleting = None
                if deleting == dns.rdataclass.ANY:
                    covers = dns.rdatatype.NONE
                    rd = None
                else:
                    rd = dns.rdata.from_wire(rdclass, rdtype, self.wire,
                                             self.current, rdlen,
                                             self.message.origin)
                    covers = rd.covers()
                if self.message.xfr and rdtype == dns.rdatatype.SOA:
                    force_unique = True
                rrset = self.message.find_rrset(section, name, rdclass, rdtype,
                                                covers, deleting, True,
                                                force_unique)
                if not rd is None:
                    rrset.add(rd, ttl)
            self.current = self.current + rdlen