PKaSHHkkdnszonetest/exceptions.py#!/usr/bin/env python # -*- coding: utf-8 -*- # vim: ai et ts=4 sw=4 sts=4 fenc=UTF-8 ft=python """ dnszonetest.exceptions ----------------------- All exceptions used in the Dnszonetest code base are defined here. """ class DnszonetestException(Exception): """ Base exception class. All Dnszonetest-specific exceptions should subclass this class. """ class UnableToResolveNameServerException(DnszonetestException): """ Raised nameserver IP number(s) could not be resolved. """ class NoZoneFileException(DnszonetestException): """ Raised when zone file does not exist. """ PKaSHccdnszonetest/main.py#!/usr/bin/env python # -*- coding: utf-8 -*- # vim: ai et ts=4 sw=4 sts=4 fenc=UTF-8 ft=python ''' dnszonetest.main ------------- Main dnszonetest ''' from __future__ import print_function from __future__ import unicode_literals import logging import socket import dns.flags import dns.message import dns.query import dns.rdatatype import dns.resolver import dns.zone from dnszonetest.exceptions import ( UnableToResolveNameServerException, NoZoneFileException, ) logger = logging.getLogger(__name__) class Record(object): def __init__(self, name, rdataset_file): self.name = name self.rdataset_file = rdataset_file self.rdataset_query = None self.query_msg = None self.query_res = None def query(self, nameserver_ip, no_recursion): logger.debug('RECORD : %s', self.name) logger.debug('FROM FILE : %s', self.rdataset_file) self.query_msg = dns.message.make_query( self.name, self.rdataset_file.rdtype ) if no_recursion: self.query_msg.flags ^= dns.flags.RD try: self.query_res = dns.query.udp( self.query_msg, nameserver_ip, timeout=10 ) except dns.exception.Timeout as err: logger.error('TIMEOUT: %s', err) try: self.rdataset_query = self.query_res.answer[0].to_rdataset() logger.debug('FROM QUERY : %s', self.rdataset_query) except (IndexError, AttributeError): logger.warning('QUERY: %s : NO RESULT', self.name) @property def rdataset_match(self): return self.rdataset_file == self.rdataset_query @property def ttl_match(self): try: res = self.rdataset_file.ttl == self.rdataset_query.ttl except AttributeError as err: logger.warning(err) res = None return res class DnsZoneTest(object): ''' API equivalent to using dnszonetest at the command line. ''' def __init__(self, zonename, zonefile, nameserver=None, verbose=False, quiet=False, no_recursion=False, compare_ttl=False, compare_ns=False, compare_soa=False): ''' :param str zonename: Zone name. :param str zonefile: Zone file name. :param bool nameserver: name server to use. :param bool verbose: verbose output. :param bool quiet: suppress output. :param bool no_recursion: do not use recursion. :param bool compare_ttl: include TTL field in comparison. :param bool compare_ns: include NS records in comparison. :param bool compare_soa: include SOA records in comparison. ''' self.zonename = zonename self.zonefile = zonefile self.nameserver = nameserver self.verbose = verbose self.quiet = quiet self.no_recursion = no_recursion self.compare_ttl = compare_ttl self.compare_ns = compare_ns self.compare_soa = compare_soa self.nameserver_ip = None self.zone_from_file = None self.mismatch_ttl = 0 self.mismatch_rdataset = 0 self.errno = 3 def get_nameserver_ip(self): ''' Get Resolver object depending on self.nameserver ''' logger.info('NAME SERVER: %s', self.nameserver) if self.nameserver is None: logger.info('Get IP number(s) of system resolvers') self.nameserver_ip = \ dns.resolver.get_default_resolver().nameservers[0] else: try: self.nameserver_ip = socket.gethostbyname_ex( self.nameserver)[2][0] except socket.gaierror as err: raise UnableToResolveNameServerException( 'Unable to resolve nameserver "{0}". {1}'.format( self.nameserver, err ) ) logger.info('NAME SERVER IP: %s', self.nameserver_ip) def get_zone_from_file(self): ''' Read records from zone file. Sets self.zone_from_file ''' try: self.zone_from_file = dns.zone.from_file( self.zonefile, origin=self.zonename, relativize=False ) except IOError as err: raise NoZoneFileException( 'Unable to read zone file: {0}'.format(err) ) def compare_rdatasets(self): for name, rdataset_file in self.zone_from_file.iterate_rdatasets(): if not self.compare_ns and \ rdataset_file.rdtype == dns.rdatatype.NS: continue if not self.compare_soa and \ rdataset_file.rdtype == dns.rdatatype.SOA: continue record = Record(name, rdataset_file) record.query(self.nameserver_ip, self.no_recursion) if self.compare_ttl and record.rdataset_query is not None: if not record.ttl_match: self.mismatch_ttl += 1 logger.warning( 'RECORD: %s TTL: %s', record.name, record.rdataset_file.ttl ) logger.warning( 'RECORD: %s TTL : %s', record.name, record.rdataset_query.ttl ) if not record.rdataset_match: self.mismatch_rdataset += 1 logger.warning( 'RECORD: %s IN ZONEFILE: %s', record.name, record.rdataset_file ) logger.warning( 'RECORD: %s FROM QUERY : %s', record.name, record.rdataset_query ) if self.mismatch_ttl > 0 or self.mismatch_rdataset > 0: self.errno = 1 else: self.errno = 0 def compare(self): self.get_nameserver_ip() self.get_zone_from_file() self.compare_rdatasets() PKaSHmLdnszonetest/cli.py#!/usr/bin/env python # -*- coding: utf-8 -*- # vim: ai et ts=4 sw=4 sts=4 fenc=UTF-8 ft=python ''' dnszonetest.cli ------------- Main dnszonetest CLI. ''' from __future__ import print_function from __future__ import unicode_literals import argparse import logging import logging.handlers import sys from dnszonetest.main import DnsZoneTest logger = logging.getLogger(__name__) def setup_logging(verbose, quiet, logfile=None): ''' Sets up logging. :param bool verbose: verbose output. :param bool quiet: suppress output. ''' if verbose: log_level = logging.DEBUG elif quiet: log_level = logging.CRITICAL else: log_level = logging.INFO # Root logger logger = logging.getLogger() # Clear all handlers [handler.close() for handler in logger.handlers] logger.handlers = [] # Root logger logs all logger.setLevel(logging.DEBUG) if logfile is None: # Console handler console_handler = logging.StreamHandler() console_handler.setFormatter( logging.Formatter(fmt='%(levelname)-10s%(message)s',) ) console_handler.setLevel(log_level) logger.addHandler(console_handler) else: # File handler file_handler = logging.FileHandler(logfile) file_handler.setFormatter( logging.Formatter(fmt='%(levelname)-10s%(message)s',) ) file_handler.setLevel(log_level) logger.addHandler(file_handler) def parse_args(args): ''' Parse the command-line arguments to dnszonetest. :param list args: list of arguments (example: sys.argv[1:]) :returns: argparse.Namespace :rtype: argparse.Namespace ''' parser = argparse.ArgumentParser( prog='dnszonetest', description='DNS Zone Test', ) parser.add_argument( 'zonename', help='zone name', ) parser.add_argument( 'zonefile', help='zone file', ) parser.add_argument( '-d', '--nameserver', help='DNS server to query.', ) parser.add_argument( '-v', '--verbose', action='store_true', help='Show verbose info (level DEBUG).', ) parser.add_argument( '-q', '--quiet', action='store_true', help='No output.', ) parser.add_argument( '-r', '--norec', action='store_true', dest='no_recursion', help='Set No Recursion flag.', ) parser.add_argument( '-t', '--ttl', action='store_true', dest='compare_ttl', help='Compare TTL values.', ) parser.add_argument( '-n', '--ns', action='store_true', dest='compare_ns', help='Compare NS records.', ) parser.add_argument( '-s', '--soa', action='store_true', dest='compare_soa', help='Compare SOA records.', ) return parser.parse_args(args) def main(): ''' Entry point for the package defined in setup.py. :returns: 0 when records from zone file correctly resolve against nameserver, 2 when not, 3 on errors. :rtype: int ''' # Parse args args = parse_args(sys.argv[1:]) # Setup basic logging setup_logging(args.verbose, args.quiet) logger.debug('Arguments: %s', args) dnszonetest = DnsZoneTest( args.zonename, args.zonefile, nameserver=args.nameserver, verbose=args.verbose, quiet=args.quiet, no_recursion=args.no_recursion, compare_ttl=args.compare_ttl, compare_ns=args.compare_ns, compare_soa=args.compare_soa, ) dnszonetest.compare() return dnszonetest.errno PKTI{Zdnszonetest/__init__.py# -*- coding: utf-8 -*- # vim: ai et ts=4 sw=4 sts=4 fenc=UTF-8 ft=python ''' dnszonetest ----------- Main package for dnszonetest. ''' __author__ = 'Maarten Diemel' __email__ = 'maarten@maartendiemel.nl' __version__ = '0.3.7' PKcIB+dnszonetest-0.3.7.dist-info/DESCRIPTION.rst============= DNS Zone Test ============= .. image:: https://img.shields.io/pypi/v/dnszonetest.svg :target: https://pypi.python.org/pypi/dnszonetest .. image:: https://img.shields.io/travis/maartenq/dnszonetest.svg :target: https://travis-ci.org/maartenq/dnszonetest .. image:: https://readthedocs.org/projects/dnszonetest/badge/?version=latest :target: https://dnszonetest.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://pyup.io/repos/github/maartenq/dnszonetest/shield.svg :target: https://pyup.io/repos/github/maartenq/dnszonetest/ :alt: Updates .. image:: https://codecov.io/gh/maartenq/dnszonetest/branch/master/graph/badge.svg :target: https://codecov.io/gh/maartenq/dnszonetest Dns Zone Test tests a DNS zone file agaist a given name server. * Free software: https://opensource.org/licenses/ISC * Documentation: https://dnszonetest.readthedocs.org * PyPi: https://pypi.python.org/pypi/dnszonetest * GitHub: https://github.com/maartenq/dnszonetest * Travis CI: https://travis-ci.org/maartenq/dnszonetest * Codecov: https://codecov.io/github/maartenq/dnszonetest ======= History ======= 0.3.7 (2016-08-19) ------------------ * requirements: Update pytest to 3.0.0 0.3.6 (2016-08-13) ------------------ * requirements: Update dnspython to 1.14.0 0.3.5 (2016-08-13) ------------------ * ISC License * Pinned requirements * Travis/Tox fixes 0.3.4 (2016-06-11) ------------------ * Factored out `pytest-runner`. Removes `setuptools_scm` dependency which breaks RPM build on RHEL6. * Added recursive remove on `*.egg` in Makefile. 0.3.3 (2016-06-11) ------------------ * Add log to file option. 0.3.2 (2016-05-12) ------------------ * Added `argparse` as requirement for Python 2.6. 0.3.1 (2016-05-12) ------------------ * Update installation docs. 0.3.0 (2016-05-11) ------------------ * First working version 0.2.3 (2016-02-06) ------------------ * Tests on cli * Project stuff 0.2.2 (2016-01-21) ------------------ * First release on PyPI. PKcIb/66,dnszonetest-0.3.7.dist-info/entry_points.txt[console_scripts] dnszonetest = dnszonetest.cli:main PKcI})dnszonetest-0.3.7.dist-info/metadata.json{"classifiers": ["Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: ISC License (ISCL)", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"], "extensions": {"python.commands": {"wrap_console": {"dnszonetest": "dnszonetest.cli:main"}}, "python.details": {"contacts": [{"email": "maarten@maartendiemel.nl", "name": "Maarten Diemel", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/maartenq/dnszonetest"}}, "python.exports": {"console_scripts": {"dnszonetest": "dnszonetest.cli:main"}}}, "extras": [], "generator": "bdist_wheel (0.28.0)", "keywords": ["dnszonetest"], "license": "ISCL", "metadata_version": "2.0", "name": "dnszonetest", "run_requires": [{"requires": ["dnspython (==1.14.0)"]}], "summary": "DNS Zone Test tests a DNS zone file agaist a given name server.", "test_requires": [{"requires": ["pytest (==3.0.0)", "pytest-cov (==2.3.1)", "tox (==2.3.1)"]}], "version": "0.3.7"}PKcIk0] )dnszonetest-0.3.7.dist-info/top_level.txtdnszonetest PKcI>nn!dnszonetest-0.3.7.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.28.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any PKcI9Gy y $dnszonetest-0.3.7.dist-info/METADATAMetadata-Version: 2.0 Name: dnszonetest Version: 0.3.7 Summary: DNS Zone Test tests a DNS zone file agaist a given name server. Home-page: https://github.com/maartenq/dnszonetest Author: Maarten Diemel Author-email: maarten@maartendiemel.nl License: ISCL Keywords: dnszonetest Platform: UNKNOWN Classifier: Development Status :: 2 - Pre-Alpha Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: ISC License (ISCL) Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Requires-Dist: dnspython (==1.14.0) ============= DNS Zone Test ============= .. image:: https://img.shields.io/pypi/v/dnszonetest.svg :target: https://pypi.python.org/pypi/dnszonetest .. image:: https://img.shields.io/travis/maartenq/dnszonetest.svg :target: https://travis-ci.org/maartenq/dnszonetest .. image:: https://readthedocs.org/projects/dnszonetest/badge/?version=latest :target: https://dnszonetest.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://pyup.io/repos/github/maartenq/dnszonetest/shield.svg :target: https://pyup.io/repos/github/maartenq/dnszonetest/ :alt: Updates .. image:: https://codecov.io/gh/maartenq/dnszonetest/branch/master/graph/badge.svg :target: https://codecov.io/gh/maartenq/dnszonetest Dns Zone Test tests a DNS zone file agaist a given name server. * Free software: https://opensource.org/licenses/ISC * Documentation: https://dnszonetest.readthedocs.org * PyPi: https://pypi.python.org/pypi/dnszonetest * GitHub: https://github.com/maartenq/dnszonetest * Travis CI: https://travis-ci.org/maartenq/dnszonetest * Codecov: https://codecov.io/github/maartenq/dnszonetest ======= History ======= 0.3.7 (2016-08-19) ------------------ * requirements: Update pytest to 3.0.0 0.3.6 (2016-08-13) ------------------ * requirements: Update dnspython to 1.14.0 0.3.5 (2016-08-13) ------------------ * ISC License * Pinned requirements * Travis/Tox fixes 0.3.4 (2016-06-11) ------------------ * Factored out `pytest-runner`. Removes `setuptools_scm` dependency which breaks RPM build on RHEL6. * Added recursive remove on `*.egg` in Makefile. 0.3.3 (2016-06-11) ------------------ * Add log to file option. 0.3.2 (2016-05-12) ------------------ * Added `argparse` as requirement for Python 2.6. 0.3.1 (2016-05-12) ------------------ * Update installation docs. 0.3.0 (2016-05-11) ------------------ * First working version 0.2.3 (2016-02-06) ------------------ * Tests on cli * Project stuff 0.2.2 (2016-01-21) ------------------ * First release on PyPI. PKcIu"dnszonetest-0.3.7.dist-info/RECORDdnszonetest/__init__.py,sha256=fnMoo_ZITydjxIrHSztH_pDFi0Z2q5F_5elcy8xqvNE,230 dnszonetest/cli.py,sha256=psOPSN26-IaZYsYmqx9eaWRde-6N1YXw2sxapRLN6kQ,3771 dnszonetest/exceptions.py,sha256=YjzJGrz0L7loVcXG0k_WQoXfsVmLZOf2lPHzyKOvmtA,619 dnszonetest/main.py,sha256=kfI3TigZb_7gkPicIqTp3CoE-A2ieWEvVDSZPSH6lQU,6243 dnszonetest-0.3.7.dist-info/DESCRIPTION.rst,sha256=W23qYEeH9dtYfPJ_1C94uGs1t6Q5lggUgOhms4B1bbQ,2069 dnszonetest-0.3.7.dist-info/METADATA,sha256=tvlS6xAsRTiy0HZvHn7m7-7IlQLoZec2P-H4ZsK8qc4,2937 dnszonetest-0.3.7.dist-info/RECORD,, dnszonetest-0.3.7.dist-info/WHEEL,sha256=c5du820PMLPXFYzXDp0SSjIjJ-7MmVRpJa1kKfTaqlc,110 dnszonetest-0.3.7.dist-info/entry_points.txt,sha256=9PnYsV2KmGTYkaqLFP-ojODWUiOepiiQyVpLexe-vsk,54 dnszonetest-0.3.7.dist-info/metadata.json,sha256=qJBxFok3hP1TlAyZHIjMDn6RMqVPEMnACqGckuxtf2w,1269 dnszonetest-0.3.7.dist-info/top_level.txt,sha256=w7eqR4RJqJRdwbnRuzPQysR5oOK0OImAN2z39NMr1_g,12 PKaSHHkkdnszonetest/exceptions.pyPKaSHccdnszonetest/main.pyPKaSHmL6dnszonetest/cli.pyPKTI{Z!*dnszonetest/__init__.pyPKcIB+<+dnszonetest-0.3.7.dist-info/DESCRIPTION.rstPKcIb/66,3dnszonetest-0.3.7.dist-info/entry_points.txtPKcI})4dnszonetest-0.3.7.dist-info/metadata.jsonPKcIk0] )V9dnszonetest-0.3.7.dist-info/top_level.txtPKcI>nn!9dnszonetest-0.3.7.dist-info/WHEELPKcI9Gy y $V:dnszonetest-0.3.7.dist-info/METADATAPKcIu"Fdnszonetest-0.3.7.dist-info/RECORDPK _I