LinkChecker-9.3/0000750000175000017500000000000012361541761014322 5ustar calvincalvin00000000000000LinkChecker-9.3/setup.py0000755000175000017500000010620512361407402016041 0ustar calvincalvin00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # Copyright (C) 2000-2014 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Setup file for the distuils module. It includes the following features: - py2exe support (including InnoScript installer generation) - py2app support (including DMG package generation) - cx_Freeze support - Qt plugin installation for py2exe and py2app - Microsoft Visual C++ DLL installation for py2exe - creation and installation of configuration files with installation data - automatic detection and usage of GNU99 standard for C compiler - automatic MANIFEST.in check - automatic generation of .mo locale files - automatic permission setting on POSIX systems for installed files Because of all the features, this script is nasty and big. Change it very carefully. """ from __future__ import print_function import sys if not (hasattr(sys, 'version_info') or sys.version_info < (2, 7, 0, 'final', 0)): raise SystemExit("This program requires Python 2.7 or later.") import os import re import codecs import subprocess import stat import glob import shutil try: unicode except NameError: unicode = lambda x: x # if a frozen Unix application should be built with cx_Freeze do_freeze = int(os.environ.get('LINKCHECKER_FREEZE', '0')) # import Distutils stuff try: # setuptools (which is needed by py2app) monkey-patches the # distutils.core.Command class. # So we need to import it before importing the distutils core import setuptools except ImportError: # ignore when setuptools is not installed setuptools = None if do_freeze: from cx_Freeze import setup, Executable else: from distutils.core import setup from distutils.core import Extension from distutils.command.install_lib import install_lib from distutils.command.build_ext import build_ext from distutils.command.sdist import sdist from distutils.command.clean import clean from distutils.command.install_data import install_data from distutils.dir_util import remove_tree from distutils.file_util import write_file from distutils.spawn import find_executable from distutils import util, log try: # py2exe monkey-patches the distutils.core.Distribution class # So we need to import it before importing the Distribution class import py2exe has_py2exe = True except ImportError: # py2exe is not installed has_py2exe = False if do_freeze: from cx_Freeze.dist import Distribution, build, install_exe executables = [Executable("linkchecker"), Executable("linkchecker-gui")] else: from distutils.core import Distribution from distutils.command.build import build executables = None try: import py2app has_py2app = True except ImportError: # py2app is not installed has_py2app = False # the application version AppVersion = "9.3" # the application name AppName = "LinkChecker" Description = "check links in web documents or full websites" def get_long_description(): """Try to read long description from README.rst.""" try: with open('README.rst') as f: return f.read() except: return Description # Microsoft Visual C++ runtime version (tested with Python 2.7.2) MSVCP90Version = '9.0.30729.6161' MSVCP90Suffix = 'x-ww_31a54e43' MSVCP90Token = '1fc8b3b9a1e18e3b' # basic includes for py2exe and py2app py_includes = ['dns.rdtypes.IN.*', 'dns.rdtypes.ANY.*', 'linkcheck.logger.*', ] # basic excludes for py2exe and py2app py_excludes = ['doctest', 'unittest', 'argcomplete', 'Tkinter', 'PyQt4.QtDesigner', 'PyQt4.QtNetwork', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtTest', 'PyQt4.QtWebKit', 'PyQt4.QtXml', 'PyQt4.phonon', ] # py2exe options for Windows packaging py2exe_options = dict( packages=["encodings"], excludes=py_excludes + ['win32com.gen_py'], # silence py2exe error about not finding msvcp90.dll dll_excludes=['MSVCP90.dll'], # add sip so that PyQt4 works # add PyQt4.QtSql so that sqlite needed by QHelpCollection works includes=py_includes + ["sip", "PyQt4.QtSql"], compressed=1, optimize=2, ) # py2app options for OSX packaging py2app_options = dict( includes=py_includes + ['sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtSql'], excludes=py_excludes, strip=True, optimize=2, iconfile='doc/html/favicon.icns', plist={ 'CFBundleIdentifier': 'org.pythonmac.%s' % AppName, 'CFBundleIconFile': 'favicon.icns', }, argv_emulation=True, ) # cx_Freeze for Linux RPM packaging cx_includes = [x[:-2] for x in py_includes] cxfreeze_options = dict( packages=["encodings"], excludes=py_excludes, includes=cx_includes + ['sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtSql'], ) def normpath (path): """Norm a path name to platform specific notation.""" return os.path.normpath(path) def cnormpath (path): """Norm a path name to platform specific notation and make it absolute.""" path = normpath(path) if os.name == 'nt': # replace slashes with backslashes path = path.replace("/", "\\") if not os.path.isabs(path): path = normpath(os.path.join(sys.prefix, path)) return path def get_nt_platform_vars (): """Return program file path and architecture for NT systems.""" platform = util.get_platform() if platform == "win-amd64": # the Visual C++ runtime files are installed in the x86 directory progvar = "%ProgramFiles(x86)%" architecture = "amd64" elif platform == "win32": progvar = "%ProgramFiles%" architecture = "x86" else: raise ValueError("Unsupported platform %r" % platform) return os.path.expandvars(progvar), architecture release_ro = re.compile(r"\(released (.+)\)") def get_release_date (): """Parse and return relase date as string from doc/changelog.txt.""" fname = os.path.join("doc", "changelog.txt") release_date = "unknown" with open(fname) as fd: # the release date is on the first line line = fd.readline() mo = release_ro.search(line) if mo: release_date = mo.groups(1) return release_date def get_portable(): """Return portable flag as string.""" return os.environ.get('LINKCHECKER_PORTABLE', '0') def get_qt_plugin_dir_win (): """Get Qt plugin dir on Windows systems.""" import PyQt4 return os.path.join(os.path.dirname(PyQt4.__file__), "plugins") def get_qt_plugin_dir_osx (): """Get Qt plugin dir on OSX systems.""" # note: works on Qt installed with homebrew qtbindir = os.path.dirname(os.path.realpath(find_executable("qmake"))) return os.path.join(os.path.dirname(qtbindir), "plugins") def add_qt_plugin_file (files, plugin_dir, dirname, filename): """Add one Qt plugin file to list of data files.""" files.append((dirname, [os.path.join(plugin_dir, dirname, filename)])) def add_qt_plugin_files (files): """Add needed Qt plugins to list of data files. Filename prefix and suffix are different for Windows and OSX.""" if os.name == 'nt': plugin_dir = get_qt_plugin_dir_win() args = ("", "4.dll") elif sys.platform == 'darwin': plugin_dir = get_qt_plugin_dir_osx() args = ("lib", ".dylib") else: raise ValueError("unsupported qt plugin platform") # Copy needed sqlite plugin files to distribution directory. add_qt_plugin_file(files, plugin_dir, "sqldrivers", "%sqsqlite%s" % args) # Copy needed gif image plugin files to distribution directory. add_qt_plugin_file(files, plugin_dir, "imageformats", "%sqgif%s" % args) def fix_qt_plugins_py2app (dist_dir): """Fix Qt plugin files installed in data_dir by moving them to app_dir/Plugins and change the install_name.""" app_dir = os.path.join(dist_dir, '%s.app' % AppName, 'Contents') plugin_dir = os.path.join(app_dir, 'Plugins') data_dir = os.path.join(app_dir, 'Resources') qt_lib_dir = os.path.join(os.path.dirname(get_qt_plugin_dir_osx()), 'lib') # make target plugin directory os.mkdir(plugin_dir) qt_plugins = ('sqldrivers', 'imageformats') qt_modules = ('QtCore', 'QtGui', 'QtSql') for plugin in qt_plugins: target_dir = os.path.join(plugin_dir, plugin) # move libraries os.rename(os.path.join(data_dir, plugin), target_dir) # fix libraries for library in glob.glob("%s/*.dylib" % target_dir): for module in qt_modules: libpath = "%s.framework/Versions/4/%s" % (module, module) oldpath = os.path.join(qt_lib_dir, libpath) newpath = '@executable_path/../Frameworks/%s' % libpath args = ['install_name_tool', '-change', oldpath, newpath, library] subprocess.check_call(args) def generate_dmg_image (dist_dir): """Generate .dmg image.""" imgPath = os.path.join(dist_dir, "%s-%s.dmg" % (AppName, AppVersion)) tmpImgPath = os.path.join(dist_dir, "%s.tmp.dmg" % AppName) print("*** generating temporary DMG image ***") args = ['hdiutil', 'create', '-srcfolder', dist_dir, '-fs', 'HFSX', '-volname', AppName, '-format', 'UDZO', tmpImgPath] subprocess.check_call(args) print("*** generating final DMG image ***") args = ['hdiutil', 'convert', tmpImgPath, '-format', 'UDZO', '-imagekey', 'zlib-level=9', '-o', imgPath] subprocess.check_call(args) os.remove(tmpImgPath) def sign_the_code (dist_dir): """Sign the OSX application code.""" app_dir = os.path.join(dist_dir, "%s.app" % AppName) args = ['codesign', '-s', myname, '-v', app_dir] print("*** signing the application code ***") try: subprocess.check_call(args) except subprocess.CalledProcessError as msg: print("WARN: codesigning failed", msg) def add_msvc_files (files): """Add needed MSVC++ runtime files. Only Version 9.0.21022.8 is tested and can be downloaded here: http://www.microsoft.com/en-us/download/details.aspx?id=5582 """ prog_dir, architecture = get_nt_platform_vars() dirname = "Microsoft.VC90.CRT" version = "%s_%s_%s" % (MSVCP90Token, MSVCP90Version, MSVCP90Suffix) args = (architecture, dirname, version) path = r'C:\Windows\WinSxS\%s_%s_%s\*.*' % args files.append((dirname, glob.glob(path))) # Copy the manifest file into the build directory and rename it # because it must have the same name as the directory. path = r'C:\Windows\WinSxS\Manifests\%s_%s_%s.manifest' % args target = os.path.join(os.getcwd(), 'build', '%s.manifest' % dirname) shutil.copy(path, target) files.append((dirname, [target])) def add_requests_cert_file(files): """Add Python requests .pem file for installers.""" import requests filename = os.path.join(os.path.dirname(requests.__file__), 'cacert.pem') dirname = 'share/linkchecker' files.append((dirname, [filename])) def insert_dns_path(): """Let py2exe, py2app and cx_Freeze find the dns package.""" lib_dir = "lib.%s-%s" % (util.get_platform(), sys.version[0:3]) if hasattr(sys, 'gettotalrefcount'): lib_dir += '-pydebug' dnspath = os.path.abspath(os.path.join('build', lib_dir, 'linkcheck_dns')) if dnspath not in sys.path: sys.path.insert(0, dnspath) class MyInstallLib (install_lib, object): """Custom library installation.""" def install (self): """Install the generated config file.""" outs = super(MyInstallLib, self).install() infile = self.create_conf_file() outfile = os.path.join(self.install_dir, os.path.basename(infile)) self.copy_file(infile, outfile) outs.append(outfile) return outs def create_conf_file (self): """Create configuration file.""" cmd_obj = self.distribution.get_command_obj("install") cmd_obj.ensure_finalized() # we have to write a configuration file because we need the # directory (and other stuff like author, url, ...) # all paths are made absolute by cnormpath() data = [] for d in ['purelib', 'platlib', 'lib', 'headers', 'scripts', 'data']: attr = 'install_%s' % d if cmd_obj.root: # cut off root path prefix cutoff = len(cmd_obj.root) # don't strip the path separator if cmd_obj.root.endswith(os.sep): cutoff -= 1 val = getattr(cmd_obj, attr)[cutoff:] else: val = getattr(cmd_obj, attr) if attr == 'install_data': cdir = os.path.join(val, "share", "linkchecker") data.append('config_dir = %r' % cnormpath(cdir)) elif attr == 'install_lib': if cmd_obj.root: _drive, tail = os.path.splitdrive(val) if tail.startswith(os.sep): tail = tail[1:] self.install_lib = os.path.join(cmd_obj.root, tail) else: self.install_lib = val data.append("%s = %r" % (attr, cnormpath(val))) self.distribution.create_conf_file(data, directory=self.install_lib) return self.get_conf_output() def get_conf_output (self): """Get name of configuration file.""" return self.distribution.get_conf_filename(self.install_lib) def get_outputs (self): """Add the generated config file to the list of outputs.""" outs = super(MyInstallLib, self).get_outputs() conf_output = self.get_conf_output() outs.append(conf_output) if self.compile: outs.extend(self._bytecode_filenames([conf_output])) return outs class MyInstallData (install_data, object): """Handle locale files and permissions.""" def run (self): """Adjust permissions on POSIX systems.""" self.add_message_files() super(MyInstallData, self).run() self.fix_permissions() def add_message_files (self): """Add locale message files to data_files list.""" for (src, dst) in list_message_files(self.distribution.get_name()): dstdir = os.path.dirname(dst) self.data_files.append((dstdir, [os.path.join("build", dst)])) def fix_permissions (self): """Set correct read permissions on POSIX systems. Might also be possible by setting umask?""" if os.name == 'posix' and not self.dry_run: # Make the data files we just installed world-readable, # and the directories world-executable as well. for path in self.get_outputs(): mode = os.stat(path)[stat.ST_MODE] if stat.S_ISDIR(mode): mode |= 0o11 mode |= 0o44 os.chmod(path, mode) # Microsoft application manifest for linkchecker-gui.exe; see also # http://msdn.microsoft.com/en-us/library/aa374191%28VS.85%29.aspx app_manifest = """ """ % dict(appversion=AppVersion, appname=AppName, msvcrtversion=MSVCP90Version, msvcrttoken=MSVCP90Token) class MyDistribution (Distribution, object): """Custom distribution class generating config file.""" def __init__ (self, attrs): """Set console and windows scripts.""" super(MyDistribution, self).__init__(attrs) self.console = ['linkchecker'] self.windows = [{ "script": "linkchecker-gui", "icon_resources": [(1, "doc/html/favicon.ico")], "other_resources": [(24, 1, app_manifest)], }] def run_commands (self): """Generate config file and run commands.""" cwd = os.getcwd() data = [] data.append('config_dir = %r' % os.path.join(cwd, "config")) data.append("install_data = %r" % cwd) data.append("install_scripts = %r" % cwd) self.create_conf_file(data) super(MyDistribution, self).run_commands() def get_conf_filename (self, directory): """Get name for config file.""" return os.path.join(directory, "_%s_configdata.py" % self.get_name()) def create_conf_file (self, data, directory=None): """Create local config file from given data (list of lines) in the directory (or current directory if not given).""" data.insert(0, "# this file is automatically created by setup.py") data.insert(0, "# -*- coding: iso-8859-1 -*-") if directory is None: directory = os.getcwd() filename = self.get_conf_filename(directory) # add metadata metanames = ("name", "version", "author", "author_email", "maintainer", "maintainer_email", "url", "license", "description", "long_description", "keywords", "platforms", "fullname", "contact", "contact_email") for name in metanames: method = "get_" + name val = getattr(self.metadata, method)() if isinstance(val, str): val = unicode(val) cmd = "%s = %r" % (name, val) data.append(cmd) data.append('release_date = "%s"' % get_release_date()) data.append('portable = %s' % get_portable()) # write the config file util.execute(write_file, (filename, data), "creating %s" % filename, self.verbose >= 1, self.dry_run) def cc_run (args): """Run the C compiler with a simple main program. @return: successful exit flag @rtype: bool """ prog = "int main(){}\n" pipe = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True) pipe.communicate(input=prog) if os.WIFEXITED(pipe.returncode): return os.WEXITSTATUS(pipe.returncode) == 0 return False def cc_supports_option (cc, option): """Check if the given C compiler supports the given option. @return: True if the compiler supports the option, else False @rtype: bool """ return cc_run([cc[0], "-E", option, "-"]) class MyBuildExt (build_ext, object): """Custom build extension command.""" def build_extensions (self): """Add -std=gnu99 to build options if supported.""" # For gcc >= 3 we can add -std=gnu99 to get rid of warnings. extra = [] if self.compiler.compiler_type == 'unix': option = "-std=gnu99" if cc_supports_option(self.compiler.compiler, option): extra.append(option) # First, sanity-check the 'extensions' list self.check_extensions_list(self.extensions) for ext in self.extensions: for opt in extra: if opt not in ext.extra_compile_args: ext.extra_compile_args.append(opt) self.build_extension(ext) def list_message_files (package, suffix=".po"): """Return list of all found message files and their installation paths.""" for fname in glob.glob("po/*" + suffix): # basename (without extension) is a locale name localename = os.path.splitext(os.path.basename(fname))[0] domainname = "%s.mo" % package.lower() yield (fname, os.path.join( "share", "locale", localename, "LC_MESSAGES", domainname)) def check_manifest (): """Snatched from roundup.sf.net. Check that the files listed in the MANIFEST are present when the source is unpacked.""" try: f = open('MANIFEST') except Exception: print('\n*** SOURCE WARNING: The MANIFEST file is missing!') return try: manifest = [l.strip() for l in f.readlines() if not l.startswith('#')] finally: f.close() err = [line for line in manifest if not os.path.exists(line)] if err: n = len(manifest) print('\n*** SOURCE WARNING: There are files missing (%d/%d found)!' % (n - len(err), n)) print('\nMissing: '.join(err)) class MyBuild (build, object): """Custom build command.""" def build_message_files (self): """For each po/*.po, build .mo file in target locale directory.""" # msgfmt.py is in the po/ subdirectory sys.path.append('po') import msgfmt for (src, dst) in list_message_files(self.distribution.get_name()): build_dst = os.path.join("build", dst) self.mkpath(os.path.dirname(build_dst)) self.announce("Compiling %s -> %s" % (src, build_dst)) msgfmt.make(src, build_dst) def run (self): """Check MANIFEST and build message files before building.""" check_manifest() self.build_message_files() build.run(self) class MyClean (clean, object): """Custom clean command.""" def run (self): """Remove share directory on clean.""" if self.all: # remove share directory directory = os.path.join("build", "share") if os.path.exists(directory): remove_tree(directory, dry_run=self.dry_run) else: log.warn("'%s' does not exist -- can't clean it", directory) clean.run(self) class MySdist (sdist, object): """Custom sdist command.""" def get_file_list (self): """Add MANIFEST to the file list.""" super(MySdist, self).get_file_list() self.filelist.append("MANIFEST") # global include dirs include_dirs = [] # global macros define_macros = [] # compiler args extra_compile_args = [] # library directories library_dirs = [] # libraries libraries = [] # scripts scripts = ['linkchecker', 'linkchecker-gui'] if os.name == 'nt': # windows does not have unistd.h define_macros.append(('YY_NO_UNISTD_H', None)) else: extra_compile_args.append("-pedantic") if sys.platform == 'darwin': define_macros.extend([('HAVE_STRLCPY', None), ('HAVE_STRLCAT', None)]) myname = "Bastian Kleineidam" myemail = "bastian.kleineidam@web.de" data_files = [ ('share/linkchecker', ['config/linkcheckerrc', 'doc/html/lccollection.qhc', 'doc/html/lcdoc.qch']), ('share/linkchecker/examples', ['cgi-bin/lconline/leer.html.en', 'cgi-bin/lconline/leer.html.de', 'cgi-bin/lconline/index.html', 'cgi-bin/lconline/lc_cgi.html.en', 'cgi-bin/lconline/lc_cgi.html.de', 'cgi-bin/lconline/check.js', 'cgi-bin/lc.wsgi', 'config/linkchecker.apache2.conf', ]), ] if os.name == 'posix': data_files.append(('share/man/man1', ['doc/en/linkchecker.1', 'doc/en/linkchecker-gui.1'])) data_files.append(('share/man/man5', ['doc/en/linkcheckerrc.5'])) data_files.append(('share/man/de/man1', ['doc/de/linkchecker.1', 'doc/de/linkchecker-gui.1'])) data_files.append(('share/man/de/man5', ['doc/de/linkcheckerrc.5'])) data_files.append(('share/linkchecker/examples', ['config/linkchecker-completion', 'doc/examples/check_blacklist.sh', 'doc/examples/check_for_x_errors.sh', 'doc/examples/check_urls.sh'])) data_files.append(('share/applications', ['doc/linkchecker.desktop'])) data_files.append(('share/applications', ['doc/linkchecker-gui.desktop'])) if 'py2app' in sys.argv[1:]: if not has_py2app: raise SystemExit("py2app module could not be imported.") # add Qt plugins which are later fixed by fix_qt_plugins_py2app() add_qt_plugin_files(data_files) # needed for Qt to load the plugins data_files.append(('', ['osx/qt.conf'])) add_requests_cert_file(data_files) insert_dns_path() elif 'py2exe' in sys.argv[1:]: if not has_py2exe: raise SystemExit("py2exe module could not be imported") add_qt_plugin_files(data_files) add_msvc_files(data_files) add_requests_cert_file(data_files) insert_dns_path() elif do_freeze: class MyInstallExe (install_exe, object): """Install cx_Freeze executables.""" def run (self): """Add generated configuration to output files.""" super(MyInstallExe, self).run() cmd_obj = self.distribution.get_command_obj("install_lib") cmd_obj.ensure_finalized() self.outfiles.append(cmd_obj.get_conf_output()+"c") insert_dns_path() class InnoScript: """Class to generate INNO script.""" def __init__(self, lib_dir, dist_dir, windows_exe_files=[], console_exe_files=[], service_exe_files=[], comserver_files=[], lib_files=[]): """Store INNO script infos.""" self.lib_dir = lib_dir self.dist_dir = dist_dir if not self.dist_dir[-1] in "\\/": self.dist_dir += "\\" self.name = AppName self.version = AppVersion self.windows_exe_files = [self.chop(p) for p in windows_exe_files] self.console_exe_files = [self.chop(p) for p in console_exe_files] self.service_exe_files = [self.chop(p) for p in service_exe_files] self.comserver_files = [self.chop(p) for p in comserver_files] self.lib_files = [self.chop(p) for p in lib_files] self.icon = os.path.abspath(r'doc\html\favicon.ico') def chop(self, pathname): """Remove distribution directory from path name.""" assert pathname.startswith(self.dist_dir) return pathname[len(self.dist_dir):] def create(self, pathname=r"dist\omt.iss"): """Create Inno script.""" self.pathname = pathname self.distfilebase = "%s-%s" % (self.name, self.version) self.distfile = self.distfilebase + ".exe" with codecs.open(self.pathname, "w", 'utf-8-sig', 'strict') as fd: self.write_inno_script(fd) def write_inno_script (self, fd): """Write Inno script contents.""" print("; WARNING: This script has been created by py2exe. Changes to this script", file=fd) print("; will be overwritten the next time py2exe is run!", file=fd) print("[Setup]", file=fd) print("AppName=%s" % self.name, file=fd) print("AppVerName=%s %s" % (self.name, self.version), file=fd) print(r"DefaultDirName={pf}\%s" % self.name, file=fd) print("DefaultGroupName=%s" % self.name, file=fd) print("OutputBaseFilename=%s" % self.distfilebase, file=fd) print("OutputDir=..", file=fd) print("SetupIconFile=%s" % self.icon, file=fd) print("UninstallDisplayIcon=%s" % self.icon, file=fd) print(file=fd) # Customize some messages print("[Messages]", file=fd) print("ConfirmUninstall=Are you sure you want to remove %1? Note that user-specific configuration files of %1 are not removed.", file=fd) print("BeveledLabel=DON'T PANIC", file=fd) print(file=fd) # List of source files files = self.windows_exe_files + \ self.console_exe_files + \ self.service_exe_files + \ self.comserver_files + \ self.lib_files print('[Files]', file=fd) for path in files: print(r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path)), file=fd) print(file=fd) # Set icon filename print('[Icons]', file=fd) for path in self.windows_exe_files: print(r'Name: "{group}\%s"; Filename: "{app}\%s"' % \ (self.name, path), file=fd) print(r'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name, file=fd) print(file=fd) # Uninstall registry keys print('[Registry]', file=fd) print(r'Root: HKCU; Subkey: "Software\Bastian\LinkChecker"; Flags: uninsdeletekey', file=fd) print(file=fd) # Uninstall optional log files print('[UninstallDelete]', file=fd) for path in (self.windows_exe_files + self.console_exe_files): exename = os.path.basename(path) print(r'Type: files; Name: "{pf}\%s\%s.log"' % (self.name, exename), file=fd) print(file=fd) def compile (self): """Compile Inno script with iscc.exe.""" progpath = get_nt_platform_vars()[0] cmd = r'%s\Inno Setup 5\iscc.exe' % progpath subprocess.check_call([cmd, self.pathname]) def sign (self): """Sign InnoSetup installer with local self-signed certificate.""" print("*** signing the inno setup installer ***") pfxfile = r'windows\linkchecker.pfx' if os.path.isfile(pfxfile): path = get_windows_sdk_path() signtool = os.path.join(path, "bin", "signtool.exe") if os.path.isfile(signtool): cmd = [signtool, 'sign', '/f', pfxfile, self.distfile] subprocess.check_call(cmd) else: print("No signed installer: signtool.exe not found.") else: print("No signed installer: certificate %s not found." % pfxfile) def get_windows_sdk_path(): """Return path of Microsoft Windows SDK installation, or None if not found.""" try: import _winreg as winreg except ImportError: import winreg sub_key = r"Software\Microsoft\Microsoft SDKs\Windows" with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, sub_key) as key: name = "CurrentInstallFolder" return winreg.QueryValueEx(key, name)[0] return None try: from py2exe.build_exe import py2exe as py2exe_build class MyPy2exe (py2exe_build): """First builds the exe file(s), then creates a Windows installer. Needs InnoSetup to be installed.""" def run (self): """Generate py2exe installer.""" # First, let py2exe do it's work. py2exe_build.run(self) print("*** preparing the inno setup script ***") lib_dir = self.lib_dir dist_dir = self.dist_dir # create the Installer, using the files py2exe has created. script = InnoScript(lib_dir, dist_dir, self.windows_exe_files, self.console_exe_files, self.service_exe_files, self.comserver_files, self.lib_files) print("*** creating the inno setup script ***") script.create() print("*** compiling the inno setup script ***") script.compile() script.sign() except ImportError: class MyPy2exe: """Dummy py2exe class.""" pass try: from py2app.build_app import py2app as py2app_build class MyPy2app (py2app_build): """First builds the app file(s), then creates a DMG installer. Needs hdiutil to be installed.""" def run (self): """Generate py2app installer.""" # First, let py2app do it's work. py2app_build.run(self) # Fix install names for Qt plugin libraries. fix_qt_plugins_py2app(self.dist_dir) sign_the_code(self.dist_dir) generate_dmg_image(self.dist_dir) except ImportError: class MyPy2app: """Dummy py2app class.""" pass args = dict( name = AppName, version = AppVersion, description = Description, keywords = "link,url,site,checking,crawling,verification,validation", author = myname, author_email = myemail, maintainer = myname, maintainer_email = myemail, url = "http://wummel.github.io/linkchecker/", license = "GPL", long_description = get_long_description(), distclass = MyDistribution, cmdclass = { 'install_lib': MyInstallLib, 'install_data': MyInstallData, 'build_ext': MyBuildExt, 'build': MyBuild, 'clean': MyClean, 'sdist': MySdist, 'py2exe': MyPy2exe, 'py2app': MyPy2app, }, package_dir = { 'linkcheck_dns.dns': 'third_party/dnspython/dns', }, packages = [ 'linkcheck', 'linkcheck.bookmarks', 'linkcheck.cache', 'linkcheck.checker', 'linkcheck.configuration', 'linkcheck.director', 'linkcheck.gui', 'linkcheck.htmlutil', 'linkcheck.HtmlParser', 'linkcheck.logger', 'linkcheck.network', 'linkcheck.parser', 'linkcheck.plugins', 'linkcheck_dns.dns', 'linkcheck_dns.dns.rdtypes', 'linkcheck_dns.dns.rdtypes.ANY', 'linkcheck_dns.dns.rdtypes.IN', ], ext_modules = [ Extension('linkcheck.HtmlParser.htmlsax', sources = [ 'linkcheck/HtmlParser/htmllex.c', 'linkcheck/HtmlParser/htmlparse.c', 'linkcheck/HtmlParser/s_util.c', ], extra_compile_args = extra_compile_args, library_dirs = library_dirs, libraries = libraries, define_macros = define_macros + [('YY_NO_INPUT', None)], include_dirs = include_dirs + [normpath("linkcheck/HtmlParser")], ), Extension("linkcheck.network._network", sources = ["linkcheck/network/_network.c"], extra_compile_args = extra_compile_args, library_dirs = library_dirs, libraries = libraries, define_macros = define_macros, include_dirs = include_dirs, ), ], scripts = scripts, data_files = data_files, classifiers = [ 'Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking', 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Programming Language :: Python', 'Programming Language :: C', ], options = { "py2exe": py2exe_options, "py2app": py2app_options, "build_exe": cxfreeze_options, }, # Requirements, usable with setuptools or the new Python packaging module. # Commented out since they are untested and not officially supported. # See also doc/install.txt for more detailed dependency documentation. #extra_requires = { # "IP country info": ['GeoIP'], # http://www.maxmind.com/app/python # "GNOME proxies": ['pygtk'], # http://www.pygtk.org/downloads.html # "Bash completion": ['argcomplete'], # https://pypi.python.org/pypi/argcomplete # "Memory debugging": ['meliae'], # https://launchpad.net/meliae #} ) if sys.platform == 'darwin': args["app"] = ['linkchecker-gui'] if executables: args["executables"] = executables args["cmdclass"]["install_exe"] = MyInstallExe if setuptools is not None: args['install_requires'] = [ 'requests >= 2.2.0', ] setup(**args) LinkChecker-9.3/PKG-INFO0000640000175000017500000000427612361541761015431 0ustar calvincalvin00000000000000Metadata-Version: 1.1 Name: LinkChecker Version: 9.3 Summary: check links in web documents or full websites Home-page: http://wummel.github.io/linkchecker/ Author: Bastian Kleineidam Author-email: bastian.kleineidam@web.de License: GPL Description: LinkChecker ============ |Build Status|_ |Latest Version|_ |License|_ .. |Build Status| image:: https://travis-ci.org/wummel/linkchecker.png?branch=master .. _Build Status: https://travis-ci.org/wummel/linkchecker .. |Latest Version| image:: http://img.shields.io/pypi/v/LinkChecker.svg .. _Latest Version: https://pypi.python.org/pypi/LinkChecker .. |License| image:: http://img.shields.io/badge/license-GPL2-d49a6a.svg .. _License: http://opensource.org/licenses/GPL-2.0 Check for broken links in web sites. Features --------- - recursive and multithreaded checking and site crawling - output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats - HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet and local file links support - restrict link checking with regular expression filters for URLs - proxy support - username/password authorization for HTTP, FTP and Telnet - honors robots.txt exclusion protocol - Cookie support - HTML5 support - a command line, GUI and web interface - various check plugins available, eg. HTML syntax and antivirus checks. Installation ------------- See doc/install.txt in the source code archive. Python 2.7.2 or later is needed. Usage ------ Execute ``linkchecker http://www.example.com``. For other options see ``linkchecker --help``. Keywords: link,url,site,checking,crawling,verification,validation Platform: UNKNOWN Classifier: Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking Classifier: Development Status :: 5 - Production/Stable Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Programming Language :: Python Classifier: Programming Language :: C LinkChecker-9.3/linkchecker.freecode0000644000175000017500000000107112361407402020277 0ustar calvincalvin00000000000000Project: LinkChecker Version: 9.3 Website-URL: http://wummel.github.io/linkchecker/ Changelog-URL: https://github.com/wummel/linkchecker/blob/master/doc/changelog.txt Source-Package-URL: https://pypi.python.org/packages/source/L/LinkChecker/LinkChecker-${version}.tar.gz Debian-Package-URL: http://packages.debian.org/linkchecker GIT-Tree-URL: https://github.com/wummel/linkchecker.git Windows-installer-URL: http://wummel.github.io/linkchecker/dist/LinkChecker-${version}.exe This file is now only used for update checks since freecode.com is not functional anymore. LinkChecker-9.3/MANIFEST.in0000644000175000017500000000264312361407402016063 0ustar calvincalvin00000000000000include README.txt COPYING MANIFEST.in include config/linkchecker-completion config/create.sql include config/linkcheckerrc include config/linkchecker.apache2.conf install-rpm.sh include linkchecker.freecode include cgi-bin/lc.wsgi cgi-bin/README include Makefile include cgi-bin/lconline/*.html cgi-bin/lconline/*.de cgi-bin/lconline/*.en include cgi-bin/lconline/*.js cgi-bin/lconline/*.css cgi-bin/lconline/*.ico include linkcheck/HtmlParser/Makefile include linkcheck/HtmlParser/htmllex.l include linkcheck/HtmlParser/htmlparse.y include linkcheck/HtmlParser/*.h include linkcheck/HtmlParser/fixincludes.awk include linkcheck/gui/Makefile include linkcheck/gui/rc/Makefile include linkcheck/gui/rc/*.png include linkcheck/gui/rc/*.qrc include linkcheck/gui/ui/*.ui include po/*.po po/*.pot po/Makefile po/msgfmt.py include doc/*.example doc/*.txt include doc/html/*.ico include doc/html/*.html include doc/html/*.txt include doc/html/*.png include doc/html/*.qhp include doc/html/*.qhcp include doc/html/Makefile include doc/po4a.conf doc/*.po doc/*.pot include doc/en/*.1 doc/en/*.5 include doc/de/*.1 doc/de/*.5 include doc/Makefile include doc/examples/*.sh doc/examples/*.bat doc/examples/*.py include doc/examples/linkcheckerrc_loginurl include scripts/*.sh scripts/*.py recursive-include third_party *.py *.txt Makefile example* recursive-include tests *.py *.result *.html *.ico *.txt *.zip *.asc *.css *.xhtml *.sqlite *.adr *.swf LinkChecker-9.3/COPYING0000644000175000017500000004310311150300124015340 0ustar calvincalvin00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. LinkChecker-9.3/third_party/0000750000175000017500000000000012361541761016653 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/dnspython/0000750000175000017500000000000012361541761020701 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/dnspython/dns/0000750000175000017500000000000012361541761021465 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/dnspython/dns/name.py0000644000175000017500000005273411570774061023001 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Names. @var root: The DNS root name. @type root: dns.name.Name object @var empty: The empty DNS name. @type empty: dns.name.Name object """ import cStringIO import struct import sys if sys.hexversion >= 0x02030000: import encodings.idna import dns.exception import dns.wiredata NAMERELN_NONE = 0 NAMERELN_SUPERDOMAIN = 1 NAMERELN_SUBDOMAIN = 2 NAMERELN_EQUAL = 3 NAMERELN_COMMONANCESTOR = 4 class EmptyLabel(dns.exception.SyntaxError): """Raised if a label is empty.""" pass class BadEscape(dns.exception.SyntaxError): """Raised if an escaped code in a text format name is invalid.""" pass class BadPointer(dns.exception.FormError): """Raised if a compression pointer points forward instead of backward.""" pass class BadLabelType(dns.exception.FormError): """Raised if the label type of a wire format name is unknown.""" pass class NeedAbsoluteNameOrOrigin(dns.exception.DNSException): """Raised if an attempt is made to convert a non-absolute name to wire when there is also a non-absolute (or missing) origin.""" pass class NameTooLong(dns.exception.FormError): """Raised if a name is > 255 octets long.""" pass class LabelTooLong(dns.exception.SyntaxError): """Raised if a label is > 63 octets long.""" pass class AbsoluteConcatenation(dns.exception.DNSException): """Raised if an attempt is made to append anything other than the empty name to an absolute name.""" pass class NoParent(dns.exception.DNSException): """Raised if an attempt is made to get the parent of the root name or the empty name.""" pass _escaped = { '"' : True, '(' : True, ')' : True, '.' : True, ';' : True, '\\' : True, '@' : True, '$' : True } def _escapify(label): """Escape the characters in label which need it. @returns: the escaped string @rtype: string""" text = '' for c in label: if c in _escaped: text += '\\' + c elif ord(c) > 0x20 and ord(c) < 0x7F: text += c else: text += '\\%03d' % ord(c) return text def _validate_labels(labels): """Check for empty labels in the middle of a label sequence, labels that are too long, and for too many labels. @raises NameTooLong: the name as a whole is too long @raises LabelTooLong: an individual label is too long @raises EmptyLabel: a label is empty (i.e. the root label) and appears in a position other than the end of the label sequence""" l = len(labels) total = 0 i = -1 j = 0 for label in labels: ll = len(label) total += ll + 1 if ll > 63: raise LabelTooLong if i < 0 and label == '': i = j j += 1 if total > 255: raise NameTooLong if i >= 0 and i != l - 1: raise EmptyLabel class Name(object): """A DNS name. The dns.name.Name class represents a DNS name as a tuple of labels. Instances of the class are immutable. @ivar labels: The tuple of labels in the name. Each label is a string of up to 63 octets.""" __slots__ = ['labels'] def __init__(self, labels): """Initialize a domain name from a list of labels. @param labels: the labels @type labels: any iterable whose values are strings """ super(Name, self).__setattr__('labels', tuple(labels)) _validate_labels(self.labels) def __setattr__(self, name, value): raise TypeError("object doesn't support attribute assignment") def is_absolute(self): """Is the most significant label of this name the root label? @rtype: bool """ return len(self.labels) > 0 and self.labels[-1] == '' def is_wild(self): """Is this name wild? (I.e. Is the least significant label '*'?) @rtype: bool """ return len(self.labels) > 0 and self.labels[0] == '*' def __hash__(self): """Return a case-insensitive hash of the name. @rtype: int """ h = 0L for label in self.labels: for c in label: h += ( h << 3 ) + ord(c.lower()) return int(h % sys.maxint) def fullcompare(self, other): """Compare two names, returning a 3-tuple (relation, order, nlabels). I{relation} describes the relation ship beween the names, and is one of: dns.name.NAMERELN_NONE, dns.name.NAMERELN_SUPERDOMAIN, dns.name.NAMERELN_SUBDOMAIN, dns.name.NAMERELN_EQUAL, or dns.name.NAMERELN_COMMONANCESTOR I{order} is < 0 if self < other, > 0 if self > other, and == 0 if self == other. A relative name is always less than an absolute name. If both names have the same relativity, then the DNSSEC order relation is used to order them. I{nlabels} is the number of significant labels that the two names have in common. """ sabs = self.is_absolute() oabs = other.is_absolute() if sabs != oabs: if sabs: return (NAMERELN_NONE, 1, 0) else: return (NAMERELN_NONE, -1, 0) l1 = len(self.labels) l2 = len(other.labels) ldiff = l1 - l2 if ldiff < 0: l = l1 else: l = l2 order = 0 nlabels = 0 namereln = NAMERELN_NONE while l > 0: l -= 1 l1 -= 1 l2 -= 1 label1 = self.labels[l1].lower() label2 = other.labels[l2].lower() if label1 < label2: order = -1 if nlabels > 0: namereln = NAMERELN_COMMONANCESTOR return (namereln, order, nlabels) elif label1 > label2: order = 1 if nlabels > 0: namereln = NAMERELN_COMMONANCESTOR return (namereln, order, nlabels) nlabels += 1 order = ldiff if ldiff < 0: namereln = NAMERELN_SUPERDOMAIN elif ldiff > 0: namereln = NAMERELN_SUBDOMAIN else: namereln = NAMERELN_EQUAL return (namereln, order, nlabels) def is_subdomain(self, other): """Is self a subdomain of other? The notion of subdomain includes equality. @rtype: bool """ (nr, o, nl) = self.fullcompare(other) if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL: return True return False def is_superdomain(self, other): """Is self a superdomain of other? The notion of subdomain includes equality. @rtype: bool """ (nr, o, nl) = self.fullcompare(other) if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL: return True return False def canonicalize(self): """Return a name which is equal to the current name, but is in DNSSEC canonical form. @rtype: dns.name.Name object """ return Name([x.lower() for x in self.labels]) def __eq__(self, other): if isinstance(other, Name): return self.fullcompare(other)[1] == 0 else: return False def __ne__(self, other): if isinstance(other, Name): return self.fullcompare(other)[1] != 0 else: return True def __lt__(self, other): if isinstance(other, Name): return self.fullcompare(other)[1] < 0 else: return NotImplemented def __le__(self, other): if isinstance(other, Name): return self.fullcompare(other)[1] <= 0 else: return NotImplemented def __ge__(self, other): if isinstance(other, Name): return self.fullcompare(other)[1] >= 0 else: return NotImplemented def __gt__(self, other): if isinstance(other, Name): return self.fullcompare(other)[1] > 0 else: return NotImplemented def __repr__(self): return '' def __str__(self): return self.to_text(False) def to_text(self, omit_final_dot = False): """Convert name to text format. @param omit_final_dot: If True, don't emit the final dot (denoting the root label) for absolute names. The default is False. @rtype: string """ if len(self.labels) == 0: return '@' if len(self.labels) == 1 and self.labels[0] == '': return '.' if omit_final_dot and self.is_absolute(): l = self.labels[:-1] else: l = self.labels s = '.'.join(map(_escapify, l)) return s def to_unicode(self, omit_final_dot = False): """Convert name to Unicode text format. IDN ACE lables are converted to Unicode. @param omit_final_dot: If True, don't emit the final dot (denoting the root label) for absolute names. The default is False. @rtype: string """ if len(self.labels) == 0: return u'@' if len(self.labels) == 1 and self.labels[0] == '': return u'.' if omit_final_dot and self.is_absolute(): l = self.labels[:-1] else: l = self.labels s = u'.'.join([encodings.idna.ToUnicode(_escapify(x)) for x in l]) return s def to_digestable(self, origin=None): """Convert name to a format suitable for digesting in hashes. The name is canonicalized and converted to uncompressed wire format. @param origin: If the name is relative and origin is not None, then origin will be appended to it. @type origin: dns.name.Name object @raises NeedAbsoluteNameOrOrigin: All names in wire format are absolute. If self is a relative name, then an origin must be supplied; if it is missing, then this exception is raised @rtype: string """ if not self.is_absolute(): if origin is None or not origin.is_absolute(): raise NeedAbsoluteNameOrOrigin labels = list(self.labels) labels.extend(list(origin.labels)) else: labels = self.labels dlabels = ["%s%s" % (chr(len(x)), x.lower()) for x in labels] return ''.join(dlabels) def to_wire(self, file = None, compress = None, origin = None): """Convert name to wire format, possibly compressing it. @param file: the file where the name is emitted (typically a cStringIO file). If None, a string containing the wire name will be returned. @type file: file or None @param compress: The compression table. If None (the default) names will not be compressed. @type compress: dict @param origin: If the name is relative and origin is not None, then origin will be appended to it. @type origin: dns.name.Name object @raises NeedAbsoluteNameOrOrigin: All names in wire format are absolute. If self is a relative name, then an origin must be supplied; if it is missing, then this exception is raised """ if file is None: file = cStringIO.StringIO() want_return = True else: want_return = False if not self.is_absolute(): if origin is None or not origin.is_absolute(): raise NeedAbsoluteNameOrOrigin labels = list(self.labels) labels.extend(list(origin.labels)) else: labels = self.labels i = 0 for label in labels: n = Name(labels[i:]) i += 1 if not compress is None: pos = compress.get(n) else: pos = None if not pos is None: value = 0xc000 + pos s = struct.pack('!H', value) file.write(s) break else: if not compress is None and len(n) > 1: pos = file.tell() if pos < 0xc000: compress[n] = pos l = len(label) file.write(chr(l)) if l > 0: file.write(label) if want_return: return file.getvalue() def __len__(self): """The length of the name (in labels). @rtype: int """ return len(self.labels) def __getitem__(self, index): return self.labels[index] def __getslice__(self, start, stop): return self.labels[start:stop] def __add__(self, other): return self.concatenate(other) def __sub__(self, other): return self.relativize(other) def split(self, depth): """Split a name into a prefix and suffix at depth. @param depth: the number of labels in the suffix @type depth: int @raises ValueError: the depth was not >= 0 and <= the length of the name. @returns: the tuple (prefix, suffix) @rtype: tuple """ l = len(self.labels) if depth == 0: return (self, dns.name.empty) elif depth == l: return (dns.name.empty, self) elif depth < 0 or depth > l: raise ValueError('depth must be >= 0 and <= the length of the name') return (Name(self[: -depth]), Name(self[-depth :])) def concatenate(self, other): """Return a new name which is the concatenation of self and other. @rtype: dns.name.Name object @raises AbsoluteConcatenation: self is absolute and other is not the empty name """ if self.is_absolute() and len(other) > 0: raise AbsoluteConcatenation labels = list(self.labels) labels.extend(list(other.labels)) return Name(labels) def relativize(self, origin): """If self is a subdomain of origin, return a new name which is self relative to origin. Otherwise return self. @rtype: dns.name.Name object """ if not origin is None and self.is_subdomain(origin): return Name(self[: -len(origin)]) else: return self def derelativize(self, origin): """If self is a relative name, return a new name which is the concatenation of self and origin. Otherwise return self. @rtype: dns.name.Name object """ if not self.is_absolute(): return self.concatenate(origin) else: return self def choose_relativity(self, origin=None, relativize=True): """Return a name with the relativity desired by the caller. If origin is None, then self is returned. Otherwise, if relativize is true the name is relativized, and if relativize is false the name is derelativized. @rtype: dns.name.Name object """ if origin: if relativize: return self.relativize(origin) else: return self.derelativize(origin) else: return self def parent(self): """Return the parent of the name. @rtype: dns.name.Name object @raises NoParent: the name is either the root name or the empty name, and thus has no parent. """ if self == root or self == empty: raise NoParent return Name(self.labels[1:]) root = Name(['']) empty = Name([]) def from_unicode(text, origin = root): """Convert unicode text into a Name object. Lables are encoded in IDN ACE form. @rtype: dns.name.Name object """ if not isinstance(text, unicode): raise ValueError("input to from_unicode() must be a unicode string") if not (origin is None or isinstance(origin, Name)): raise ValueError("origin must be a Name or None") labels = [] label = u'' escaping = False edigits = 0 total = 0 if text == u'@': text = u'' if text: if text == u'.': return Name(['']) # no Unicode "u" on this constant! for c in text: if escaping: if edigits == 0: if c.isdigit(): total = int(c) edigits += 1 else: label += c escaping = False else: if not c.isdigit(): raise BadEscape total *= 10 total += int(c) edigits += 1 if edigits == 3: escaping = False label += chr(total) elif c == u'.' or c == u'\u3002' or \ c == u'\uff0e' or c == u'\uff61': if len(label) == 0: raise EmptyLabel labels.append(encodings.idna.ToASCII(label)) label = u'' elif c == u'\\': escaping = True edigits = 0 total = 0 else: label += c if escaping: raise BadEscape if len(label) > 0: labels.append(encodings.idna.ToASCII(label)) else: labels.append('') if (len(labels) == 0 or labels[-1] != '') and not origin is None: labels.extend(list(origin.labels)) return Name(labels) def from_text(text, origin = root): """Convert text into a Name object. @rtype: dns.name.Name object """ if not isinstance(text, str): if isinstance(text, unicode) and sys.hexversion >= 0x02030000: return from_unicode(text, origin) else: raise ValueError("input to from_text() must be a string") if not (origin is None or isinstance(origin, Name)): raise ValueError("origin must be a Name or None") labels = [] label = '' escaping = False edigits = 0 total = 0 if text == '@': text = '' if text: if text == '.': return Name(['']) for c in text: if escaping: if edigits == 0: if c.isdigit(): total = int(c) edigits += 1 else: label += c escaping = False else: if not c.isdigit(): raise BadEscape total *= 10 total += int(c) edigits += 1 if edigits == 3: escaping = False label += chr(total) elif c == '.': if len(label) == 0: raise EmptyLabel labels.append(label) label = '' elif c == '\\': escaping = True edigits = 0 total = 0 else: label += c if escaping: raise BadEscape if len(label) > 0: labels.append(label) else: labels.append('') if (len(labels) == 0 or labels[-1] != '') and not origin is None: labels.extend(list(origin.labels)) return Name(labels) def from_wire(message, current): """Convert possibly compressed wire format into a Name. @param message: the entire DNS message @type message: string @param current: the offset of the beginning of the name from the start of the message @type current: int @raises dns.name.BadPointer: a compression pointer did not point backwards in the message @raises dns.name.BadLabelType: an invalid label type was encountered. @returns: a tuple consisting of the name that was read and the number of bytes of the wire format message which were consumed reading it @rtype: (dns.name.Name object, int) tuple """ if not isinstance(message, str): raise ValueError("input to from_wire() must be a byte string") message = dns.wiredata.maybe_wrap(message) labels = [] biggest_pointer = current hops = 0 count = ord(message[current]) current += 1 cused = 1 while count != 0: if count < 64: labels.append(message[current : current + count].unwrap()) current += count if hops == 0: cused += count elif count >= 192: current = (count & 0x3f) * 256 + ord(message[current]) if hops == 0: cused += 1 if current >= biggest_pointer: raise BadPointer biggest_pointer = current hops += 1 else: raise BadLabelType count = ord(message[current]) current += 1 if hops == 0: cused += 1 labels.append('') return (Name(labels), cused) LinkChecker-9.3/third_party/dnspython/dns/reversename.py0000644000175000017500000000560011570774061024363 0ustar calvincalvin00000000000000# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Reverse Map Names. @var ipv4_reverse_domain: The DNS IPv4 reverse-map domain, in-addr.arpa. @type ipv4_reverse_domain: dns.name.Name object @var ipv6_reverse_domain: The DNS IPv6 reverse-map domain, ip6.arpa. @type ipv6_reverse_domain: dns.name.Name object """ import dns.name import dns.ipv6 import dns.ipv4 ipv4_reverse_domain = dns.name.from_text('in-addr.arpa.') ipv6_reverse_domain = dns.name.from_text('ip6.arpa.') def from_address(text): """Convert an IPv4 or IPv6 address in textual form into a Name object whose value is the reverse-map domain name of the address. @param text: an IPv4 or IPv6 address in textual form (e.g. '127.0.0.1', '::1') @type text: str @rtype: dns.name.Name object """ try: parts = list(dns.ipv6.inet_aton(text).encode('hex_codec')) origin = ipv6_reverse_domain except StandardError: parts = ['%d' % ord(byte) for byte in dns.ipv4.inet_aton(text)] origin = ipv4_reverse_domain parts.reverse() return dns.name.from_text('.'.join(parts), origin=origin) 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') LinkChecker-9.3/third_party/dnspython/dns/ipv6.py0000644000175000017500000001160211570774061022732 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """IPv6 helper functions.""" import re import dns.exception import dns.ipv4 _leading_zero = re.compile(r'0+([0-9a-f]+)') def inet_ntoa(address): """Convert a network format IPv6 address into text. @param address: the binary address @type address: string @rtype: string @raises ValueError: the address isn't 16 bytes long """ if len(address) != 16: raise ValueError("IPv6 addresses are 16 bytes long") hex = address.encode('hex_codec') chunks = [] i = 0 l = len(hex) while i < l: chunk = hex[i : i + 4] # strip leading zeros. we do this with an re instead of # with lstrip() because lstrip() didn't support chars until # python 2.2.2 m = _leading_zero.match(chunk) if not m is None: chunk = m.group(1) chunks.append(chunk) i += 4 # # Compress the longest subsequence of 0-value chunks to :: # best_start = 0 best_len = 0 start = -1 last_was_zero = False for i in xrange(8): if chunks[i] != '0': if last_was_zero: end = i current_len = end - start if current_len > best_len: best_start = start best_len = current_len last_was_zero = False elif not last_was_zero: start = i last_was_zero = True if last_was_zero: end = 8 current_len = end - start if current_len > best_len: best_start = start best_len = current_len if best_len > 0: if best_start == 0 and \ (best_len == 6 or best_len == 5 and chunks[5] == 'ffff'): # We have an embedded IPv4 address if best_len == 6: prefix = '::' else: prefix = '::ffff:' hex = prefix + dns.ipv4.inet_ntoa(address[12:]) else: hex = ':'.join(chunks[:best_start]) + '::' + \ ':'.join(chunks[best_start + best_len:]) else: hex = ':'.join(chunks) return hex _v4_ending = re.compile(r'(.*):(\d+)\.(\d+)\.(\d+)\.(\d+)$') _colon_colon_start = re.compile(r'::.*') _colon_colon_end = re.compile(r'.*::$') def inet_aton(text): """Convert a text format IPv6 address into network format. @param text: the textual address @type text: string @rtype: string @raises dns.exception.SyntaxError: the text was not properly formatted """ # # Our aim here is not something fast; we just want something that works. # if text == '::': text = '0::' # # Get rid of the icky dot-quad syntax if we have it. # m = _v4_ending.match(text) if not m is None: text = "%s:%04x:%04x" % (m.group(1), int(m.group(2)) * 256 + int(m.group(3)), int(m.group(4)) * 256 + int(m.group(5))) # # Try to turn '::' into ':'; if no match try to # turn '::' into ':' # m = _colon_colon_start.match(text) if not m is None: text = text[1:] else: m = _colon_colon_end.match(text) if not m is None: text = text[:-1] # # Now canonicalize into 8 chunks of 4 hex digits each # chunks = text.split(':') l = len(chunks) if l > 8: raise dns.exception.SyntaxError seen_empty = False canonical = [] for c in chunks: if c == '': if seen_empty: raise dns.exception.SyntaxError seen_empty = True for i in xrange(0, 8 - l + 1): canonical.append('0000') else: lc = len(c) if lc > 4: raise dns.exception.SyntaxError if lc != 4: c = ('0' * (4 - lc)) + c canonical.append(c) if l < 8 and not seen_empty: raise dns.exception.SyntaxError text = ''.join(canonical) # # Finally we can go to binary. # try: return text.decode('hex_codec') except TypeError: raise dns.exception.SyntaxError LinkChecker-9.3/third_party/dnspython/dns/wiredata.py0000644000175000017500000000406411570774060023651 0ustar calvincalvin00000000000000# Copyright (C) 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Wire Data Helper""" import sys import dns.exception class WireData(str): # WireData is a string with stricter slicing def __getitem__(self, key): try: return WireData(super(WireData, self).__getitem__(key)) except IndexError: raise dns.exception.FormError def __getslice__(self, i, j): try: if j == sys.maxint: # handle the case where the right bound is unspecified j = len(self) if i < 0 or j < 0: raise dns.exception.FormError # If it's not an empty slice, access left and right bounds # to make sure they're valid if i != j: super(WireData, self).__getitem__(i) super(WireData, self).__getitem__(j - 1) return WireData(super(WireData, self).__getslice__(i, j)) except IndexError: raise dns.exception.FormError def __iter__(self): i = 0 while 1: try: yield self[i] i += 1 except dns.exception.FormError: raise StopIteration def unwrap(self): return str(self) def maybe_wrap(wire): if not isinstance(wire, WireData): return WireData(wire) else: return wire LinkChecker-9.3/third_party/dnspython/dns/renderer.py0000644000175000017500000002720611570774061023663 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Help for building DNS wire format messages""" import cStringIO import struct import random import time import dns.exception import dns.tsig QUESTION = 0 ANSWER = 1 AUTHORITY = 2 ADDITIONAL = 3 class Renderer(object): """Helper class for building DNS wire-format messages. Most applications can use the higher-level L{dns.message.Message} class and its to_wire() method to generate wire-format messages. This class is for those applications which need finer control over the generation of messages. Typical use:: r = dns.renderer.Renderer(id=1, flags=0x80, max_size=512) r.add_question(qname, qtype, qclass) r.add_rrset(dns.renderer.ANSWER, rrset_1) r.add_rrset(dns.renderer.ANSWER, rrset_2) r.add_rrset(dns.renderer.AUTHORITY, ns_rrset) r.add_edns(0, 0, 4096) r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_1) r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_2) r.write_header() r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac) wire = r.get_wire() @ivar output: where rendering is written @type output: cStringIO.StringIO object @ivar id: the message id @type id: int @ivar flags: the message flags @type flags: int @ivar max_size: the maximum size of the message @type max_size: int @ivar origin: the origin to use when rendering relative names @type origin: dns.name.Name object @ivar compress: the compression table @type compress: dict @ivar section: the section currently being rendered @type section: int (dns.renderer.QUESTION, dns.renderer.ANSWER, dns.renderer.AUTHORITY, or dns.renderer.ADDITIONAL) @ivar counts: list of the number of RRs in each section @type counts: int list of length 4 @ivar mac: the MAC of the rendered message (if TSIG was used) @type mac: string """ def __init__(self, id=None, flags=0, max_size=65535, origin=None): """Initialize a new renderer. @param id: the message id @type id: int @param flags: the DNS message flags @type flags: int @param max_size: the maximum message size; the default is 65535. If rendering results in a message greater than I{max_size}, then L{dns.exception.TooBig} will be raised. @type max_size: int @param origin: the origin to use when rendering relative names @type origin: dns.name.Namem or None. """ self.output = cStringIO.StringIO() if id is None: self.id = random.randint(0, 65535) else: self.id = id self.flags = flags self.max_size = max_size self.origin = origin self.compress = {} self.section = QUESTION self.counts = [0, 0, 0, 0] self.output.write('\x00' * 12) self.mac = '' def _rollback(self, where): """Truncate the output buffer at offset I{where}, and remove any compression table entries that pointed beyond the truncation point. @param where: the offset @type where: int """ self.output.seek(where) self.output.truncate() keys_to_delete = [] for k, v in self.compress.iteritems(): if v >= where: keys_to_delete.append(k) for k in keys_to_delete: del self.compress[k] def _set_section(self, section): """Set the renderer's current section. Sections must be rendered order: QUESTION, ANSWER, AUTHORITY, ADDITIONAL. Sections may be empty. @param section: the section @type section: int @raises dns.exception.FormError: an attempt was made to set a section value less than the current section. """ if self.section != section: if self.section > section: raise dns.exception.FormError self.section = section def add_question(self, qname, rdtype, rdclass=dns.rdataclass.IN): """Add a question to the message. @param qname: the question name @type qname: dns.name.Name @param rdtype: the question rdata type @type rdtype: int @param rdclass: the question rdata class @type rdclass: int """ self._set_section(QUESTION) before = self.output.tell() qname.to_wire(self.output, self.compress, self.origin) self.output.write(struct.pack("!HH", rdtype, rdclass)) after = self.output.tell() if after >= self.max_size: self._rollback(before) raise dns.exception.TooBig self.counts[QUESTION] += 1 def add_rrset(self, section, rrset, **kw): """Add the rrset to the specified section. Any keyword arguments are passed on to the rdataset's to_wire() routine. @param section: the section @type section: int @param rrset: the rrset @type rrset: dns.rrset.RRset object """ self._set_section(section) before = self.output.tell() n = rrset.to_wire(self.output, self.compress, self.origin, **kw) after = self.output.tell() if after >= self.max_size: self._rollback(before) raise dns.exception.TooBig self.counts[section] += n def add_rdataset(self, section, name, rdataset, **kw): """Add the rdataset to the specified section, using the specified name as the owner name. Any keyword arguments are passed on to the rdataset's to_wire() routine. @param section: the section @type section: int @param name: the owner name @type name: dns.name.Name object @param rdataset: the rdataset @type rdataset: dns.rdataset.Rdataset object """ self._set_section(section) before = self.output.tell() n = rdataset.to_wire(name, self.output, self.compress, self.origin, **kw) after = self.output.tell() if after >= self.max_size: self._rollback(before) raise dns.exception.TooBig self.counts[section] += n def add_edns(self, edns, ednsflags, payload, options=None): """Add an EDNS OPT record to the message. @param edns: The EDNS level to use. @type edns: int @param ednsflags: EDNS flag values. @type ednsflags: int @param payload: The EDNS sender's payload field, which is the maximum size of UDP datagram the sender can handle. @type payload: int @param options: The EDNS options list @type options: list of dns.edns.Option instances @see: RFC 2671 """ # make sure the EDNS version in ednsflags agrees with edns ednsflags &= 0xFF00FFFFL ednsflags |= (edns << 16) self._set_section(ADDITIONAL) before = self.output.tell() self.output.write(struct.pack('!BHHIH', 0, dns.rdatatype.OPT, payload, ednsflags, 0)) if not options is None: lstart = self.output.tell() for opt in options: stuff = struct.pack("!HH", opt.otype, 0) self.output.write(stuff) start = self.output.tell() opt.to_wire(self.output) end = self.output.tell() assert end - start < 65536 self.output.seek(start - 2) stuff = struct.pack("!H", end - start) self.output.write(stuff) self.output.seek(0, 2) lend = self.output.tell() assert lend - lstart < 65536 self.output.seek(lstart - 2) stuff = struct.pack("!H", lend - lstart) self.output.write(stuff) self.output.seek(0, 2) after = self.output.tell() if after >= self.max_size: self._rollback(before) raise dns.exception.TooBig self.counts[ADDITIONAL] += 1 def add_tsig(self, keyname, secret, fudge, id, tsig_error, other_data, request_mac, algorithm=dns.tsig.default_algorithm): """Add a TSIG signature to the message. @param keyname: the TSIG key name @type keyname: dns.name.Name object @param secret: the secret to use @type secret: string @param fudge: TSIG time fudge @type fudge: int @param id: the message id to encode in the tsig signature @type id: int @param tsig_error: TSIG error code; default is 0. @type tsig_error: int @param other_data: TSIG other data. @type other_data: string @param request_mac: This message is a response to the request which had the specified MAC. @type request_mac: string @param algorithm: the TSIG algorithm to use @type algorithm: dns.name.Name object """ self._set_section(ADDITIONAL) before = self.output.tell() s = self.output.getvalue() (tsig_rdata, self.mac, ctx) = dns.tsig.sign(s, keyname, secret, int(time.time()), fudge, id, tsig_error, other_data, request_mac, algorithm=algorithm) keyname.to_wire(self.output, self.compress, self.origin) self.output.write(struct.pack('!HHIH', dns.rdatatype.TSIG, dns.rdataclass.ANY, 0, 0)) rdata_start = self.output.tell() self.output.write(tsig_rdata) after = self.output.tell() assert after - rdata_start < 65536 if after >= self.max_size: self._rollback(before) raise dns.exception.TooBig self.output.seek(rdata_start - 2) self.output.write(struct.pack('!H', after - rdata_start)) self.counts[ADDITIONAL] += 1 self.output.seek(10) self.output.write(struct.pack('!H', self.counts[ADDITIONAL])) self.output.seek(0, 2) def write_header(self): """Write the DNS message header. Writing the DNS message header is done asfter all sections have been rendered, but before the optional TSIG signature is added. """ self.output.seek(0) self.output.write(struct.pack('!HHHHHH', self.id, self.flags, self.counts[0], self.counts[1], self.counts[2], self.counts[3])) self.output.seek(0, 2) def get_wire(self): """Return the wire format message. @rtype: string """ return self.output.getvalue() LinkChecker-9.3/third_party/dnspython/dns/update.py0000644000175000017500000002366311570774061023342 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Dynamic Update Support""" import dns.message import dns.name import dns.opcode import dns.rdata import dns.rdataclass import dns.rdataset import dns.tsig class Update(dns.message.Message): def __init__(self, zone, rdclass=dns.rdataclass.IN, keyring=None, keyname=None, keyalgorithm=dns.tsig.default_algorithm): """Initialize a new DNS Update object. @param zone: The zone which is being updated. @type zone: A dns.name.Name or string @param rdclass: The class of the zone; defaults to dns.rdataclass.IN. @type rdclass: An int designating the class, or a string whose value is the name of a class. @param keyring: The TSIG keyring to use; defaults to None. @type keyring: dict @param keyname: The name of the TSIG key to use; defaults to None. The key must be defined in the keyring. If a keyring is specified but a keyname is not, then the key used will be the first key in the keyring. Note that the order of keys in a dictionary is not defined, so applications should supply a keyname when a keyring is used, unless they know the keyring contains only one key. @type keyname: dns.name.Name or string @param keyalgorithm: The TSIG algorithm to use; defaults to dns.tsig.default_algorithm. Constants for TSIG algorithms are defined in dns.tsig, and the currently implemented algorithms are HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and HMAC_SHA512. @type keyalgorithm: string """ super(Update, self).__init__() self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE) if isinstance(zone, (str, unicode)): zone = dns.name.from_text(zone) self.origin = zone if isinstance(rdclass, str): rdclass = dns.rdataclass.from_text(rdclass) self.zone_rdclass = rdclass self.find_rrset(self.question, self.origin, rdclass, dns.rdatatype.SOA, create=True, force_unique=True) if not keyring is None: self.use_tsig(keyring, keyname, algorithm=keyalgorithm) def _add_rr(self, name, ttl, rd, deleting=None, section=None): """Add a single RR to the update section.""" if section is None: section = self.authority covers = rd.covers() rrset = self.find_rrset(section, name, self.zone_rdclass, rd.rdtype, covers, deleting, True, True) rrset.add(rd, ttl) def _add(self, replace, section, name, *args): """Add records. The first argument is the replace mode. If false, RRs are added to an existing RRset; if true, the RRset is replaced with the specified contents. The second argument is the section to add to. The third argument is always a name. The other arguments can be: - rdataset... - ttl, rdata... - ttl, rdtype, string...""" if isinstance(name, (str, unicode)): name = dns.name.from_text(name, None) if isinstance(args[0], dns.rdataset.Rdataset): for rds in args: if replace: self.delete(name, rds.rdtype) for rd in rds: self._add_rr(name, rds.ttl, rd, section=section) else: args = list(args) ttl = int(args.pop(0)) if isinstance(args[0], dns.rdata.Rdata): if replace: self.delete(name, args[0].rdtype) for rd in args: self._add_rr(name, ttl, rd, section=section) else: rdtype = args.pop(0) if isinstance(rdtype, str): rdtype = dns.rdatatype.from_text(rdtype) if replace: self.delete(name, rdtype) for s in args: rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, self.origin) self._add_rr(name, ttl, rd, section=section) def add(self, name, *args): """Add records. The first argument is always a name. The other arguments can be: - rdataset... - ttl, rdata... - ttl, rdtype, string...""" self._add(False, self.authority, name, *args) def delete(self, name, *args): """Delete records. The first argument is always a name. The other arguments can be: - I{nothing} - rdataset... - rdata... - rdtype, [string...]""" if isinstance(name, (str, unicode)): name = dns.name.from_text(name, None) if len(args) == 0: rrset = self.find_rrset(self.authority, name, dns.rdataclass.ANY, dns.rdatatype.ANY, dns.rdatatype.NONE, dns.rdatatype.ANY, True, True) elif isinstance(args[0], dns.rdataset.Rdataset): for rds in args: for rd in rds: self._add_rr(name, 0, rd, dns.rdataclass.NONE) else: args = list(args) if isinstance(args[0], dns.rdata.Rdata): for rd in args: self._add_rr(name, 0, rd, dns.rdataclass.NONE) else: rdtype = args.pop(0) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) if len(args) == 0: rrset = self.find_rrset(self.authority, name, self.zone_rdclass, rdtype, dns.rdatatype.NONE, dns.rdataclass.ANY, True, True) else: for s in args: rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, self.origin) self._add_rr(name, 0, rd, dns.rdataclass.NONE) def replace(self, name, *args): """Replace records. The first argument is always a name. The other arguments can be: - rdataset... - ttl, rdata... - ttl, rdtype, string... Note that if you want to replace the entire node, you should do a delete of the name followed by one or more calls to add.""" self._add(True, self.authority, name, *args) def present(self, name, *args): """Require that an owner name (and optionally an rdata type, or specific rdataset) exists as a prerequisite to the execution of the update. The first argument is always a name. The other arguments can be: - rdataset... - rdata... - rdtype, string...""" if isinstance(name, (str, unicode)): name = dns.name.from_text(name, None) if len(args) == 0: rrset = self.find_rrset(self.answer, name, dns.rdataclass.ANY, dns.rdatatype.ANY, dns.rdatatype.NONE, None, True, True) elif isinstance(args[0], dns.rdataset.Rdataset) or \ isinstance(args[0], dns.rdata.Rdata) or \ len(args) > 1: if not isinstance(args[0], dns.rdataset.Rdataset): # Add a 0 TTL args = list(args) args.insert(0, 0) self._add(False, self.answer, name, *args) else: rdtype = args[0] if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) rrset = self.find_rrset(self.answer, name, dns.rdataclass.ANY, rdtype, dns.rdatatype.NONE, None, True, True) def absent(self, name, rdtype=None): """Require that an owner name (and optionally an rdata type) does not exist as a prerequisite to the execution of the update.""" if isinstance(name, (str, unicode)): name = dns.name.from_text(name, None) if rdtype is None: rrset = self.find_rrset(self.answer, name, dns.rdataclass.NONE, dns.rdatatype.ANY, dns.rdatatype.NONE, None, True, True) else: if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) rrset = self.find_rrset(self.answer, name, dns.rdataclass.NONE, rdtype, dns.rdatatype.NONE, None, True, True) def to_wire(self, origin=None, max_size=65535): """Return a string containing the update in DNS compressed wire format. @rtype: string""" if origin is None: origin = self.origin return super(Update, self).to_wire(origin, max_size) LinkChecker-9.3/third_party/dnspython/dns/flags.py0000644000175000017500000000517211570774061023147 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Message Flags.""" # Standard DNS flags QR = 0x8000 AA = 0x0400 TC = 0x0200 RD = 0x0100 RA = 0x0080 AD = 0x0020 CD = 0x0010 # EDNS flags DO = 0x8000 _by_text = { 'QR' : QR, 'AA' : AA, 'TC' : TC, 'RD' : RD, 'RA' : RA, 'AD' : AD, 'CD' : CD } _edns_by_text = { 'DO' : DO } # We construct the inverse mappings programmatically to ensure that we # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that # would cause the mappings not to be true inverses. _by_value = dict([(y, x) for x, y in _by_text.iteritems()]) _edns_by_value = dict([(y, x) for x, y in _edns_by_text.iteritems()]) def _order_flags(table): order = list(table.iteritems()) order.sort() order.reverse() return order _flags_order = _order_flags(_by_value) _edns_flags_order = _order_flags(_edns_by_value) def _from_text(text, table): flags = 0 tokens = text.split() for t in tokens: flags = flags | table[t.upper()] return flags def _to_text(flags, table, order): text_flags = [] for k, v in order: if flags & k != 0: text_flags.append(v) return ' '.join(text_flags) def from_text(text): """Convert a space-separated list of flag text values into a flags value. @rtype: int""" return _from_text(text, _by_text) def to_text(flags): """Convert a flags value into a space-separated list of flag text values. @rtype: string""" return _to_text(flags, _by_value, _flags_order) def edns_from_text(text): """Convert a space-separated list of EDNS flag text values into a EDNS flags value. @rtype: int""" return _from_text(text, _edns_by_text) def edns_to_text(flags): """Convert an EDNS flags value into a space-separated list of EDNS flag text values. @rtype: string""" return _to_text(flags, _edns_by_value, _edns_flags_order) LinkChecker-9.3/third_party/dnspython/dns/exception.py0000644000175000017500000000245211570774061024047 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Common DNS Exceptions.""" class DNSException(StandardError): """Abstract base class shared by all dnspython exceptions.""" pass class FormError(DNSException): """DNS message is malformed.""" pass class SyntaxError(DNSException): """Text input is malformed.""" pass class UnexpectedEnd(SyntaxError): """Raised if text input ends unexpectedly.""" pass class TooBig(DNSException): """The message is too big.""" pass class Timeout(DNSException): """The operation timed out.""" pass LinkChecker-9.3/third_party/dnspython/dns/tokenizer.py0000644000175000017500000004305111570774061024063 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Tokenize DNS master file format""" import cStringIO import sys import dns.exception import dns.name import dns.ttl _DELIMITERS = { ' ' : True, '\t' : True, '\n' : True, ';' : True, '(' : True, ')' : True, '"' : True } _QUOTING_DELIMITERS = { '"' : True } EOF = 0 EOL = 1 WHITESPACE = 2 IDENTIFIER = 3 QUOTED_STRING = 4 COMMENT = 5 DELIMITER = 6 class UngetBufferFull(dns.exception.DNSException): """Raised when an attempt is made to unget a token when the unget buffer is full.""" pass class Token(object): """A DNS master file format token. @ivar ttype: The token type @type ttype: int @ivar value: The token value @type value: string @ivar has_escape: Does the token value contain escapes? @type has_escape: bool """ def __init__(self, ttype, value='', has_escape=False): """Initialize a token instance. @param ttype: The token type @type ttype: int @ivar value: The token value @type value: string @ivar has_escape: Does the token value contain escapes? @type has_escape: bool """ self.ttype = ttype self.value = value self.has_escape = has_escape def is_eof(self): return self.ttype == EOF def is_eol(self): return self.ttype == EOL def is_whitespace(self): return self.ttype == WHITESPACE def is_identifier(self): return self.ttype == IDENTIFIER def is_quoted_string(self): return self.ttype == QUOTED_STRING def is_comment(self): return self.ttype == COMMENT def is_delimiter(self): return self.ttype == DELIMITER def is_eol_or_eof(self): return (self.ttype == EOL or self.ttype == EOF) def __eq__(self, other): if not isinstance(other, Token): return False return (self.ttype == other.ttype and self.value == other.value) def __ne__(self, other): if not isinstance(other, Token): return True return (self.ttype != other.ttype or self.value != other.value) def __str__(self): return '%d "%s"' % (self.ttype, self.value) def unescape(self): if not self.has_escape: return self unescaped = '' l = len(self.value) i = 0 while i < l: c = self.value[i] i += 1 if c == '\\': if i >= l: raise dns.exception.UnexpectedEnd c = self.value[i] i += 1 if c.isdigit(): if i >= l: raise dns.exception.UnexpectedEnd c2 = self.value[i] i += 1 if i >= l: raise dns.exception.UnexpectedEnd c3 = self.value[i] i += 1 if not (c2.isdigit() and c3.isdigit()): raise dns.exception.SyntaxError c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) unescaped += c return Token(self.ttype, unescaped) # compatibility for old-style tuple tokens def __len__(self): return 2 def __iter__(self): return iter((self.ttype, self.value)) def __getitem__(self, i): if i == 0: return self.ttype elif i == 1: return self.value else: raise IndexError class Tokenizer(object): """A DNS master file format tokenizer. A token is a (type, value) tuple, where I{type} is an int, and I{value} is a string. The valid types are EOF, EOL, WHITESPACE, IDENTIFIER, QUOTED_STRING, COMMENT, and DELIMITER. @ivar file: The file to tokenize @type file: file @ivar ungotten_char: The most recently ungotten character, or None. @type ungotten_char: string @ivar ungotten_token: The most recently ungotten token, or None. @type ungotten_token: (int, string) token tuple @ivar multiline: The current multiline level. This value is increased by one every time a '(' delimiter is read, and decreased by one every time a ')' delimiter is read. @type multiline: int @ivar quoting: This variable is true if the tokenizer is currently reading a quoted string. @type quoting: bool @ivar eof: This variable is true if the tokenizer has encountered EOF. @type eof: bool @ivar delimiters: The current delimiter dictionary. @type delimiters: dict @ivar line_number: The current line number @type line_number: int @ivar filename: A filename that will be returned by the L{where} method. @type filename: string """ def __init__(self, f=sys.stdin, filename=None): """Initialize a tokenizer instance. @param f: The file to tokenize. The default is sys.stdin. This parameter may also be a string, in which case the tokenizer will take its input from the contents of the string. @type f: file or string @param filename: the name of the filename that the L{where} method will return. @type filename: string """ if isinstance(f, str): f = cStringIO.StringIO(f) if filename is None: filename = '' else: if filename is None: if f is sys.stdin: filename = '' else: filename = '' self.file = f self.ungotten_char = None self.ungotten_token = None self.multiline = 0 self.quoting = False self.eof = False self.delimiters = _DELIMITERS self.line_number = 1 self.filename = filename def _get_char(self): """Read a character from input. @rtype: string """ if self.ungotten_char is None: if self.eof: c = '' else: c = self.file.read(1) if c == '': self.eof = True elif c == '\n': self.line_number += 1 else: c = self.ungotten_char self.ungotten_char = None return c def where(self): """Return the current location in the input. @rtype: (string, int) tuple. The first item is the filename of the input, the second is the current line number. """ return (self.filename, self.line_number) def _unget_char(self, c): """Unget a character. The unget buffer for characters is only one character large; it is an error to try to unget a character when the unget buffer is not empty. @param c: the character to unget @type c: string @raises UngetBufferFull: there is already an ungotten char """ if not self.ungotten_char is None: raise UngetBufferFull self.ungotten_char = c def skip_whitespace(self): """Consume input until a non-whitespace character is encountered. The non-whitespace character is then ungotten, and the number of whitespace characters consumed is returned. If the tokenizer is in multiline mode, then newlines are whitespace. @rtype: int """ skipped = 0 while True: c = self._get_char() if c != ' ' and c != '\t': if (c != '\n') or not self.multiline: self._unget_char(c) return skipped skipped += 1 def get(self, want_leading = False, want_comment = False): """Get the next token. @param want_leading: If True, return a WHITESPACE token if the first character read is whitespace. The default is False. @type want_leading: bool @param want_comment: If True, return a COMMENT token if the first token read is a comment. The default is False. @type want_comment: bool @rtype: Token object @raises dns.exception.UnexpectedEnd: input ended prematurely @raises dns.exception.SyntaxError: input was badly formed """ if not self.ungotten_token is None: token = self.ungotten_token self.ungotten_token = None if token.is_whitespace(): if want_leading: return token elif token.is_comment(): if want_comment: return token else: return token skipped = self.skip_whitespace() if want_leading and skipped > 0: return Token(WHITESPACE, ' ') token = '' ttype = IDENTIFIER has_escape = False while True: c = self._get_char() if c == '' or c in self.delimiters: if c == '' and self.quoting: raise dns.exception.UnexpectedEnd if token == '' and ttype != QUOTED_STRING: if c == '(': self.multiline += 1 self.skip_whitespace() continue elif c == ')': if not self.multiline > 0: raise dns.exception.SyntaxError self.multiline -= 1 self.skip_whitespace() continue elif c == '"': if not self.quoting: self.quoting = True self.delimiters = _QUOTING_DELIMITERS ttype = QUOTED_STRING continue else: self.quoting = False self.delimiters = _DELIMITERS self.skip_whitespace() continue elif c == '\n': return Token(EOL, '\n') elif c == ';': while 1: c = self._get_char() if c == '\n' or c == '': break token += c if want_comment: self._unget_char(c) return Token(COMMENT, token) elif c == '': if self.multiline: raise dns.exception.SyntaxError('unbalanced parentheses') return Token(EOF) elif self.multiline: self.skip_whitespace() token = '' continue else: return Token(EOL, '\n') else: # This code exists in case we ever want a # delimiter to be returned. It never produces # a token currently. token = c ttype = DELIMITER else: self._unget_char(c) break elif self.quoting: if c == '\\': c = self._get_char() if c == '': raise dns.exception.UnexpectedEnd if c.isdigit(): c2 = self._get_char() if c2 == '': raise dns.exception.UnexpectedEnd c3 = self._get_char() if c == '': raise dns.exception.UnexpectedEnd if not (c2.isdigit() and c3.isdigit()): raise dns.exception.SyntaxError c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) elif c == '\n': raise dns.exception.SyntaxError('newline in quoted string') elif c == '\\': # # It's an escape. Put it and the next character into # the token; it will be checked later for goodness. # token += c has_escape = True c = self._get_char() if c == '' or c == '\n': raise dns.exception.UnexpectedEnd token += c if token == '' and ttype != QUOTED_STRING: if self.multiline: raise dns.exception.SyntaxError('unbalanced parentheses') ttype = EOF return Token(ttype, token, has_escape) def unget(self, token): """Unget a token. The unget buffer for tokens is only one token large; it is an error to try to unget a token when the unget buffer is not empty. @param token: the token to unget @type token: Token object @raises UngetBufferFull: there is already an ungotten token """ if not self.ungotten_token is None: raise UngetBufferFull self.ungotten_token = token def next(self): """Return the next item in an iteration. @rtype: (int, string) """ token = self.get() if token.is_eof(): raise StopIteration return token def __iter__(self): return self # Helpers def get_int(self): """Read the next token and interpret it as an integer. @raises dns.exception.SyntaxError: @rtype: int """ token = self.get().unescape() if not token.is_identifier(): raise dns.exception.SyntaxError('expecting an identifier') if not token.value.isdigit(): raise dns.exception.SyntaxError('expecting an integer') return int(token.value) def get_uint8(self): """Read the next token and interpret it as an 8-bit unsigned integer. @raises dns.exception.SyntaxError: @rtype: int """ value = self.get_int() if value < 0 or value > 255: raise dns.exception.SyntaxError('%d is not an unsigned 8-bit integer' % value) return value def get_uint16(self): """Read the next token and interpret it as a 16-bit unsigned integer. @raises dns.exception.SyntaxError: @rtype: int """ value = self.get_int() if value < 0 or value > 65535: raise dns.exception.SyntaxError('%d is not an unsigned 16-bit integer' % value) return value def get_uint32(self): """Read the next token and interpret it as a 32-bit unsigned integer. @raises dns.exception.SyntaxError: @rtype: int """ token = self.get().unescape() if not token.is_identifier(): raise dns.exception.SyntaxError('expecting an identifier') if not token.value.isdigit(): raise dns.exception.SyntaxError('expecting an integer') value = long(token.value) if value < 0 or value > 4294967296L: raise dns.exception.SyntaxError('%d is not an unsigned 32-bit integer' % value) return value def get_string(self, origin=None): """Read the next token and interpret it as a string. @raises dns.exception.SyntaxError: @rtype: string """ token = self.get().unescape() if not (token.is_identifier() or token.is_quoted_string()): raise dns.exception.SyntaxError('expecting a string') return token.value def get_identifier(self, origin=None): """Read the next token and raise an exception if it is not an identifier. @raises dns.exception.SyntaxError: @rtype: string """ token = self.get().unescape() if not token.is_identifier(): raise dns.exception.SyntaxError('expecting an identifier') return token.value def get_name(self, origin=None): """Read the next token and interpret it as a DNS name. @raises dns.exception.SyntaxError: @rtype: dns.name.Name object""" token = self.get() if not token.is_identifier(): raise dns.exception.SyntaxError('expecting an identifier') return dns.name.from_text(token.value, origin) def get_eol(self): """Read the next token and raise an exception if it isn't EOL or EOF. @raises dns.exception.SyntaxError: @rtype: string """ token = self.get() if not token.is_eol_or_eof(): raise dns.exception.SyntaxError('expected EOL or EOF, got %d "%s"' % (token.ttype, token.value)) return token.value def get_ttl(self): token = self.get().unescape() if not token.is_identifier(): raise dns.exception.SyntaxError('expecting an identifier') return dns.ttl.from_text(token.value) LinkChecker-9.3/third_party/dnspython/dns/query.py0000644000175000017500000004263611570774061023226 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Talk to a DNS server.""" from __future__ import generators import errno import select import socket import struct import sys import time import dns.exception import dns.inet import dns.name import dns.message import dns.rdataclass import dns.rdatatype class UnexpectedSource(dns.exception.DNSException): """Raised if a query response comes from an unexpected address or port.""" pass class BadResponse(dns.exception.FormError): """Raised if a query response does not respond to the question asked.""" pass def _compute_expiration(timeout): if timeout is None: return None else: return time.time() + timeout def _poll_for(fd, readable, writable, error, timeout): """ @param fd: File descriptor (int). @param readable: Whether to wait for readability (bool). @param writable: Whether to wait for writability (bool). @param expiration: Deadline timeout (expiration time, in seconds (float)). @return True on success, False on timeout """ event_mask = 0 if readable: event_mask |= select.POLLIN if writable: event_mask |= select.POLLOUT if error: event_mask |= select.POLLERR pollable = select.poll() pollable.register(fd, event_mask) if timeout: event_list = pollable.poll(long(timeout * 1000)) else: event_list = pollable.poll() return bool(event_list) def _select_for(fd, readable, writable, error, timeout): """ @param fd: File descriptor (int). @param readable: Whether to wait for readability (bool). @param writable: Whether to wait for writability (bool). @param expiration: Deadline timeout (expiration time, in seconds (float)). @return True on success, False on timeout """ rset, wset, xset = [], [], [] if readable: rset = [fd] if writable: wset = [fd] if error: xset = [fd] if timeout is None: (rcount, wcount, xcount) = select.select(rset, wset, xset) else: (rcount, wcount, xcount) = select.select(rset, wset, xset, timeout) return bool((rcount or wcount or xcount)) def _wait_for(fd, readable, writable, error, expiration): done = False while not done: if expiration is None: timeout = None else: timeout = expiration - time.time() if timeout <= 0.0: raise dns.exception.Timeout try: if not _polling_backend(fd, readable, writable, error, timeout): raise dns.exception.Timeout except select.error, e: if e.args[0] != errno.EINTR: raise e done = True def _set_polling_backend(fn): """ Internal API. Do not use. """ global _polling_backend _polling_backend = fn if hasattr(select, 'poll'): # Prefer poll() on platforms that support it because it has no # limits on the maximum value of a file descriptor (plus it will # be more efficient for high values). _polling_backend = _poll_for else: _polling_backend = _select_for def _wait_for_readable(s, expiration): _wait_for(s, True, False, True, expiration) def _wait_for_writable(s, expiration): _wait_for(s, False, True, True, expiration) def _addresses_equal(af, a1, a2): # Convert the first value of the tuple, which is a textual format # address into binary form, so that we are not confused by different # textual representations of the same address n1 = dns.inet.inet_pton(af, a1[0]) n2 = dns.inet.inet_pton(af, a2[0]) return n1 == n2 and a1[1:] == a2[1:] def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, ignore_unexpected=False, one_rr_per_rrset=False): """Return the response obtained after sending a query via UDP. @param q: the query @type q: dns.message.Message @param where: where to send the message @type where: string containing an IPv4 or IPv6 address @param timeout: The number of seconds to wait before the query times out. If None, the default, wait forever. @type timeout: float @param port: The port to which to send the message. The default is 53. @type port: int @param af: the address family to use. The default is None, which causes the address family to use to be inferred from the form of of where. If the inference attempt fails, AF_INET is used. @type af: int @rtype: dns.message.Message object @param source: source address. The default is the IPv4 wildcard address. @type source: string @param source_port: The port from which to send the message. The default is 0. @type source_port: int @param ignore_unexpected: If True, ignore responses from unexpected sources. The default is False. @type ignore_unexpected: bool @param one_rr_per_rrset: Put each RR into its own RRset @type one_rr_per_rrset: bool """ wire = q.to_wire() if af is None: try: af = dns.inet.af_for_address(where) except StandardError: af = dns.inet.AF_INET if af == dns.inet.AF_INET: destination = (where, port) if source is not None: source = (source, source_port) elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) s = socket.socket(af, socket.SOCK_DGRAM, 0) try: expiration = _compute_expiration(timeout) s.setblocking(0) if source is not None: s.bind(source) _wait_for_writable(s, expiration) s.sendto(wire, destination) while 1: _wait_for_readable(s, expiration) (wire, from_address) = s.recvfrom(65535) if _addresses_equal(af, from_address, destination) or \ (dns.inet.is_multicast(where) and \ from_address[1:] == destination[1:]): break if not ignore_unexpected: raise UnexpectedSource('got a response from ' '%s instead of %s' % (from_address, destination)) finally: s.close() r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, one_rr_per_rrset=one_rr_per_rrset) if not q.is_response(r): raise BadResponse return r def _net_read(sock, count, expiration): """Read the specified number of bytes from sock. Keep trying until we either get the desired amount, or we hit EOF. A Timeout exception will be raised if the operation is not completed by the expiration time. """ s = '' while count > 0: _wait_for_readable(sock, expiration) n = sock.recv(count) if n == '': raise EOFError count = count - len(n) s = s + n return s def _net_write(sock, data, expiration): """Write the specified data to the socket. A Timeout exception will be raised if the operation is not completed by the expiration time. """ current = 0 l = len(data) while current < l: _wait_for_writable(sock, expiration) current += sock.send(data[current:]) def _connect(s, address): try: s.connect(address) except socket.error: (ty, v) = sys.exc_info()[:2] if v[0] != errno.EINPROGRESS and \ v[0] != errno.EWOULDBLOCK and \ v[0] != errno.EALREADY: raise v def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, one_rr_per_rrset=False): """Return the response obtained after sending a query via TCP. @param q: the query @type q: dns.message.Message object @param where: where to send the message @type where: string containing an IPv4 or IPv6 address @param timeout: The number of seconds to wait before the query times out. If None, the default, wait forever. @type timeout: float @param port: The port to which to send the message. The default is 53. @type port: int @param af: the address family to use. The default is None, which causes the address family to use to be inferred from the form of of where. If the inference attempt fails, AF_INET is used. @type af: int @rtype: dns.message.Message object @param source: source address. The default is the IPv4 wildcard address. @type source: string @param source_port: The port from which to send the message. The default is 0. @type source_port: int @param one_rr_per_rrset: Put each RR into its own RRset @type one_rr_per_rrset: bool """ wire = q.to_wire() if af is None: try: af = dns.inet.af_for_address(where) except StandardError: af = dns.inet.AF_INET if af == dns.inet.AF_INET: destination = (where, port) if source is not None: source = (source, source_port) elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) s = socket.socket(af, socket.SOCK_STREAM, 0) try: expiration = _compute_expiration(timeout) s.setblocking(0) if source is not None: s.bind(source) _connect(s, destination) l = len(wire) # copying the wire into tcpmsg is inefficient, but lets us # avoid writev() or doing a short write that would get pushed # onto the net tcpmsg = struct.pack("!H", l) + wire _net_write(s, tcpmsg, expiration) ldata = _net_read(s, 2, expiration) (l,) = struct.unpack("!H", ldata) wire = _net_read(s, l, expiration) finally: s.close() r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, one_rr_per_rrset=one_rr_per_rrset) if not q.is_response(r): raise BadResponse return r def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, timeout=None, port=53, keyring=None, keyname=None, relativize=True, af=None, lifetime=None, source=None, source_port=0, serial=0, use_udp=False, keyalgorithm=dns.tsig.default_algorithm): """Return a generator for the responses to a zone transfer. @param where: where to send the message @type where: string containing an IPv4 or IPv6 address @param zone: The name of the zone to transfer @type zone: dns.name.Name object or string @param rdtype: The type of zone transfer. The default is dns.rdatatype.AXFR. @type rdtype: int or string @param rdclass: The class of the zone transfer. The default is dns.rdatatype.IN. @type rdclass: int or string @param timeout: The number of seconds to wait for each response message. If None, the default, wait forever. @type timeout: float @param port: The port to which to send the message. The default is 53. @type port: int @param keyring: The TSIG keyring to use @type keyring: dict @param keyname: The name of the TSIG key to use @type keyname: dns.name.Name object or string @param relativize: If True, all names in the zone will be relativized to the zone origin. It is essential that the relativize setting matches the one specified to dns.zone.from_xfr(). @type relativize: bool @param af: the address family to use. The default is None, which causes the address family to use to be inferred from the form of of where. If the inference attempt fails, AF_INET is used. @type af: int @param lifetime: The total number of seconds to spend doing the transfer. If None, the default, then there is no limit on the time the transfer may take. @type lifetime: float @rtype: generator of dns.message.Message objects. @param source: source address. The default is the IPv4 wildcard address. @type source: string @param source_port: The port from which to send the message. The default is 0. @type source_port: int @param serial: The SOA serial number to use as the base for an IXFR diff sequence (only meaningful if rdtype == dns.rdatatype.IXFR). @type serial: int @param use_udp: Use UDP (only meaningful for IXFR) @type use_udp: bool @param keyalgorithm: The TSIG algorithm to use; defaults to dns.tsig.default_algorithm @type keyalgorithm: string """ if isinstance(zone, (str, unicode)): zone = dns.name.from_text(zone) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) q = dns.message.make_query(zone, rdtype, rdclass) if rdtype == dns.rdatatype.IXFR: rrset = dns.rrset.from_text(zone, 0, 'IN', 'SOA', '. . %u 0 0 0 0' % serial) q.authority.append(rrset) if not keyring is None: q.use_tsig(keyring, keyname, algorithm=keyalgorithm) wire = q.to_wire() if af is None: try: af = dns.inet.af_for_address(where) except StandardError: af = dns.inet.AF_INET if af == dns.inet.AF_INET: destination = (where, port) if source is not None: source = (source, source_port) elif af == dns.inet.AF_INET6: destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) if use_udp: if rdtype != dns.rdatatype.IXFR: raise ValueError('cannot do a UDP AXFR') s = socket.socket(af, socket.SOCK_DGRAM, 0) else: s = socket.socket(af, socket.SOCK_STREAM, 0) s.setblocking(0) if source is not None: s.bind(source) expiration = _compute_expiration(lifetime) _connect(s, destination) l = len(wire) if use_udp: _wait_for_writable(s, expiration) s.send(wire) else: tcpmsg = struct.pack("!H", l) + wire _net_write(s, tcpmsg, expiration) done = False soa_rrset = None soa_count = 0 if relativize: origin = zone oname = dns.name.empty else: origin = None oname = zone tsig_ctx = None first = True while not done: mexpiration = _compute_expiration(timeout) if mexpiration is None or mexpiration > expiration: mexpiration = expiration if use_udp: _wait_for_readable(s, expiration) (wire, from_address) = s.recvfrom(65535) else: ldata = _net_read(s, 2, mexpiration) (l,) = struct.unpack("!H", ldata) wire = _net_read(s, l, mexpiration) r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, xfr=True, origin=origin, tsig_ctx=tsig_ctx, multi=True, first=first, one_rr_per_rrset=(rdtype==dns.rdatatype.IXFR)) tsig_ctx = r.tsig_ctx first = False answer_index = 0 delete_mode = False expecting_SOA = False if soa_rrset is None: if not r.answer or r.answer[0].name != oname: raise dns.exception.FormError rrset = r.answer[0] if rrset.rdtype != dns.rdatatype.SOA: raise dns.exception.FormError("first RRset is not an SOA") answer_index = 1 soa_rrset = rrset.copy() if rdtype == dns.rdatatype.IXFR: if soa_rrset[0].serial == serial: # # We're already up-to-date. # done = True else: expecting_SOA = True # # Process SOAs in the answer section (other than the initial # SOA in the first message). # for rrset in r.answer[answer_index:]: if done: raise dns.exception.FormError("answers after final SOA") if rrset.rdtype == dns.rdatatype.SOA and rrset.name == oname: if expecting_SOA: if rrset[0].serial != serial: raise dns.exception.FormError("IXFR base serial mismatch") expecting_SOA = False elif rdtype == dns.rdatatype.IXFR: delete_mode = not delete_mode if rrset == soa_rrset and not delete_mode: done = True elif expecting_SOA: # # We made an IXFR request and are expecting another # SOA RR, but saw something else, so this must be an # AXFR response. # rdtype = dns.rdatatype.AXFR expecting_SOA = False if done and q.keyring and not r.had_tsig: raise dns.exception.FormError("missing TSIG") yield r s.close() LinkChecker-9.3/third_party/dnspython/dns/opcode.py0000644000175000017500000000504211570774061023320 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Opcodes.""" import dns.exception QUERY = 0 IQUERY = 1 STATUS = 2 NOTIFY = 4 UPDATE = 5 _by_text = { 'QUERY' : QUERY, 'IQUERY' : IQUERY, 'STATUS' : STATUS, 'NOTIFY' : NOTIFY, 'UPDATE' : UPDATE } # We construct the inverse mapping programmatically to ensure that we # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that # would cause the mapping not to be true inverse. _by_value = dict([(y, x) for x, y in _by_text.iteritems()]) class UnknownOpcode(dns.exception.DNSException): """Raised if an opcode is unknown.""" pass def from_text(text): """Convert text into an opcode. @param text: the textual opcode @type text: string @raises UnknownOpcode: the opcode is unknown @rtype: int """ if text.isdigit(): value = int(text) if value >= 0 and value <= 15: return value value = _by_text.get(text.upper()) if value is None: raise UnknownOpcode return value def from_flags(flags): """Extract an opcode from DNS message flags. @param flags: int @rtype: int """ return (flags & 0x7800) >> 11 def to_flags(value): """Convert an opcode to a value suitable for ORing into DNS message flags. @rtype: int """ return (value << 11) & 0x7800 def to_text(value): """Convert an opcode to text. @param value: the opcdoe @type value: int @raises UnknownOpcode: the opcode is unknown @rtype: string """ text = _by_value.get(value) if text is None: text = str(value) return text def is_update(flags): """True if the opcode in flags is UPDATE. @param flags: DNS flags @type flags: int @rtype: bool """ if (from_flags(flags) == UPDATE): return True return False LinkChecker-9.3/third_party/dnspython/dns/rcode.py0000644000175000017500000000604111570774061023143 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Result Codes.""" import dns.exception NOERROR = 0 FORMERR = 1 SERVFAIL = 2 NXDOMAIN = 3 NOTIMP = 4 REFUSED = 5 YXDOMAIN = 6 YXRRSET = 7 NXRRSET = 8 NOTAUTH = 9 NOTZONE = 10 BADVERS = 16 _by_text = { 'NOERROR' : NOERROR, 'FORMERR' : FORMERR, 'SERVFAIL' : SERVFAIL, 'NXDOMAIN' : NXDOMAIN, 'NOTIMP' : NOTIMP, 'REFUSED' : REFUSED, 'YXDOMAIN' : YXDOMAIN, 'YXRRSET' : YXRRSET, 'NXRRSET' : NXRRSET, 'NOTAUTH' : NOTAUTH, 'NOTZONE' : NOTZONE, 'BADVERS' : BADVERS } # We construct the inverse mapping programmatically to ensure that we # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that # would cause the mapping not to be a true inverse. _by_value = dict([(y, x) for x, y in _by_text.iteritems()]) class UnknownRcode(dns.exception.DNSException): """Raised if an rcode is unknown.""" pass def from_text(text): """Convert text into an rcode. @param text: the texual rcode @type text: string @raises UnknownRcode: the rcode is unknown @rtype: int """ if text.isdigit(): v = int(text) if v >= 0 and v <= 4095: return v v = _by_text.get(text.upper()) if v is None: raise UnknownRcode return v def from_flags(flags, ednsflags): """Return the rcode value encoded by flags and ednsflags. @param flags: the DNS flags @type flags: int @param ednsflags: the EDNS flags @type ednsflags: int @raises ValueError: rcode is < 0 or > 4095 @rtype: int """ value = (flags & 0x000f) | ((ednsflags >> 20) & 0xff0) if value < 0 or value > 4095: raise ValueError('rcode must be >= 0 and <= 4095') return value def to_flags(value): """Return a (flags, ednsflags) tuple which encodes the rcode. @param value: the rcode @type value: int @raises ValueError: rcode is < 0 or > 4095 @rtype: (int, int) tuple """ if value < 0 or value > 4095: raise ValueError('rcode must be >= 0 and <= 4095') v = value & 0xf ev = long(value & 0xff0) << 20 return (v, ev) def to_text(value): """Convert rcode into text. @param value: the rcode @type value: int @rtype: string """ text = _by_value.get(value) if text is None: text = str(value) return text LinkChecker-9.3/third_party/dnspython/dns/ttl.py0000644000175000017500000000420311570774061022650 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS TTL conversion.""" import dns.exception class BadTTL(dns.exception.SyntaxError): pass def from_text(text): """Convert the text form of a TTL to an integer. The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported. @param text: the textual TTL @type text: string @raises dns.ttl.BadTTL: the TTL is not well-formed @rtype: int """ if text.isdigit(): total = long(text) else: if not text[0].isdigit(): raise BadTTL total = 0L current = 0L for c in text: if c.isdigit(): current *= 10 current += long(c) else: c = c.lower() if c == 'w': total += current * 604800L elif c == 'd': total += current * 86400L elif c == 'h': total += current * 3600L elif c == 'm': total += current * 60L elif c == 's': total += current else: raise BadTTL("unknown unit '%s'" % c) current = 0 if not current == 0: raise BadTTL("trailing integer") if total < 0L or total > 2147483647L: raise BadTTL("TTL should be between 0 and 2^31 - 1 (inclusive)") return total LinkChecker-9.3/third_party/dnspython/dns/ipv4.py0000644000175000017500000000252411570774061022733 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """IPv4 helper functions.""" import socket import sys if sys.hexversion < 0x02030000 or sys.platform == 'win32': # # Some versions of Python 2.2 have an inet_aton which rejects # the valid IP address '255.255.255.255'. It appears this # problem is still present on the Win32 platform even in 2.3. # We'll work around the problem. # def inet_aton(text): if text == '255.255.255.255': return '\xff' * 4 else: return socket.inet_aton(text) else: inet_aton = socket.inet_aton inet_ntoa = socket.inet_ntoa LinkChecker-9.3/third_party/dnspython/dns/set.py0000644000175000017500000001724211570774060022646 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """A simple Set class.""" class Set(object): """A simple set class. Sets are not in Python until 2.3, and rdata are not immutable so we cannot use sets.Set anyway. This class implements subset of the 2.3 Set interface using a list as the container. @ivar items: A list of the items which are in the set @type items: list""" __slots__ = ['items'] def __init__(self, items=None): """Initialize the set. @param items: the initial set of items @type items: any iterable or None """ self.items = [] if not items is None: for item in items: self.add(item) def __repr__(self): return "dns.simpleset.Set(%s)" % repr(self.items) def add(self, item): """Add an item to the set.""" if not item in self.items: self.items.append(item) def remove(self, item): """Remove an item from the set.""" self.items.remove(item) def discard(self, item): """Remove an item from the set if present.""" try: self.items.remove(item) except ValueError: pass def _clone(self): """Make a (shallow) copy of the set. There is a 'clone protocol' that subclasses of this class should use. To make a copy, first call your super's _clone() method, and use the object returned as the new instance. Then make shallow copies of the attributes defined in the subclass. This protocol allows us to write the set algorithms that return new instances (e.g. union) once, and keep using them in subclasses. """ cls = self.__class__ obj = cls.__new__(cls) obj.items = list(self.items) return obj def __copy__(self): """Make a (shallow) copy of the set.""" return self._clone() def copy(self): """Make a (shallow) copy of the set.""" return self._clone() def union_update(self, other): """Update the set, adding any elements from other which are not already in the set. @param other: the collection of items with which to update the set @type other: Set object """ if not isinstance(other, Set): raise ValueError('other must be a Set instance') if self is other: return for item in other.items: self.add(item) def intersection_update(self, other): """Update the set, removing any elements from other which are not in both sets. @param other: the collection of items with which to update the set @type other: Set object """ if not isinstance(other, Set): raise ValueError('other must be a Set instance') if self is other: return # we make a copy of the list so that we can remove items from # the list without breaking the iterator. for item in list(self.items): if item not in other.items: self.items.remove(item) def difference_update(self, other): """Update the set, removing any elements from other which are in the set. @param other: the collection of items with which to update the set @type other: Set object """ if not isinstance(other, Set): raise ValueError('other must be a Set instance') if self is other: self.items = [] else: for item in other.items: self.discard(item) def union(self, other): """Return a new set which is the union of I{self} and I{other}. @param other: the other set @type other: Set object @rtype: the same type as I{self} """ obj = self._clone() obj.union_update(other) return obj def intersection(self, other): """Return a new set which is the intersection of I{self} and I{other}. @param other: the other set @type other: Set object @rtype: the same type as I{self} """ obj = self._clone() obj.intersection_update(other) return obj def difference(self, other): """Return a new set which I{self} - I{other}, i.e. the items in I{self} which are not also in I{other}. @param other: the other set @type other: Set object @rtype: the same type as I{self} """ obj = self._clone() obj.difference_update(other) return obj def __or__(self, other): return self.union(other) def __and__(self, other): return self.intersection(other) def __add__(self, other): return self.union(other) def __sub__(self, other): return self.difference(other) def __ior__(self, other): self.union_update(other) return self def __iand__(self, other): self.intersection_update(other) return self def __iadd__(self, other): self.union_update(other) return self def __isub__(self, other): self.difference_update(other) return self def update(self, other): """Update the set, adding any elements from other which are not already in the set. @param other: the collection of items with which to update the set @type other: any iterable type""" for item in other: self.add(item) def clear(self): """Make the set empty.""" self.items = [] def __eq__(self, other): # Yes, this is inefficient but the sets we're dealing with are # usually quite small, so it shouldn't hurt too much. for item in self.items: if not item in other.items: return False for item in other.items: if not item in self.items: return False return True def __ne__(self, other): return not self.__eq__(other) def __len__(self): return len(self.items) def __iter__(self): return iter(self.items) def __getitem__(self, i): return self.items[i] def __delitem__(self, i): del self.items[i] def __getslice__(self, i, j): return self.items[i:j] def __delslice__(self, i, j): del self.items[i:j] def issubset(self, other): """Is I{self} a subset of I{other}? @rtype: bool """ if not isinstance(other, Set): raise ValueError('other must be a Set instance') for item in self.items: if not item in other.items: return False return True def issuperset(self, other): """Is I{self} a superset of I{other}? @rtype: bool """ if not isinstance(other, Set): raise ValueError('other must be a Set instance') for item in other.items: if not item in self.items: return False return True LinkChecker-9.3/third_party/dnspython/dns/tsigkeyring.py0000644000175000017500000000316111570774061024406 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """A place to store TSIG keys.""" import base64 import dns.name def from_text(textring): """Convert a dictionary containing (textual DNS name, base64 secret) pairs into a binary keyring which has (dns.name.Name, binary secret) pairs. @rtype: dict""" keyring = {} for keytext in textring: keyname = dns.name.from_text(keytext) secret = base64.decodestring(textring[keytext]) keyring[keyname] = secret return keyring def to_text(keyring): """Convert a dictionary containing (dns.name.Name, binary secret) pairs into a text keyring which has (textual DNS name, base64 secret) pairs. @rtype: dict""" textring = {} for keyname in keyring: keytext = dns.name.to_text(keyname) secret = base64.encodestring(keyring[keyname]) textring[keytext] = secret return textring LinkChecker-9.3/third_party/dnspython/dns/version.py0000644000175000017500000000236211570774061023536 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """dnspython release version information.""" MAJOR = 1 MINOR = 9 MICRO = 5 RELEASELEVEL = 0x0f SERIAL = 0 if RELEASELEVEL == 0x0f: version = '%d.%d.%d' % (MAJOR, MINOR, MICRO) elif RELEASELEVEL == 0x00: version = '%d.%d.%dx%d' % \ (MAJOR, MINOR, MICRO, SERIAL) else: version = '%d.%d.%d%x%d' % \ (MAJOR, MINOR, MICRO, RELEASELEVEL, SERIAL) hexversion = MAJOR << 24 | MINOR << 16 | MICRO << 8 | RELEASELEVEL << 4 | \ SERIAL LinkChecker-9.3/third_party/dnspython/dns/rdataset.py0000644000175000017500000002643411570774061023666 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS rdatasets (an rdataset is a set of rdatas of a given type and class)""" import random import StringIO import struct import dns.exception import dns.rdatatype import dns.rdataclass import dns.rdata import dns.set # define SimpleSet here for backwards compatibility SimpleSet = dns.set.Set class DifferingCovers(dns.exception.DNSException): """Raised if an attempt is made to add a SIG/RRSIG whose covered type is not the same as that of the other rdatas in the rdataset.""" pass class IncompatibleTypes(dns.exception.DNSException): """Raised if an attempt is made to add rdata of an incompatible type.""" pass class Rdataset(dns.set.Set): """A DNS rdataset. @ivar rdclass: The class of the rdataset @type rdclass: int @ivar rdtype: The type of the rdataset @type rdtype: int @ivar covers: The covered type. Usually this value is dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or dns.rdatatype.RRSIG, then the covers value will be the rdata type the SIG/RRSIG covers. The library treats the SIG and RRSIG types as if they were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much easier to work with than if RRSIGs covering different rdata types were aggregated into a single RRSIG rdataset. @type covers: int @ivar ttl: The DNS TTL (Time To Live) value @type ttl: int """ __slots__ = ['rdclass', 'rdtype', 'covers', 'ttl'] def __init__(self, rdclass, rdtype, covers=dns.rdatatype.NONE): """Create a new rdataset of the specified class and type. @see: the description of the class instance variables for the meaning of I{rdclass} and I{rdtype}""" super(Rdataset, self).__init__() self.rdclass = rdclass self.rdtype = rdtype self.covers = covers self.ttl = 0 def _clone(self): obj = super(Rdataset, self)._clone() obj.rdclass = self.rdclass obj.rdtype = self.rdtype obj.covers = self.covers obj.ttl = self.ttl return obj def update_ttl(self, ttl): """Set the TTL of the rdataset to be the lesser of the set's current TTL or the specified TTL. If the set contains no rdatas, set the TTL to the specified TTL. @param ttl: The TTL @type ttl: int""" if len(self) == 0: self.ttl = ttl elif ttl < self.ttl: self.ttl = ttl def add(self, rd, ttl=None): """Add the specified rdata to the rdataset. If the optional I{ttl} parameter is supplied, then self.update_ttl(ttl) will be called prior to adding the rdata. @param rd: The rdata @type rd: dns.rdata.Rdata object @param ttl: The TTL @type ttl: int""" # # If we're adding a signature, do some special handling to # check that the signature covers the same type as the # other rdatas in this rdataset. If this is the first rdata # in the set, initialize the covers field. # if self.rdclass != rd.rdclass or self.rdtype != rd.rdtype: raise IncompatibleTypes if not ttl is None: self.update_ttl(ttl) if self.rdtype == dns.rdatatype.RRSIG or \ self.rdtype == dns.rdatatype.SIG: covers = rd.covers() if len(self) == 0 and self.covers == dns.rdatatype.NONE: self.covers = covers elif self.covers != covers: raise DifferingCovers if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0: self.clear() super(Rdataset, self).add(rd) def union_update(self, other): self.update_ttl(other.ttl) super(Rdataset, self).union_update(other) def intersection_update(self, other): self.update_ttl(other.ttl) super(Rdataset, self).intersection_update(other) def update(self, other): """Add all rdatas in other to self. @param other: The rdataset from which to update @type other: dns.rdataset.Rdataset object""" self.update_ttl(other.ttl) super(Rdataset, self).update(other) def __repr__(self): if self.covers == 0: ctext = '' else: ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' return '' def __str__(self): return self.to_text() def __eq__(self, other): """Two rdatasets are equal if they have the same class, type, and covers, and contain the same rdata. @rtype: bool""" if not isinstance(other, Rdataset): return False if self.rdclass != other.rdclass or \ self.rdtype != other.rdtype or \ self.covers != other.covers: return False return super(Rdataset, self).__eq__(other) def __ne__(self, other): return not self.__eq__(other) def to_text(self, name=None, origin=None, relativize=True, override_rdclass=None, **kw): """Convert the rdataset into DNS master file format. @see: L{dns.name.Name.choose_relativity} for more information on how I{origin} and I{relativize} determine the way names are emitted. Any additional keyword arguments are passed on to the rdata to_text() method. @param name: If name is not None, emit a RRs with I{name} as the owner name. @type name: dns.name.Name object @param origin: The origin for relative names, or None. @type origin: dns.name.Name object @param relativize: True if names should names be relativized @type relativize: bool""" if not name is None: name = name.choose_relativity(origin, relativize) ntext = str(name) pad = ' ' else: ntext = '' pad = '' s = StringIO.StringIO() if not override_rdclass is None: rdclass = override_rdclass else: rdclass = self.rdclass if len(self) == 0: # # Empty rdatasets are used for the question section, and in # some dynamic updates, so we don't need to print out the TTL # (which is meaningless anyway). # print >> s, '%s%s%s %s' % (ntext, pad, dns.rdataclass.to_text(rdclass), dns.rdatatype.to_text(self.rdtype)) else: for rd in self: print >> s, '%s%s%d %s %s %s' % \ (ntext, pad, self.ttl, dns.rdataclass.to_text(rdclass), dns.rdatatype.to_text(self.rdtype), rd.to_text(origin=origin, relativize=relativize, **kw)) # # We strip off the final \n for the caller's convenience in printing # return s.getvalue()[:-1] def to_wire(self, name, file, compress=None, origin=None, override_rdclass=None, want_shuffle=True): """Convert the rdataset to wire format. @param name: The owner name of the RRset that will be emitted @type name: dns.name.Name object @param file: The file to which the wire format data will be appended @type file: file @param compress: The compression table to use; the default is None. @type compress: dict @param origin: The origin to be appended to any relative names when they are emitted. The default is None. @returns: the number of records emitted @rtype: int """ if not override_rdclass is None: rdclass = override_rdclass want_shuffle = False else: rdclass = self.rdclass file.seek(0, 2) if len(self) == 0: name.to_wire(file, compress, origin) stuff = struct.pack("!HHIH", self.rdtype, rdclass, 0, 0) file.write(stuff) return 1 else: if want_shuffle: l = list(self) random.shuffle(l) else: l = self for rd in l: name.to_wire(file, compress, origin) stuff = struct.pack("!HHIH", self.rdtype, rdclass, self.ttl, 0) file.write(stuff) start = file.tell() rd.to_wire(file, compress, origin) end = file.tell() assert end - start < 65536 file.seek(start - 2) stuff = struct.pack("!H", end - start) file.write(stuff) file.seek(0, 2) return len(self) def match(self, rdclass, rdtype, covers): """Returns True if this rdataset matches the specified class, type, and covers""" if self.rdclass == rdclass and \ self.rdtype == rdtype and \ self.covers == covers: return True return False def from_text_list(rdclass, rdtype, ttl, text_rdatas): """Create an rdataset with the specified class, type, and TTL, and with the specified list of rdatas in text format. @rtype: dns.rdataset.Rdataset object """ if isinstance(rdclass, (str, unicode)): rdclass = dns.rdataclass.from_text(rdclass) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) r = Rdataset(rdclass, rdtype) r.update_ttl(ttl) for t in text_rdatas: rd = dns.rdata.from_text(r.rdclass, r.rdtype, t) r.add(rd) return r def from_text(rdclass, rdtype, ttl, *text_rdatas): """Create an rdataset with the specified class, type, and TTL, and with the specified rdatas in text format. @rtype: dns.rdataset.Rdataset object """ return from_text_list(rdclass, rdtype, ttl, text_rdatas) def from_rdata_list(ttl, rdatas): """Create an rdataset with the specified TTL, and with the specified list of rdata objects. @rtype: dns.rdataset.Rdataset object """ if len(rdatas) == 0: raise ValueError("rdata list must not be empty") r = None for rd in rdatas: if r is None: r = Rdataset(rd.rdclass, rd.rdtype) r.update_ttl(ttl) first_time = False r.add(rd) return r def from_rdata(ttl, *rdatas): """Create an rdataset with the specified TTL, and with the specified rdata objects. @rtype: dns.rdataset.Rdataset object """ return from_rdata_list(ttl, rdatas) LinkChecker-9.3/third_party/dnspython/dns/zone.py0000644000175000017500000007646111570774061023037 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Zones.""" from __future__ import generators import sys import dns.exception import dns.name import dns.node import dns.rdataclass import dns.rdatatype import dns.rdata import dns.rrset import dns.tokenizer import dns.ttl class BadZone(dns.exception.DNSException): """The zone is malformed.""" pass class NoSOA(BadZone): """The zone has no SOA RR at its origin.""" pass class NoNS(BadZone): """The zone has no NS RRset at its origin.""" pass class UnknownOrigin(BadZone): """The zone's origin is unknown.""" pass class Zone(object): """A DNS zone. A Zone is a mapping from names to nodes. The zone object may be treated like a Python dictionary, e.g. zone[name] will retrieve the node associated with that name. The I{name} may be a dns.name.Name object, or it may be a string. In the either case, if the name is relative it is treated as relative to the origin of the zone. @ivar rdclass: The zone's rdata class; the default is class IN. @type rdclass: int @ivar origin: The origin of the zone. @type origin: dns.name.Name object @ivar nodes: A dictionary mapping the names of nodes in the zone to the nodes themselves. @type nodes: dict @ivar relativize: should names in the zone be relativized? @type relativize: bool @cvar node_factory: the factory used to create a new node @type node_factory: class or callable """ node_factory = dns.node.Node __slots__ = ['rdclass', 'origin', 'nodes', 'relativize'] def __init__(self, origin, rdclass=dns.rdataclass.IN, relativize=True): """Initialize a zone object. @param origin: The origin of the zone. @type origin: dns.name.Name object @param rdclass: The zone's rdata class; the default is class IN. @type rdclass: int""" self.rdclass = rdclass self.origin = origin self.nodes = {} self.relativize = relativize def __eq__(self, other): """Two zones are equal if they have the same origin, class, and nodes. @rtype: bool """ if not isinstance(other, Zone): return False if self.rdclass != other.rdclass or \ self.origin != other.origin or \ self.nodes != other.nodes: return False return True def __ne__(self, other): """Are two zones not equal? @rtype: bool """ return not self.__eq__(other) 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 def __getitem__(self, key): key = self._validate_name(key) return self.nodes[key] def __setitem__(self, key, value): key = self._validate_name(key) self.nodes[key] = value def __delitem__(self, key): key = self._validate_name(key) del self.nodes[key] def __iter__(self): return self.nodes.iterkeys() def iterkeys(self): return self.nodes.iterkeys() def keys(self): return self.nodes.keys() def itervalues(self): return self.nodes.itervalues() def values(self): return self.nodes.values() def iteritems(self): return self.nodes.iteritems() def items(self): return self.nodes.items() def get(self, key): key = self._validate_name(key) return self.nodes.get(key) def __contains__(self, other): return other in self.nodes def find_node(self, name, create=False): """Find a node in the zone, possibly creating it. @param name: the name of the node to find @type name: dns.name.Name object or string @param create: should the node be created if it doesn't exist? @type create: bool @raises KeyError: the name is not known and create was not specified. @rtype: dns.node.Node object """ name = self._validate_name(name) node = self.nodes.get(name) if node is None: if not create: raise KeyError node = self.node_factory() self.nodes[name] = node return node def get_node(self, name, create=False): """Get a node in the zone, possibly creating it. This method is like L{find_node}, except it returns None instead of raising an exception if the node does not exist and creation has not been requested. @param name: the name of the node to find @type name: dns.name.Name object or string @param create: should the node be created if it doesn't exist? @type create: bool @rtype: dns.node.Node object or None """ try: node = self.find_node(name, create) except KeyError: node = None return node def delete_node(self, name): """Delete the specified node if it exists. It is not an error if the node does not exist. """ name = self._validate_name(name) if name in self.nodes: del self.nodes[name] def find_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, create=False): """Look for rdata with the specified name and type in the zone, and return an rdataset encapsulating it. The I{name}, I{rdtype}, and I{covers} parameters may be strings, in which case they will be converted to their proper type. The rdataset returned is not a copy; changes to it will change the zone. KeyError is raised if the name or type are not found. Use L{get_rdataset} if you want to have None returned instead. @param name: the owner name to look for @type name: DNS.name.Name object or string @param rdtype: the rdata type desired @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string @param create: should the node and rdataset be created if they do not exist? @type create: bool @raises KeyError: the node or rdata could not be found @rtype: dns.rrset.RRset object """ name = self._validate_name(name) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) if isinstance(covers, (str, unicode)): covers = dns.rdatatype.from_text(covers) node = self.find_node(name, create) return node.find_rdataset(self.rdclass, rdtype, covers, create) def get_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, create=False): """Look for rdata with the specified name and type in the zone, and return an rdataset encapsulating it. The I{name}, I{rdtype}, and I{covers} parameters may be strings, in which case they will be converted to their proper type. The rdataset returned is not a copy; changes to it will change the zone. None is returned if the name or type are not found. Use L{find_rdataset} if you want to have KeyError raised instead. @param name: the owner name to look for @type name: DNS.name.Name object or string @param rdtype: the rdata type desired @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string @param create: should the node and rdataset be created if they do not exist? @type create: bool @rtype: dns.rrset.RRset object """ try: rdataset = self.find_rdataset(name, rdtype, covers, create) except KeyError: rdataset = None return rdataset def delete_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE): """Delete the rdataset matching I{rdtype} and I{covers}, if it exists at the node specified by I{name}. The I{name}, I{rdtype}, and I{covers} parameters may be strings, in which case they will be converted to their proper type. It is not an error if the node does not exist, or if there is no matching rdataset at the node. If the node has no rdatasets after the deletion, it will itself be deleted. @param name: the owner name to look for @type name: DNS.name.Name object or string @param rdtype: the rdata type desired @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string """ name = self._validate_name(name) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) if isinstance(covers, (str, unicode)): covers = dns.rdatatype.from_text(covers) node = self.get_node(name) if not node is None: node.delete_rdataset(self.rdclass, rdtype, covers) if len(node) == 0: self.delete_node(name) def replace_rdataset(self, name, replacement): """Replace an rdataset at name. It is not an error if there is no rdataset matching I{replacement}. Ownership of the I{replacement} object is transferred to the zone; in other words, this method does not store a copy of I{replacement} at the node, it stores I{replacement} itself. If the I{name} node does not exist, it is created. @param name: the owner name @type name: DNS.name.Name object or string @param replacement: the replacement rdataset @type replacement: dns.rdataset.Rdataset """ if replacement.rdclass != self.rdclass: raise ValueError('replacement.rdclass != zone.rdclass') node = self.find_node(name, True) node.replace_rdataset(replacement) def find_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): """Look for rdata with the specified name and type in the zone, and return an RRset encapsulating it. The I{name}, I{rdtype}, and I{covers} parameters may be strings, in which case they will be converted to their proper type. This method is less efficient than the similar L{find_rdataset} because it creates an RRset instead of returning the matching rdataset. It may be more convenient for some uses since it returns an object which binds the owner name to the rdata. This method may not be used to create new nodes or rdatasets; use L{find_rdataset} instead. KeyError is raised if the name or type are not found. Use L{get_rrset} if you want to have None returned instead. @param name: the owner name to look for @type name: DNS.name.Name object or string @param rdtype: the rdata type desired @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string @raises KeyError: the node or rdata could not be found @rtype: dns.rrset.RRset object """ name = self._validate_name(name) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) if isinstance(covers, (str, unicode)): covers = dns.rdatatype.from_text(covers) rdataset = self.nodes[name].find_rdataset(self.rdclass, rdtype, covers) rrset = dns.rrset.RRset(name, self.rdclass, rdtype, covers) rrset.update(rdataset) return rrset def get_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): """Look for rdata with the specified name and type in the zone, and return an RRset encapsulating it. The I{name}, I{rdtype}, and I{covers} parameters may be strings, in which case they will be converted to their proper type. This method is less efficient than the similar L{get_rdataset} because it creates an RRset instead of returning the matching rdataset. It may be more convenient for some uses since it returns an object which binds the owner name to the rdata. This method may not be used to create new nodes or rdatasets; use L{find_rdataset} instead. None is returned if the name or type are not found. Use L{find_rrset} if you want to have KeyError raised instead. @param name: the owner name to look for @type name: DNS.name.Name object or string @param rdtype: the rdata type desired @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string @rtype: dns.rrset.RRset object """ try: rrset = self.find_rrset(name, rdtype, covers) except KeyError: rrset = None return rrset def iterate_rdatasets(self, rdtype=dns.rdatatype.ANY, covers=dns.rdatatype.NONE): """Return a generator which yields (name, rdataset) tuples for all rdatasets in the zone which have the specified I{rdtype} and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, then all rdatasets will be matched. @param rdtype: int or string @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string """ if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) if isinstance(covers, (str, unicode)): covers = dns.rdatatype.from_text(covers) for (name, node) in self.iteritems(): for rds in node: if rdtype == dns.rdatatype.ANY or \ (rds.rdtype == rdtype and rds.covers == covers): yield (name, rds) def iterate_rdatas(self, rdtype=dns.rdatatype.ANY, covers=dns.rdatatype.NONE): """Return a generator which yields (name, ttl, rdata) tuples for all rdatas in the zone which have the specified I{rdtype} and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, then all rdatas will be matched. @param rdtype: int or string @type rdtype: int or string @param covers: the covered type (defaults to None) @type covers: int or string """ if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) if isinstance(covers, (str, unicode)): covers = dns.rdatatype.from_text(covers) for (name, node) in self.iteritems(): for rds in node: if rdtype == dns.rdatatype.ANY or \ (rds.rdtype == rdtype and rds.covers == covers): for rdata in rds: yield (name, rds.ttl, rdata) def to_file(self, f, sorted=True, relativize=True, nl=None): """Write a zone to a file. @param f: file or string. If I{f} is a string, it is treated as the name of a file to open. @param sorted: if True, the file will be written with the names sorted in DNSSEC order from least to greatest. Otherwise the names will be written in whatever order they happen to have in the zone's dictionary. @param relativize: if True, domain names in the output will be relativized to the zone's origin (if possible). @type relativize: bool @param nl: The end of line string. If not specified, the output will use the platform's native end-of-line marker (i.e. LF on POSIX, CRLF on Windows, CR on Macintosh). @type nl: string or None """ if sys.hexversion >= 0x02030000: # allow Unicode filenames str_type = basestring else: str_type = str if nl is None: opts = 'w' else: opts = 'wb' if isinstance(f, str_type): f = file(f, opts) want_close = True else: want_close = False try: if sorted: names = self.keys() names.sort() else: names = self.iterkeys() for n in names: l = self[n].to_text(n, origin=self.origin, relativize=relativize) if nl is None: print >> f, l else: f.write(l) f.write(nl) finally: if want_close: f.close() def check_origin(self): """Do some simple checking of the zone's origin. @raises dns.zone.NoSOA: there is no SOA RR @raises dns.zone.NoNS: there is no NS RRset @raises KeyError: there is no origin node """ if self.relativize: name = dns.name.empty else: name = self.origin if self.get_rdataset(name, dns.rdatatype.SOA) is None: raise NoSOA if self.get_rdataset(name, dns.rdatatype.NS) is None: raise NoNS class _MasterReader(object): """Read a DNS master file @ivar tok: The tokenizer @type tok: dns.tokenizer.Tokenizer object @ivar ttl: The default TTL @type ttl: int @ivar last_name: The last name read @type last_name: dns.name.Name object @ivar current_origin: The current origin @type current_origin: dns.name.Name object @ivar relativize: should names in the zone be relativized? @type relativize: bool @ivar zone: the zone @type zone: dns.zone.Zone object @ivar saved_state: saved reader state (used when processing $INCLUDE) @type saved_state: list of (tokenizer, current_origin, last_name, file) tuples. @ivar current_file: the file object of the $INCLUDed file being parsed (None if no $INCLUDE is active). @ivar allow_include: is $INCLUDE allowed? @type allow_include: bool @ivar check_origin: should sanity checks of the origin node be done? The default is True. @type check_origin: bool """ def __init__(self, tok, origin, rdclass, relativize, zone_factory=Zone, allow_include=False, check_origin=True): if isinstance(origin, (str, unicode)): origin = dns.name.from_text(origin) self.tok = tok self.current_origin = origin self.relativize = relativize self.ttl = 0 self.last_name = None self.zone = zone_factory(origin, rdclass, relativize=relativize) self.saved_state = [] self.current_file = None self.allow_include = allow_include self.check_origin = check_origin def _eat_line(self): while 1: token = self.tok.get() if token.is_eol_or_eof(): break 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 except StandardError: 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 StandardError: 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 StandardError: # 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) def read(self): """Read a DNS master file and build a zone object. @raises dns.zone.NoSOA: No SOA RR was found at the zone origin @raises dns.zone.NoNS: No NS RRset was found at the zone origin """ try: while 1: token = self.tok.get(True, True).unescape() if token.is_eof(): if not self.current_file is None: self.current_file.close() if len(self.saved_state) > 0: (self.tok, self.current_origin, self.last_name, self.current_file, self.ttl) = self.saved_state.pop(-1) continue break elif token.is_eol(): continue elif token.is_comment(): self.tok.get_eol() continue elif token.value[0] == '$': u = token.value.upper() if u == '$TTL': token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError("bad $TTL") self.ttl = dns.ttl.from_text(token.value) self.tok.get_eol() elif u == '$ORIGIN': self.current_origin = self.tok.get_name() self.tok.get_eol() if self.zone.origin is None: self.zone.origin = self.current_origin elif u == '$INCLUDE' and self.allow_include: token = self.tok.get() if not token.is_quoted_string(): raise dns.exception.SyntaxError("bad filename in $INCLUDE") filename = token.value token = self.tok.get() if token.is_identifier(): new_origin = dns.name.from_text(token.value, \ self.current_origin) self.tok.get_eol() elif not token.is_eol_or_eof(): raise dns.exception.SyntaxError("bad origin in $INCLUDE") else: new_origin = self.current_origin self.saved_state.append((self.tok, self.current_origin, self.last_name, self.current_file, self.ttl)) self.current_file = file(filename, 'r') self.tok = dns.tokenizer.Tokenizer(self.current_file, filename) self.current_origin = new_origin else: raise dns.exception.SyntaxError("Unknown master file directive '" + u + "'") continue self.tok.unget(token) self._rr_line() except dns.exception.SyntaxError, detail: (filename, line_number) = self.tok.where() if detail is None: detail = "syntax error" raise dns.exception.SyntaxError("%s:%d: %s" % (filename, line_number, detail)) # Now that we're done reading, do some basic checking of the zone. if self.check_origin: self.zone.check_origin() def from_text(text, origin = None, rdclass = dns.rdataclass.IN, relativize = True, zone_factory=Zone, filename=None, allow_include=False, check_origin=True): """Build a zone object from a master file format string. @param text: the master file format input @type text: string. @param origin: The origin of the zone; if not specified, the first $ORIGIN statement in the master file will determine the origin of the zone. @type origin: dns.name.Name object or string @param rdclass: The zone's rdata class; the default is class IN. @type rdclass: int @param relativize: should names be relativized? The default is True @type relativize: bool @param zone_factory: The zone factory to use @type zone_factory: function returning a Zone @param filename: The filename to emit when describing where an error occurred; the default is ''. @type filename: string @param allow_include: is $INCLUDE allowed? @type allow_include: bool @param check_origin: should sanity checks of the origin node be done? The default is True. @type check_origin: bool @raises dns.zone.NoSOA: No SOA RR was found at the zone origin @raises dns.zone.NoNS: No NS RRset was found at the zone origin @rtype: dns.zone.Zone object """ # 'text' can also be a file, but we don't publish that fact # since it's an implementation detail. The official file # interface is from_file(). if filename is None: filename = '' tok = dns.tokenizer.Tokenizer(text, filename) reader = _MasterReader(tok, origin, rdclass, relativize, zone_factory, allow_include=allow_include, check_origin=check_origin) reader.read() return reader.zone def from_file(f, origin = None, rdclass = dns.rdataclass.IN, relativize = True, zone_factory=Zone, filename=None, allow_include=True, check_origin=True): """Read a master file and build a zone object. @param f: file or string. If I{f} is a string, it is treated as the name of a file to open. @param origin: The origin of the zone; if not specified, the first $ORIGIN statement in the master file will determine the origin of the zone. @type origin: dns.name.Name object or string @param rdclass: The zone's rdata class; the default is class IN. @type rdclass: int @param relativize: should names be relativized? The default is True @type relativize: bool @param zone_factory: The zone factory to use @type zone_factory: function returning a Zone @param filename: The filename to emit when describing where an error occurred; the default is '', or the value of I{f} if I{f} is a string. @type filename: string @param allow_include: is $INCLUDE allowed? @type allow_include: bool @param check_origin: should sanity checks of the origin node be done? The default is True. @type check_origin: bool @raises dns.zone.NoSOA: No SOA RR was found at the zone origin @raises dns.zone.NoNS: No NS RRset was found at the zone origin @rtype: dns.zone.Zone object """ if sys.hexversion >= 0x02030000: # allow Unicode filenames; turn on universal newline support str_type = basestring opts = 'rU' else: str_type = str opts = 'r' if isinstance(f, str_type): if filename is None: filename = f f = file(f, opts) want_close = True else: if filename is None: filename = '' want_close = False try: z = from_text(f, origin, rdclass, relativize, zone_factory, filename, allow_include, check_origin) finally: if want_close: f.close() return z def from_xfr(xfr, zone_factory=Zone, relativize=True): """Convert the output of a zone transfer generator into a zone object. @param xfr: The xfr generator @type xfr: generator of dns.message.Message objects @param relativize: should names be relativized? The default is True. It is essential that the relativize setting matches the one specified to dns.query.xfr(). @type relativize: bool @raises dns.zone.NoSOA: No SOA RR was found at the zone origin @raises dns.zone.NoNS: No NS RRset was found at the zone origin @rtype: dns.zone.Zone object """ z = None for r in xfr: if z is None: if relativize: origin = r.origin else: origin = r.answer[0].name rdclass = r.answer[0].rdclass z = zone_factory(origin, rdclass, relativize=relativize) for rrset in r.answer: znode = z.nodes.get(rrset.name) if not znode: znode = z.node_factory() z.nodes[rrset.name] = znode zrds = znode.find_rdataset(rrset.rdclass, rrset.rdtype, rrset.covers, True) zrds.update_ttl(rrset.ttl) for rd in rrset: rd.choose_relativity(z.origin, relativize) zrds.add(rd) z.check_origin() return z LinkChecker-9.3/third_party/dnspython/dns/edns.py0000644000175000017500000001034511570774061023002 0ustar calvincalvin00000000000000# Copyright (C) 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """EDNS Options""" NSID = 3 class Option(object): """Base class for all EDNS option types. """ def __init__(self, otype): """Initialize an option. @param rdtype: The rdata type @type rdtype: int """ self.otype = otype def to_wire(self, file): """Convert an option to wire format. """ raise NotImplementedError def from_wire(cls, otype, wire, current, olen): """Build an EDNS option object from wire format @param otype: The option type @type otype: int @param wire: The wire-format message @type wire: string @param current: The offet in wire of the beginning of the rdata. @type current: int @param olen: The length of the wire-format option data @type olen: int @rtype: dns.ends.Option instance""" raise NotImplementedError from_wire = classmethod(from_wire) def _cmp(self, other): """Compare an ENDS option with another option of the same type. Return < 0 if self < other, 0 if self == other, and > 0 if self > other. """ raise NotImplementedError def __eq__(self, other): if not isinstance(other, Option): return False if self.otype != other.otype: return False return self._cmp(other) == 0 def __ne__(self, other): if not isinstance(other, Option): return False if self.otype != other.otype: return False return self._cmp(other) != 0 def __lt__(self, other): if not isinstance(other, Option) or \ self.otype != other.otype: return NotImplemented return self._cmp(other) < 0 def __le__(self, other): if not isinstance(other, Option) or \ self.otype != other.otype: return NotImplemented return self._cmp(other) <= 0 def __ge__(self, other): if not isinstance(other, Option) or \ self.otype != other.otype: return NotImplemented return self._cmp(other) >= 0 def __gt__(self, other): if not isinstance(other, Option) or \ self.otype != other.otype: return NotImplemented return self._cmp(other) > 0 class GenericOption(Option): """Generate Rdata Class This class is used for EDNS option types for which we have no better implementation. """ def __init__(self, otype, data): super(GenericOption, self).__init__(otype) self.data = data def to_wire(self, file): file.write(self.data) def from_wire(cls, otype, wire, current, olen): return cls(otype, wire[current : current + olen]) from_wire = classmethod(from_wire) def _cmp(self, other): return cmp(self.data, other.data) _type_to_class = { } def get_option_class(otype): cls = _type_to_class.get(otype) if cls is None: cls = GenericOption return cls def option_from_wire(otype, wire, current, olen): """Build an EDNS option object from wire format @param otype: The option type @type otype: int @param wire: The wire-format message @type wire: string @param current: The offet in wire of the beginning of the rdata. @type current: int @param olen: The length of the wire-format option data @type olen: int @rtype: dns.ends.Option instance""" cls = get_option_class(otype) return cls.from_wire(otype, wire, current, olen) LinkChecker-9.3/third_party/dnspython/dns/resolver.py0000644000175000017500000010117611570774061023715 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS stub resolver. @var default_resolver: The default resolver object @type default_resolver: dns.resolver.Resolver object""" import socket import sys import os import time import dns.exception import dns.message import dns.name import dns.query import dns.rcode import dns.rdataclass import dns.rdatatype if sys.platform == 'win32': import _winreg class NXDOMAIN(dns.exception.DNSException): """The query name does not exist.""" pass # The definition of the Timeout exception has moved from here to the # dns.exception module. We keep dns.resolver.Timeout defined for # backwards compatibility. Timeout = dns.exception.Timeout class NoAnswer(dns.exception.DNSException): """The response did not contain an answer to the question.""" pass class NoNameservers(dns.exception.DNSException): """No non-broken nameservers are available to answer the query.""" pass class NotAbsolute(dns.exception.DNSException): """Raised if an absolute domain name is required but a relative name was provided.""" pass class NoRootSOA(dns.exception.DNSException): """Raised if for some reason there is no SOA at the root name. This should never happen!""" pass class NoMetaqueries(dns.exception.DNSException): """Metaqueries are not allowed.""" pass class Answer(object): """DNS stub resolver answer Instances of this class bundle up the result of a successful DNS resolution. For convenience, the answer object implements much of the sequence protocol, forwarding to its rrset. E.g. "for a in answer" is equivalent to "for a in answer.rrset", "answer[i]" is equivalent to "answer.rrset[i]", and "answer[i:j]" is equivalent to "answer.rrset[i:j]". Note that CNAMEs or DNAMEs in the response may mean that answer node's name might not be the query name. @ivar qname: The query name @type qname: dns.name.Name object @ivar rdtype: The query type @type rdtype: int @ivar rdclass: The query class @type rdclass: int @ivar response: The response message @type response: dns.message.Message object @ivar rrset: The answer @type rrset: dns.rrset.RRset object @ivar expiration: The time when the answer expires @type expiration: float (seconds since the epoch) @ivar canonical_name: The canonical name of the query name @type canonical_name: dns.name.Name object """ def __init__(self, qname, rdtype, rdclass, response, raise_on_no_answer=True): self.qname = qname self.rdtype = rdtype self.rdclass = rdclass self.response = response min_ttl = -1 rrset = None for count in xrange(0, 15): try: rrset = response.find_rrset(response.answer, qname, rdclass, rdtype) if min_ttl == -1 or rrset.ttl < min_ttl: min_ttl = rrset.ttl break except KeyError: if rdtype != dns.rdatatype.CNAME: try: crrset = response.find_rrset(response.answer, qname, rdclass, dns.rdatatype.CNAME) if min_ttl == -1 or crrset.ttl < min_ttl: min_ttl = crrset.ttl for rd in crrset: qname = rd.target break continue except KeyError: if raise_on_no_answer: raise NoAnswer("DNS response had no answer") if raise_on_no_answer: raise NoAnswer("DNS response had no answer") if rrset is None and raise_on_no_answer: raise NoAnswer("DNS response had no answer") self.canonical_name = qname self.rrset = rrset if rrset is None: while 1: # Look for a SOA RR whose owner name is a superdomain # of qname. try: srrset = response.find_rrset(response.authority, qname, rdclass, dns.rdatatype.SOA) if min_ttl == -1 or srrset.ttl < min_ttl: min_ttl = srrset.ttl if srrset[0].minimum < min_ttl: min_ttl = srrset[0].minimum break except KeyError: try: qname = qname.parent() except dns.name.NoParent: break self.expiration = time.time() + min_ttl def __str__ (self): return str(self.rrset) def __getattr__(self, attr): if attr == 'name': return self.rrset.name elif attr == 'ttl': return self.rrset.ttl elif attr == 'covers': return self.rrset.covers elif attr == 'rdclass': return self.rrset.rdclass elif attr == 'rdtype': return self.rrset.rdtype else: raise AttributeError(attr) def __len__(self): return len(self.rrset) def __iter__(self): return iter(self.rrset) def __getitem__(self, i): return self.rrset[i] def __delitem__(self, i): del self.rrset[i] def __getslice__(self, i, j): return self.rrset[i:j] def __delslice__(self, i, j): del self.rrset[i:j] class Cache(object): """Simple DNS answer cache. @ivar data: A dictionary of cached data @type data: dict @ivar cleaning_interval: The number of seconds between cleanings. The default is 300 (5 minutes). @type cleaning_interval: float @ivar next_cleaning: The time the cache should next be cleaned (in seconds since the epoch.) @type next_cleaning: float """ def __init__(self, cleaning_interval=300.0): """Initialize a DNS cache. @param cleaning_interval: the number of seconds between periodic cleanings. The default is 300.0 @type cleaning_interval: float. """ self.data = {} self.cleaning_interval = cleaning_interval self.next_cleaning = time.time() + self.cleaning_interval def maybe_clean(self): """Clean the cache if it's time to do so.""" now = time.time() if self.next_cleaning <= now: keys_to_delete = [] for (k, v) in self.data.iteritems(): if v.expiration <= now: keys_to_delete.append(k) for k in keys_to_delete: del self.data[k] now = time.time() self.next_cleaning = now + self.cleaning_interval def get(self, key): """Get the answer associated with I{key}. Returns None if no answer is cached for the key. @param key: the key @type key: (dns.name.Name, int, int) tuple whose values are the query name, rdtype, and rdclass. @rtype: dns.resolver.Answer object or None """ self.maybe_clean() v = self.data.get(key) if v is None or v.expiration <= time.time(): return None return v def put(self, key, value): """Associate key and value in the cache. @param key: the key @type key: (dns.name.Name, int, int) tuple whose values are the query name, rdtype, and rdclass. @param value: The answer being cached @type value: dns.resolver.Answer object """ self.maybe_clean() self.data[key] = value def flush(self, key=None): """Flush the cache. If I{key} is specified, only that item is flushed. Otherwise the entire cache is flushed. @param key: the key to flush @type key: (dns.name.Name, int, int) tuple or None """ if not key is None: if key in self.data: del self.data[key] else: self.data = {} self.next_cleaning = time.time() + self.cleaning_interval class Resolver(object): """DNS stub resolver @ivar domain: The domain of this host @type domain: dns.name.Name object @ivar nameservers: A list of nameservers to query. Each nameserver is a string which contains the IP address of a nameserver. @type nameservers: list of strings @ivar search: The search list. If the query name is a relative name, the resolver will construct an absolute query name by appending the search names one by one to the query name. @type search: list of dns.name.Name objects @ivar port: The port to which to send queries. The default is 53. @type port: int @ivar timeout: The number of seconds to wait for a response from a server, before timing out. @type timeout: float @ivar lifetime: The total number of seconds to spend trying to get an answer to the question. If the lifetime expires, a Timeout exception will occur. @type lifetime: float @ivar keyring: The TSIG keyring to use. The default is None. @type keyring: dict @ivar keyname: The TSIG keyname to use. The default is None. @type keyname: dns.name.Name object @ivar keyalgorithm: The TSIG key algorithm to use. The default is dns.tsig.default_algorithm. @type keyalgorithm: string @ivar edns: The EDNS level to use. The default is -1, no Edns. @type edns: int @ivar ednsflags: The EDNS flags @type ednsflags: int @ivar payload: The EDNS payload size. The default is 0. @type payload: int @ivar cache: The cache to use. The default is None. @type cache: dns.resolver.Cache object """ def __init__(self, filename='/etc/resolv.conf', configure=True): """Initialize a resolver instance. @param filename: The filename of a configuration file in standard /etc/resolv.conf format. This parameter is meaningful only when I{configure} is true and the platform is POSIX. @type filename: string or file object @param configure: If True (the default), the resolver instance is configured in the normal fashion for the operating system the resolver is running on. (I.e. a /etc/resolv.conf file on POSIX systems and from the registry on Windows systems.) @type configure: bool""" self.reset() if configure: if sys.platform == 'win32': self.read_registry() elif filename: self.read_resolv_conf(filename) self.read_local_hosts() if len(self.search) == 0: self.search.add(self.domain) def reset(self): """Reset all resolver configuration to the defaults.""" self.domain = \ dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) if len(self.domain) == 0: self.domain = dns.name.root self.nameservers = [] self.localhosts = set([ 'localhost', 'loopback', '127.0.0.1', '0.0.0.0', '::1', 'ip6-localhost', 'ip6-loopback', ]) # connected and active network interfaces self.interfaces = set() self.search = set() self.search_patterns = ['www.%s.com', 'www.%s.org', 'www.%s.net', ] self.port = 53 self.timeout = 2.0 self.lifetime = 30.0 self.keyring = None self.keyname = None self.keyalgorithm = dns.tsig.default_algorithm self.edns = -1 self.ednsflags = 0 self.payload = 0 self.cache = None def read_resolv_conf(self, f): """Process f as a file in the /etc/resolv.conf format. If f is a string, it is used as the name of the file to open; otherwise it is treated as the file itself.""" if isinstance(f, basestring): try: f = open(f, 'r') except IOError: # /etc/resolv.conf doesn't exist, can't be read, etc. # We'll just use the default resolver configuration. self.nameservers = ['127.0.0.1'] return want_close = True else: want_close = False try: for l in f: l = l.strip() if len(l) == 0 or l[0] == '#' or l[0] == ';': continue tokens = l.split() if len(tokens) < 2: continue if tokens[0] == 'nameserver': self.nameservers.append(tokens[1]) elif tokens[0] == 'domain': self.domain = dns.name.from_text(tokens[1]) elif tokens[0] == 'search': for suffix in tokens[1:]: self.search.add(dns.name.from_text(suffix)) finally: if want_close: f.close() if len(self.nameservers) == 0: self.nameservers.append('127.0.0.1') def read_local_hosts (self): self.add_addrinfo(socket.gethostname()) # add system specific hosts for all enabled interfaces self.add_addrinfo('localhost', interface=True) for addr in self.read_local_ifaddrs(): self.add_addrinfo(addr, interface=True) def read_local_ifaddrs (self): """ IP addresses for all active interfaces. @return: list of IP addresses @rtype: list of strings """ if os.name != 'posix': # only POSIX is supported right now return [] try: from linkcheck.network import IfConfig except ImportError: return [] ifaddrs = [] ifc = IfConfig() for iface in ifc.getInterfaceList(flags=IfConfig.IFF_UP): addr = ifc.getAddr(iface) if addr: ifaddrs.append(addr) return ifaddrs def add_addrinfo (self, host, interface=False): try: addrinfo = socket.gethostbyaddr(host) except socket.error: self.localhosts.add(host.lower()) if interface: self.interfaces.add(host.lower()) return self.localhosts.add(addrinfo[0].lower()) if interface: self.interfaces.add(addrinfo[0].lower()) for h in addrinfo[1]: self.localhosts.add(h.lower()) for h in addrinfo[2]: self.localhosts.add(h.lower()) def _determine_split_char(self, entry): # The windows registry irritatingly changes the list element # delimiter in between ' ' and ',' (and vice-versa) in various # versions of windows. if entry.find(' ') >= 0: split_char = ' ' elif entry.find(',') >= 0: split_char = ',' else: # probably a singleton; treat as a space-separated list. split_char = ' ' return split_char def _config_win32_nameservers(self, nameservers): """Configure a NameServer registry entry.""" # we call str() on nameservers to convert it from unicode to ascii nameservers = str(nameservers) split_char = self._determine_split_char(nameservers) ns_list = nameservers.split(split_char) for ns in ns_list: if not ns in self.nameservers: self.nameservers.append(ns) def _config_win32_domain(self, domain): """Configure a Domain registry entry.""" # we call str() on domain to convert it from unicode to ascii self.domain = dns.name.from_text(str(domain)) def _config_win32_search(self, search): """Configure a Search registry entry.""" # we call str() on search to convert it from unicode to ascii search = str(search) split_char = self._determine_split_char(search) search_list = search.split(split_char) for s in search_list: if not s in self.search: self.search.add(dns.name.from_text(s)) def _config_win32_add_ifaddr (self, key, name): """Add interface ip address to self.localhosts.""" try: ip, rtype = _winreg.QueryValueEx(key, name) if isinstance(ip, basestring) and ip: ip = str(ip).lower() self.localhosts.add(ip) self.interfaces.add(ip) except WindowsError: pass def _config_win32_fromkey(self, key): """Extract DNS info from a registry key.""" try: enable_dhcp, rtype = _winreg.QueryValueEx(key, 'EnableDHCP') except WindowsError: enable_dhcp = False if enable_dhcp: try: servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') except WindowsError: servers = None if servers: self._config_win32_nameservers(servers) try: dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain') if dom: self._config_win32_domain(servers) except WindowsError: pass self._config_win32_add_ifaddr(key, 'DhcpIPAddress') else: try: servers, rtype = _winreg.QueryValueEx(key, 'NameServer') except WindowsError: servers = None if servers: self._config_win32_nameservers(servers) try: dom, rtype = _winreg.QueryValueEx(key, 'Domain') if dom: self._config_win32_domain(servers) except WindowsError: pass self._config_win32_add_ifaddr(key, 'IPAddress') try: search, rtype = _winreg.QueryValueEx(key, 'SearchList') except WindowsError: search = None if search: self._config_win32_search(search) def read_registry(self): """Extract resolver configuration from the Windows registry.""" lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) want_scan = False try: try: # XP, 2000 tcp_params = _winreg.OpenKey(lm, r'SYSTEM\CurrentControlSet' r'\Services\Tcpip\Parameters') want_scan = True except EnvironmentError: # ME tcp_params = _winreg.OpenKey(lm, r'SYSTEM\CurrentControlSet' r'\Services\VxD\MSTCP') try: self._config_win32_fromkey(tcp_params) finally: tcp_params.Close() if want_scan: interfaces = _winreg.OpenKey(lm, r'SYSTEM\CurrentControlSet' r'\Services\Tcpip\Parameters' r'\Interfaces') try: i = 0 while True: try: guid = _winreg.EnumKey(interfaces, i) i += 1 key = _winreg.OpenKey(interfaces, guid) if not self._win32_is_nic_enabled(lm, guid, key): continue try: self._config_win32_fromkey(key) finally: key.Close() except EnvironmentError: break finally: interfaces.Close() finally: lm.Close() def _win32_is_nic_enabled(self, lm, guid, interface_key): # Look in the Windows Registry to determine whether the network # interface corresponding to the given guid is enabled. # (Code contributed by Paul Marks, thanks!) try: # This hard-coded location seems to be consistent, at least # from Windows 2000 through Vista. connection_key = _winreg.OpenKey( lm, r'SYSTEM\CurrentControlSet\Control\Network' r'\{4D36E972-E325-11CE-BFC1-08002BE10318}' r'\%s\Connection' % guid) try: # The PnpInstanceID points to a key inside Enum (pnp_id, ttype) = _winreg.QueryValueEx( connection_key, 'PnpInstanceID') if ttype != _winreg.REG_SZ: raise ValueError device_key = _winreg.OpenKey( lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id) try: # Get ConfigFlags for this device (flags, ttype) = _winreg.QueryValueEx( device_key, 'ConfigFlags') if ttype != _winreg.REG_DWORD: raise ValueError # Based on experimentation, bit 0x1 indicates that the # device is disabled. return not (flags & 0x1) finally: device_key.Close() finally: connection_key.Close() except (EnvironmentError, ValueError): # Pre-vista, enabled interfaces seem to have a non-empty # NTEContextList; this was how dnspython detected enabled # nics before the code above was contributed. We've retained # the old method since we don't know if the code above works # on Windows 95/98/ME. try: (nte, ttype) = _winreg.QueryValueEx(interface_key, 'NTEContextList') return nte is not None except WindowsError: return False def _compute_timeout(self, start): now = time.time() if now < start: if start - now > 1: # Time going backwards is bad. Just give up. raise Timeout else: # Time went backwards, but only a little. This can # happen, e.g. under vmware with older linux kernels. # Pretend it didn't happen. now = start duration = now - start if duration >= self.lifetime: raise Timeout return min(self.lifetime - duration, self.timeout) def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, tcp=False, source=None, raise_on_no_answer=True): """Query nameservers to find the answer to the question. The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects of the appropriate type, or strings that can be converted into objects of the appropriate type. E.g. For I{rdtype} the integer 2 and the the string 'NS' both mean to query for records with DNS rdata type NS. @param qname: the query name @type qname: dns.name.Name object or string @param rdtype: the query type @type rdtype: int or string @param rdclass: the query class @type rdclass: int or string @param tcp: use TCP to make the query (default is False). @type tcp: bool @param source: bind to this IP address (defaults to machine default IP). @type source: IP address in dotted quad notation @param raise_on_no_answer: raise NoAnswer if there's no answer (defaults is True). @type raise_on_no_answer: bool @rtype: dns.resolver.Answer instance @raises Timeout: no answers could be found in the specified lifetime @raises NXDOMAIN: the query name does not exist @raises NoAnswer: the response did not contain an answer and raise_on_no_answer is True. @raises NoNameservers: no non-broken nameservers are available to answer the question.""" if isinstance(qname, basestring): qname = dns.name.from_text(qname, None) if isinstance(rdtype, basestring): rdtype = dns.rdatatype.from_text(rdtype) if dns.rdatatype.is_metatype(rdtype): raise NoMetaqueries if isinstance(rdclass, basestring): rdclass = dns.rdataclass.from_text(rdclass) if dns.rdataclass.is_metaclass(rdclass): raise NoMetaqueries qnames_to_try = [] if qname.is_absolute(): qnames_to_try.append(qname) else: if len(qname) > 1: qnames_to_try.append(qname.concatenate(dns.name.root)) if self.search: for suffix in self.search: qnames_to_try.append(qname.concatenate(suffix)) else: qnames_to_try.append(qname.concatenate(self.domain)) all_nxdomain = True start = time.time() for qname in qnames_to_try: if self.cache: answer = self.cache.get((qname, rdtype, rdclass)) if answer: return answer request = dns.message.make_query(qname, rdtype, rdclass) if not self.keyname is None: request.use_tsig(self.keyring, self.keyname, algorithm=self.keyalgorithm) request.use_edns(self.edns, self.ednsflags, self.payload) response = None # make a copy of the servers list so we can alter it later. nameservers = self.nameservers[:] backoff = 0.10 while response is None: if len(nameservers) == 0: raise NoNameservers("No DNS servers %s could answer the query %s" % \ (str(self.nameservers), str(qname))) for nameserver in nameservers[:]: timeout = self._compute_timeout(start) try: if tcp: response = dns.query.tcp(request, nameserver, timeout, self.port, source=source) else: response = dns.query.udp(request, nameserver, timeout, self.port, source=source) except (socket.error, dns.exception.Timeout): # Communication failure or timeout. Go to the # next server response = None continue except dns.query.UnexpectedSource: # Who knows? Keep going. response = None continue except dns.exception.FormError: # We don't understand what this server is # saying. Take it out of the mix and # continue. nameservers.remove(nameserver) response = None continue rcode = response.rcode() if rcode == dns.rcode.NOERROR or \ rcode == dns.rcode.NXDOMAIN: break # We got a response, but we're not happy with the # rcode in it. Remove the server from the mix if # the rcode isn't SERVFAIL. if rcode != dns.rcode.SERVFAIL: nameservers.remove(nameserver) response = None if response is not None: break # All nameservers failed! if len(nameservers) > 0: # But we still have servers to try. Sleep a bit # so we don't pound them! timeout = self._compute_timeout(start) sleep_time = min(timeout, backoff) backoff *= 2 time.sleep(sleep_time) if response.rcode() == dns.rcode.NXDOMAIN: continue all_nxdomain = False break if all_nxdomain: raise NXDOMAIN("Domain does not exist") answer = Answer(qname, rdtype, rdclass, response, raise_on_no_answer) if self.cache: self.cache.put((qname, rdtype, rdclass), answer) return answer def use_tsig(self, keyring, keyname=None, algorithm=dns.tsig.default_algorithm): """Add a TSIG signature to the query. @param keyring: The TSIG keyring to use; defaults to None. @type keyring: dict @param keyname: The name of the TSIG key to use; defaults to None. The key must be defined in the keyring. If a keyring is specified but a keyname is not, then the key used will be the first key in the keyring. Note that the order of keys in a dictionary is not defined, so applications should supply a keyname when a keyring is used, unless they know the keyring contains only one key. @param algorithm: The TSIG key algorithm to use. The default is dns.tsig.default_algorithm. @type algorithm: string""" self.keyring = keyring if keyname is None: self.keyname = self.keyring.keys()[0] else: self.keyname = keyname self.keyalgorithm = algorithm def use_edns(self, edns, ednsflags, payload): """Configure Edns. @param edns: The EDNS level to use. The default is -1, no Edns. @type edns: int @param ednsflags: The EDNS flags @type ednsflags: int @param payload: The EDNS payload size. The default is 0. @type payload: int""" if edns is None: edns = -1 self.edns = edns self.ednsflags = ednsflags self.payload = payload default_resolver = None def get_default_resolver(): """Get the default resolver, initializing it if necessary.""" global default_resolver if default_resolver is None: default_resolver = Resolver() return default_resolver def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, tcp=False, source=None, raise_on_no_answer=True, resolver=None): """Query nameservers to find the answer to the question. This is a convenience function that uses the default resolver object to make the query. @see: L{dns.resolver.Resolver.query} for more information on the parameters.""" if resolver is None: resolver = get_default_resolver() return resolver.query(qname, rdtype, rdclass, tcp, source, raise_on_no_answer) def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None): """Find the name of the zone which contains the specified name. @param name: the query name @type name: absolute dns.name.Name object or string @param rdclass: The query class @type rdclass: int @param tcp: use TCP to make the query (default is False). @type tcp: bool @param resolver: the resolver to use @type resolver: dns.resolver.Resolver object or None @rtype: dns.name.Name""" if isinstance(name, basestring): name = dns.name.from_text(name, dns.name.root) if resolver is None: resolver = get_default_resolver() if not name.is_absolute(): raise NotAbsolute(name) while 1: try: answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) if answer.rrset.name == name: return name # otherwise we were CNAMEd or DNAMEd and need to look higher except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): pass try: name = name.parent() except dns.name.NoParent: raise NoRootSOA LinkChecker-9.3/third_party/dnspython/dns/tsig.py0000644000175000017500000001700111570774061023013 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS TSIG support.""" import hmac import struct import sys import dns.exception import dns.hash import dns.rdataclass import dns.name class BadTime(dns.exception.DNSException): """Raised if the current time is not within the TSIG's validity time.""" pass class BadSignature(dns.exception.DNSException): """Raised if the TSIG signature fails to verify.""" pass class PeerError(dns.exception.DNSException): """Base class for all TSIG errors generated by the remote peer""" pass class PeerBadKey(PeerError): """Raised if the peer didn't know the key we used""" pass class PeerBadSignature(PeerError): """Raised if the peer didn't like the signature we sent""" pass class PeerBadTime(PeerError): """Raised if the peer didn't like the time we sent""" pass class PeerBadTruncation(PeerError): """Raised if the peer didn't like amount of truncation in the TSIG we sent""" pass # TSIG Algorithms HMAC_MD5 = dns.name.from_text("HMAC-MD5.SIG-ALG.REG.INT") HMAC_SHA1 = dns.name.from_text("hmac-sha1") HMAC_SHA224 = dns.name.from_text("hmac-sha224") HMAC_SHA256 = dns.name.from_text("hmac-sha256") HMAC_SHA384 = dns.name.from_text("hmac-sha384") HMAC_SHA512 = dns.name.from_text("hmac-sha512") default_algorithm = HMAC_MD5 BADSIG = 16 BADKEY = 17 BADTIME = 18 BADTRUNC = 22 def sign(wire, keyname, secret, time, fudge, original_id, error, other_data, request_mac, ctx=None, multi=False, first=True, algorithm=default_algorithm): """Return a (tsig_rdata, mac, ctx) tuple containing the HMAC TSIG rdata for the input parameters, the HMAC MAC calculated by applying the TSIG signature algorithm, and the TSIG digest context. @rtype: (string, string, hmac.HMAC object) @raises ValueError: I{other_data} is too long @raises NotImplementedError: I{algorithm} is not supported """ (algorithm_name, digestmod) = get_algorithm(algorithm) if first: ctx = hmac.new(secret, digestmod=digestmod) ml = len(request_mac) if ml > 0: ctx.update(struct.pack('!H', ml)) ctx.update(request_mac) id = struct.pack('!H', original_id) ctx.update(id) ctx.update(wire[2:]) if first: ctx.update(keyname.to_digestable()) ctx.update(struct.pack('!H', dns.rdataclass.ANY)) ctx.update(struct.pack('!I', 0)) long_time = time + 0L upper_time = (long_time >> 32) & 0xffffL lower_time = long_time & 0xffffffffL time_mac = struct.pack('!HIH', upper_time, lower_time, fudge) pre_mac = algorithm_name + time_mac ol = len(other_data) if ol > 65535: raise ValueError('TSIG Other Data is > 65535 bytes') post_mac = struct.pack('!HH', error, ol) + other_data if first: ctx.update(pre_mac) ctx.update(post_mac) else: ctx.update(time_mac) mac = ctx.digest() mpack = struct.pack('!H', len(mac)) tsig_rdata = pre_mac + mpack + mac + id + post_mac if multi: ctx = hmac.new(secret) ml = len(mac) ctx.update(struct.pack('!H', ml)) ctx.update(mac) else: ctx = None return (tsig_rdata, mac, ctx) def hmac_md5(wire, keyname, secret, time, fudge, original_id, error, other_data, request_mac, ctx=None, multi=False, first=True, algorithm=default_algorithm): return sign(wire, keyname, secret, time, fudge, original_id, error, other_data, request_mac, ctx, multi, first, algorithm) def validate(wire, keyname, secret, now, request_mac, tsig_start, tsig_rdata, tsig_rdlen, ctx=None, multi=False, first=True): """Validate the specified TSIG rdata against the other input parameters. @raises FormError: The TSIG is badly formed. @raises BadTime: There is too much time skew between the client and the server. @raises BadSignature: The TSIG signature did not validate @rtype: hmac.HMAC object""" (adcount,) = struct.unpack("!H", wire[10:12]) if adcount == 0: raise dns.exception.FormError adcount -= 1 new_wire = wire[0:10] + struct.pack("!H", adcount) + wire[12:tsig_start] current = tsig_rdata (aname, used) = dns.name.from_wire(wire, current) current = current + used (upper_time, lower_time, fudge, mac_size) = \ struct.unpack("!HIHH", wire[current:current + 10]) time = ((upper_time + 0L) << 32) + (lower_time + 0L) current += 10 mac = wire[current:current + mac_size] current += mac_size (original_id, error, other_size) = \ struct.unpack("!HHH", wire[current:current + 6]) current += 6 other_data = wire[current:current + other_size] current += other_size if current != tsig_rdata + tsig_rdlen: raise dns.exception.FormError if error != 0: if error == BADSIG: raise PeerBadSignature elif error == BADKEY: raise PeerBadKey elif error == BADTIME: raise PeerBadTime elif error == BADTRUNC: raise PeerBadTruncation else: raise PeerError('unknown TSIG error code %d' % error) time_low = time - fudge time_high = time + fudge if now < time_low or now > time_high: raise BadTime (junk, our_mac, ctx) = sign(new_wire, keyname, secret, time, fudge, original_id, error, other_data, request_mac, ctx, multi, first, aname) if (our_mac != mac): raise BadSignature return ctx _hashes = None def _maybe_add_hash(tsig_alg, hash_alg): try: _hashes[tsig_alg] = dns.hash.get(hash_alg) except KeyError: pass def _setup_hashes(): global _hashes _hashes = {} _maybe_add_hash(HMAC_SHA224, 'SHA224') _maybe_add_hash(HMAC_SHA256, 'SHA256') _maybe_add_hash(HMAC_SHA384, 'SHA384') _maybe_add_hash(HMAC_SHA512, 'SHA512') _maybe_add_hash(HMAC_SHA1, 'SHA1') _maybe_add_hash(HMAC_MD5, 'MD5') def get_algorithm(algorithm): """Returns the wire format string and the hash module to use for the specified TSIG algorithm @rtype: (string, hash constructor) @raises NotImplementedError: I{algorithm} is not supported """ global _hashes if _hashes is None: _setup_hashes() if isinstance(algorithm, (str, unicode)): algorithm = dns.name.from_text(algorithm) if sys.hexversion < 0x02050200 and \ (algorithm == HMAC_SHA384 or algorithm == HMAC_SHA512): raise NotImplementedError("TSIG algorithm " + str(algorithm) + " requires Python 2.5.2 or later") try: return (algorithm.to_digestable(), _hashes[algorithm]) except KeyError: raise NotImplementedError("TSIG algorithm " + str(algorithm) + " is not supported") LinkChecker-9.3/third_party/dnspython/dns/rdataclass.py0000644000175000017500000000634011570774061024172 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Rdata Classes. @var _by_text: The rdata class textual name to value mapping @type _by_text: dict @var _by_value: The rdata class value to textual name mapping @type _by_value: dict @var _metaclasses: If an rdataclass is a metaclass, there will be a mapping whose key is the rdatatype value and whose value is True in this dictionary. @type _metaclasses: dict""" import re import dns.exception RESERVED0 = 0 IN = 1 CH = 3 HS = 4 NONE = 254 ANY = 255 _by_text = { 'RESERVED0' : RESERVED0, 'IN' : IN, 'CH' : CH, 'HS' : HS, 'NONE' : NONE, 'ANY' : ANY } # We construct the inverse mapping programmatically to ensure that we # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that # would cause the mapping not to be true inverse. _by_value = dict([(y, x) for x, y in _by_text.iteritems()]) # Now that we've built the inverse map, we can add class aliases to # the _by_text mapping. _by_text.update({ 'INTERNET' : IN, 'CHAOS' : CH, 'HESIOD' : HS }) _metaclasses = { NONE : True, ANY : True } _unknown_class_pattern = re.compile('CLASS([0-9]+)$', re.I); class UnknownRdataclass(dns.exception.DNSException): """Raised when a class is unknown.""" pass def from_text(text): """Convert text into a DNS rdata class value. @param text: the text @type text: string @rtype: int @raises dns.rdataclass.UnknownRdataClass: the class is unknown @raises ValueError: the rdata class value is not >= 0 and <= 65535 """ value = _by_text.get(text.upper()) if value is None: match = _unknown_class_pattern.match(text) if match == None: raise UnknownRdataclass value = int(match.group(1)) if value < 0 or value > 65535: raise ValueError("class must be between >= 0 and <= 65535") return value def to_text(value): """Convert a DNS rdata class to text. @param value: the rdata class value @type value: int @rtype: string @raises ValueError: the rdata class value is not >= 0 and <= 65535 """ if value < 0 or value > 65535: raise ValueError("class must be between >= 0 and <= 65535") text = _by_value.get(value) if text is None: text = 'CLASS' + `value` return text def is_metaclass(rdclass): """True if the class is a metaclass. @param rdclass: the rdata class @type rdclass: int @rtype: bool""" if rdclass in _metaclasses: return True return False LinkChecker-9.3/third_party/dnspython/dns/hash.py0000644000175000017500000000453311570774060022775 0ustar calvincalvin00000000000000# Copyright (C) 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Hashing backwards compatibility wrapper""" import sys _hashes = None def _need_later_python(alg): def func(*args, **kwargs): raise NotImplementedError("TSIG algorithm " + alg + " requires Python 2.5.2 or later") return func def _setup(): global _hashes _hashes = {} try: import hashlib _hashes['MD5'] = hashlib.md5 _hashes['SHA1'] = hashlib.sha1 _hashes['SHA224'] = hashlib.sha224 _hashes['SHA256'] = hashlib.sha256 if sys.hexversion >= 0x02050200: _hashes['SHA384'] = hashlib.sha384 _hashes['SHA512'] = hashlib.sha512 else: _hashes['SHA384'] = _need_later_python('SHA384') _hashes['SHA512'] = _need_later_python('SHA512') if sys.hexversion < 0x02050000: # hashlib doesn't conform to PEP 247: API for # Cryptographic Hash Functions, which hmac before python # 2.5 requires, so add the necessary items. class HashlibWrapper: def __init__(self, basehash): self.basehash = basehash self.digest_size = self.basehash().digest_size def new(self, *args, **kwargs): return self.basehash(*args, **kwargs) for name in _hashes: _hashes[name] = HashlibWrapper(_hashes[name]) except ImportError: import md5, sha _hashes['MD5'] = md5 _hashes['SHA1'] = sha def get(algorithm): if _hashes is None: _setup() return _hashes[algorithm.upper()] LinkChecker-9.3/third_party/dnspython/dns/rdtypes/0000750000175000017500000000000012361541761023157 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/dnspython/dns/rdtypes/txtbase.py0000644000175000017500000000566211570774061025223 0ustar calvincalvin00000000000000# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """TXT-like base class.""" import dns.exception import dns.rdata import dns.tokenizer class TXTBase(dns.rdata.Rdata): """Base class for rdata that is like a TXT record @ivar strings: the text strings @type strings: list of string @see: RFC 1035""" __slots__ = ['strings'] def __init__(self, rdclass, rdtype, strings): super(TXTBase, self).__init__(rdclass, rdtype) if isinstance(strings, str): strings = [ strings ] self.strings = strings[:] def to_text(self, origin=None, relativize=True, **kw): txt = '' prefix = '' for s in self.strings: txt += '%s"%s"' % (prefix, dns.rdata._escapify(s)) prefix = ' ' return txt def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): strings = [] while 1: token = tok.get().unescape() if token.is_eol_or_eof(): break if not (token.is_quoted_string() or token.is_identifier()): raise dns.exception.SyntaxError("expected a string") if len(token.value) > 255: raise dns.exception.SyntaxError("string too long") strings.append(token.value) if len(strings) == 0: raise dns.exception.UnexpectedEnd return cls(rdclass, rdtype, strings) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): for s in self.strings: l = len(s) assert l < 256 byte = chr(l) file.write(byte) file.write(s) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): strings = [] while rdlen > 0: l = ord(wire[current]) current += 1 rdlen -= 1 if l > rdlen: raise dns.exception.FormError s = wire[current : current + l].unwrap() current += l rdlen -= l strings.append(s) return cls(rdclass, rdtype, strings) from_wire = classmethod(from_wire) def _cmp(self, other): return cmp(self.strings, other.strings) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/0000750000175000017500000000000012361541761023465 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/DHCID.py0000644000175000017500000000411411570774061024661 0ustar calvincalvin00000000000000# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception class DHCID(dns.rdata.Rdata): """DHCID record @ivar data: the data (the content of the RR is opaque as far as the DNS is concerned) @type data: string @see: RFC 4701""" __slots__ = ['data'] def __init__(self, rdclass, rdtype, data): super(DHCID, self).__init__(rdclass, rdtype) self.data = data def to_text(self, origin=None, relativize=True, **kw): return dns.rdata._base64ify(self.data) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) data = b64.decode('base64_codec') return cls(rdclass, rdtype, data) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): file.write(self.data) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): data = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, data) from_wire = classmethod(from_wire) def _cmp(self, other): return cmp(self.data, other.data) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/A.py0000644000175000017500000000400611570774061024226 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.ipv4 import dns.rdata import dns.tokenizer class A(dns.rdata.Rdata): """A record. @ivar address: an IPv4 address @type address: string (in the standard "dotted quad" format)""" __slots__ = ['address'] def __init__(self, rdclass, rdtype, address): super(A, self).__init__(rdclass, rdtype) # check that it's OK junk = dns.ipv4.inet_aton(address) self.address = address def to_text(self, origin=None, relativize=True, **kw): return self.address def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_identifier() tok.get_eol() return cls(rdclass, rdtype, address) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): file.write(dns.ipv4.inet_aton(self.address)) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): address = dns.ipv4.inet_ntoa(wire[current : current + rdlen]) return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) def _cmp(self, other): sa = dns.ipv4.inet_aton(self.address) oa = dns.ipv4.inet_aton(other.address) return cmp(sa, oa) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/NSAP.py0000644000175000017500000000420511570774061024610 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.rdata import dns.tokenizer class NSAP(dns.rdata.Rdata): """NSAP record. @ivar address: a NASP @type address: string @see: RFC 1706""" __slots__ = ['address'] def __init__(self, rdclass, rdtype, address): super(NSAP, self).__init__(rdclass, rdtype) self.address = address def to_text(self, origin=None, relativize=True, **kw): return "0x%s" % self.address.encode('hex_codec') def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_string() t = tok.get_eol() if address[0:2] != '0x': raise dns.exception.SyntaxError('string does not start with 0x') address = address[2:].replace('.', '') if len(address) % 2 != 0: raise dns.exception.SyntaxError('hexstring has odd length') address = address.decode('hex_codec') return cls(rdclass, rdtype, address) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): file.write(self.address) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): address = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) def _cmp(self, other): return cmp(self.address, other.address) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/IPSECKEY.py0000644000175000017500000001355111570774061025267 0ustar calvincalvin00000000000000# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import struct import dns.exception import dns.inet import dns.name class IPSECKEY(dns.rdata.Rdata): """IPSECKEY record @ivar precedence: the precedence for this key data @type precedence: int @ivar gateway_type: the gateway type @type gateway_type: int @ivar algorithm: the algorithm to use @type algorithm: int @ivar gateway: the public key @type gateway: None, IPv4 address, IPV6 address, or domain name @ivar key: the public key @type key: string @see: RFC 4025""" __slots__ = ['precedence', 'gateway_type', 'algorithm', 'gateway', 'key'] def __init__(self, rdclass, rdtype, precedence, gateway_type, algorithm, gateway, key): super(IPSECKEY, self).__init__(rdclass, rdtype) if gateway_type == 0: if gateway != '.' and not gateway is None: raise SyntaxError('invalid gateway for gateway type 0') gateway = None elif gateway_type == 1: # check that it's OK junk = dns.inet.inet_pton(dns.inet.AF_INET, gateway) elif gateway_type == 2: # check that it's OK junk = dns.inet.inet_pton(dns.inet.AF_INET6, gateway) elif gateway_type == 3: pass else: raise SyntaxError('invalid IPSECKEY gateway type: %d' % gateway_type) self.precedence = precedence self.gateway_type = gateway_type self.algorithm = algorithm self.gateway = gateway self.key = key def to_text(self, origin=None, relativize=True, **kw): if self.gateway_type == 0: gateway = '.' elif self.gateway_type == 1: gateway = self.gateway elif self.gateway_type == 2: gateway = self.gateway elif self.gateway_type == 3: gateway = str(self.gateway.choose_relativity(origin, relativize)) else: raise ValueError('invalid gateway type') return '%d %d %d %s %s' % (self.precedence, self.gateway_type, self.algorithm, gateway, dns.rdata._base64ify(self.key)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): precedence = tok.get_uint8() gateway_type = tok.get_uint8() algorithm = tok.get_uint8() if gateway_type == 3: gateway = tok.get_name().choose_relativity(origin, relativize) else: gateway = tok.get_string() chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) key = b64.decode('base64_codec') return cls(rdclass, rdtype, precedence, gateway_type, algorithm, gateway, key) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): header = struct.pack("!BBB", self.precedence, self.gateway_type, self.algorithm) file.write(header) if self.gateway_type == 0: pass elif self.gateway_type == 1: file.write(dns.inet.inet_pton(dns.inet.AF_INET, self.gateway)) elif self.gateway_type == 2: file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.gateway)) elif self.gateway_type == 3: self.gateway.to_wire(file, None, origin) else: raise ValueError('invalid gateway type') file.write(self.key) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): if rdlen < 3: raise dns.exception.FormError header = struct.unpack('!BBB', wire[current : current + 3]) gateway_type = header[1] current += 3 rdlen -= 3 if gateway_type == 0: gateway = None elif gateway_type == 1: gateway = dns.inet.inet_ntop(dns.inet.AF_INET, wire[current : current + 4]) current += 4 rdlen -= 4 elif gateway_type == 2: gateway = dns.inet.inet_ntop(dns.inet.AF_INET6, wire[current : current + 16]) current += 16 rdlen -= 16 elif gateway_type == 3: (gateway, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused else: raise dns.exception.FormError('invalid IPSECKEY gateway type') key = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], gateway_type, header[2], gateway, key) from_wire = classmethod(from_wire) def _cmp(self, other): f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) f.truncate() other.to_wire(f) wire2 = f.getvalue() f.close() return cmp(wire1, wire2) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/NAPTR.py0000644000175000017500000001141111570774061024730 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import struct import dns.exception import dns.name import dns.rdata def _write_string(file, s): l = len(s) assert l < 256 byte = chr(l) file.write(byte) file.write(s) class NAPTR(dns.rdata.Rdata): """NAPTR record @ivar order: order @type order: int @ivar preference: preference @type preference: int @ivar flags: flags @type flags: string @ivar service: service @type service: string @ivar regexp: regular expression @type regexp: string @ivar replacement: replacement name @type replacement: dns.name.Name object @see: RFC 3403""" __slots__ = ['order', 'preference', 'flags', 'service', 'regexp', 'replacement'] def __init__(self, rdclass, rdtype, order, preference, flags, service, regexp, replacement): super(NAPTR, self).__init__(rdclass, rdtype) self.order = order self.preference = preference self.flags = flags self.service = service self.regexp = regexp self.replacement = replacement def to_text(self, origin=None, relativize=True, **kw): replacement = self.replacement.choose_relativity(origin, relativize) return '%d %d "%s" "%s" "%s" %s' % \ (self.order, self.preference, dns.rdata._escapify(self.flags), dns.rdata._escapify(self.service), dns.rdata._escapify(self.regexp), self.replacement) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): order = tok.get_uint16() preference = tok.get_uint16() flags = tok.get_string() service = tok.get_string() regexp = tok.get_string() replacement = tok.get_name() replacement = replacement.choose_relativity(origin, relativize) tok.get_eol() return cls(rdclass, rdtype, order, preference, flags, service, regexp, replacement) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): two_ints = struct.pack("!HH", self.order, self.preference) file.write(two_ints) _write_string(file, self.flags) _write_string(file, self.service) _write_string(file, self.regexp) self.replacement.to_wire(file, compress, origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (order, preference) = struct.unpack('!HH', wire[current : current + 4]) current += 4 rdlen -= 4 strings = [] for i in xrange(3): l = ord(wire[current]) current += 1 rdlen -= 1 if l > rdlen or rdlen < 0: raise dns.exception.FormError s = wire[current : current + l].unwrap() current += l rdlen -= l strings.append(s) (replacement, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: raise dns.exception.FormError if not origin is None: replacement = replacement.relativize(origin) return cls(rdclass, rdtype, order, preference, strings[0], strings[1], strings[2], replacement) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.replacement = self.replacement.choose_relativity(origin, relativize) def _cmp(self, other): sp = struct.pack("!HH", self.order, self.preference) op = struct.pack("!HH", other.order, other.preference) v = cmp(sp, op) if v == 0: v = cmp(self.flags, other.flags) if v == 0: v = cmp(self.service, other.service) if v == 0: v = cmp(self.regexp, other.regexp) if v == 0: v = cmp(self.replacement, other.replacement) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/SRV.py0000644000175000017500000000650311570774061024524 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import struct import dns.exception import dns.rdata import dns.name class SRV(dns.rdata.Rdata): """SRV record @ivar priority: the priority @type priority: int @ivar weight: the weight @type weight: int @ivar port: the port of the service @type port: int @ivar target: the target host @type target: dns.name.Name object @see: RFC 2782""" __slots__ = ['priority', 'weight', 'port', 'target'] def __init__(self, rdclass, rdtype, priority, weight, port, target): super(SRV, self).__init__(rdclass, rdtype) self.priority = priority self.weight = weight self.port = port self.target = target def to_text(self, origin=None, relativize=True, **kw): target = self.target.choose_relativity(origin, relativize) return '%d %d %d %s' % (self.priority, self.weight, self.port, target) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): priority = tok.get_uint16() weight = tok.get_uint16() port = tok.get_uint16() target = tok.get_name(None) target = target.choose_relativity(origin, relativize) tok.get_eol() return cls(rdclass, rdtype, priority, weight, port, target) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): three_ints = struct.pack("!HHH", self.priority, self.weight, self.port) file.write(three_ints) self.target.to_wire(file, compress, origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (priority, weight, port) = struct.unpack('!HHH', wire[current : current + 6]) current += 6 rdlen -= 6 (target, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: raise dns.exception.FormError if not origin is None: target = target.relativize(origin) return cls(rdclass, rdtype, priority, weight, port, target) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.target = self.target.choose_relativity(origin, relativize) def _cmp(self, other): sp = struct.pack("!HHH", self.priority, self.weight, self.port) op = struct.pack("!HHH", other.priority, other.weight, other.port) v = cmp(sp, op) if v == 0: v = cmp(self.target, other.target) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/PX.py0000644000175000017500000000726311570774061024405 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import struct import dns.exception import dns.rdata import dns.name class PX(dns.rdata.Rdata): """PX record. @ivar preference: the preference value @type preference: int @ivar map822: the map822 name @type map822: dns.name.Name object @ivar mapx400: the mapx400 name @type mapx400: dns.name.Name object @see: RFC 2163""" __slots__ = ['preference', 'map822', 'mapx400'] def __init__(self, rdclass, rdtype, preference, map822, mapx400): super(PX, self).__init__(rdclass, rdtype) self.preference = preference self.map822 = map822 self.mapx400 = mapx400 def to_text(self, origin=None, relativize=True, **kw): map822 = self.map822.choose_relativity(origin, relativize) mapx400 = self.mapx400.choose_relativity(origin, relativize) return '%d %s %s' % (self.preference, map822, mapx400) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): preference = tok.get_uint16() map822 = tok.get_name() map822 = map822.choose_relativity(origin, relativize) mapx400 = tok.get_name(None) mapx400 = mapx400.choose_relativity(origin, relativize) tok.get_eol() return cls(rdclass, rdtype, preference, map822, mapx400) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): pref = struct.pack("!H", self.preference) file.write(pref) self.map822.to_wire(file, None, origin) self.mapx400.to_wire(file, None, origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (preference, ) = struct.unpack('!H', wire[current : current + 2]) current += 2 rdlen -= 2 (map822, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused > rdlen: raise dns.exception.FormError current += cused rdlen -= cused if not origin is None: map822 = map822.relativize(origin) (mapx400, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: raise dns.exception.FormError if not origin is None: mapx400 = mapx400.relativize(origin) return cls(rdclass, rdtype, preference, map822, mapx400) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.map822 = self.map822.choose_relativity(origin, relativize) self.mapx400 = self.mapx400.choose_relativity(origin, relativize) def _cmp(self, other): sp = struct.pack("!H", self.preference) op = struct.pack("!H", other.preference) v = cmp(sp, op) if v == 0: v = cmp(self.map822, other.map822) if v == 0: v = cmp(self.mapx400, other.mapx400) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/KX.py0000644000175000017500000000157011570774061024373 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.mxbase class KX(dns.rdtypes.mxbase.UncompressedMX): """KX record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/APL.py0000644000175000017500000001263511570774061024471 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import struct import dns.exception import dns.inet import dns.rdata import dns.tokenizer class APLItem(object): """An APL list item. @ivar family: the address family (IANA address family registry) @type family: int @ivar negation: is this item negated? @type negation: bool @ivar address: the address @type address: string @ivar prefix: the prefix length @type prefix: int """ __slots__ = ['family', 'negation', 'address', 'prefix'] def __init__(self, family, negation, address, prefix): self.family = family self.negation = negation self.address = address self.prefix = prefix def __str__(self): if self.negation: return "!%d:%s/%s" % (self.family, self.address, self.prefix) else: return "%d:%s/%s" % (self.family, self.address, self.prefix) def to_wire(self, file): if self.family == 1: address = dns.inet.inet_pton(dns.inet.AF_INET, self.address) elif self.family == 2: address = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) else: address = self.address.decode('hex_codec') # # Truncate least significant zero bytes. # last = 0 for i in xrange(len(address) - 1, -1, -1): if address[i] != chr(0): last = i + 1 break address = address[0 : last] l = len(address) assert l < 128 if self.negation: l |= 0x80 header = struct.pack('!HBB', self.family, self.prefix, l) file.write(header) file.write(address) class APL(dns.rdata.Rdata): """APL record. @ivar items: a list of APL items @type items: list of APL_Item @see: RFC 3123""" __slots__ = ['items'] def __init__(self, rdclass, rdtype, items): super(APL, self).__init__(rdclass, rdtype) self.items = items def to_text(self, origin=None, relativize=True, **kw): return ' '.join(map(lambda x: str(x), self.items)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): items = [] while 1: token = tok.get().unescape() if token.is_eol_or_eof(): break item = token.value if item[0] == '!': negation = True item = item[1:] else: negation = False (family, rest) = item.split(':', 1) family = int(family) (address, prefix) = rest.split('/', 1) prefix = int(prefix) item = APLItem(family, negation, address, prefix) items.append(item) return cls(rdclass, rdtype, items) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): for item in self.items: item.to_wire(file) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): items = [] while 1: if rdlen < 4: raise dns.exception.FormError header = struct.unpack('!HBB', wire[current : current + 4]) afdlen = header[2] if afdlen > 127: negation = True afdlen -= 128 else: negation = False current += 4 rdlen -= 4 if rdlen < afdlen: raise dns.exception.FormError address = wire[current : current + afdlen].unwrap() l = len(address) if header[0] == 1: if l < 4: address += '\x00' * (4 - l) address = dns.inet.inet_ntop(dns.inet.AF_INET, address) elif header[0] == 2: if l < 16: address += '\x00' * (16 - l) address = dns.inet.inet_ntop(dns.inet.AF_INET6, address) else: # # This isn't really right according to the RFC, but it # seems better than throwing an exception # address = address.encode('hex_codec') current += afdlen rdlen -= afdlen item = APLItem(header[0], negation, address, header[1]) items.append(item) if rdlen == 0: break return cls(rdclass, rdtype, items) from_wire = classmethod(from_wire) def _cmp(self, other): f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) f.truncate() other.to_wire(f) wire2 = f.getvalue() f.close() return cmp(wire1, wire2) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/WKS.py0000644000175000017500000001003411570774061024510 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import socket import struct import dns.ipv4 import dns.rdata _proto_tcp = socket.getprotobyname('tcp') _proto_udp = socket.getprotobyname('udp') class WKS(dns.rdata.Rdata): """WKS record @ivar address: the address @type address: string @ivar protocol: the protocol @type protocol: int @ivar bitmap: the bitmap @type bitmap: string @see: RFC 1035""" __slots__ = ['address', 'protocol', 'bitmap'] def __init__(self, rdclass, rdtype, address, protocol, bitmap): super(WKS, self).__init__(rdclass, rdtype) self.address = address self.protocol = protocol self.bitmap = bitmap def to_text(self, origin=None, relativize=True, **kw): bits = [] for i in xrange(0, len(self.bitmap)): byte = ord(self.bitmap[i]) for j in xrange(0, 8): if byte & (0x80 >> j): bits.append(str(i * 8 + j)) text = ' '.join(bits) return '%s %d %s' % (self.address, self.protocol, text) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_string() protocol = tok.get_string() if protocol.isdigit(): protocol = int(protocol) else: protocol = socket.getprotobyname(protocol) bitmap = [] while 1: token = tok.get().unescape() if token.is_eol_or_eof(): break if token.value.isdigit(): serv = int(token.value) else: if protocol != _proto_udp and protocol != _proto_tcp: raise NotImplementedError("protocol must be TCP or UDP") if protocol == _proto_udp: protocol_text = "udp" else: protocol_text = "tcp" serv = socket.getservbyname(token.value, protocol_text) i = serv // 8 l = len(bitmap) if l < i + 1: for j in xrange(l, i + 1): bitmap.append('\x00') bitmap[i] = chr(ord(bitmap[i]) | (0x80 >> (serv % 8))) bitmap = dns.rdata._truncate_bitmap(bitmap) return cls(rdclass, rdtype, address, protocol, bitmap) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): file.write(dns.ipv4.inet_aton(self.address)) protocol = struct.pack('!B', self.protocol) file.write(protocol) file.write(self.bitmap) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): address = dns.ipv4.inet_ntoa(wire[current : current + 4]) protocol, = struct.unpack('!B', wire[current + 4 : current + 5]) current += 5 rdlen -= 5 bitmap = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, address, protocol, bitmap) from_wire = classmethod(from_wire) def _cmp(self, other): sa = dns.ipv4.inet_aton(self.address) oa = dns.ipv4.inet_aton(other.address) v = cmp(sa, oa) if v == 0: sp = struct.pack('!B', self.protocol) op = struct.pack('!B', other.protocol) v = cmp(sp, op) if v == 0: v = cmp(self.bitmap, other.bitmap) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/__init__.py0000644000175000017500000000170511570774061025610 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Class IN rdata type classes.""" __all__ = [ 'A', 'AAAA', 'APL', 'DHCID', 'KX', 'NAPTR', 'NSAP', 'NSAP_PTR', 'PX', 'SRV', 'WKS', ] LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/AAAA.py0000644000175000017500000000421211570774061024530 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.inet import dns.rdata import dns.tokenizer class AAAA(dns.rdata.Rdata): """AAAA record. @ivar address: an IPv6 address @type address: string (in the standard IPv6 format)""" __slots__ = ['address'] def __init__(self, rdclass, rdtype, address): super(AAAA, self).__init__(rdclass, rdtype) # check that it's OK junk = dns.inet.inet_pton(dns.inet.AF_INET6, address) self.address = address def to_text(self, origin=None, relativize=True, **kw): return self.address def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_identifier() tok.get_eol() return cls(rdclass, rdtype, address) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.address)) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): address = dns.inet.inet_ntop(dns.inet.AF_INET6, wire[current : current + rdlen]) return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) def _cmp(self, other): sa = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) oa = dns.inet.inet_pton(dns.inet.AF_INET6, other.address) return cmp(sa, oa) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/IN/NSAP_PTR.py0000644000175000017500000000160411570774061025335 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.nsbase class NSAP_PTR(dns.rdtypes.nsbase.UncompressedNS): """NSAP-PTR record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/0000750000175000017500000000000012361541761023606 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/RRSIG.py0000644000175000017500000001315111570774061025056 0ustar calvincalvin00000000000000# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import calendar import struct import time import dns.dnssec import dns.exception import dns.rdata import dns.rdatatype class BadSigTime(dns.exception.DNSException): """Raised when a SIG or RRSIG RR's time cannot be parsed.""" pass def sigtime_to_posixtime(what): if len(what) != 14: raise BadSigTime year = int(what[0:4]) month = int(what[4:6]) day = int(what[6:8]) hour = int(what[8:10]) minute = int(what[10:12]) second = int(what[12:14]) return calendar.timegm((year, month, day, hour, minute, second, 0, 0, 0)) def posixtime_to_sigtime(what): return time.strftime('%Y%m%d%H%M%S', time.gmtime(what)) class RRSIG(dns.rdata.Rdata): """RRSIG record @ivar type_covered: the rdata type this signature covers @type type_covered: int @ivar algorithm: the algorithm used for the sig @type algorithm: int @ivar labels: number of labels @type labels: int @ivar original_ttl: the original TTL @type original_ttl: long @ivar expiration: signature expiration time @type expiration: long @ivar inception: signature inception time @type inception: long @ivar key_tag: the key tag @type key_tag: int @ivar signer: the signer @type signer: dns.name.Name object @ivar signature: the signature @type signature: string""" __slots__ = ['type_covered', 'algorithm', 'labels', 'original_ttl', 'expiration', 'inception', 'key_tag', 'signer', 'signature'] def __init__(self, rdclass, rdtype, type_covered, algorithm, labels, original_ttl, expiration, inception, key_tag, signer, signature): super(RRSIG, self).__init__(rdclass, rdtype) self.type_covered = type_covered self.algorithm = algorithm self.labels = labels self.original_ttl = original_ttl self.expiration = expiration self.inception = inception self.key_tag = key_tag self.signer = signer self.signature = signature def covers(self): return self.type_covered def to_text(self, origin=None, relativize=True, **kw): return '%s %d %d %d %s %s %d %s %s' % ( dns.rdatatype.to_text(self.type_covered), self.algorithm, self.labels, self.original_ttl, posixtime_to_sigtime(self.expiration), posixtime_to_sigtime(self.inception), self.key_tag, self.signer, dns.rdata._base64ify(self.signature) ) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): type_covered = dns.rdatatype.from_text(tok.get_string()) algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) labels = tok.get_int() original_ttl = tok.get_ttl() expiration = sigtime_to_posixtime(tok.get_string()) inception = sigtime_to_posixtime(tok.get_string()) key_tag = tok.get_int() signer = tok.get_name() signer = signer.choose_relativity(origin, relativize) chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) signature = b64.decode('base64_codec') return cls(rdclass, rdtype, type_covered, algorithm, labels, original_ttl, expiration, inception, key_tag, signer, signature) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): header = struct.pack('!HBBIIIH', self.type_covered, self.algorithm, self.labels, self.original_ttl, self.expiration, self.inception, self.key_tag) file.write(header) self.signer.to_wire(file, None, origin) file.write(self.signature) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): header = struct.unpack('!HBBIIIH', wire[current : current + 18]) current += 18 rdlen -= 18 (signer, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused if not origin is None: signer = signer.relativize(origin) signature = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], header[3], header[4], header[5], header[6], signer, signature) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.signer = self.signer.choose_relativity(origin, relativize) def _cmp(self, other): return self._wire_cmp(other) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/RP.py0000644000175000017500000000631211570774061024512 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.rdata import dns.name class RP(dns.rdata.Rdata): """RP record @ivar mbox: The responsible person's mailbox @type mbox: dns.name.Name object @ivar txt: The owner name of a node with TXT records, or the root name if no TXT records are associated with this RP. @type txt: dns.name.Name object @see: RFC 1183""" __slots__ = ['mbox', 'txt'] def __init__(self, rdclass, rdtype, mbox, txt): super(RP, self).__init__(rdclass, rdtype) self.mbox = mbox self.txt = txt def to_text(self, origin=None, relativize=True, **kw): mbox = self.mbox.choose_relativity(origin, relativize) txt = self.txt.choose_relativity(origin, relativize) return "%s %s" % (str(mbox), str(txt)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): mbox = tok.get_name() txt = tok.get_name() mbox = mbox.choose_relativity(origin, relativize) txt = txt.choose_relativity(origin, relativize) tok.get_eol() return cls(rdclass, rdtype, mbox, txt) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): self.mbox.to_wire(file, None, origin) self.txt.to_wire(file, None, origin) def to_digestable(self, origin = None): return self.mbox.to_digestable(origin) + \ self.txt.to_digestable(origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (mbox, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused if rdlen <= 0: raise dns.exception.FormError (txt, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: raise dns.exception.FormError if not origin is None: mbox = mbox.relativize(origin) txt = txt.relativize(origin) return cls(rdclass, rdtype, mbox, txt) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.mbox = self.mbox.choose_relativity(origin, relativize) self.txt = self.txt.choose_relativity(origin, relativize) def _cmp(self, other): v = cmp(self.mbox, other.mbox) if v == 0: v = cmp(self.txt, other.txt) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/NSEC.py0000644000175000017500000001131411570774061024717 0ustar calvincalvin00000000000000# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import dns.exception import dns.rdata import dns.rdatatype import dns.name class NSEC(dns.rdata.Rdata): """NSEC record @ivar next: the next name @type next: dns.name.Name object @ivar windows: the windowed bitmap list @type windows: list of (window number, string) tuples""" __slots__ = ['next', 'windows'] def __init__(self, rdclass, rdtype, next, windows): super(NSEC, self).__init__(rdclass, rdtype) self.next = next self.windows = windows def to_text(self, origin=None, relativize=True, **kw): next = self.next.choose_relativity(origin, relativize) text = '' for (window, bitmap) in self.windows: bits = [] for i in xrange(0, len(bitmap)): byte = ord(bitmap[i]) for j in xrange(0, 8): if byte & (0x80 >> j): bits.append(dns.rdatatype.to_text(window * 256 + \ i * 8 + j)) text += (' ' + ' '.join(bits)) return '%s%s' % (next, text) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): next = tok.get_name() next = next.choose_relativity(origin, relativize) rdtypes = [] while 1: token = tok.get().unescape() if token.is_eol_or_eof(): break nrdtype = dns.rdatatype.from_text(token.value) if nrdtype == 0: raise dns.exception.SyntaxError("NSEC with bit 0") if nrdtype > 65535: raise dns.exception.SyntaxError("NSEC with bit > 65535") rdtypes.append(nrdtype) rdtypes.sort() window = 0 octets = 0 prior_rdtype = 0 bitmap = ['\0'] * 32 windows = [] for nrdtype in rdtypes: if nrdtype == prior_rdtype: continue prior_rdtype = nrdtype new_window = nrdtype // 256 if new_window != window: windows.append((window, ''.join(bitmap[0:octets]))) bitmap = ['\0'] * 32 window = new_window offset = nrdtype % 256 byte = offset // 8 bit = offset % 8 octets = byte + 1 bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit)) windows.append((window, ''.join(bitmap[0:octets]))) return cls(rdclass, rdtype, next, windows) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): self.next.to_wire(file, None, origin) for (window, bitmap) in self.windows: file.write(chr(window)) file.write(chr(len(bitmap))) file.write(bitmap) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (next, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused windows = [] while rdlen > 0: if rdlen < 3: raise dns.exception.FormError("NSEC too short") window = ord(wire[current]) octets = ord(wire[current + 1]) if octets == 0 or octets > 32: raise dns.exception.FormError("bad NSEC octets") current += 2 rdlen -= 2 if rdlen < octets: raise dns.exception.FormError("bad NSEC bitmap length") bitmap = wire[current : current + octets].unwrap() current += octets rdlen -= octets windows.append((window, bitmap)) if not origin is None: next = next.relativize(origin) return cls(rdclass, rdtype, next, windows) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.next = self.next.choose_relativity(origin, relativize) def _cmp(self, other): return self._wire_cmp(other) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/SSHFP.py0000644000175000017500000000552511570774061025061 0ustar calvincalvin00000000000000# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import struct import dns.rdata import dns.rdatatype class SSHFP(dns.rdata.Rdata): """SSHFP record @ivar algorithm: the algorithm @type algorithm: int @ivar fp_type: the digest type @type fp_type: int @ivar fingerprint: the fingerprint @type fingerprint: string @see: draft-ietf-secsh-dns-05.txt""" __slots__ = ['algorithm', 'fp_type', 'fingerprint'] def __init__(self, rdclass, rdtype, algorithm, fp_type, fingerprint): super(SSHFP, self).__init__(rdclass, rdtype) self.algorithm = algorithm self.fp_type = fp_type self.fingerprint = fingerprint def to_text(self, origin=None, relativize=True, **kw): return '%d %d %s' % (self.algorithm, self.fp_type, dns.rdata._hexify(self.fingerprint, chunksize=128)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): algorithm = tok.get_uint8() fp_type = tok.get_uint8() fingerprint = tok.get_string() fingerprint = fingerprint.decode('hex_codec') tok.get_eol() return cls(rdclass, rdtype, algorithm, fp_type, fingerprint) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): header = struct.pack("!BB", self.algorithm, self.fp_type) file.write(header) file.write(self.fingerprint) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): header = struct.unpack("!BB", wire[current : current + 2]) current += 2 rdlen -= 2 fingerprint = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], fingerprint) from_wire = classmethod(from_wire) def _cmp(self, other): hs = struct.pack("!BB", self.algorithm, self.fp_type) ho = struct.pack("!BB", other.algorithm, other.fp_type) v = cmp(hs, ho) if v == 0: v = cmp(self.fingerprint, other.fingerprint) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/CERT.py0000644000175000017500000001027011570774061024724 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import struct import dns.exception import dns.dnssec import dns.rdata import dns.tokenizer _ctype_by_value = { 1 : 'PKIX', 2 : 'SPKI', 3 : 'PGP', 253 : 'URI', 254 : 'OID', } _ctype_by_name = { 'PKIX' : 1, 'SPKI' : 2, 'PGP' : 3, 'URI' : 253, 'OID' : 254, } def _ctype_from_text(what): v = _ctype_by_name.get(what) if not v is None: return v return int(what) def _ctype_to_text(what): v = _ctype_by_value.get(what) if not v is None: return v return str(what) class CERT(dns.rdata.Rdata): """CERT record @ivar certificate_type: certificate type @type certificate_type: int @ivar key_tag: key tag @type key_tag: int @ivar algorithm: algorithm @type algorithm: int @ivar certificate: the certificate or CRL @type certificate: string @see: RFC 2538""" __slots__ = ['certificate_type', 'key_tag', 'algorithm', 'certificate'] def __init__(self, rdclass, rdtype, certificate_type, key_tag, algorithm, certificate): super(CERT, self).__init__(rdclass, rdtype) self.certificate_type = certificate_type self.key_tag = key_tag self.algorithm = algorithm self.certificate = certificate def to_text(self, origin=None, relativize=True, **kw): certificate_type = _ctype_to_text(self.certificate_type) return "%s %d %s %s" % (certificate_type, self.key_tag, dns.dnssec.algorithm_to_text(self.algorithm), dns.rdata._base64ify(self.certificate)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): certificate_type = _ctype_from_text(tok.get_string()) key_tag = tok.get_uint16() algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) if algorithm < 0 or algorithm > 255: raise dns.exception.SyntaxError("bad algorithm type") chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) certificate = b64.decode('base64_codec') return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): prefix = struct.pack("!HHB", self.certificate_type, self.key_tag, self.algorithm) file.write(prefix) file.write(self.certificate) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): prefix = wire[current : current + 5].unwrap() current += 5 rdlen -= 5 if rdlen < 0: raise dns.exception.FormError (certificate_type, key_tag, algorithm) = struct.unpack("!HHB", prefix) certificate = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate) from_wire = classmethod(from_wire) def _cmp(self, other): f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) f.truncate() other.to_wire(f) wire2 = f.getvalue() f.close() return cmp(wire1, wire2) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/RT.py0000644000175000017500000000160211570774061024513 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.mxbase class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX): """RT record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/DNAME.py0000644000175000017500000000172311570774061025016 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.nsbase class DNAME(dns.rdtypes.nsbase.UncompressedNS): """DNAME record""" def to_digestable(self, origin = None): return self.target.to_digestable(origin) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/GPOS.py0000644000175000017500000001226611570774061024746 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.rdata import dns.tokenizer def _validate_float_string(what): if what[0] == '-' or what[0] == '+': what = what[1:] if what.isdigit(): return (left, right) = what.split('.') if left == '' and right == '': raise dns.exception.FormError if not left == '' and not left.isdigit(): raise dns.exception.FormError if not right == '' and not right.isdigit(): raise dns.exception.FormError class GPOS(dns.rdata.Rdata): """GPOS record @ivar latitude: latitude @type latitude: string @ivar longitude: longitude @type longitude: string @ivar altitude: altitude @type altitude: string @see: RFC 1712""" __slots__ = ['latitude', 'longitude', 'altitude'] def __init__(self, rdclass, rdtype, latitude, longitude, altitude): super(GPOS, self).__init__(rdclass, rdtype) if isinstance(latitude, float) or \ isinstance(latitude, int) or \ isinstance(latitude, long): latitude = str(latitude) if isinstance(longitude, float) or \ isinstance(longitude, int) or \ isinstance(longitude, long): longitude = str(longitude) if isinstance(altitude, float) or \ isinstance(altitude, int) or \ isinstance(altitude, long): altitude = str(altitude) _validate_float_string(latitude) _validate_float_string(longitude) _validate_float_string(altitude) self.latitude = latitude self.longitude = longitude self.altitude = altitude def to_text(self, origin=None, relativize=True, **kw): return '%s %s %s' % (self.latitude, self.longitude, self.altitude) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): latitude = tok.get_string() longitude = tok.get_string() altitude = tok.get_string() tok.get_eol() return cls(rdclass, rdtype, latitude, longitude, altitude) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): l = len(self.latitude) assert l < 256 byte = chr(l) file.write(byte) file.write(self.latitude) l = len(self.longitude) assert l < 256 byte = chr(l) file.write(byte) file.write(self.longitude) l = len(self.altitude) assert l < 256 byte = chr(l) file.write(byte) file.write(self.altitude) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): l = ord(wire[current]) current += 1 rdlen -= 1 if l > rdlen: raise dns.exception.FormError latitude = wire[current : current + l].unwrap() current += l rdlen -= l l = ord(wire[current]) current += 1 rdlen -= 1 if l > rdlen: raise dns.exception.FormError longitude = wire[current : current + l].unwrap() current += l rdlen -= l l = ord(wire[current]) current += 1 rdlen -= 1 if l != rdlen: raise dns.exception.FormError altitude = wire[current : current + l].unwrap() return cls(rdclass, rdtype, latitude, longitude, altitude) from_wire = classmethod(from_wire) def _cmp(self, other): v = cmp(self.latitude, other.latitude) if v == 0: v = cmp(self.longitude, other.longitude) if v == 0: v = cmp(self.altitude, other.altitude) return v def _get_float_latitude(self): return float(self.latitude) def _set_float_latitude(self, value): self.latitude = str(value) float_latitude = property(_get_float_latitude, _set_float_latitude, doc="latitude as a floating point value") def _get_float_longitude(self): return float(self.longitude) def _set_float_longitude(self, value): self.longitude = str(value) float_longitude = property(_get_float_longitude, _set_float_longitude, doc="longitude as a floating point value") def _get_float_altitude(self): return float(self.altitude) def _set_float_altitude(self, value): self.altitude = str(value) float_altitude = property(_get_float_altitude, _set_float_altitude, doc="altitude as a floating point value") LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/DLV.py0000644000175000017500000000154711570774061024623 0ustar calvincalvin00000000000000# Copyright (C) 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.dsbase class DLV(dns.rdtypes.dsbase.DSBase): """DLV record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/MX.py0000644000175000017500000000156011570774061024515 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.mxbase class MX(dns.rdtypes.mxbase.MXBase): """MX record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/DNSKEY.py0000644000175000017500000000637011570774061025172 0ustar calvincalvin00000000000000# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import struct import dns.exception import dns.dnssec import dns.rdata # flag constants SEP = 0x0001 REVOKE = 0x0080 ZONE = 0x0100 class DNSKEY(dns.rdata.Rdata): """DNSKEY record @ivar flags: the key flags @type flags: int @ivar protocol: the protocol for which this key may be used @type protocol: int @ivar algorithm: the algorithm used for the key @type algorithm: int @ivar key: the public key @type key: string""" __slots__ = ['flags', 'protocol', 'algorithm', 'key'] def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): super(DNSKEY, self).__init__(rdclass, rdtype) self.flags = flags self.protocol = protocol self.algorithm = algorithm self.key = key def to_text(self, origin=None, relativize=True, **kw): return '%d %d %d %s' % (self.flags, self.protocol, self.algorithm, dns.rdata._base64ify(self.key)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): flags = tok.get_uint16() protocol = tok.get_uint8() algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): raise dns.exception.SyntaxError chunks.append(t.value) b64 = ''.join(chunks) key = b64.decode('base64_codec') return cls(rdclass, rdtype, flags, protocol, algorithm, key) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) file.write(header) file.write(self.key) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): if rdlen < 4: raise dns.exception.FormError header = struct.unpack('!HBB', wire[current : current + 4]) current += 4 rdlen -= 4 key = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], key) from_wire = classmethod(from_wire) def _cmp(self, other): hs = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) ho = struct.pack("!HBB", other.flags, other.protocol, other.algorithm) v = cmp(hs, ho) if v == 0: v = cmp(self.key, other.key) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/LOC.py0000644000175000017500000003046611570774061024615 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import struct import dns.exception import dns.rdata _pows = (1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L, 1000000000L, 10000000000L) def _exponent_of(what, desc): exp = None for i in xrange(len(_pows)): if what // _pows[i] == 0L: exp = i - 1 break if exp is None or exp < 0: raise dns.exception.SyntaxError("%s value out of bounds" % desc) return exp def _float_to_tuple(what): if what < 0: sign = -1 what *= -1 else: sign = 1 what = long(round(what * 3600000)) degrees = int(what // 3600000) what -= degrees * 3600000 minutes = int(what // 60000) what -= minutes * 60000 seconds = int(what // 1000) what -= int(seconds * 1000) what = int(what) return (degrees * sign, minutes, seconds, what) def _tuple_to_float(what): if what[0] < 0: sign = -1 value = float(what[0]) * -1 else: sign = 1 value = float(what[0]) value += float(what[1]) / 60.0 value += float(what[2]) / 3600.0 value += float(what[3]) / 3600000.0 return sign * value def _encode_size(what, desc): what = long(what); exponent = _exponent_of(what, desc) & 0xF base = what // pow(10, exponent) & 0xF return base * 16 + exponent def _decode_size(what, desc): exponent = what & 0x0F if exponent > 9: raise dns.exception.SyntaxError("bad %s exponent" % desc) base = (what & 0xF0) >> 4 if base > 9: raise dns.exception.SyntaxError("bad %s base" % desc) return long(base) * pow(10, exponent) class LOC(dns.rdata.Rdata): """LOC record @ivar latitude: latitude @type latitude: (int, int, int, int) tuple specifying the degrees, minutes, seconds, and milliseconds of the coordinate. @ivar longitude: longitude @type longitude: (int, int, int, int) tuple specifying the degrees, minutes, seconds, and milliseconds of the coordinate. @ivar altitude: altitude @type altitude: float @ivar size: size of the sphere @type size: float @ivar horizontal_precision: horizontal precision @type horizontal_precision: float @ivar vertical_precision: vertical precision @type vertical_precision: float @see: RFC 1876""" __slots__ = ['latitude', 'longitude', 'altitude', 'size', 'horizontal_precision', 'vertical_precision'] def __init__(self, rdclass, rdtype, latitude, longitude, altitude, size=1.0, hprec=10000.0, vprec=10.0): """Initialize a LOC record instance. The parameters I{latitude} and I{longitude} may be either a 4-tuple of integers specifying (degrees, minutes, seconds, milliseconds), or they may be floating point values specifying the number of degrees. The other parameters are floats.""" super(LOC, self).__init__(rdclass, rdtype) if isinstance(latitude, int) or isinstance(latitude, long): latitude = float(latitude) if isinstance(latitude, float): latitude = _float_to_tuple(latitude) self.latitude = latitude if isinstance(longitude, int) or isinstance(longitude, long): longitude = float(longitude) if isinstance(longitude, float): longitude = _float_to_tuple(longitude) self.longitude = longitude self.altitude = float(altitude) self.size = float(size) self.horizontal_precision = float(hprec) self.vertical_precision = float(vprec) def to_text(self, origin=None, relativize=True, **kw): if self.latitude[0] > 0: lat_hemisphere = 'N' lat_degrees = self.latitude[0] else: lat_hemisphere = 'S' lat_degrees = -1 * self.latitude[0] if self.longitude[0] > 0: long_hemisphere = 'E' long_degrees = self.longitude[0] else: long_hemisphere = 'W' long_degrees = -1 * self.longitude[0] text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % ( lat_degrees, self.latitude[1], self.latitude[2], self.latitude[3], lat_hemisphere, long_degrees, self.longitude[1], self.longitude[2], self.longitude[3], long_hemisphere, self.altitude / 100.0 ) if self.size != 1.0 or self.horizontal_precision != 10000.0 or \ self.vertical_precision != 10.0: text += " %0.2fm %0.2fm %0.2fm" % ( self.size / 100.0, self.horizontal_precision / 100.0, self.vertical_precision / 100.0 ) return text def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): latitude = [0, 0, 0, 0] longitude = [0, 0, 0, 0] size = 1.0 hprec = 10000.0 vprec = 10.0 latitude[0] = tok.get_int() t = tok.get_string() if t.isdigit(): latitude[1] = int(t) t = tok.get_string() if '.' in t: (seconds, milliseconds) = t.split('.') if not seconds.isdigit(): raise dns.exception.SyntaxError('bad latitude seconds value') latitude[2] = int(seconds) if latitude[2] >= 60: raise dns.exception.SyntaxError('latitude seconds >= 60') l = len(milliseconds) if l == 0 or l > 3 or not milliseconds.isdigit(): raise dns.exception.SyntaxError('bad latitude milliseconds value') if l == 1: m = 100 elif l == 2: m = 10 else: m = 1 latitude[3] = m * int(milliseconds) t = tok.get_string() elif t.isdigit(): latitude[2] = int(t) t = tok.get_string() if t == 'S': latitude[0] *= -1 elif t != 'N': raise dns.exception.SyntaxError('bad latitude hemisphere value') longitude[0] = tok.get_int() t = tok.get_string() if t.isdigit(): longitude[1] = int(t) t = tok.get_string() if '.' in t: (seconds, milliseconds) = t.split('.') if not seconds.isdigit(): raise dns.exception.SyntaxError('bad longitude seconds value') longitude[2] = int(seconds) if longitude[2] >= 60: raise dns.exception.SyntaxError('longitude seconds >= 60') l = len(milliseconds) if l == 0 or l > 3 or not milliseconds.isdigit(): raise dns.exception.SyntaxError('bad longitude milliseconds value') if l == 1: m = 100 elif l == 2: m = 10 else: m = 1 longitude[3] = m * int(milliseconds) t = tok.get_string() elif t.isdigit(): longitude[2] = int(t) t = tok.get_string() if t == 'W': longitude[0] *= -1 elif t != 'E': raise dns.exception.SyntaxError('bad longitude hemisphere value') t = tok.get_string() if t[-1] == 'm': t = t[0 : -1] altitude = float(t) * 100.0 # m -> cm token = tok.get().unescape() if not token.is_eol_or_eof(): value = token.value if value[-1] == 'm': value = value[0 : -1] size = float(value) * 100.0 # m -> cm token = tok.get().unescape() if not token.is_eol_or_eof(): value = token.value if value[-1] == 'm': value = value[0 : -1] hprec = float(value) * 100.0 # m -> cm token = tok.get().unescape() if not token.is_eol_or_eof(): value = token.value if value[-1] == 'm': value = value[0 : -1] vprec = float(value) * 100.0 # m -> cm tok.get_eol() return cls(rdclass, rdtype, latitude, longitude, altitude, size, hprec, vprec) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): if self.latitude[0] < 0: sign = -1 degrees = long(-1 * self.latitude[0]) else: sign = 1 degrees = long(self.latitude[0]) milliseconds = (degrees * 3600000 + self.latitude[1] * 60000 + self.latitude[2] * 1000 + self.latitude[3]) * sign latitude = 0x80000000L + milliseconds if self.longitude[0] < 0: sign = -1 degrees = long(-1 * self.longitude[0]) else: sign = 1 degrees = long(self.longitude[0]) milliseconds = (degrees * 3600000 + self.longitude[1] * 60000 + self.longitude[2] * 1000 + self.longitude[3]) * sign longitude = 0x80000000L + milliseconds altitude = long(self.altitude) + 10000000L size = _encode_size(self.size, "size") hprec = _encode_size(self.horizontal_precision, "horizontal precision") vprec = _encode_size(self.vertical_precision, "vertical precision") wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude, longitude, altitude) file.write(wire) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (version, size, hprec, vprec, latitude, longitude, altitude) = \ struct.unpack("!BBBBIII", wire[current : current + rdlen]) if latitude > 0x80000000L: latitude = float(latitude - 0x80000000L) / 3600000 else: latitude = -1 * float(0x80000000L - latitude) / 3600000 if latitude < -90.0 or latitude > 90.0: raise dns.exception.FormError("bad latitude") if longitude > 0x80000000L: longitude = float(longitude - 0x80000000L) / 3600000 else: longitude = -1 * float(0x80000000L - longitude) / 3600000 if longitude < -180.0 or longitude > 180.0: raise dns.exception.FormError("bad longitude") altitude = float(altitude) - 10000000.0 size = _decode_size(size, "size") hprec = _decode_size(hprec, "horizontal precision") vprec = _decode_size(vprec, "vertical precision") return cls(rdclass, rdtype, latitude, longitude, altitude, size, hprec, vprec) from_wire = classmethod(from_wire) def _cmp(self, other): f = cStringIO.StringIO() self.to_wire(f) wire1 = f.getvalue() f.seek(0) f.truncate() other.to_wire(f) wire2 = f.getvalue() f.close() return cmp(wire1, wire2) def _get_float_latitude(self): return _tuple_to_float(self.latitude) def _set_float_latitude(self, value): self.latitude = _float_to_tuple(value) float_latitude = property(_get_float_latitude, _set_float_latitude, doc="latitude as a floating point value") def _get_float_longitude(self): return _tuple_to_float(self.longitude) def _set_float_longitude(self, value): self.longitude = _float_to_tuple(value) float_longitude = property(_get_float_longitude, _set_float_longitude, doc="longitude as a floating point value") LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/DS.py0000644000175000017500000000156011570774061024477 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.dsbase class DS(dns.rdtypes.dsbase.DSBase): """DS record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/TXT.py0000644000175000017500000000156511570774061024655 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.txtbase class TXT(dns.rdtypes.txtbase.TXTBase): """TXT record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/SOA.py0000644000175000017500000001205311570774061024612 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import struct import dns.exception import dns.rdata import dns.name class SOA(dns.rdata.Rdata): """SOA record @ivar mname: the SOA MNAME (master name) field @type mname: dns.name.Name object @ivar rname: the SOA RNAME (responsible name) field @type rname: dns.name.Name object @ivar serial: The zone's serial number @type serial: int @ivar refresh: The zone's refresh value (in seconds) @type refresh: int @ivar retry: The zone's retry value (in seconds) @type retry: int @ivar expire: The zone's expiration value (in seconds) @type expire: int @ivar minimum: The zone's negative caching time (in seconds, called "minimum" for historical reasons) @type minimum: int @see: RFC 1035""" __slots__ = ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 'minimum'] def __init__(self, rdclass, rdtype, mname, rname, serial, refresh, retry, expire, minimum): super(SOA, self).__init__(rdclass, rdtype) self.mname = mname self.rname = rname self.serial = serial self.refresh = refresh self.retry = retry self.expire = expire self.minimum = minimum def to_text(self, origin=None, relativize=True, **kw): mname = self.mname.choose_relativity(origin, relativize) rname = self.rname.choose_relativity(origin, relativize) return '%s %s %d %d %d %d %d' % ( mname, rname, self.serial, self.refresh, self.retry, self.expire, self.minimum ) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): mname = tok.get_name() rname = tok.get_name() mname = mname.choose_relativity(origin, relativize) rname = rname.choose_relativity(origin, relativize) serial = tok.get_uint32() refresh = tok.get_ttl() retry = tok.get_ttl() expire = tok.get_ttl() minimum = tok.get_ttl() tok.get_eol() return cls(rdclass, rdtype, mname, rname, serial, refresh, retry, expire, minimum ) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): self.mname.to_wire(file, compress, origin) self.rname.to_wire(file, compress, origin) five_ints = struct.pack('!IIIII', self.serial, self.refresh, self.retry, self.expire, self.minimum) file.write(five_ints) def to_digestable(self, origin = None): return self.mname.to_digestable(origin) + \ self.rname.to_digestable(origin) + \ struct.pack('!IIIII', self.serial, self.refresh, self.retry, self.expire, self.minimum) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (mname, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused (rname, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused if rdlen != 20: raise dns.exception.FormError five_ints = struct.unpack('!IIIII', wire[current : current + rdlen]) if not origin is None: mname = mname.relativize(origin) rname = rname.relativize(origin) return cls(rdclass, rdtype, mname, rname, five_ints[0], five_ints[1], five_ints[2], five_ints[3], five_ints[4]) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.mname = self.mname.choose_relativity(origin, relativize) self.rname = self.rname.choose_relativity(origin, relativize) def _cmp(self, other): v = cmp(self.mname, other.mname) if v == 0: v = cmp(self.rname, other.rname) if v == 0: self_ints = struct.pack('!IIIII', self.serial, self.refresh, self.retry, self.expire, self.minimum) other_ints = struct.pack('!IIIII', other.serial, other.refresh, other.retry, other.expire, other.minimum) v = cmp(self_ints, other_ints) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/NSEC3.py0000644000175000017500000001512711570774061025010 0ustar calvincalvin00000000000000# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import base64 import cStringIO import string import struct import dns.exception import dns.rdata import dns.rdatatype b32_hex_to_normal = string.maketrans('0123456789ABCDEFGHIJKLMNOPQRSTUV', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') b32_normal_to_hex = string.maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', '0123456789ABCDEFGHIJKLMNOPQRSTUV') # hash algorithm constants SHA1 = 1 # flag constants OPTOUT = 1 class NSEC3(dns.rdata.Rdata): """NSEC3 record @ivar algorithm: the hash algorithm number @type algorithm: int @ivar flags: the flags @type flags: int @ivar iterations: the number of iterations @type iterations: int @ivar salt: the salt @type salt: string @ivar next: the next name hash @type next: string @ivar windows: the windowed bitmap list @type windows: list of (window number, string) tuples""" __slots__ = ['algorithm', 'flags', 'iterations', 'salt', 'next', 'windows'] def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt, next, windows): super(NSEC3, self).__init__(rdclass, rdtype) self.algorithm = algorithm self.flags = flags self.iterations = iterations self.salt = salt self.next = next self.windows = windows def to_text(self, origin=None, relativize=True, **kw): next = base64.b32encode(self.next).translate(b32_normal_to_hex).lower() if self.salt == '': salt = '-' else: salt = self.salt.encode('hex-codec') text = '' for (window, bitmap) in self.windows: bits = [] for i in xrange(0, len(bitmap)): byte = ord(bitmap[i]) for j in xrange(0, 8): if byte & (0x80 >> j): bits.append(dns.rdatatype.to_text(window * 256 + \ i * 8 + j)) text += (' ' + ' '.join(bits)) return '%u %u %u %s %s%s' % (self.algorithm, self.flags, self.iterations, salt, next, text) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): algorithm = tok.get_uint8() flags = tok.get_uint8() iterations = tok.get_uint16() salt = tok.get_string() if salt == '-': salt = '' else: salt = salt.decode('hex-codec') next = tok.get_string().upper().translate(b32_hex_to_normal) next = base64.b32decode(next) rdtypes = [] while 1: token = tok.get().unescape() if token.is_eol_or_eof(): break nrdtype = dns.rdatatype.from_text(token.value) if nrdtype == 0: raise dns.exception.SyntaxError("NSEC3 with bit 0") if nrdtype > 65535: raise dns.exception.SyntaxError("NSEC3 with bit > 65535") rdtypes.append(nrdtype) rdtypes.sort() window = 0 octets = 0 prior_rdtype = 0 bitmap = ['\0'] * 32 windows = [] for nrdtype in rdtypes: if nrdtype == prior_rdtype: continue prior_rdtype = nrdtype new_window = nrdtype // 256 if new_window != window: windows.append((window, ''.join(bitmap[0:octets]))) bitmap = ['\0'] * 32 window = new_window offset = nrdtype % 256 byte = offset // 8 bit = offset % 8 octets = byte + 1 bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit)) windows.append((window, ''.join(bitmap[0:octets]))) return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, windows) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): l = len(self.salt) file.write(struct.pack("!BBHB", self.algorithm, self.flags, self.iterations, l)) file.write(self.salt) l = len(self.next) file.write(struct.pack("!B", l)) file.write(self.next) for (window, bitmap) in self.windows: file.write(chr(window)) file.write(chr(len(bitmap))) file.write(bitmap) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (algorithm, flags, iterations, slen) = struct.unpack('!BBHB', wire[current : current + 5]) current += 5 rdlen -= 5 salt = wire[current : current + slen].unwrap() current += slen rdlen -= slen (nlen, ) = struct.unpack('!B', wire[current]) current += 1 rdlen -= 1 next = wire[current : current + nlen].unwrap() current += nlen rdlen -= nlen windows = [] while rdlen > 0: if rdlen < 3: raise dns.exception.FormError("NSEC3 too short") window = ord(wire[current]) octets = ord(wire[current + 1]) if octets == 0 or octets > 32: raise dns.exception.FormError("bad NSEC3 octets") current += 2 rdlen -= 2 if rdlen < octets: raise dns.exception.FormError("bad NSEC3 bitmap length") bitmap = wire[current : current + octets].unwrap() current += octets rdlen -= octets windows.append((window, bitmap)) return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, windows) from_wire = classmethod(from_wire) def _cmp(self, other): b1 = cStringIO.StringIO() self.to_wire(b1) b2 = cStringIO.StringIO() other.to_wire(b2) return cmp(b1.getvalue(), b2.getvalue()) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/AFSDB.py0000644000175000017500000000346611570774061025017 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.mxbase class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX): """AFSDB record @ivar subtype: the subtype value @type subtype: int @ivar hostname: the hostname name @type hostname: dns.name.Name object""" # Use the property mechanism to make "subtype" an alias for the # "preference" attribute, and "hostname" an alias for the "exchange" # attribute. # # This lets us inherit the UncompressedMX implementation but lets # the caller use appropriate attribute names for the rdata type. # # We probably lose some performance vs. a cut-and-paste # implementation, but this way we don't copy code, and that's # good. def get_subtype(self): return self.preference def set_subtype(self, subtype): self.preference = subtype subtype = property(get_subtype, set_subtype) def get_hostname(self): return self.exchange def set_hostname(self, hostname): self.exchange = hostname hostname = property(get_hostname, set_hostname) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/ISDN.py0000644000175000017500000000626211570774061024732 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.rdata import dns.tokenizer class ISDN(dns.rdata.Rdata): """ISDN record @ivar address: the ISDN address @type address: string @ivar subaddress: the ISDN subaddress (or '' if not present) @type subaddress: string @see: RFC 1183""" __slots__ = ['address', 'subaddress'] def __init__(self, rdclass, rdtype, address, subaddress): super(ISDN, self).__init__(rdclass, rdtype) self.address = address self.subaddress = subaddress def to_text(self, origin=None, relativize=True, **kw): if self.subaddress: return '"%s" "%s"' % (dns.rdata._escapify(self.address), dns.rdata._escapify(self.subaddress)) else: return '"%s"' % dns.rdata._escapify(self.address) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_string() t = tok.get() if not t.is_eol_or_eof(): tok.unget(t) subaddress = tok.get_string() else: tok.unget(t) subaddress = '' tok.get_eol() return cls(rdclass, rdtype, address, subaddress) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): l = len(self.address) assert l < 256 byte = chr(l) file.write(byte) file.write(self.address) l = len(self.subaddress) if l > 0: assert l < 256 byte = chr(l) file.write(byte) file.write(self.subaddress) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): l = ord(wire[current]) current += 1 rdlen -= 1 if l > rdlen: raise dns.exception.FormError address = wire[current : current + l].unwrap() current += l rdlen -= l if rdlen > 0: l = ord(wire[current]) current += 1 rdlen -= 1 if l != rdlen: raise dns.exception.FormError subaddress = wire[current : current + l].unwrap() else: subaddress = '' return cls(rdclass, rdtype, address, subaddress) from_wire = classmethod(from_wire) def _cmp(self, other): v = cmp(self.address, other.address) if v == 0: v = cmp(self.subaddress, other.subaddress) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/X25.py0000644000175000017500000000407311570774061024551 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.rdata import dns.tokenizer class X25(dns.rdata.Rdata): """X25 record @ivar address: the PSDN address @type address: string @see: RFC 1183""" __slots__ = ['address'] def __init__(self, rdclass, rdtype, address): super(X25, self).__init__(rdclass, rdtype) self.address = address def to_text(self, origin=None, relativize=True, **kw): return '"%s"' % dns.rdata._escapify(self.address) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): address = tok.get_string() tok.get_eol() return cls(rdclass, rdtype, address) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): l = len(self.address) assert l < 256 byte = chr(l) file.write(byte) file.write(self.address) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): l = ord(wire[current]) current += 1 rdlen -= 1 if l != rdlen: raise dns.exception.FormError address = wire[current : current + l].unwrap() return cls(rdclass, rdtype, address) from_wire = classmethod(from_wire) def _cmp(self, other): return cmp(self.address, other.address) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/NS.py0000644000175000017500000000156011570774061024511 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.nsbase class NS(dns.rdtypes.nsbase.NSBase): """NS record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/CNAME.py0000644000175000017500000000210311570774061025006 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.nsbase class CNAME(dns.rdtypes.nsbase.NSBase): """CNAME record Note: although CNAME is officially a singleton type, dnspython allows non-singleton CNAME rdatasets because such sets have been commonly used by BIND and other nameservers for load balancing.""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py0000644000175000017500000000614111570774061025565 0ustar calvincalvin00000000000000# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import struct import dns.exception import dns.rdata class NSEC3PARAM(dns.rdata.Rdata): """NSEC3PARAM record @ivar algorithm: the hash algorithm number @type algorithm: int @ivar flags: the flags @type flags: int @ivar iterations: the number of iterations @type iterations: int @ivar salt: the salt @type salt: string""" __slots__ = ['algorithm', 'flags', 'iterations', 'salt'] def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt): super(NSEC3PARAM, self).__init__(rdclass, rdtype) self.algorithm = algorithm self.flags = flags self.iterations = iterations self.salt = salt def to_text(self, origin=None, relativize=True, **kw): if self.salt == '': salt = '-' else: salt = self.salt.encode('hex-codec') return '%u %u %u %s' % (self.algorithm, self.flags, self.iterations, salt) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): algorithm = tok.get_uint8() flags = tok.get_uint8() iterations = tok.get_uint16() salt = tok.get_string() if salt == '-': salt = '' else: salt = salt.decode('hex-codec') return cls(rdclass, rdtype, algorithm, flags, iterations, salt) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): l = len(self.salt) file.write(struct.pack("!BBHB", self.algorithm, self.flags, self.iterations, l)) file.write(self.salt) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (algorithm, flags, iterations, slen) = struct.unpack('!BBHB', wire[current : current + 5]) current += 5 rdlen -= 5 salt = wire[current : current + slen].unwrap() current += slen rdlen -= slen if rdlen != 0: raise dns.exception.FormError return cls(rdclass, rdtype, algorithm, flags, iterations, salt) from_wire = classmethod(from_wire) def _cmp(self, other): b1 = cStringIO.StringIO() self.to_wire(b1) b2 = cStringIO.StringIO() other.to_wire(b2) return cmp(b1.getvalue(), b2.getvalue()) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/__init__.py0000644000175000017500000000220511570774061025725 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Class ANY (generic) rdata type classes.""" __all__ = [ 'AFSDB', 'CERT', 'CNAME', 'DLV', 'DNAME', 'DNSKEY', 'DS', 'GPOS', 'HINFO', 'HIP', 'ISDN', 'LOC', 'MX', 'NS', 'NSEC', 'NSEC3', 'NSEC3PARAM', 'PTR', 'RP', 'RRSIG', 'RT', 'SOA', 'SPF', 'SSHFP', 'TXT', 'X25', ] LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/HIP.py0000644000175000017500000001153511570774061024614 0ustar calvincalvin00000000000000# Copyright (C) 2010, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import string import struct import dns.exception import dns.rdata import dns.rdatatype class HIP(dns.rdata.Rdata): """HIP record @ivar hit: the host identity tag @type hit: string @ivar algorithm: the public key cryptographic algorithm @type algorithm: int @ivar key: the public key @type key: string @ivar servers: the rendezvous servers @type servers: list of dns.name.Name objects @see: RFC 5205""" __slots__ = ['hit', 'algorithm', 'key', 'servers'] def __init__(self, rdclass, rdtype, hit, algorithm, key, servers): super(HIP, self).__init__(rdclass, rdtype) self.hit = hit self.algorithm = algorithm self.key = key self.servers = servers def to_text(self, origin=None, relativize=True, **kw): hit = self.hit.encode('hex-codec') key = self.key.encode('base64-codec').replace('\n', '') text = '' servers = [] for server in self.servers: servers.append(str(server.choose_relativity(origin, relativize))) if len(servers) > 0: text += (' ' + ' '.join(servers)) return '%u %s %s%s' % (self.algorithm, hit, key, text) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): algorithm = tok.get_uint8() hit = tok.get_string().decode('hex-codec') if len(hit) > 255: raise dns.exception.SyntaxError("HIT too long") key = tok.get_string().decode('base64-codec') servers = [] while 1: token = tok.get() if token.is_eol_or_eof(): break server = dns.name.from_text(token.value, origin) server.choose_relativity(origin, relativize) servers.append(server) return cls(rdclass, rdtype, hit, algorithm, key, servers) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): lh = len(self.hit) lk = len(self.key) file.write(struct.pack("!BBH", lh, self.algorithm, lk)) file.write(self.hit) file.write(self.key) for server in self.servers: server.to_wire(file, None, origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (lh, algorithm, lk) = struct.unpack('!BBH', wire[current : current + 4]) current += 4 rdlen -= 4 hit = wire[current : current + lh].unwrap() current += lh rdlen -= lh key = wire[current : current + lk].unwrap() current += lk rdlen -= lk servers = [] while rdlen > 0: (server, cused) = dns.name.from_wire(wire[: current + rdlen], current) current += cused rdlen -= cused if not origin is None: server = server.relativize(origin) servers.append(server) return cls(rdclass, rdtype, hit, algorithm, key, servers) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): servers = [] for server in self.servers: server = server.choose_relativity(origin, relativize) servers.append(server) self.servers = servers def _cmp(self, other): b1 = cStringIO.StringIO() lh = len(self.hit) lk = len(self.key) b1.write(struct.pack("!BBH", lh, self.algorithm, lk)) b1.write(self.hit) b1.write(self.key) b2 = cStringIO.StringIO() lh = len(other.hit) lk = len(other.key) b2.write(struct.pack("!BBH", lh, other.algorithm, lk)) b2.write(other.hit) b2.write(other.key) v = cmp(b1.getvalue(), b2.getvalue()) if v != 0: return v ls = len(self.servers) lo = len(other.servers) count = min(ls, lo) i = 0 while i < count: v = cmp(self.servers[i], other.servers[i]) if v != 0: return v i += 1 return ls - lo LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/SPF.py0000644000175000017500000000161211570774061024617 0ustar calvincalvin00000000000000# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.txtbase class SPF(dns.rdtypes.txtbase.TXTBase): """SPF record @see: RFC 4408""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/HINFO.py0000644000175000017500000000513411570774061025035 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.exception import dns.rdata import dns.tokenizer class HINFO(dns.rdata.Rdata): """HINFO record @ivar cpu: the CPU type @type cpu: string @ivar os: the OS type @type os: string @see: RFC 1035""" __slots__ = ['cpu', 'os'] def __init__(self, rdclass, rdtype, cpu, os): super(HINFO, self).__init__(rdclass, rdtype) self.cpu = cpu self.os = os def to_text(self, origin=None, relativize=True, **kw): return '"%s" "%s"' % (dns.rdata._escapify(self.cpu), dns.rdata._escapify(self.os)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): cpu = tok.get_string() os = tok.get_string() tok.get_eol() return cls(rdclass, rdtype, cpu, os) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): l = len(self.cpu) assert l < 256 byte = chr(l) file.write(byte) file.write(self.cpu) l = len(self.os) assert l < 256 byte = chr(l) file.write(byte) file.write(self.os) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): l = ord(wire[current]) current += 1 rdlen -= 1 if l > rdlen: raise dns.exception.FormError cpu = wire[current : current + l].unwrap() current += l rdlen -= l l = ord(wire[current]) current += 1 rdlen -= 1 if l != rdlen: raise dns.exception.FormError os = wire[current : current + l].unwrap() return cls(rdclass, rdtype, cpu, os) from_wire = classmethod(from_wire) def _cmp(self, other): v = cmp(self.cpu, other.cpu) if v == 0: v = cmp(self.os, other.os) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/ANY/PTR.py0000644000175000017500000000156211570774061024640 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import dns.rdtypes.nsbase class PTR(dns.rdtypes.nsbase.NSBase): """PTR record""" pass LinkChecker-9.3/third_party/dnspython/dns/rdtypes/dsbase.py0000644000175000017500000000660411570774061025007 0ustar calvincalvin00000000000000# Copyright (C) 2010, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import struct import dns.rdata import dns.rdatatype class DSBase(dns.rdata.Rdata): """Base class for rdata that is like a DS record @ivar key_tag: the key tag @type key_tag: int @ivar algorithm: the algorithm @type algorithm: int @ivar digest_type: the digest type @type digest_type: int @ivar digest: the digest @type digest: int @see: draft-ietf-dnsext-delegation-signer-14.txt""" __slots__ = ['key_tag', 'algorithm', 'digest_type', 'digest'] def __init__(self, rdclass, rdtype, key_tag, algorithm, digest_type, digest): super(DSBase, self).__init__(rdclass, rdtype) self.key_tag = key_tag self.algorithm = algorithm self.digest_type = digest_type self.digest = digest def to_text(self, origin=None, relativize=True, **kw): return '%d %d %d %s' % (self.key_tag, self.algorithm, self.digest_type, dns.rdata._hexify(self.digest, chunksize=128)) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): key_tag = tok.get_uint16() algorithm = tok.get_uint8() digest_type = tok.get_uint8() chunks = [] while 1: t = tok.get().unescape() if t.is_eol_or_eof(): break if not t.is_identifier(): raise dns.exception.SyntaxError chunks.append(t.value) digest = ''.join(chunks) digest = digest.decode('hex_codec') return cls(rdclass, rdtype, key_tag, algorithm, digest_type, digest) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): header = struct.pack("!HBB", self.key_tag, self.algorithm, self.digest_type) file.write(header) file.write(self.digest) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): header = struct.unpack("!HBB", wire[current : current + 4]) current += 4 rdlen -= 4 digest = wire[current : current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], digest) from_wire = classmethod(from_wire) def _cmp(self, other): hs = struct.pack("!HBB", self.key_tag, self.algorithm, self.digest_type) ho = struct.pack("!HBB", other.key_tag, other.algorithm, other.digest_type) v = cmp(hs, ho) if v == 0: v = cmp(self.digest, other.digest) return v LinkChecker-9.3/third_party/dnspython/dns/rdtypes/mxbase.py0000644000175000017500000000760011570774061025022 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """MX-like base classes.""" import cStringIO import struct import dns.exception import dns.rdata import dns.name class MXBase(dns.rdata.Rdata): """Base class for rdata that is like an MX record. @ivar preference: the preference value @type preference: int @ivar exchange: the exchange name @type exchange: dns.name.Name object""" __slots__ = ['preference', 'exchange'] def __init__(self, rdclass, rdtype, preference, exchange): super(MXBase, self).__init__(rdclass, rdtype) self.preference = preference self.exchange = exchange def to_text(self, origin=None, relativize=True, **kw): exchange = self.exchange.choose_relativity(origin, relativize) return '%d %s' % (self.preference, exchange) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): preference = tok.get_uint16() exchange = tok.get_name() exchange = exchange.choose_relativity(origin, relativize) tok.get_eol() return cls(rdclass, rdtype, preference, exchange) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): pref = struct.pack("!H", self.preference) file.write(pref) self.exchange.to_wire(file, compress, origin) def to_digestable(self, origin = None): return struct.pack("!H", self.preference) + \ self.exchange.to_digestable(origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (preference, ) = struct.unpack('!H', wire[current : current + 2]) current += 2 rdlen -= 2 (exchange, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: raise dns.exception.FormError if not origin is None: exchange = exchange.relativize(origin) return cls(rdclass, rdtype, preference, exchange) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.exchange = self.exchange.choose_relativity(origin, relativize) def _cmp(self, other): sp = struct.pack("!H", self.preference) op = struct.pack("!H", other.preference) v = cmp(sp, op) if v == 0: v = cmp(self.exchange, other.exchange) return v class UncompressedMX(MXBase): """Base class for rdata that is like an MX record, but whose name is not compressed when converted to DNS wire format, and whose digestable form is not downcased.""" def to_wire(self, file, compress = None, origin = None): super(UncompressedMX, self).to_wire(file, None, origin) def to_digestable(self, origin = None): f = cStringIO.StringIO() self.to_wire(f, None, origin) return f.getvalue() class UncompressedDowncasingMX(MXBase): """Base class for rdata that is like an MX record, but whose name is not compressed when convert to DNS wire format.""" def to_wire(self, file, compress = None, origin = None): super(UncompressedDowncasingMX, self).to_wire(file, None, origin) LinkChecker-9.3/third_party/dnspython/dns/rdtypes/__init__.py0000644000175000017500000000156011570774061025301 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS rdata type classes""" __all__ = [ 'ANY', 'IN', 'mxbase', 'nsbase', ] LinkChecker-9.3/third_party/dnspython/dns/rdtypes/nsbase.py0000644000175000017500000000566211570774061025024 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """NS-like base classes.""" import cStringIO import dns.exception import dns.rdata import dns.name class NSBase(dns.rdata.Rdata): """Base class for rdata that is like an NS record. @ivar target: the target name of the rdata @type target: dns.name.Name object""" __slots__ = ['target'] def __init__(self, rdclass, rdtype, target): super(NSBase, self).__init__(rdclass, rdtype) self.target = target def to_text(self, origin=None, relativize=True, **kw): target = self.target.choose_relativity(origin, relativize) return str(target) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): target = tok.get_name() target = target.choose_relativity(origin, relativize) tok.get_eol() return cls(rdclass, rdtype, target) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): self.target.to_wire(file, compress, origin) def to_digestable(self, origin = None): return self.target.to_digestable(origin) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): (target, cused) = dns.name.from_wire(wire[: current + rdlen], current) if cused != rdlen: raise dns.exception.FormError if not origin is None: target = target.relativize(origin) return cls(rdclass, rdtype, target) from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): self.target = self.target.choose_relativity(origin, relativize) def _cmp(self, other): return cmp(self.target, other.target) class UncompressedNS(NSBase): """Base class for rdata that is like an NS record, but whose name is not compressed when convert to DNS wire format, and whose digestable form is not downcased.""" def to_wire(self, file, compress = None, origin = None): super(UncompressedNS, self).to_wire(file, None, origin) def to_digestable(self, origin = None): f = cStringIO.StringIO() self.to_wire(f, None, origin) return f.getvalue() LinkChecker-9.3/third_party/dnspython/dns/rdata.py0000644000175000017500000003635011570774061023150 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS rdata. @var _rdata_modules: A dictionary mapping a (rdclass, rdtype) tuple to the module which implements that type. @type _rdata_modules: dict @var _module_prefix: The prefix to use when forming modules names. The default is 'dns.rdtypes'. Changing this value will break the library. @type _module_prefix: string @var _hex_chunk: At most this many octets that will be represented in each chunk of hexstring that _hexify() produces before whitespace occurs. @type _hex_chunk: int""" import cStringIO import dns.exception import dns.name import dns.rdataclass import dns.rdatatype import dns.tokenizer import dns.wiredata _hex_chunksize = 32 def _hexify(data, chunksize=None): """Convert a binary string into its hex encoding, broken up into chunks of I{chunksize} characters separated by a space. @param data: the binary string @type data: string @param chunksize: the chunk size. Default is L{dns.rdata._hex_chunksize} @rtype: string """ if chunksize is None: chunksize = _hex_chunksize hex = data.encode('hex_codec') l = len(hex) if l > chunksize: chunks = [] i = 0 while i < l: chunks.append(hex[i : i + chunksize]) i += chunksize hex = ' '.join(chunks) return hex _base64_chunksize = 32 def _base64ify(data, chunksize=None): """Convert a binary string into its base64 encoding, broken up into chunks of I{chunksize} characters separated by a space. @param data: the binary string @type data: string @param chunksize: the chunk size. Default is L{dns.rdata._base64_chunksize} @rtype: string """ if chunksize is None: chunksize = _base64_chunksize b64 = data.encode('base64_codec') b64 = b64.replace('\n', '') l = len(b64) if l > chunksize: chunks = [] i = 0 while i < l: chunks.append(b64[i : i + chunksize]) i += chunksize b64 = ' '.join(chunks) return b64 __escaped = { '"' : True, '\\' : True, } def _escapify(qstring): """Escape the characters in a quoted string which need it. @param qstring: the string @type qstring: string @returns: the escaped string @rtype: string """ text = '' for c in qstring: if c in __escaped: text += '\\' + c elif ord(c) >= 0x20 and ord(c) < 0x7F: text += c else: text += '\\%03d' % ord(c) return text def _truncate_bitmap(what): """Determine the index of greatest byte that isn't all zeros, and return the bitmap that contains all the bytes less than that index. @param what: a string of octets representing a bitmap. @type what: string @rtype: string """ for i in xrange(len(what) - 1, -1, -1): if what[i] != '\x00': break return ''.join(what[0 : i + 1]) class Rdata(object): """Base class for all DNS rdata types. """ __slots__ = ['rdclass', 'rdtype'] def __init__(self, rdclass, rdtype): """Initialize an rdata. @param rdclass: The rdata class @type rdclass: int @param rdtype: The rdata type @type rdtype: int """ self.rdclass = rdclass self.rdtype = rdtype def covers(self): """DNS SIG/RRSIG rdatas apply to a specific type; this type is returned by the covers() function. If the rdata type is not SIG or RRSIG, dns.rdatatype.NONE is returned. This is useful when creating rdatasets, allowing the rdataset to contain only RRSIGs of a particular type, e.g. RRSIG(NS). @rtype: int """ return dns.rdatatype.NONE def extended_rdatatype(self): """Return a 32-bit type value, the least significant 16 bits of which are the ordinary DNS type, and the upper 16 bits of which are the "covered" type, if any. @rtype: int """ return self.covers() << 16 | self.rdtype def to_text(self, origin=None, relativize=True, **kw): """Convert an rdata to text format. @rtype: string """ raise NotImplementedError def to_wire(self, file, compress = None, origin = None): """Convert an rdata to wire format. @rtype: string """ raise NotImplementedError def to_digestable(self, origin = None): """Convert rdata to a format suitable for digesting in hashes. This is also the DNSSEC canonical form.""" f = cStringIO.StringIO() self.to_wire(f, None, origin) return f.getvalue() def validate(self): """Check that the current contents of the rdata's fields are valid. If you change an rdata by assigning to its fields, it is a good idea to call validate() when you are done making changes. """ dns.rdata.from_text(self.rdclass, self.rdtype, self.to_text()) def __repr__(self): covers = self.covers() if covers == dns.rdatatype.NONE: ctext = '' else: ctext = '(' + dns.rdatatype.to_text(covers) + ')' return '' def __str__(self): return self.to_text() def _cmp(self, other): """Compare an rdata with another rdata of the same rdtype and rdclass. Return < 0 if self < other in the DNSSEC ordering, 0 if self == other, and > 0 if self > other. """ raise NotImplementedError def __eq__(self, other): if not isinstance(other, Rdata): return False if self.rdclass != other.rdclass or \ self.rdtype != other.rdtype: return False return self._cmp(other) == 0 def __ne__(self, other): if not isinstance(other, Rdata): return True if self.rdclass != other.rdclass or \ self.rdtype != other.rdtype: return True return self._cmp(other) != 0 def __lt__(self, other): if not isinstance(other, Rdata) or \ self.rdclass != other.rdclass or \ self.rdtype != other.rdtype: return NotImplemented return self._cmp(other) < 0 def __le__(self, other): if not isinstance(other, Rdata) or \ self.rdclass != other.rdclass or \ self.rdtype != other.rdtype: return NotImplemented return self._cmp(other) <= 0 def __ge__(self, other): if not isinstance(other, Rdata) or \ self.rdclass != other.rdclass or \ self.rdtype != other.rdtype: return NotImplemented return self._cmp(other) >= 0 def __gt__(self, other): if not isinstance(other, Rdata) or \ self.rdclass != other.rdclass or \ self.rdtype != other.rdtype: return NotImplemented return self._cmp(other) > 0 def __hash__(self): return hash(self.to_digestable(dns.name.root)) def _wire_cmp(self, other): # A number of types compare rdata in wire form, so we provide # the method here instead of duplicating it. # # We specifiy an arbitrary origin of '.' when doing the # comparison, since the rdata may have relative names and we # can't convert a relative name to wire without an origin. b1 = cStringIO.StringIO() self.to_wire(b1, None, dns.name.root) b2 = cStringIO.StringIO() other.to_wire(b2, None, dns.name.root) return cmp(b1.getvalue(), b2.getvalue()) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): """Build an rdata object from text format. @param rdclass: The rdata class @type rdclass: int @param rdtype: The rdata type @type rdtype: int @param tok: The tokenizer @type tok: dns.tokenizer.Tokenizer @param origin: The origin to use for relative names @type origin: dns.name.Name @param relativize: should names be relativized? @type relativize: bool @rtype: dns.rdata.Rdata instance """ raise NotImplementedError from_text = classmethod(from_text) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): """Build an rdata object from wire format @param rdclass: The rdata class @type rdclass: int @param rdtype: The rdata type @type rdtype: int @param wire: The wire-format message @type wire: string @param current: The offet in wire of the beginning of the rdata. @type current: int @param rdlen: The length of the wire-format rdata @type rdlen: int @param origin: The origin to use for relative names @type origin: dns.name.Name @rtype: dns.rdata.Rdata instance """ raise NotImplementedError from_wire = classmethod(from_wire) def choose_relativity(self, origin = None, relativize = True): """Convert any domain names in the rdata to the specified relativization. """ pass class GenericRdata(Rdata): """Generate Rdata Class This class is used for rdata types for which we have no better implementation. It implements the DNS "unknown RRs" scheme. """ __slots__ = ['data'] def __init__(self, rdclass, rdtype, data): super(GenericRdata, self).__init__(rdclass, rdtype) self.data = data def to_text(self, origin=None, relativize=True, **kw): return r'\# %d ' % len(self.data) + _hexify(self.data) def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): token = tok.get() if not token.is_identifier() or token.value != '\#': raise dns.exception.SyntaxError(r'generic rdata does not start with \#') length = tok.get_int() chunks = [] while 1: token = tok.get() if token.is_eol_or_eof(): break chunks.append(token.value) hex = ''.join(chunks) data = hex.decode('hex_codec') if len(data) != length: raise dns.exception.SyntaxError('generic rdata hex data has wrong length') return cls(rdclass, rdtype, data) from_text = classmethod(from_text) def to_wire(self, file, compress = None, origin = None): file.write(self.data) def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): return cls(rdclass, rdtype, wire[current : current + rdlen]) from_wire = classmethod(from_wire) def _cmp(self, other): return cmp(self.data, other.data) _rdata_modules = {} _module_prefix = 'dns.rdtypes' def get_rdata_class(rdclass, rdtype): def import_module(name): mod = __import__(name) components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod mod = _rdata_modules.get((rdclass, rdtype)) rdclass_text = dns.rdataclass.to_text(rdclass) rdtype_text = dns.rdatatype.to_text(rdtype) rdtype_text = rdtype_text.replace('-', '_') if not mod: mod = _rdata_modules.get((dns.rdatatype.ANY, rdtype)) if not mod: try: mod = import_module('.'.join([_module_prefix, rdclass_text, rdtype_text])) _rdata_modules[(rdclass, rdtype)] = mod except ImportError: try: mod = import_module('.'.join([_module_prefix, 'ANY', rdtype_text])) _rdata_modules[(dns.rdataclass.ANY, rdtype)] = mod except ImportError: mod = None if mod: cls = getattr(mod, rdtype_text) else: cls = GenericRdata return cls def from_text(rdclass, rdtype, tok, origin = None, relativize = True): """Build an rdata object from text format. This function attempts to dynamically load a class which implements the specified rdata class and type. If there is no class-and-type-specific implementation, the GenericRdata class is used. Once a class is chosen, its from_text() class method is called with the parameters to this function. @param rdclass: The rdata class @type rdclass: int @param rdtype: The rdata type @type rdtype: int @param tok: The tokenizer @type tok: dns.tokenizer.Tokenizer @param origin: The origin to use for relative names @type origin: dns.name.Name @param relativize: Should names be relativized? @type relativize: bool @rtype: dns.rdata.Rdata instance""" if isinstance(tok, str): tok = dns.tokenizer.Tokenizer(tok) cls = get_rdata_class(rdclass, rdtype) if cls != GenericRdata: # peek at first token token = tok.get() tok.unget(token) if token.is_identifier() and \ token.value == r'\#': # # Known type using the generic syntax. Extract the # wire form from the generic syntax, and then run # from_wire on it. # rdata = GenericRdata.from_text(rdclass, rdtype, tok, origin, relativize) return from_wire(rdclass, rdtype, rdata.data, 0, len(rdata.data), origin) return cls.from_text(rdclass, rdtype, tok, origin, relativize) def from_wire(rdclass, rdtype, wire, current, rdlen, origin = None): """Build an rdata object from wire format This function attempts to dynamically load a class which implements the specified rdata class and type. If there is no class-and-type-specific implementation, the GenericRdata class is used. Once a class is chosen, its from_wire() class method is called with the parameters to this function. @param rdclass: The rdata class @type rdclass: int @param rdtype: The rdata type @type rdtype: int @param wire: The wire-format message @type wire: string @param current: The offet in wire of the beginning of the rdata. @type current: int @param rdlen: The length of the wire-format rdata @type rdlen: int @param origin: The origin to use for relative names @type origin: dns.name.Name @rtype: dns.rdata.Rdata instance""" wire = dns.wiredata.maybe_wrap(wire) cls = get_rdata_class(rdclass, rdtype) return cls.from_wire(rdclass, rdtype, wire, current, rdlen, origin) LinkChecker-9.3/third_party/dnspython/dns/dnssec.py0000644000175000017500000002744411570774060023337 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Common DNSSEC-related functions and constants.""" import cStringIO import struct import time import dns.exception import dns.hash import dns.name import dns.node import dns.rdataset import dns.rdata import dns.rdatatype import dns.rdataclass class UnsupportedAlgorithm(dns.exception.DNSException): """Raised if an algorithm is not supported.""" pass class ValidationFailure(dns.exception.DNSException): """The DNSSEC signature is invalid.""" pass RSAMD5 = 1 DH = 2 DSA = 3 ECC = 4 RSASHA1 = 5 DSANSEC3SHA1 = 6 RSASHA1NSEC3SHA1 = 7 RSASHA256 = 8 RSASHA512 = 10 INDIRECT = 252 PRIVATEDNS = 253 PRIVATEOID = 254 _algorithm_by_text = { 'RSAMD5' : RSAMD5, 'DH' : DH, 'DSA' : DSA, 'ECC' : ECC, 'RSASHA1' : RSASHA1, 'DSANSEC3SHA1' : DSANSEC3SHA1, 'RSASHA1NSEC3SHA1' : RSASHA1NSEC3SHA1, 'RSASHA256' : RSASHA256, 'RSASHA512' : RSASHA512, 'INDIRECT' : INDIRECT, 'PRIVATEDNS' : PRIVATEDNS, 'PRIVATEOID' : PRIVATEOID, } # We construct the inverse mapping programmatically to ensure that we # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that # would cause the mapping not to be true inverse. _algorithm_by_value = dict([(y, x) for x, y in _algorithm_by_text.iteritems()]) def algorithm_from_text(text): """Convert text into a DNSSEC algorithm value @rtype: int""" value = _algorithm_by_text.get(text.upper()) if value is None: value = int(text) return value def algorithm_to_text(value): """Convert a DNSSEC algorithm value to text @rtype: string""" text = _algorithm_by_value.get(value) if text is None: text = str(value) return text def _to_rdata(record, origin): s = cStringIO.StringIO() record.to_wire(s, origin=origin) return s.getvalue() def key_id(key, origin=None): rdata = _to_rdata(key, origin) if key.algorithm == RSAMD5: return (ord(rdata[-3]) << 8) + ord(rdata[-2]) else: total = 0 for i in range(len(rdata) // 2): total += (ord(rdata[2 * i]) << 8) + ord(rdata[2 * i + 1]) if len(rdata) % 2 != 0: total += ord(rdata[len(rdata) - 1]) << 8 total += ((total >> 16) & 0xffff); return total & 0xffff def make_ds(name, key, algorithm, origin=None): if algorithm.upper() == 'SHA1': dsalg = 1 hash = dns.hash.get('SHA1')() elif algorithm.upper() == 'SHA256': dsalg = 2 hash = dns.hash.get('SHA256')() else: raise UnsupportedAlgorithm, 'unsupported algorithm "%s"' % algorithm if isinstance(name, (str, unicode)): name = dns.name.from_text(name, origin) hash.update(name.canonicalize().to_wire()) hash.update(_to_rdata(key, origin)) digest = hash.digest() dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata)) def _find_key(keys, rrsig): value = keys.get(rrsig.signer) if value is None: return None if isinstance(value, dns.node.Node): try: rdataset = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.DNSKEY) except KeyError: return None else: rdataset = value for rdata in rdataset: if rdata.algorithm == rrsig.algorithm and \ key_id(rdata) == rrsig.key_tag: return rdata return None def _is_rsa(algorithm): return algorithm in (RSAMD5, RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512) def _is_dsa(algorithm): return algorithm in (DSA, DSANSEC3SHA1) def _is_md5(algorithm): return algorithm == RSAMD5 def _is_sha1(algorithm): return algorithm in (DSA, RSASHA1, DSANSEC3SHA1, RSASHA1NSEC3SHA1) def _is_sha256(algorithm): return algorithm == RSASHA256 def _is_sha512(algorithm): return algorithm == RSASHA512 def _make_hash(algorithm): if _is_md5(algorithm): return dns.hash.get('MD5')() if _is_sha1(algorithm): return dns.hash.get('SHA1')() if _is_sha256(algorithm): return dns.hash.get('SHA256')() if _is_sha512(algorithm): return dns.hash.get('SHA512')() raise ValidationFailure, 'unknown hash for algorithm %u' % algorithm def _make_algorithm_id(algorithm): if _is_md5(algorithm): oid = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05] elif _is_sha1(algorithm): oid = [0x2b, 0x0e, 0x03, 0x02, 0x1a] elif _is_sha256(algorithm): oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01] elif _is_sha512(algorithm): oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03] else: raise ValidationFailure, 'unknown algorithm %u' % algorithm olen = len(oid) dlen = _make_hash(algorithm).digest_size idbytes = [0x30] + [8 + olen + dlen] + \ [0x30, olen + 4] + [0x06, olen] + oid + \ [0x05, 0x00] + [0x04, dlen] return ''.join(map(chr, idbytes)) def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): """Validate an RRset against a single signature rdata The owner name of the rrsig is assumed to be the same as the owner name of the rrset. @param rrset: The RRset to validate @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) tuple @param rrsig: The signature rdata @type rrsig: dns.rrset.Rdata @param keys: The key dictionary. @type keys: a dictionary keyed by dns.name.Name with node or rdataset values @param origin: The origin to use for relative names @type origin: dns.name.Name or None @param now: The time to use when validating the signatures. The default is the current time. @type now: int """ if isinstance(origin, (str, unicode)): origin = dns.name.from_text(origin, dns.name.root) key = _find_key(keys, rrsig) if not key: raise ValidationFailure, 'unknown key' # For convenience, allow the rrset to be specified as a (name, rdataset) # tuple as well as a proper rrset if isinstance(rrset, tuple): rrname = rrset[0] rdataset = rrset[1] else: rrname = rrset.name rdataset = rrset if now is None: now = time.time() if rrsig.expiration < now: raise ValidationFailure, 'expired' if rrsig.inception > now: raise ValidationFailure, 'not yet valid' hash = _make_hash(rrsig.algorithm) if _is_rsa(rrsig.algorithm): keyptr = key.key (bytes,) = struct.unpack('!B', keyptr[0:1]) keyptr = keyptr[1:] if bytes == 0: (bytes,) = struct.unpack('!H', keyptr[0:2]) keyptr = keyptr[2:] rsa_e = keyptr[0:bytes] rsa_n = keyptr[bytes:] keylen = len(rsa_n) * 8 pubkey = Crypto.PublicKey.RSA.construct( (Crypto.Util.number.bytes_to_long(rsa_n), Crypto.Util.number.bytes_to_long(rsa_e))) sig = (Crypto.Util.number.bytes_to_long(rrsig.signature),) elif _is_dsa(rrsig.algorithm): keyptr = key.key (t,) = struct.unpack('!B', keyptr[0:1]) keyptr = keyptr[1:] octets = 64 + t * 8 dsa_q = keyptr[0:20] keyptr = keyptr[20:] dsa_p = keyptr[0:octets] keyptr = keyptr[octets:] dsa_g = keyptr[0:octets] keyptr = keyptr[octets:] dsa_y = keyptr[0:octets] pubkey = Crypto.PublicKey.DSA.construct( (Crypto.Util.number.bytes_to_long(dsa_y), Crypto.Util.number.bytes_to_long(dsa_g), Crypto.Util.number.bytes_to_long(dsa_p), Crypto.Util.number.bytes_to_long(dsa_q))) (dsa_r, dsa_s) = struct.unpack('!20s20s', rrsig.signature[1:]) sig = (Crypto.Util.number.bytes_to_long(dsa_r), Crypto.Util.number.bytes_to_long(dsa_s)) else: raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm hash.update(_to_rdata(rrsig, origin)[:18]) hash.update(rrsig.signer.to_digestable(origin)) if rrsig.labels < len(rrname) - 1: suffix = rrname.split(rrsig.labels + 1)[1] rrname = dns.name.from_text('*', suffix) rrnamebuf = rrname.to_digestable(origin) rrfixed = struct.pack('!HHI', rdataset.rdtype, rdataset.rdclass, rrsig.original_ttl) rrlist = sorted(rdataset); for rr in rrlist: hash.update(rrnamebuf) hash.update(rrfixed) rrdata = rr.to_digestable(origin) rrlen = struct.pack('!H', len(rrdata)) hash.update(rrlen) hash.update(rrdata) digest = hash.digest() if _is_rsa(rrsig.algorithm): # PKCS1 algorithm identifier goop digest = _make_algorithm_id(rrsig.algorithm) + digest padlen = keylen // 8 - len(digest) - 3 digest = chr(0) + chr(1) + chr(0xFF) * padlen + chr(0) + digest elif _is_dsa(rrsig.algorithm): pass else: # Raise here for code clarity; this won't actually ever happen # since if the algorithm is really unknown we'd already have # raised an exception above raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm if not pubkey.verify(digest, sig): raise ValidationFailure, 'verify failure' def _validate(rrset, rrsigset, keys, origin=None, now=None): """Validate an RRset @param rrset: The RRset to validate @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) tuple @param rrsigset: The signature RRset @type rrsigset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) tuple @param keys: The key dictionary. @type keys: a dictionary keyed by dns.name.Name with node or rdataset values @param origin: The origin to use for relative names @type origin: dns.name.Name or None @param now: The time to use when validating the signatures. The default is the current time. @type now: int """ if isinstance(origin, (str, unicode)): origin = dns.name.from_text(origin, dns.name.root) if isinstance(rrset, tuple): rrname = rrset[0] else: rrname = rrset.name if isinstance(rrsigset, tuple): rrsigname = rrsigset[0] rrsigrdataset = rrsigset[1] else: rrsigname = rrsigset.name rrsigrdataset = rrsigset rrname = rrname.choose_relativity(origin) rrsigname = rrname.choose_relativity(origin) if rrname != rrsigname: raise ValidationFailure, "owner names do not match" for rrsig in rrsigrdataset: try: _validate_rrsig(rrset, rrsig, keys, origin, now) return except ValidationFailure, e: pass raise ValidationFailure, "no RRSIGs validated" def _need_pycrypto(*args, **kwargs): raise NotImplementedError, "DNSSEC validation requires pycrypto" try: import Crypto.PublicKey.RSA import Crypto.PublicKey.DSA import Crypto.Util.number validate = _validate validate_rrsig = _validate_rrsig except ImportError: validate = _need_pycrypto validate_rrsig = _need_pycrypto LinkChecker-9.3/third_party/dnspython/dns/rrset.py0000644000175000017500000001340711570774061023212 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS RRsets (an RRset is a named rdataset)""" import dns.name import dns.rdataset import dns.rdataclass import dns.renderer class RRset(dns.rdataset.Rdataset): """A DNS RRset (named rdataset). RRset inherits from Rdataset, and RRsets can be treated as Rdatasets in most cases. There are, however, a few notable exceptions. RRsets have different to_wire() and to_text() method arguments, reflecting the fact that RRsets always have an owner name. """ __slots__ = ['name', 'deleting'] def __init__(self, name, rdclass, rdtype, covers=dns.rdatatype.NONE, deleting=None): """Create a new RRset.""" super(RRset, self).__init__(rdclass, rdtype, covers) self.name = name self.deleting = deleting def _clone(self): obj = super(RRset, self)._clone() obj.name = self.name obj.deleting = self.deleting return obj def __repr__(self): if self.covers == 0: ctext = '' else: ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' if not self.deleting is None: dtext = ' delete=' + dns.rdataclass.to_text(self.deleting) else: dtext = '' return '' def __str__(self): return self.to_text() def __eq__(self, other): """Two RRsets are equal if they have the same name and the same rdataset @rtype: bool""" if not isinstance(other, RRset): return False if self.name != other.name: return False return super(RRset, self).__eq__(other) def match(self, name, rdclass, rdtype, covers, deleting=None): """Returns True if this rrset matches the specified class, type, covers, and deletion state.""" if not super(RRset, self).match(rdclass, rdtype, covers): return False if self.name != name or self.deleting != deleting: return False return True def to_text(self, origin=None, relativize=True, **kw): """Convert the RRset into DNS master file format. @see: L{dns.name.Name.choose_relativity} for more information on how I{origin} and I{relativize} determine the way names are emitted. Any additional keyword arguments are passed on to the rdata to_text() method. @param origin: The origin for relative names, or None. @type origin: dns.name.Name object @param relativize: True if names should names be relativized @type relativize: bool""" return super(RRset, self).to_text(self.name, origin, relativize, self.deleting, **kw) def to_wire(self, file, compress=None, origin=None, **kw): """Convert the RRset to wire format.""" return super(RRset, self).to_wire(self.name, file, compress, origin, self.deleting, **kw) def to_rdataset(self): """Convert an RRset into an Rdataset. @rtype: dns.rdataset.Rdataset object """ return dns.rdataset.from_rdata_list(self.ttl, list(self)) def from_text_list(name, ttl, rdclass, rdtype, text_rdatas): """Create an RRset with the specified name, TTL, class, and type, and with the specified list of rdatas in text format. @rtype: dns.rrset.RRset object """ if isinstance(name, (str, unicode)): name = dns.name.from_text(name, None) if isinstance(rdclass, (str, unicode)): rdclass = dns.rdataclass.from_text(rdclass) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) r = RRset(name, rdclass, rdtype) r.update_ttl(ttl) for t in text_rdatas: rd = dns.rdata.from_text(r.rdclass, r.rdtype, t) r.add(rd) return r def from_text(name, ttl, rdclass, rdtype, *text_rdatas): """Create an RRset with the specified name, TTL, class, and type and with the specified rdatas in text format. @rtype: dns.rrset.RRset object """ return from_text_list(name, ttl, rdclass, rdtype, text_rdatas) def from_rdata_list(name, ttl, rdatas): """Create an RRset with the specified name and TTL, and with the specified list of rdata objects. @rtype: dns.rrset.RRset object """ if isinstance(name, (str, unicode)): name = dns.name.from_text(name, None) if len(rdatas) == 0: raise ValueError("rdata list must not be empty") r = None for rd in rdatas: if r is None: r = RRset(name, rd.rdclass, rd.rdtype) r.update_ttl(ttl) first_time = False r.add(rd) return r def from_rdata(name, ttl, *rdatas): """Create an RRset with the specified name and TTL, and with the specified rdata objects. @rtype: dns.rrset.RRset object """ return from_rdata_list(name, ttl, rdatas) LinkChecker-9.3/third_party/dnspython/dns/rdatatype.py0000644000175000017500000001203711570774061024046 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Rdata Types. @var _by_text: The rdata type textual name to value mapping @type _by_text: dict @var _by_value: The rdata type value to textual name mapping @type _by_value: dict @var _metatypes: If an rdatatype is a metatype, there will be a mapping whose key is the rdatatype value and whose value is True in this dictionary. @type _metatypes: dict @var _singletons: If an rdatatype is a singleton, there will be a mapping whose key is the rdatatype value and whose value is True in this dictionary. @type _singletons: dict""" import re import dns.exception NONE = 0 A = 1 NS = 2 MD = 3 MF = 4 CNAME = 5 SOA = 6 MB = 7 MG = 8 MR = 9 NULL = 10 WKS = 11 PTR = 12 HINFO = 13 MINFO = 14 MX = 15 TXT = 16 RP = 17 AFSDB = 18 X25 = 19 ISDN = 20 RT = 21 NSAP = 22 NSAP_PTR = 23 SIG = 24 KEY = 25 PX = 26 GPOS = 27 AAAA = 28 LOC = 29 NXT = 30 SRV = 33 NAPTR = 35 KX = 36 CERT = 37 A6 = 38 DNAME = 39 OPT = 41 APL = 42 DS = 43 SSHFP = 44 IPSECKEY = 45 RRSIG = 46 NSEC = 47 DNSKEY = 48 DHCID = 49 NSEC3 = 50 NSEC3PARAM = 51 HIP = 55 SPF = 99 UNSPEC = 103 TKEY = 249 TSIG = 250 IXFR = 251 AXFR = 252 MAILB = 253 MAILA = 254 ANY = 255 TA = 32768 DLV = 32769 _by_text = { 'NONE' : NONE, 'A' : A, 'NS' : NS, 'MD' : MD, 'MF' : MF, 'CNAME' : CNAME, 'SOA' : SOA, 'MB' : MB, 'MG' : MG, 'MR' : MR, 'NULL' : NULL, 'WKS' : WKS, 'PTR' : PTR, 'HINFO' : HINFO, 'MINFO' : MINFO, 'MX' : MX, 'TXT' : TXT, 'RP' : RP, 'AFSDB' : AFSDB, 'X25' : X25, 'ISDN' : ISDN, 'RT' : RT, 'NSAP' : NSAP, 'NSAP-PTR' : NSAP_PTR, 'SIG' : SIG, 'KEY' : KEY, 'PX' : PX, 'GPOS' : GPOS, 'AAAA' : AAAA, 'LOC' : LOC, 'NXT' : NXT, 'SRV' : SRV, 'NAPTR' : NAPTR, 'KX' : KX, 'CERT' : CERT, 'A6' : A6, 'DNAME' : DNAME, 'OPT' : OPT, 'APL' : APL, 'DS' : DS, 'SSHFP' : SSHFP, 'IPSECKEY' : IPSECKEY, 'RRSIG' : RRSIG, 'NSEC' : NSEC, 'DNSKEY' : DNSKEY, 'DHCID' : DHCID, 'NSEC3' : NSEC3, 'NSEC3PARAM' : NSEC3PARAM, 'HIP' : HIP, 'SPF' : SPF, 'UNSPEC' : UNSPEC, 'TKEY' : TKEY, 'TSIG' : TSIG, 'IXFR' : IXFR, 'AXFR' : AXFR, 'MAILB' : MAILB, 'MAILA' : MAILA, 'ANY' : ANY, 'TA' : TA, 'DLV' : DLV, } # We construct the inverse mapping programmatically to ensure that we # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that # would cause the mapping not to be true inverse. _by_value = dict([(y, x) for x, y in _by_text.iteritems()]) _metatypes = { OPT : True } _singletons = { SOA : True, NXT : True, DNAME : True, NSEC : True, # CNAME is technically a singleton, but we allow multiple CNAMEs. } _unknown_type_pattern = re.compile('TYPE([0-9]+)$', re.I); class UnknownRdatatype(dns.exception.DNSException): """Raised if a type is unknown.""" pass def from_text(text): """Convert text into a DNS rdata type value. @param text: the text @type text: string @raises dns.rdatatype.UnknownRdatatype: the type is unknown @raises ValueError: the rdata type value is not >= 0 and <= 65535 @rtype: int""" value = _by_text.get(text.upper()) if value is None: match = _unknown_type_pattern.match(text) if match == None: raise UnknownRdatatype value = int(match.group(1)) if value < 0 or value > 65535: raise ValueError("type must be between >= 0 and <= 65535") return value def to_text(value): """Convert a DNS rdata type to text. @param value: the rdata type value @type value: int @raises ValueError: the rdata type value is not >= 0 and <= 65535 @rtype: string""" if value < 0 or value > 65535: raise ValueError("type must be between >= 0 and <= 65535") text = _by_value.get(value) if text is None: text = 'TYPE' + `value` return text def is_metatype(rdtype): """True if the type is a metatype. @param rdtype: the type @type rdtype: int @rtype: bool""" if rdtype >= TKEY and rdtype <= ANY or rdtype in _metatypes: return True return False def is_singleton(rdtype): """True if the type is a singleton. @param rdtype: the type @type rdtype: int @rtype: bool""" if rdtype in _singletons: return True return False LinkChecker-9.3/third_party/dnspython/dns/e164.py0000644000175000017500000000577511570774061022543 0ustar calvincalvin00000000000000# Copyright (C) 2006, 2007, 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS E.164 helpers @var public_enum_domain: The DNS public ENUM domain, e164.arpa. @type public_enum_domain: dns.name.Name object """ import dns.exception import dns.name import dns.resolver public_enum_domain = dns.name.from_text('e164.arpa.') def from_e164(text, origin=public_enum_domain): """Convert an E.164 number in textual form into a Name object whose value is the ENUM domain name for that number. @param text: an E.164 number in textual form. @type text: str @param origin: The domain in which the number should be constructed. The default is e164.arpa. @type: dns.name.Name object or None @rtype: dns.name.Name object """ parts = [d for d in text if d.isdigit()] parts.reverse() return dns.name.from_text('.'.join(parts), origin=origin) 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: 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 def query(number, domains, resolver=None): """Look for NAPTR RRs for the specified number in the specified domains. e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.']) """ if resolver is None: resolver = dns.resolver.get_default_resolver() for domain in domains: if isinstance(domain, (str, unicode)): domain = dns.name.from_text(domain) qname = dns.e164.from_e164(number, domain) try: return resolver.query(qname, 'NAPTR') except dns.resolver.NXDOMAIN: pass raise dns.resolver.NXDOMAIN LinkChecker-9.3/third_party/dnspython/dns/node.py0000644000175000017500000001335511570774061023002 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS nodes. A node is a set of rdatasets.""" import StringIO import dns.rdataset import dns.rdatatype import dns.renderer class Node(object): """A DNS node. A node is a set of rdatasets @ivar rdatasets: the node's rdatasets @type rdatasets: list of dns.rdataset.Rdataset objects""" __slots__ = ['rdatasets'] def __init__(self): """Initialize a DNS node. """ self.rdatasets = []; def to_text(self, name, **kw): """Convert a node to text format. Each rdataset at the node is printed. Any keyword arguments to this method are passed on to the rdataset's to_text() method. @param name: the owner name of the rdatasets @type name: dns.name.Name object @rtype: string """ s = StringIO.StringIO() for rds in self.rdatasets: print >> s, rds.to_text(name, **kw) return s.getvalue()[:-1] def __repr__(self): return '' def __eq__(self, other): """Two nodes are equal if they have the same rdatasets. @rtype: bool """ # # This is inefficient. Good thing we don't need to do it much. # for rd in self.rdatasets: if rd not in other.rdatasets: return False for rd in other.rdatasets: if rd not in self.rdatasets: return False return True def __ne__(self, other): return not self.__eq__(other) def __len__(self): return len(self.rdatasets) def __iter__(self): return iter(self.rdatasets) def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE, create=False): """Find an rdataset matching the specified properties in the current node. @param rdclass: The class of the rdataset @type rdclass: int @param rdtype: The type of the rdataset @type rdtype: int @param covers: The covered type. Usually this value is dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or dns.rdatatype.RRSIG, then the covers value will be the rdata type the SIG/RRSIG covers. The library treats the SIG and RRSIG types as if they were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much easier to work with than if RRSIGs covering different rdata types were aggregated into a single RRSIG rdataset. @type covers: int @param create: If True, create the rdataset if it is not found. @type create: bool @raises KeyError: An rdataset of the desired type and class does not exist and I{create} is not True. @rtype: dns.rdataset.Rdataset object """ for rds in self.rdatasets: if rds.match(rdclass, rdtype, covers): return rds if not create: raise KeyError rds = dns.rdataset.Rdataset(rdclass, rdtype) self.rdatasets.append(rds) return rds def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE, create=False): """Get an rdataset matching the specified properties in the current node. None is returned if an rdataset of the specified type and class does not exist and I{create} is not True. @param rdclass: The class of the rdataset @type rdclass: int @param rdtype: The type of the rdataset @type rdtype: int @param covers: The covered type. @type covers: int @param create: If True, create the rdataset if it is not found. @type create: bool @rtype: dns.rdataset.Rdataset object or None """ try: rds = self.find_rdataset(rdclass, rdtype, covers, create) except KeyError: rds = None return rds def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE): """Delete the rdataset matching the specified properties in the current node. If a matching rdataset does not exist, it is not an error. @param rdclass: The class of the rdataset @type rdclass: int @param rdtype: The type of the rdataset @type rdtype: int @param covers: The covered type. @type covers: int """ rds = self.get_rdataset(rdclass, rdtype, covers) if not rds is None: self.rdatasets.remove(rds) def replace_rdataset(self, replacement): """Replace an rdataset. It is not an error if there is no rdataset matching I{replacement}. Ownership of the I{replacement} object is transferred to the node; in other words, this method does not store a copy of I{replacement} at the node, it stores I{replacement} itself. """ self.delete_rdataset(replacement.rdclass, replacement.rdtype, replacement.covers) self.rdatasets.append(replacement) LinkChecker-9.3/third_party/dnspython/dns/inet.py0000644000175000017500000000632311570774061023011 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Generic Internet address helper functions.""" import socket import dns.ipv4 import dns.ipv6 # We assume that AF_INET is always defined. AF_INET = socket.AF_INET # AF_INET6 might not be defined in the socket module, but we need it. # We'll try to use the socket module's value, and if it doesn't work, # we'll use our own value. try: AF_INET6 = socket.AF_INET6 except AttributeError: AF_INET6 = 9999 def inet_pton(family, text): """Convert the textual form of a network address into its binary form. @param family: the address family @type family: int @param text: the textual address @type text: string @raises NotImplementedError: the address family specified is not implemented. @rtype: string """ if family == AF_INET: return dns.ipv4.inet_aton(text) elif family == AF_INET6: return dns.ipv6.inet_aton(text) else: raise NotImplementedError def inet_ntop(family, address): """Convert the binary form of a network address into its textual form. @param family: the address family @type family: int @param address: the binary address @type address: string @raises NotImplementedError: the address family specified is not implemented. @rtype: string """ if family == AF_INET: return dns.ipv4.inet_ntoa(address) elif family == AF_INET6: return dns.ipv6.inet_ntoa(address) else: raise NotImplementedError def af_for_address(text): """Determine the address family of a textual-form network address. @param text: the textual address @type text: string @raises ValueError: the address family cannot be determined from the input. @rtype: int """ try: junk = dns.ipv4.inet_aton(text) return AF_INET except StandardError: try: junk = dns.ipv6.inet_aton(text) return AF_INET6 except StandardError: raise ValueError def is_multicast(text): """Is the textual-form network address a multicast address? @param text: the textual address @raises ValueError: the address family cannot be determined from the input. @rtype: bool """ try: first = ord(dns.ipv4.inet_aton(text)[0]) return (first >= 224 and first <= 239) except StandardError: try: first = ord(dns.ipv6.inet_aton(text)[0]) return (first == 255) except StandardError: raise ValueError LinkChecker-9.3/third_party/dnspython/dns/__init__.py0000644000175000017500000000245711570774061023615 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """dnspython DNS toolkit""" __all__ = [ 'dnssec', 'e164', 'edns', 'entropy', 'exception', 'flags', 'hash', 'inet', 'ipv4', 'ipv6', 'message', 'name', 'namedict', 'node', 'opcode', 'query', 'rcode', 'rdata', 'rdataclass', 'rdataset', 'rdatatype', 'renderer', 'resolver', 'reversename', 'rrset', 'set', 'tokenizer', 'tsig', 'tsigkeyring', 'ttl', 'rdtypes', 'update', 'version', 'wiredata', 'zone', ] LinkChecker-9.3/third_party/dnspython/dns/entropy.py0000644000175000017500000000754511570774061023561 0ustar calvincalvin00000000000000# Copyright (C) 2009, 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import os import time try: import threading as _threading except ImportError: import dummy_threading as _threading class EntropyPool(object): def __init__(self, seed=None): self.pool_index = 0 self.digest = None self.next_byte = 0 self.lock = _threading.Lock() try: import hashlib self.hash = hashlib.sha1() self.hash_len = 20 except StandardError: try: import sha self.hash = sha.new() self.hash_len = 20 except StandardError: import md5 self.hash = md5.new() self.hash_len = 16 self.pool = '\0' * self.hash_len if not seed is None: self.stir(seed) self.seeded = True else: self.seeded = False def stir(self, entropy, already_locked=False): if not already_locked: self.lock.acquire() try: bytes = [ord(c) for c in self.pool] for c in entropy: if self.pool_index == self.hash_len: self.pool_index = 0 b = ord(c) & 0xff bytes[self.pool_index] ^= b self.pool_index += 1 self.pool = ''.join([chr(c) for c in bytes]) finally: if not already_locked: self.lock.release() def _maybe_seed(self): if not self.seeded: try: seed = os.urandom(16) except StandardError: try: r = file('/dev/urandom', 'r', 0) try: seed = r.read(16) finally: r.close() except StandardError: seed = str(time.time()) self.seeded = True self.stir(seed, True) def random_8(self): self.lock.acquire() self._maybe_seed() try: if self.digest is None or self.next_byte == self.hash_len: self.hash.update(self.pool) self.digest = self.hash.digest() self.stir(self.digest, True) self.next_byte = 0 value = ord(self.digest[self.next_byte]) self.next_byte += 1 finally: self.lock.release() return value def random_16(self): return self.random_8() * 256 + self.random_8() def random_32(self): return self.random_16() * 65536 + self.random_16() def random_between(self, first, last): size = last - first + 1 if size > 4294967296L: raise ValueError('too big') if size > 65536: rand = self.random_32 max = 4294967295L elif size > 256: rand = self.random_16 max = 65535 else: rand = self.random_8 max = 255 return (first + size * rand() // (max + 1)) pool = EntropyPool() def random_16(): return pool.random_16() def between(first, last): return pool.random_between(first, last) LinkChecker-9.3/third_party/dnspython/dns/message.py0000644000175000017500000012046411570774061023501 0ustar calvincalvin00000000000000# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS Messages""" import cStringIO import random import struct import sys import time import dns.edns import dns.exception import dns.flags import dns.name import dns.opcode import dns.entropy import dns.rcode import dns.rdata import dns.rdataclass import dns.rdatatype import dns.rrset import dns.renderer import dns.tsig import dns.wiredata class ShortHeader(dns.exception.FormError): """Raised if the DNS packet passed to from_wire() is too short.""" pass class TrailingJunk(dns.exception.FormError): """Raised if the DNS packet passed to from_wire() has extra junk at the end of it.""" pass class UnknownHeaderField(dns.exception.DNSException): """Raised if a header field name is not recognized when converting from text into a message.""" pass class BadEDNS(dns.exception.FormError): """Raised if an OPT record occurs somewhere other than the start of the additional data section.""" pass class BadTSIG(dns.exception.FormError): """Raised if a TSIG record occurs somewhere other than the end of the additional data section.""" pass class UnknownTSIGKey(dns.exception.DNSException): """Raised if we got a TSIG but don't know the key.""" pass class Message(object): """A DNS message. @ivar id: The query id; the default is a randomly chosen id. @type id: int @ivar flags: The DNS flags of the message. @see: RFC 1035 for an explanation of these flags. @type flags: int @ivar question: The question section. @type question: list of dns.rrset.RRset objects @ivar answer: The answer section. @type answer: list of dns.rrset.RRset objects @ivar authority: The authority section. @type authority: list of dns.rrset.RRset objects @ivar additional: The additional data section. @type additional: list of dns.rrset.RRset objects @ivar edns: The EDNS level to use. The default is -1, no Edns. @type edns: int @ivar ednsflags: The EDNS flags @type ednsflags: long @ivar payload: The EDNS payload size. The default is 0. @type payload: int @ivar options: The EDNS options @type options: list of dns.edns.Option objects @ivar request_payload: The associated request's EDNS payload size. @type request_payload: int @ivar keyring: The TSIG keyring to use. The default is None. @type keyring: dict @ivar keyname: The TSIG keyname to use. The default is None. @type keyname: dns.name.Name object @ivar keyalgorithm: The TSIG algorithm to use; defaults to dns.tsig.default_algorithm. Constants for TSIG algorithms are defined in dns.tsig, and the currently implemented algorithms are HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and HMAC_SHA512. @type keyalgorithm: string @ivar request_mac: The TSIG MAC of the request message associated with this message; used when validating TSIG signatures. @see: RFC 2845 for more information on TSIG fields. @type request_mac: string @ivar fudge: TSIG time fudge; default is 300 seconds. @type fudge: int @ivar original_id: TSIG original id; defaults to the message's id @type original_id: int @ivar tsig_error: TSIG error code; default is 0. @type tsig_error: int @ivar other_data: TSIG other data. @type other_data: string @ivar mac: The TSIG MAC for this message. @type mac: string @ivar xfr: Is the message being used to contain the results of a DNS zone transfer? The default is False. @type xfr: bool @ivar origin: The origin of the zone in messages which are used for zone transfers or for DNS dynamic updates. The default is None. @type origin: dns.name.Name object @ivar tsig_ctx: The TSIG signature context associated with this message. The default is None. @type tsig_ctx: hmac.HMAC object @ivar had_tsig: Did the message decoded from wire format have a TSIG signature? @type had_tsig: bool @ivar multi: Is this message part of a multi-message sequence? The default is false. This variable is used when validating TSIG signatures on messages which are part of a zone transfer. @type multi: bool @ivar first: Is this message standalone, or the first of a multi message sequence? This variable is used when validating TSIG signatures on messages which are part of a zone transfer. @type first: bool @ivar index: An index of rrsets in the message. The index key is (section, name, rdclass, rdtype, covers, deleting). Indexing can be disabled by setting the index to None. @type index: dict """ def __init__(self, id=None): if id is None: self.id = dns.entropy.random_16() else: self.id = id self.flags = 0 self.question = [] self.answer = [] self.authority = [] self.additional = [] self.edns = -1 self.ednsflags = 0 self.payload = 0 self.options = [] self.request_payload = 0 self.keyring = None self.keyname = None self.keyalgorithm = dns.tsig.default_algorithm self.request_mac = '' self.other_data = '' self.tsig_error = 0 self.fudge = 300 self.original_id = self.id self.mac = '' self.xfr = False self.origin = None self.tsig_ctx = None self.had_tsig = False self.multi = False self.first = True self.index = {} def __repr__(self): return '' def __str__(self): return self.to_text() def to_text(self, origin=None, relativize=True, **kw): """Convert the message to text. The I{origin}, I{relativize}, and any other keyword arguments are passed to the rrset to_wire() method. @rtype: string """ s = cStringIO.StringIO() print >> s, 'id %d' % self.id print >> s, 'opcode %s' % \ dns.opcode.to_text(dns.opcode.from_flags(self.flags)) rc = dns.rcode.from_flags(self.flags, self.ednsflags) print >> s, 'rcode %s' % dns.rcode.to_text(rc) print >> s, 'flags %s' % dns.flags.to_text(self.flags) if self.edns >= 0: print >> s, 'edns %s' % self.edns if self.ednsflags != 0: print >> s, 'eflags %s' % \ dns.flags.edns_to_text(self.ednsflags) print >> s, 'payload', self.payload is_update = dns.opcode.is_update(self.flags) if is_update: print >> s, ';ZONE' else: print >> s, ';QUESTION' for rrset in self.question: print >> s, rrset.to_text(origin, relativize, **kw) if is_update: print >> s, ';PREREQ' else: print >> s, ';ANSWER' for rrset in self.answer: print >> s, rrset.to_text(origin, relativize, **kw) if is_update: print >> s, ';UPDATE' else: print >> s, ';AUTHORITY' for rrset in self.authority: print >> s, rrset.to_text(origin, relativize, **kw) print >> s, ';ADDITIONAL' for rrset in self.additional: print >> s, rrset.to_text(origin, relativize, **kw) # # We strip off the final \n so the caller can print the result without # doing weird things to get around eccentricities in Python print # formatting # return s.getvalue()[:-1] def __eq__(self, other): """Two messages are equal if they have the same content in the header, question, answer, and authority sections. @rtype: bool""" if not isinstance(other, Message): return False if self.id != other.id: return False if self.flags != other.flags: return False for n in self.question: if n not in other.question: return False for n in other.question: if n not in self.question: return False for n in self.answer: if n not in other.answer: return False for n in other.answer: if n not in self.answer: return False for n in self.authority: if n not in other.authority: return False for n in other.authority: if n not in self.authority: return False return True def __ne__(self, other): """Are two messages not equal? @rtype: bool""" return not self.__eq__(other) def is_response(self, other): """Is other a response to self? @rtype: bool""" if other.flags & dns.flags.QR == 0 or \ self.id != other.id or \ dns.opcode.from_flags(self.flags) != \ dns.opcode.from_flags(other.flags): return False if dns.rcode.from_flags(other.flags, other.ednsflags) != \ dns.rcode.NOERROR: return True if dns.opcode.is_update(self.flags): return True for n in self.question: if n not in other.question: return False for n in other.question: if n not in self.question: return False return True def section_number(self, section): if section is self.question: return 0 elif section is self.answer: return 1 elif section is self.authority: return 2 elif section is self.additional: return 3 else: raise ValueError('unknown section') def find_rrset(self, section, name, rdclass, rdtype, covers=dns.rdatatype.NONE, deleting=None, create=False, force_unique=False): """Find the RRset with the given attributes in the specified section. @param section: the section of the message to look in, e.g. self.answer. @type section: list of dns.rrset.RRset objects @param name: the name of the RRset @type name: dns.name.Name object @param rdclass: the class of the RRset @type rdclass: int @param rdtype: the type of the RRset @type rdtype: int @param covers: the covers value of the RRset @type covers: int @param deleting: the deleting value of the RRset @type deleting: int @param create: If True, create the RRset if it is not found. The created RRset is appended to I{section}. @type create: bool @param force_unique: If True and create is also True, create a new RRset regardless of whether a matching RRset exists already. @type force_unique: bool @raises KeyError: the RRset was not found and create was False @rtype: dns.rrset.RRset object""" key = (self.section_number(section), name, rdclass, rdtype, covers, deleting) if not force_unique: if not self.index is None: rrset = self.index.get(key) if not rrset is None: return rrset else: for rrset in section: if rrset.match(name, rdclass, rdtype, covers, deleting): return rrset if not create: raise KeyError rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting) section.append(rrset) if not self.index is None: self.index[key] = rrset return rrset def get_rrset(self, section, name, rdclass, rdtype, covers=dns.rdatatype.NONE, deleting=None, create=False, force_unique=False): """Get the RRset with the given attributes in the specified section. If the RRset is not found, None is returned. @param section: the section of the message to look in, e.g. self.answer. @type section: list of dns.rrset.RRset objects @param name: the name of the RRset @type name: dns.name.Name object @param rdclass: the class of the RRset @type rdclass: int @param rdtype: the type of the RRset @type rdtype: int @param covers: the covers value of the RRset @type covers: int @param deleting: the deleting value of the RRset @type deleting: int @param create: If True, create the RRset if it is not found. The created RRset is appended to I{section}. @type create: bool @param force_unique: If True and create is also True, create a new RRset regardless of whether a matching RRset exists already. @type force_unique: bool @rtype: dns.rrset.RRset object or None""" try: rrset = self.find_rrset(section, name, rdclass, rdtype, covers, deleting, create, force_unique) except KeyError: rrset = None return rrset def to_wire(self, origin=None, max_size=0, **kw): """Return a string containing the message in DNS compressed wire format. Additional keyword arguments are passed to the rrset to_wire() method. @param origin: The origin to be appended to any relative names. @type origin: dns.name.Name object @param max_size: The maximum size of the wire format output; default is 0, which means 'the message's request payload, if nonzero, or 65536'. @type max_size: int @raises dns.exception.TooBig: max_size was exceeded @rtype: string """ if max_size == 0: if self.request_payload != 0: max_size = self.request_payload else: max_size = 65535 if max_size < 512: max_size = 512 elif max_size > 65535: max_size = 65535 r = dns.renderer.Renderer(self.id, self.flags, max_size, origin) for rrset in self.question: r.add_question(rrset.name, rrset.rdtype, rrset.rdclass) for rrset in self.answer: r.add_rrset(dns.renderer.ANSWER, rrset, **kw) for rrset in self.authority: r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw) if self.edns >= 0: r.add_edns(self.edns, self.ednsflags, self.payload, self.options) for rrset in self.additional: r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw) r.write_header() if not self.keyname is None: r.add_tsig(self.keyname, self.keyring[self.keyname], self.fudge, self.original_id, self.tsig_error, self.other_data, self.request_mac, self.keyalgorithm) self.mac = r.mac return r.get_wire() def use_tsig(self, keyring, keyname=None, fudge=300, original_id=None, tsig_error=0, other_data='', algorithm=dns.tsig.default_algorithm): """When sending, a TSIG signature using the specified keyring and keyname should be added. @param keyring: The TSIG keyring to use; defaults to None. @type keyring: dict @param keyname: The name of the TSIG key to use; defaults to None. The key must be defined in the keyring. If a keyring is specified but a keyname is not, then the key used will be the first key in the keyring. Note that the order of keys in a dictionary is not defined, so applications should supply a keyname when a keyring is used, unless they know the keyring contains only one key. @type keyname: dns.name.Name or string @param fudge: TSIG time fudge; default is 300 seconds. @type fudge: int @param original_id: TSIG original id; defaults to the message's id @type original_id: int @param tsig_error: TSIG error code; default is 0. @type tsig_error: int @param other_data: TSIG other data. @type other_data: string @param algorithm: The TSIG algorithm to use; defaults to dns.tsig.default_algorithm """ self.keyring = keyring if keyname is None: self.keyname = self.keyring.keys()[0] else: if isinstance(keyname, (str, unicode)): keyname = dns.name.from_text(keyname) self.keyname = keyname self.keyalgorithm = algorithm self.fudge = fudge if original_id is None: self.original_id = self.id else: self.original_id = original_id self.tsig_error = tsig_error self.other_data = other_data def use_edns(self, edns=0, ednsflags=0, payload=1280, request_payload=None, options=None): """Configure EDNS behavior. @param edns: The EDNS level to use. Specifying None, False, or -1 means 'do not use EDNS', and in this case the other parameters are ignored. Specifying True is equivalent to specifying 0, i.e. 'use EDNS0'. @type edns: int or bool or None @param ednsflags: EDNS flag values. @type ednsflags: int @param payload: The EDNS sender's payload field, which is the maximum size of UDP datagram the sender can handle. @type payload: int @param request_payload: The EDNS payload size to use when sending this message. If not specified, defaults to the value of payload. @type request_payload: int or None @param options: The EDNS options @type options: None or list of dns.edns.Option objects @see: RFC 2671 """ if edns is None or edns is False: edns = -1 if edns is True: edns = 0 if request_payload is None: request_payload = payload if edns < 0: ednsflags = 0 payload = 0 request_payload = 0 options = [] else: # make sure the EDNS version in ednsflags agrees with edns ednsflags &= 0xFF00FFFFL ednsflags |= (edns << 16) if options is None: options = [] self.edns = edns self.ednsflags = ednsflags self.payload = payload self.options = options self.request_payload = request_payload def want_dnssec(self, wanted=True): """Enable or disable 'DNSSEC desired' flag in requests. @param wanted: Is DNSSEC desired? If True, EDNS is enabled if required, and then the DO bit is set. If False, the DO bit is cleared if EDNS is enabled. @type wanted: bool """ if wanted: if self.edns < 0: self.use_edns() self.ednsflags |= dns.flags.DO elif self.edns >= 0: self.ednsflags &= ~dns.flags.DO def rcode(self): """Return the rcode. @rtype: int """ return dns.rcode.from_flags(self.flags, self.ednsflags) def set_rcode(self, rcode): """Set the rcode. @param rcode: the rcode @type rcode: int """ (value, evalue) = dns.rcode.to_flags(rcode) self.flags &= 0xFFF0 self.flags |= value self.ednsflags &= 0x00FFFFFFL self.ednsflags |= evalue if self.ednsflags != 0 and self.edns < 0: self.edns = 0 def opcode(self): """Return the opcode. @rtype: int """ return dns.opcode.from_flags(self.flags) def set_opcode(self, opcode): """Set the opcode. @param opcode: the opcode @type opcode: int """ self.flags &= 0x87FF self.flags |= dns.opcode.to_flags(opcode) class _WireReader(object): """Wire format reader. @ivar wire: the wire-format message. @type wire: string @ivar message: The message object being built @type message: dns.message.Message object @ivar current: When building a message object from wire format, this variable contains the offset from the beginning of wire of the next octet to be read. @type current: int @ivar updating: Is the message a dynamic update? @type updating: bool @ivar one_rr_per_rrset: Put each RR into its own RRset? @type one_rr_per_rrset: bool @ivar zone_rdclass: The class of the zone in messages which are DNS dynamic updates. @type zone_rdclass: int """ def __init__(self, wire, message, question_only=False, one_rr_per_rrset=False): self.wire = dns.wiredata.maybe_wrap(wire) self.message = message self.current = 0 self.updating = False self.zone_rdclass = dns.rdataclass.IN self.question_only = question_only self.one_rr_per_rrset = one_rr_per_rrset def _get_question(self, qcount): """Read the next I{qcount} records from the wire data and add them to the question section. @param qcount: the number of questions in the message @type qcount: int""" if self.updating and qcount > 1: raise dns.exception.FormError for i in xrange(0, qcount): (qname, used) = dns.name.from_wire(self.wire, self.current) if not self.message.origin is None: qname = qname.relativize(self.message.origin) self.current = self.current + used (rdtype, rdclass) = \ struct.unpack('!HH', self.wire[self.current:self.current + 4]) self.current = self.current + 4 self.message.find_rrset(self.message.question, qname, rdclass, rdtype, create=True, force_unique=True) if self.updating: self.zone_rdclass = rdclass 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 def read(self): """Read a wire format DNS message and build a dns.message.Message object.""" l = len(self.wire) if l < 12: raise ShortHeader (self.message.id, self.message.flags, qcount, ancount, aucount, adcount) = struct.unpack('!HHHHHH', self.wire[:12]) self.current = 12 if dns.opcode.is_update(self.message.flags): self.updating = True self._get_question(qcount) if self.question_only: return self._get_section(self.message.answer, ancount) self._get_section(self.message.authority, aucount) self._get_section(self.message.additional, adcount) if self.current != l: raise TrailingJunk if self.message.multi and self.message.tsig_ctx and \ not self.message.had_tsig: self.message.tsig_ctx.update(self.wire) def from_wire(wire, keyring=None, request_mac='', xfr=False, origin=None, tsig_ctx = None, multi = False, first = True, question_only = False, one_rr_per_rrset = False): """Convert a DNS wire format message into a message object. @param keyring: The keyring to use if the message is signed. @type keyring: dict @param request_mac: If the message is a response to a TSIG-signed request, I{request_mac} should be set to the MAC of that request. @type request_mac: string @param xfr: Is this message part of a zone transfer? @type xfr: bool @param origin: If the message is part of a zone transfer, I{origin} should be the origin name of the zone. @type origin: dns.name.Name object @param tsig_ctx: The ongoing TSIG context, used when validating zone transfers. @type tsig_ctx: hmac.HMAC object @param multi: Is this message part of a multiple message sequence? @type multi: bool @param first: Is this message standalone, or the first of a multi message sequence? @type first: bool @param question_only: Read only up to the end of the question section? @type question_only: bool @param one_rr_per_rrset: Put each RR into its own RRset @type one_rr_per_rrset: bool @raises ShortHeader: The message is less than 12 octets long. @raises TrailingJunk: There were octets in the message past the end of the proper DNS message. @raises BadEDNS: An OPT record was in the wrong section, or occurred more than once. @raises BadTSIG: A TSIG record was not the last record of the additional data section. @rtype: dns.message.Message object""" m = Message(id=0) m.keyring = keyring m.request_mac = request_mac m.xfr = xfr m.origin = origin m.tsig_ctx = tsig_ctx m.multi = multi m.first = first reader = _WireReader(wire, m, question_only, one_rr_per_rrset) reader.read() return m class _TextReader(object): """Text format reader. @ivar tok: the tokenizer @type tok: dns.tokenizer.Tokenizer object @ivar message: The message object being built @type message: dns.message.Message object @ivar updating: Is the message a dynamic update? @type updating: bool @ivar zone_rdclass: The class of the zone in messages which are DNS dynamic updates. @type zone_rdclass: int @ivar last_name: The most recently read name when building a message object from text format. @type last_name: dns.name.Name object """ def __init__(self, text, message): self.message = message self.tok = dns.tokenizer.Tokenizer(text) self.last_name = None self.zone_rdclass = dns.rdataclass.IN self.updating = False def _header_line(self, section): """Process one line from the text format header section.""" token = self.tok.get() what = token.value if what == 'id': self.message.id = self.tok.get_int() elif what == 'flags': while True: token = self.tok.get() if not token.is_identifier(): self.tok.unget(token) break self.message.flags = self.message.flags | \ dns.flags.from_text(token.value) if dns.opcode.is_update(self.message.flags): self.updating = True elif what == 'edns': self.message.edns = self.tok.get_int() self.message.ednsflags = self.message.ednsflags | \ (self.message.edns << 16) elif what == 'eflags': if self.message.edns < 0: self.message.edns = 0 while True: token = self.tok.get() if not token.is_identifier(): self.tok.unget(token) break self.message.ednsflags = self.message.ednsflags | \ dns.flags.edns_from_text(token.value) elif what == 'payload': self.message.payload = self.tok.get_int() if self.message.edns < 0: self.message.edns = 0 elif what == 'opcode': text = self.tok.get_string() self.message.flags = self.message.flags | \ dns.opcode.to_flags(dns.opcode.from_text(text)) elif what == 'rcode': text = self.tok.get_string() self.message.set_rcode(dns.rcode.from_text(text)) else: raise UnknownHeaderField self.tok.get_eol() def _question_line(self, section): """Process one line from the text format question section.""" token = self.tok.get(want_leading = True) if not token.is_whitespace(): self.last_name = dns.name.from_text(token.value, None) name = self.last_name token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError # 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 StandardError: rdclass = dns.rdataclass.IN # Type rdtype = dns.rdatatype.from_text(token.value) self.message.find_rrset(self.message.question, name, rdclass, rdtype, create=True, force_unique=True) if self.updating: self.zone_rdclass = rdclass self.tok.get_eol() def _rr_line(self, section): """Process one line from the text format answer, authority, or additional data sections. """ deleting = None # Name token = self.tok.get(want_leading = True) if not token.is_whitespace(): self.last_name = dns.name.from_text(token.value, None) name = self.last_name token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError # TTL try: ttl = int(token.value, 0) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError except StandardError: ttl = 0 # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError if rdclass == dns.rdataclass.ANY or rdclass == dns.rdataclass.NONE: deleting = rdclass rdclass = self.zone_rdclass except dns.exception.SyntaxError: raise dns.exception.SyntaxError except StandardError: rdclass = dns.rdataclass.IN # Type rdtype = dns.rdatatype.from_text(token.value) token = self.tok.get() if not token.is_eol_or_eof(): self.tok.unget(token) rd = dns.rdata.from_text(rdclass, rdtype, self.tok, None) covers = rd.covers() else: rd = None covers = dns.rdatatype.NONE rrset = self.message.find_rrset(section, name, rdclass, rdtype, covers, deleting, True, self.updating) if not rd is None: rrset.add(rd, ttl) def read(self): """Read a text format DNS message and build a dns.message.Message object.""" line_method = self._header_line section = None while 1: token = self.tok.get(True, True) if token.is_eol_or_eof(): break if token.is_comment(): u = token.value.upper() if u == 'HEADER': line_method = self._header_line elif u == 'QUESTION' or u == 'ZONE': line_method = self._question_line section = self.message.question elif u == 'ANSWER' or u == 'PREREQ': line_method = self._rr_line section = self.message.answer elif u == 'AUTHORITY' or u == 'UPDATE': line_method = self._rr_line section = self.message.authority elif u == 'ADDITIONAL': line_method = self._rr_line section = self.message.additional self.tok.get_eol() continue self.tok.unget(token) line_method(section) def from_text(text): """Convert the text format message into a message object. @param text: The text format message. @type text: string @raises UnknownHeaderField: @raises dns.exception.SyntaxError: @rtype: dns.message.Message object""" # 'text' can also be a file, but we don't publish that fact # since it's an implementation detail. The official file # interface is from_file(). m = Message() reader = _TextReader(text, m) reader.read() return m def from_file(f): """Read the next text format message from the specified file. @param f: file or string. If I{f} is a string, it is treated as the name of a file to open. @raises UnknownHeaderField: @raises dns.exception.SyntaxError: @rtype: dns.message.Message object""" if sys.hexversion >= 0x02030000: # allow Unicode filenames; turn on universal newline support str_type = basestring opts = 'rU' else: str_type = str opts = 'r' if isinstance(f, str_type): f = file(f, opts) want_close = True else: want_close = False try: m = from_text(f) finally: if want_close: f.close() return m def make_query(qname, rdtype, rdclass = dns.rdataclass.IN, use_edns=None, want_dnssec=False): """Make a query message. The query name, type, and class may all be specified either as objects of the appropriate type, or as strings. The query will have a randomly choosen query id, and its DNS flags will be set to dns.flags.RD. @param qname: The query name. @type qname: dns.name.Name object or string @param rdtype: The desired rdata type. @type rdtype: int @param rdclass: The desired rdata class; the default is class IN. @type rdclass: int @param use_edns: The EDNS level to use; the default is None (no EDNS). See the description of dns.message.Message.use_edns() for the possible values for use_edns and their meanings. @type use_edns: int or bool or None @param want_dnssec: Should the query indicate that DNSSEC is desired? @type want_dnssec: bool @rtype: dns.message.Message object""" if isinstance(qname, (str, unicode)): qname = dns.name.from_text(qname) if isinstance(rdtype, (str, unicode)): rdtype = dns.rdatatype.from_text(rdtype) if isinstance(rdclass, (str, unicode)): rdclass = dns.rdataclass.from_text(rdclass) m = Message() m.flags |= dns.flags.RD m.find_rrset(m.question, qname, rdclass, rdtype, create=True, force_unique=True) m.use_edns(use_edns) m.want_dnssec(want_dnssec) return m def make_response(query, recursion_available=False, our_payload=8192): """Make a message which is a response for the specified query. The message returned is really a response skeleton; it has all of the infrastructure required of a response, but none of the content. The response's question section is a shallow copy of the query's question section, so the query's question RRsets should not be changed. @param query: the query to respond to @type query: dns.message.Message object @param recursion_available: should RA be set in the response? @type recursion_available: bool @param our_payload: payload size to advertise in EDNS responses; default is 8192. @type our_payload: int @rtype: dns.message.Message object""" if query.flags & dns.flags.QR: raise dns.exception.FormError('specified query message is not a query') response = dns.message.Message(query.id) response.flags = dns.flags.QR | (query.flags & dns.flags.RD) if recursion_available: response.flags |= dns.flags.RA response.set_opcode(query.opcode()) response.question = list(query.question) if query.edns >= 0: response.use_edns(0, 0, our_payload, query.payload) if not query.keyname is None: response.keyname = query.keyname response.keyring = query.keyring response.request_mac = query.mac return response LinkChecker-9.3/third_party/dnspython/dns/namedict.py0000644000175000017500000000406411570774061023636 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """DNS name dictionary""" import dns.name class NameDict(dict): """A dictionary whose keys are dns.name.Name objects. @ivar max_depth: the maximum depth of the keys that have ever been added to the dictionary. @type max_depth: int """ def __init__(self, *args, **kwargs): super(NameDict, self).__init__(*args, **kwargs) self.max_depth = 0 def __setitem__(self, key, value): if not isinstance(key, dns.name.Name): raise ValueError('NameDict key must be a name') depth = len(key) if depth > self.max_depth: self.max_depth = depth super(NameDict, self).__setitem__(key, value) def get_deepest_match(self, name): """Find the deepest match to I{name} in the dictionary. The deepest match is the longest name in the dictionary which is a superdomain of I{name}. @param name: the name @type name: dns.name.Name object @rtype: (key, value) tuple """ depth = len(name) if depth > self.max_depth: depth = self.max_depth for i in xrange(-depth, 0): n = dns.name.Name(name[i:]) if n in self: return (n, self[n]) v = self[dns.name.empty] return (dns.name.empty, v) LinkChecker-9.3/third_party/dnspython/changelog.txt0000644000175000017500000000130311570774060023374 0ustar calvincalvin00000000000000The following changes were made to the original dnspython sources: * Replace bare "except:" with "except StandardError:" and make DNSException inherit from StandardError. Avoids catching StopIteration and Warning exceptions. Changed: *.py * Replace "x.has_key(y)" with "y in x". Changed: *.py * honor EnableDHCP flag in Windows registry config and add __str__() method Changed: resolver.py * strip() lines from /etc/resolv.conf Changed: resolver.py * added set of localhost addresses to resolver config Changed: resolver.py Added: ifconfig.py * added search patterns for domain names Changed: resolver.py * Replaced tabs with spaces, remove trailing whitespace. Changed: *.py LinkChecker-9.3/third_party/dnspython/tests/0000750000175000017500000000000012361541761022043 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/dnspython/tests/name.py0000644000175000017500000006054111570774060023351 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import cStringIO import socket import dns.name import dns.reversename import dns.e164 class NameTestCase(unittest.TestCase): def setUp(self): self.origin = dns.name.from_text('example.') def testFromTextRel1(self): n = dns.name.from_text('foo.bar') self.failUnless(n.labels == ('foo', 'bar', '')) def testFromTextRel2(self): n = dns.name.from_text('foo.bar', origin=self.origin) self.failUnless(n.labels == ('foo', 'bar', 'example', '')) def testFromTextRel3(self): n = dns.name.from_text('foo.bar', origin=None) self.failUnless(n.labels == ('foo', 'bar')) def testFromTextRel4(self): n = dns.name.from_text('@', origin=None) self.failUnless(n == dns.name.empty) def testFromTextRel5(self): n = dns.name.from_text('@', origin=self.origin) self.failUnless(n == self.origin) def testFromTextAbs1(self): n = dns.name.from_text('foo.bar.') self.failUnless(n.labels == ('foo', 'bar', '')) def testTortureFromText(self): good = [ r'.', r'a', r'a.', r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', r'\000.\008.\010.\032.\046.\092.\099.\255', r'\\', r'\..\.', r'\\.\\', r'!"#%&/()=+-', r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', ] bad = [ r'..', r'.a', r'\\..', '\\', # yes, we don't want the 'r' prefix! r'\0', r'\00', r'\00Z', r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', r'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', r'\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255.\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255', ] for t in good: try: n = dns.name.from_text(t) except: self.fail("good test '%s' raised an exception" % t) for t in bad: caught = False try: n = dns.name.from_text(t) except: caught = True if not caught: self.fail("bad test '%s' did not raise an exception" % t) def testImmutable1(self): def bad(): self.origin.labels = () self.failUnlessRaises(TypeError, bad) def testImmutable2(self): def bad(): self.origin.labels[0] = 'foo' self.failUnlessRaises(TypeError, bad) def testAbs1(self): self.failUnless(dns.name.root.is_absolute()) def testAbs2(self): self.failUnless(not dns.name.empty.is_absolute()) def testAbs3(self): self.failUnless(self.origin.is_absolute()) def testAbs3(self): n = dns.name.from_text('foo', origin=None) self.failUnless(not n.is_absolute()) def testWild1(self): n = dns.name.from_text('*.foo', origin=None) self.failUnless(n.is_wild()) def testWild2(self): n = dns.name.from_text('*a.foo', origin=None) self.failUnless(not n.is_wild()) def testWild3(self): n = dns.name.from_text('a.*.foo', origin=None) self.failUnless(not n.is_wild()) def testWild4(self): self.failUnless(not dns.name.root.is_wild()) def testWild5(self): self.failUnless(not dns.name.empty.is_wild()) def testHash1(self): n1 = dns.name.from_text('fOo.COM') n2 = dns.name.from_text('foo.com') self.failUnless(hash(n1) == hash(n2)) def testCompare1(self): n1 = dns.name.from_text('a') n2 = dns.name.from_text('b') self.failUnless(n1 < n2) self.failUnless(n2 > n1) def testCompare2(self): n1 = dns.name.from_text('') n2 = dns.name.from_text('b') self.failUnless(n1 < n2) self.failUnless(n2 > n1) def testCompare3(self): self.failUnless(dns.name.empty < dns.name.root) self.failUnless(dns.name.root > dns.name.empty) def testCompare4(self): self.failUnless(dns.name.root != 1) def testCompare5(self): self.failUnless(dns.name.root < 1 or dns.name.root > 1) def testSubdomain1(self): self.failUnless(not dns.name.empty.is_subdomain(dns.name.root)) def testSubdomain2(self): self.failUnless(not dns.name.root.is_subdomain(dns.name.empty)) def testSubdomain3(self): n = dns.name.from_text('foo', origin=self.origin) self.failUnless(n.is_subdomain(self.origin)) def testSubdomain4(self): n = dns.name.from_text('foo', origin=self.origin) self.failUnless(n.is_subdomain(dns.name.root)) def testSubdomain5(self): n = dns.name.from_text('foo', origin=self.origin) self.failUnless(n.is_subdomain(n)) def testSuperdomain1(self): self.failUnless(not dns.name.empty.is_superdomain(dns.name.root)) def testSuperdomain2(self): self.failUnless(not dns.name.root.is_superdomain(dns.name.empty)) def testSuperdomain3(self): n = dns.name.from_text('foo', origin=self.origin) self.failUnless(self.origin.is_superdomain(n)) def testSuperdomain4(self): n = dns.name.from_text('foo', origin=self.origin) self.failUnless(dns.name.root.is_superdomain(n)) def testSuperdomain5(self): n = dns.name.from_text('foo', origin=self.origin) self.failUnless(n.is_superdomain(n)) def testCanonicalize1(self): n = dns.name.from_text('FOO.bar', origin=self.origin) c = n.canonicalize() self.failUnless(c.labels == ('foo', 'bar', 'example', '')) def testToText1(self): n = dns.name.from_text('FOO.bar', origin=self.origin) t = n.to_text() self.failUnless(t == 'FOO.bar.example.') def testToText2(self): n = dns.name.from_text('FOO.bar', origin=self.origin) t = n.to_text(True) self.failUnless(t == 'FOO.bar.example') def testToText3(self): n = dns.name.from_text('FOO.bar', origin=None) t = n.to_text() self.failUnless(t == 'FOO.bar') def testToText4(self): t = dns.name.empty.to_text() self.failUnless(t == '@') def testToText5(self): t = dns.name.root.to_text() self.failUnless(t == '.') def testToText6(self): n = dns.name.from_text('FOO bar', origin=None) t = n.to_text() self.failUnless(t == r'FOO\032bar') def testToText7(self): n = dns.name.from_text(r'FOO\.bar', origin=None) t = n.to_text() self.failUnless(t == r'FOO\.bar') def testToText8(self): n = dns.name.from_text(r'\070OO\.bar', origin=None) t = n.to_text() self.failUnless(t == r'FOO\.bar') def testSlice1(self): n = dns.name.from_text(r'a.b.c.', origin=None) s = n[:] self.failUnless(s == ('a', 'b', 'c', '')) def testSlice2(self): n = dns.name.from_text(r'a.b.c.', origin=None) s = n[:2] self.failUnless(s == ('a', 'b')) def testSlice3(self): n = dns.name.from_text(r'a.b.c.', origin=None) s = n[2:] self.failUnless(s == ('c', '')) def testEmptyLabel1(self): def bad(): n = dns.name.Name(['a', '', 'b']) self.failUnlessRaises(dns.name.EmptyLabel, bad) def testEmptyLabel2(self): def bad(): n = dns.name.Name(['', 'b']) self.failUnlessRaises(dns.name.EmptyLabel, bad) def testEmptyLabel3(self): n = dns.name.Name(['b', '']) self.failUnless(n) def testLongLabel(self): n = dns.name.Name(['a' * 63]) self.failUnless(n) def testLabelTooLong(self): def bad(): n = dns.name.Name(['a' * 64, 'b']) self.failUnlessRaises(dns.name.LabelTooLong, bad) def testLongName(self): n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 62]) self.failUnless(n) def testNameTooLong(self): def bad(): n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 63]) self.failUnlessRaises(dns.name.NameTooLong, bad) def testConcat1(self): n1 = dns.name.Name(['a', 'b']) n2 = dns.name.Name(['c', 'd']) e = dns.name.Name(['a', 'b', 'c', 'd']) r = n1 + n2 self.failUnless(r == e) def testConcat2(self): n1 = dns.name.Name(['a', 'b']) n2 = dns.name.Name([]) e = dns.name.Name(['a', 'b']) r = n1 + n2 self.failUnless(r == e) def testConcat2(self): n1 = dns.name.Name([]) n2 = dns.name.Name(['a', 'b']) e = dns.name.Name(['a', 'b']) r = n1 + n2 self.failUnless(r == e) def testConcat3(self): n1 = dns.name.Name(['a', 'b', '']) n2 = dns.name.Name([]) e = dns.name.Name(['a', 'b', '']) r = n1 + n2 self.failUnless(r == e) def testConcat4(self): n1 = dns.name.Name(['a', 'b']) n2 = dns.name.Name(['c', '']) e = dns.name.Name(['a', 'b', 'c', '']) r = n1 + n2 self.failUnless(r == e) def testConcat5(self): def bad(): n1 = dns.name.Name(['a', 'b', '']) n2 = dns.name.Name(['c']) r = n1 + n2 self.failUnlessRaises(dns.name.AbsoluteConcatenation, bad) def testBadEscape(self): def bad(): n = dns.name.from_text(r'a.b\0q1.c.') print n self.failUnlessRaises(dns.name.BadEscape, bad) def testDigestable1(self): n = dns.name.from_text('FOO.bar') d = n.to_digestable() self.failUnless(d == '\x03foo\x03bar\x00') def testDigestable2(self): n1 = dns.name.from_text('FOO.bar') n2 = dns.name.from_text('foo.BAR.') d1 = n1.to_digestable() d2 = n2.to_digestable() self.failUnless(d1 == d2) def testDigestable3(self): d = dns.name.root.to_digestable() self.failUnless(d == '\x00') def testDigestable4(self): n = dns.name.from_text('FOO.bar', None) d = n.to_digestable(dns.name.root) self.failUnless(d == '\x03foo\x03bar\x00') def testBadDigestable(self): def bad(): n = dns.name.from_text('FOO.bar', None) d = n.to_digestable() self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) def testToWire1(self): n = dns.name.from_text('FOO.bar') f = cStringIO.StringIO() compress = {} n.to_wire(f, compress) self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00') def testToWire2(self): n = dns.name.from_text('FOO.bar') f = cStringIO.StringIO() compress = {} n.to_wire(f, compress) n.to_wire(f, compress) self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\xc0\x00') def testToWire3(self): n1 = dns.name.from_text('FOO.bar') n2 = dns.name.from_text('foo.bar') f = cStringIO.StringIO() compress = {} n1.to_wire(f, compress) n2.to_wire(f, compress) self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\xc0\x00') def testToWire4(self): n1 = dns.name.from_text('FOO.bar') n2 = dns.name.from_text('a.foo.bar') f = cStringIO.StringIO() compress = {} n1.to_wire(f, compress) n2.to_wire(f, compress) self.failUnless(f.getvalue() == '\x03FOO\x03bar\x00\x01\x61\xc0\x00') def testToWire5(self): n1 = dns.name.from_text('FOO.bar') n2 = dns.name.from_text('a.foo.bar') f = cStringIO.StringIO() compress = {} n1.to_wire(f, compress) n2.to_wire(f, None) self.failUnless(f.getvalue() == \ '\x03FOO\x03bar\x00\x01\x61\x03foo\x03bar\x00') def testToWire6(self): n = dns.name.from_text('FOO.bar') v = n.to_wire() self.failUnless(v == '\x03FOO\x03bar\x00') def testBadToWire(self): def bad(): n = dns.name.from_text('FOO.bar', None) f = cStringIO.StringIO() compress = {} n.to_wire(f, compress) self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) def testSplit1(self): n = dns.name.from_text('foo.bar.') (prefix, suffix) = n.split(2) ep = dns.name.from_text('foo', None) es = dns.name.from_text('bar.', None) self.failUnless(prefix == ep and suffix == es) def testSplit2(self): n = dns.name.from_text('foo.bar.') (prefix, suffix) = n.split(1) ep = dns.name.from_text('foo.bar', None) es = dns.name.from_text('.', None) self.failUnless(prefix == ep and suffix == es) def testSplit3(self): n = dns.name.from_text('foo.bar.') (prefix, suffix) = n.split(0) ep = dns.name.from_text('foo.bar.', None) es = dns.name.from_text('', None) self.failUnless(prefix == ep and suffix == es) def testSplit4(self): n = dns.name.from_text('foo.bar.') (prefix, suffix) = n.split(3) ep = dns.name.from_text('', None) es = dns.name.from_text('foo.bar.', None) self.failUnless(prefix == ep and suffix == es) def testBadSplit1(self): def bad(): n = dns.name.from_text('foo.bar.') (prefix, suffix) = n.split(-1) self.failUnlessRaises(ValueError, bad) def testBadSplit2(self): def bad(): n = dns.name.from_text('foo.bar.') (prefix, suffix) = n.split(4) self.failUnlessRaises(ValueError, bad) def testRelativize1(self): n = dns.name.from_text('a.foo.bar.', None) o = dns.name.from_text('bar.', None) e = dns.name.from_text('a.foo', None) self.failUnless(n.relativize(o) == e) def testRelativize2(self): n = dns.name.from_text('a.foo.bar.', None) o = n e = dns.name.empty self.failUnless(n.relativize(o) == e) def testRelativize3(self): n = dns.name.from_text('a.foo.bar.', None) o = dns.name.from_text('blaz.', None) e = n self.failUnless(n.relativize(o) == e) def testRelativize4(self): n = dns.name.from_text('a.foo', None) o = dns.name.root e = n self.failUnless(n.relativize(o) == e) def testDerelativize1(self): n = dns.name.from_text('a.foo', None) o = dns.name.from_text('bar.', None) e = dns.name.from_text('a.foo.bar.', None) self.failUnless(n.derelativize(o) == e) def testDerelativize2(self): n = dns.name.empty o = dns.name.from_text('a.foo.bar.', None) e = o self.failUnless(n.derelativize(o) == e) def testDerelativize3(self): n = dns.name.from_text('a.foo.bar.', None) o = dns.name.from_text('blaz.', None) e = n self.failUnless(n.derelativize(o) == e) def testChooseRelativity1(self): n = dns.name.from_text('a.foo.bar.', None) o = dns.name.from_text('bar.', None) e = dns.name.from_text('a.foo', None) self.failUnless(n.choose_relativity(o, True) == e) def testChooseRelativity2(self): n = dns.name.from_text('a.foo.bar.', None) o = dns.name.from_text('bar.', None) e = n self.failUnless(n.choose_relativity(o, False) == e) def testChooseRelativity3(self): n = dns.name.from_text('a.foo', None) o = dns.name.from_text('bar.', None) e = dns.name.from_text('a.foo.bar.', None) self.failUnless(n.choose_relativity(o, False) == e) def testChooseRelativity4(self): n = dns.name.from_text('a.foo', None) o = None e = n self.failUnless(n.choose_relativity(o, True) == e) def testChooseRelativity5(self): n = dns.name.from_text('a.foo', None) o = None e = n self.failUnless(n.choose_relativity(o, False) == e) def testChooseRelativity6(self): n = dns.name.from_text('a.foo.', None) o = None e = n self.failUnless(n.choose_relativity(o, True) == e) def testChooseRelativity7(self): n = dns.name.from_text('a.foo.', None) o = None e = n self.failUnless(n.choose_relativity(o, False) == e) def testFromWire1(self): w = '\x03foo\x00\xc0\x00' (n1, cused1) = dns.name.from_wire(w, 0) (n2, cused2) = dns.name.from_wire(w, cused1) en1 = dns.name.from_text('foo.') en2 = en1 ecused1 = 5 ecused2 = 2 self.failUnless(n1 == en1 and cused1 == ecused1 and \ n2 == en2 and cused2 == ecused2) def testFromWire1(self): w = '\x03foo\x00\x01a\xc0\x00\x01b\xc0\x05' current = 0 (n1, cused1) = dns.name.from_wire(w, current) current += cused1 (n2, cused2) = dns.name.from_wire(w, current) current += cused2 (n3, cused3) = dns.name.from_wire(w, current) en1 = dns.name.from_text('foo.') en2 = dns.name.from_text('a.foo.') en3 = dns.name.from_text('b.a.foo.') ecused1 = 5 ecused2 = 4 ecused3 = 4 self.failUnless(n1 == en1 and cused1 == ecused1 and \ n2 == en2 and cused2 == ecused2 and \ n3 == en3 and cused3 == ecused3) def testBadFromWire1(self): def bad(): w = '\x03foo\xc0\x04' (n, cused) = dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadPointer, bad) def testBadFromWire2(self): def bad(): w = '\x03foo\xc0\x05' (n, cused) = dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadPointer, bad) def testBadFromWire3(self): def bad(): w = '\xbffoo' (n, cused) = dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadLabelType, bad) def testBadFromWire4(self): def bad(): w = '\x41foo' (n, cused) = dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadLabelType, bad) def testParent1(self): n = dns.name.from_text('foo.bar.') self.failUnless(n.parent() == dns.name.from_text('bar.')) self.failUnless(n.parent().parent() == dns.name.root) def testParent2(self): n = dns.name.from_text('foo.bar', None) self.failUnless(n.parent() == dns.name.from_text('bar', None)) self.failUnless(n.parent().parent() == dns.name.empty) def testParent3(self): def bad(): n = dns.name.root n.parent() self.failUnlessRaises(dns.name.NoParent, bad) def testParent4(self): def bad(): n = dns.name.empty n.parent() self.failUnlessRaises(dns.name.NoParent, bad) def testFromUnicode1(self): n = dns.name.from_text(u'foo.bar') self.failUnless(n.labels == ('foo', 'bar', '')) def testFromUnicode2(self): n = dns.name.from_text(u'foo\u1234bar.bar') self.failUnless(n.labels == ('xn--foobar-r5z', 'bar', '')) def testFromUnicodeAlternateDot1(self): n = dns.name.from_text(u'foo\u3002bar') self.failUnless(n.labels == ('foo', 'bar', '')) def testFromUnicodeAlternateDot2(self): n = dns.name.from_text(u'foo\uff0ebar') self.failUnless(n.labels == ('foo', 'bar', '')) def testFromUnicodeAlternateDot3(self): n = dns.name.from_text(u'foo\uff61bar') self.failUnless(n.labels == ('foo', 'bar', '')) def testToUnicode1(self): n = dns.name.from_text(u'foo.bar') s = n.to_unicode() self.failUnless(s == u'foo.bar.') def testToUnicode2(self): n = dns.name.from_text(u'foo\u1234bar.bar') s = n.to_unicode() self.failUnless(s == u'foo\u1234bar.bar.') def testToUnicode3(self): n = dns.name.from_text('foo.bar') s = n.to_unicode() self.failUnless(s == u'foo.bar.') def testReverseIPv4(self): e = dns.name.from_text('1.0.0.127.in-addr.arpa.') n = dns.reversename.from_address('127.0.0.1') self.failUnless(e == n) def testReverseIPv6(self): e = dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') n = dns.reversename.from_address('::1') self.failUnless(e == n) def testBadReverseIPv4(self): def bad(): n = dns.reversename.from_address('127.0.foo.1') self.failUnlessRaises(socket.error, bad) def testBadReverseIPv6(self): def bad(): n = dns.reversename.from_address('::1::1') self.failUnlessRaises(socket.error, bad) def testForwardIPv4(self): n = dns.name.from_text('1.0.0.127.in-addr.arpa.') e = '127.0.0.1' text = dns.reversename.to_address(n) self.failUnless(text == e) def testForwardIPv6(self): n = dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') e = '::1' text = dns.reversename.to_address(n) self.failUnless(text == e) def testE164ToEnum(self): text = '+1 650 555 1212' e = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') n = dns.e164.from_e164(text) self.failUnless(n == e) def testEnumToE164(self): n = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') e = '+16505551212' text = dns.e164.to_e164(n) self.failUnless(text == e) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/update.py0000644000175000017500000000751711570774061023720 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.update import dns.rdata import dns.rdataset goodhex = '0001 2800 0001 0005 0007 0000' \ '076578616d706c6500 0006 0001' \ '03666f6fc00c 00ff 00ff 00000000 0000' \ 'c019 0001 00ff 00000000 0000' \ '03626172c00c 0001 0001 00000000 0004 0a000005' \ '05626c617a32c00c 00ff 00fe 00000000 0000' \ 'c049 0001 00fe 00000000 0000' \ 'c019 0001 00ff 00000000 0000' \ 'c019 0001 0001 0000012c 0004 0a000001' \ 'c019 0001 0001 0000012c 0004 0a000002' \ 'c035 0001 0001 0000012c 0004 0a000003' \ 'c035 0001 00fe 00000000 0004 0a000004' \ '04626c617ac00c 0001 00ff 00000000 0000' \ 'c049 00ff 00ff 00000000 0000' goodwire = goodhex.replace(' ', '').decode('hex_codec') update_text="""id 1 opcode UPDATE rcode NOERROR ;ZONE example. IN SOA ;PREREQ foo ANY ANY foo ANY A bar 0 IN A 10.0.0.5 blaz2 NONE ANY blaz2 NONE A ;UPDATE foo ANY A foo 300 IN A 10.0.0.1 foo 300 IN A 10.0.0.2 bar 300 IN A 10.0.0.3 bar 0 NONE A 10.0.0.4 blaz ANY A blaz2 ANY ANY """ class UpdateTestCase(unittest.TestCase): def test_to_wire1(self): update = dns.update.Update('example') update.id = 1 update.present('foo') update.present('foo', 'a') update.present('bar', 'a', '10.0.0.5') update.absent('blaz2') update.absent('blaz2', 'a') update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') update.add('bar', 300, 'a', '10.0.0.3') update.delete('bar', 'a', '10.0.0.4') update.delete('blaz','a') update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) def test_to_wire2(self): update = dns.update.Update('example') update.id = 1 update.present('foo') update.present('foo', 'a') update.present('bar', 'a', '10.0.0.5') update.absent('blaz2') update.absent('blaz2', 'a') update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') update.add('bar', 300, dns.rdata.from_text(1, 1, '10.0.0.3')) update.delete('bar', 'a', '10.0.0.4') update.delete('blaz','a') update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) def test_to_wire3(self): update = dns.update.Update('example') update.id = 1 update.present('foo') update.present('foo', 'a') update.present('bar', 'a', '10.0.0.5') update.absent('blaz2') update.absent('blaz2', 'a') update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') update.add('bar', dns.rdataset.from_text(1, 1, 300, '10.0.0.3')) update.delete('bar', 'a', '10.0.0.4') update.delete('blaz','a') update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) def test_from_text1(self): update = dns.message.from_text(update_text) w = update.to_wire(origin=dns.name.from_text('example'), want_shuffle=False) self.failUnless(w == goodwire) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/flags.py0000644000175000017500000000405411570774060023522 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.flags import dns.rcode import dns.opcode class FlagsTestCase(unittest.TestCase): def test_rcode1(self): self.failUnless(dns.rcode.from_text('FORMERR') == dns.rcode.FORMERR) def test_rcode2(self): self.failUnless(dns.rcode.to_text(dns.rcode.FORMERR) == "FORMERR") def test_rcode3(self): self.failUnless(dns.rcode.to_flags(dns.rcode.FORMERR) == (1, 0)) def test_rcode4(self): self.failUnless(dns.rcode.to_flags(dns.rcode.BADVERS) == \ (0, 0x01000000)) def test_rcode6(self): self.failUnless(dns.rcode.from_flags(0, 0x01000000) == \ dns.rcode.BADVERS) def test_rcode6(self): self.failUnless(dns.rcode.from_flags(5, 0) == dns.rcode.REFUSED) def test_rcode7(self): def bad(): dns.rcode.to_flags(4096) self.failUnlessRaises(ValueError, bad) def test_flags1(self): self.failUnless(dns.flags.from_text("RA RD AA QR") == \ dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA) def test_flags2(self): flags = dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA self.failUnless(dns.flags.to_text(flags) == "QR AA RD RA") if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/tokenizer.py0000644000175000017500000001520511570774060024440 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.exception import dns.tokenizer Token = dns.tokenizer.Token class TokenizerTestCase(unittest.TestCase): def testQuotedString1(self): tok = dns.tokenizer.Tokenizer(r'"foo"') token = tok.get() self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo')) def testQuotedString2(self): tok = dns.tokenizer.Tokenizer(r'""') token = tok.get() self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '')) def testQuotedString3(self): tok = dns.tokenizer.Tokenizer(r'"\"foo\""') token = tok.get() self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '"foo"')) def testQuotedString4(self): tok = dns.tokenizer.Tokenizer(r'"foo\010bar"') token = tok.get() self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo\x0abar')) def testQuotedString5(self): def bad(): tok = dns.tokenizer.Tokenizer(r'"foo') token = tok.get() self.failUnlessRaises(dns.exception.UnexpectedEnd, bad) def testQuotedString6(self): def bad(): tok = dns.tokenizer.Tokenizer(r'"foo\01') token = tok.get() self.failUnlessRaises(dns.exception.SyntaxError, bad) def testQuotedString7(self): def bad(): tok = dns.tokenizer.Tokenizer('"foo\nbar"') token = tok.get() self.failUnlessRaises(dns.exception.SyntaxError, bad) def testEmpty1(self): tok = dns.tokenizer.Tokenizer('') token = tok.get() self.failUnless(token.is_eof()) def testEmpty2(self): tok = dns.tokenizer.Tokenizer('') token1 = tok.get() token2 = tok.get() self.failUnless(token1.is_eof() and token2.is_eof()) def testEOL(self): tok = dns.tokenizer.Tokenizer('\n') token1 = tok.get() token2 = tok.get() self.failUnless(token1.is_eol() and token2.is_eof()) def testWS1(self): tok = dns.tokenizer.Tokenizer(' \n') token1 = tok.get() self.failUnless(token1.is_eol()) def testWS2(self): tok = dns.tokenizer.Tokenizer(' \n') token1 = tok.get(want_leading=True) self.failUnless(token1.is_whitespace()) def testComment1(self): tok = dns.tokenizer.Tokenizer(' ;foo\n') token1 = tok.get() self.failUnless(token1.is_eol()) def testComment2(self): tok = dns.tokenizer.Tokenizer(' ;foo\n') token1 = tok.get(want_comment = True) token2 = tok.get() self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo') and token2.is_eol()) def testComment3(self): tok = dns.tokenizer.Tokenizer(' ;foo bar\n') token1 = tok.get(want_comment = True) token2 = tok.get() self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo bar') and token2.is_eol()) def testMultiline1(self): tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)') tokens = list(iter(tok)) self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), Token(dns.tokenizer.IDENTIFIER, 'bar')]) def testMultiline2(self): tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)\n') tokens = list(iter(tok)) self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), Token(dns.tokenizer.IDENTIFIER, 'bar'), Token(dns.tokenizer.EOL, '\n')]) def testMultiline3(self): def bad(): tok = dns.tokenizer.Tokenizer('foo)') tokens = list(iter(tok)) self.failUnlessRaises(dns.exception.SyntaxError, bad) def testMultiline4(self): def bad(): tok = dns.tokenizer.Tokenizer('((foo)') tokens = list(iter(tok)) self.failUnlessRaises(dns.exception.SyntaxError, bad) def testUnget1(self): tok = dns.tokenizer.Tokenizer('foo') t1 = tok.get() tok.unget(t1) t2 = tok.get() self.failUnless(t1 == t2 and t1.ttype == dns.tokenizer.IDENTIFIER and \ t1.value == 'foo') def testUnget2(self): def bad(): tok = dns.tokenizer.Tokenizer('foo') t1 = tok.get() tok.unget(t1) tok.unget(t1) self.failUnlessRaises(dns.tokenizer.UngetBufferFull, bad) def testGetEOL1(self): tok = dns.tokenizer.Tokenizer('\n') t = tok.get_eol() self.failUnless(t == '\n') def testGetEOL2(self): tok = dns.tokenizer.Tokenizer('') t = tok.get_eol() self.failUnless(t == '') def testEscapedDelimiter1(self): tok = dns.tokenizer.Tokenizer(r'ch\ ld') t = tok.get() self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ ld') def testEscapedDelimiter2(self): tok = dns.tokenizer.Tokenizer(r'ch\032ld') t = tok.get() self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\032ld') def testEscapedDelimiter3(self): tok = dns.tokenizer.Tokenizer(r'ch\ild') t = tok.get() self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ild') def testEscapedDelimiter1u(self): tok = dns.tokenizer.Tokenizer(r'ch\ ld') t = tok.get().unescape() self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch ld') def testEscapedDelimiter2u(self): tok = dns.tokenizer.Tokenizer(r'ch\032ld') t = tok.get().unescape() self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == 'ch ld') def testEscapedDelimiter3u(self): tok = dns.tokenizer.Tokenizer(r'ch\ild') t = tok.get().unescape() self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'child') if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/example2.good0000644000175000017500000001462711570774061024453 0ustar calvincalvin00000000000000example. 300 IN SOA ns1.example. hostmaster.example. 1 2000 2000 1814400 3600 example. 300 IN NS ns1.example. example. 300 IN NS ns2.example. *.example. 300 IN MX 10 mail.example. a.example. 300 IN TXT "foo foo foo" a.example. 300 IN PTR foo.net. a01.example. 3600 IN A 0.0.0.0 a02.example. 3600 IN A 255.255.255.255 aaaa01.example. 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff aaaa02.example. 3600 IN AAAA ::1 afsdb01.example. 3600 IN AFSDB 0 hostname.example. afsdb02.example. 3600 IN AFSDB 65535 . apl01.example. 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28 apl02.example. 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 b.example. 300 IN CNAME foo.net. c.example. 300 IN A 73.80.65.49 cert01.example. 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= cname01.example. 3600 IN CNAME cname-target. cname02.example. 3600 IN CNAME cname-target.example. cname03.example. 3600 IN CNAME . d.example. 300 IN A 73.80.65.49 dhcid01.example. 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= dhcid02.example. 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= dhcid03.example. 3600 IN DHCID AAABxLmlskllE0MVjd57zHcWmEH3pCQ6 VytcKD//7es/deY= dlv01.example. 3600 IN DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 dname01.example. 3600 IN DNAME dname-target. dname02.example. 3600 IN DNAME dname-target.example. dname03.example. 3600 IN DNAME . dnskey01.example. 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= dnskey02.example. 3600 IN DNSKEY 257 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= ds01.example. 3600 IN DS 12345 3 1 123456789abcdef67890123456789abcdef67890 e.example. 300 IN MX 10 mail.example. e.example. 300 IN TXT "one" e.example. 300 IN TXT "three" e.example. 300 IN TXT "two" e.example. 300 IN A 73.80.65.49 e.example. 300 IN A 73.80.65.50 e.example. 300 IN A 73.80.65.52 e.example. 300 IN A 73.80.65.51 f.example. 300 IN A 73.80.65.52 gpos01.example. 3600 IN GPOS -22.6882 116.8652 250.0 hinfo01.example. 3600 IN HINFO "Generic PC clone" "NetBSD-1.4" hinfo02.example. 3600 IN HINFO "PC" "NetBSD" hip01.example. 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example. ipseckey01.example. 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey02.example. 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey03.example. 3600 IN IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey04.example. 3600 IN IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey05.example. 3600 IN IPSECKEY 10 3 2 mygateway2.example. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== isdn01.example. 3600 IN ISDN "isdn-address" isdn02.example. 3600 IN ISDN "isdn-address" "subaddress" isdn03.example. 3600 IN ISDN "isdn-address" isdn04.example. 3600 IN ISDN "isdn-address" "subaddress" kx01.example. 3600 IN KX 10 kdc.example. kx02.example. 3600 IN KX 10 . loc01.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m loc02.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m loc03.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m loc04.example. 3600 IN LOC 60 9 1.500 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m loc05.example. 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m mx01.example. 3600 IN MX 10 mail.example. mx02.example. 3600 IN MX 10 . naptr01.example. 3600 IN NAPTR 0 0 "" "" "" . naptr02.example. 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo. ns1.example. 300 IN A 10.53.0.1 ns2.example. 300 IN A 10.53.0.2 nsap-ptr01.example. 3600 IN NSAP-PTR foo. nsap-ptr01.example. 3600 IN NSAP-PTR . nsap01.example. 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 nsap02.example. 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 nsec01.example. 3600 IN NSEC a.secure. A MX RRSIG NSEC TYPE1234 nsec02.example. 3600 IN NSEC . NSAP-PTR NSEC nsec03.example. 3600 IN NSEC . NSEC TYPE65535 nsec301.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM nsec302.example. 3600 IN NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM nsec3param01.example. 3600 IN NSEC3PARAM 1 1 12 aabbccdd nsec3param02.example. 3600 IN NSEC3PARAM 1 1 12 - ptr01.example. 3600 IN PTR example. px01.example. 3600 IN PX 65535 foo. bar. px02.example. 3600 IN PX 65535 . . rp01.example. 3600 IN RP mbox-dname.example. txt-dname.example. rp02.example. 3600 IN RP . . rrsig01.example. 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo.example. MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= rt01.example. 3600 IN RT 0 intermediate-host.example. rt02.example. 3600 IN RT 65535 . s.example. 300 IN NS ns.s.example. ns.s.example. 300 IN A 73.80.65.49 spf.example. 3600 IN SPF "v=spf1 mx -all" srv01.example. 3600 IN SRV 0 0 0 . srv02.example. 3600 IN SRV 65535 65535 65535 old-slow-box.example.com. sshfp1.example. 3600 IN SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab t.example. 301 IN A 73.80.65.49 txt01.example. 3600 IN TXT "foo" txt02.example. 3600 IN TXT "foo" "bar" txt03.example. 3600 IN TXT "foo" txt04.example. 3600 IN TXT "foo" "bar" txt05.example. 3600 IN TXT "foo bar" txt06.example. 3600 IN TXT "foo bar" txt07.example. 3600 IN TXT "foo bar" txt08.example. 3600 IN TXT "foo\010bar" txt09.example. 3600 IN TXT "foo\010bar" txt10.example. 3600 IN TXT "foo bar" txt11.example. 3600 IN TXT "\"foo\"" txt12.example. 3600 IN TXT "\"foo\"" txt13.example. 3600 IN TXT "foo" u.example. 300 IN TXT "txt-not-in-nxt" a.u.example. 300 IN A 73.80.65.49 b.u.example. 300 IN A 73.80.65.49 unknown2.example. 3600 IN TYPE999 \# 8 0a0000010a000001 unknown3.example. 3600 IN A 127.0.0.2 wks01.example. 3600 IN WKS 10.0.0.1 6 0 1 2 21 23 wks02.example. 3600 IN WKS 10.0.0.1 17 0 1 2 53 wks03.example. 3600 IN WKS 10.0.0.2 6 65535 x2501.example. 3600 IN X25 "123456789" LinkChecker-9.3/third_party/dnspython/tests/set.py0000644000175000017500000001220711570774060023220 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.set # for convenience S = dns.set.Set class SimpleSetTestCase(unittest.TestCase): def testLen1(self): s1 = S() self.failUnless(len(s1) == 0) def testLen2(self): s1 = S([1, 2, 3]) self.failUnless(len(s1) == 3) def testLen3(self): s1 = S([1, 2, 3, 3, 3]) self.failUnless(len(s1) == 3) def testUnion1(self): s1 = S([1, 2, 3]) s2 = S([1, 2, 3]) e = S([1, 2, 3]) self.failUnless(s1 | s2 == e) def testUnion2(self): s1 = S([1, 2, 3]) s2 = S([]) e = S([1, 2, 3]) self.failUnless(s1 | s2 == e) def testUnion3(self): s1 = S([1, 2, 3]) s2 = S([3, 4]) e = S([1, 2, 3, 4]) self.failUnless(s1 | s2 == e) def testIntersection1(self): s1 = S([1, 2, 3]) s2 = S([1, 2, 3]) e = S([1, 2, 3]) self.failUnless(s1 & s2 == e) def testIntersection2(self): s1 = S([0, 1, 2, 3]) s2 = S([1, 2, 3, 4]) e = S([1, 2, 3]) self.failUnless(s1 & s2 == e) def testIntersection3(self): s1 = S([1, 2, 3]) s2 = S([]) e = S([]) self.failUnless(s1 & s2 == e) def testIntersection4(self): s1 = S([1, 2, 3]) s2 = S([5, 4]) e = S([]) self.failUnless(s1 & s2 == e) def testDifference1(self): s1 = S([1, 2, 3]) s2 = S([5, 4]) e = S([1, 2, 3]) self.failUnless(s1 - s2 == e) def testDifference2(self): s1 = S([1, 2, 3]) s2 = S([]) e = S([1, 2, 3]) self.failUnless(s1 - s2 == e) def testDifference3(self): s1 = S([1, 2, 3]) s2 = S([3, 2]) e = S([1]) self.failUnless(s1 - s2 == e) def testDifference4(self): s1 = S([1, 2, 3]) s2 = S([3, 2, 1]) e = S([]) self.failUnless(s1 - s2 == e) def testSubset1(self): s1 = S([1, 2, 3]) s2 = S([3, 2, 1]) self.failUnless(s1.issubset(s2)) def testSubset2(self): s1 = S([1, 2, 3]) self.failUnless(s1.issubset(s1)) def testSubset3(self): s1 = S([]) s2 = S([1, 2, 3]) self.failUnless(s1.issubset(s2)) def testSubset4(self): s1 = S([1]) s2 = S([1, 2, 3]) self.failUnless(s1.issubset(s2)) def testSubset5(self): s1 = S([]) s2 = S([]) self.failUnless(s1.issubset(s2)) def testSubset6(self): s1 = S([1, 4]) s2 = S([1, 2, 3]) self.failUnless(not s1.issubset(s2)) def testSuperset1(self): s1 = S([1, 2, 3]) s2 = S([3, 2, 1]) self.failUnless(s1.issuperset(s2)) def testSuperset2(self): s1 = S([1, 2, 3]) self.failUnless(s1.issuperset(s1)) def testSuperset3(self): s1 = S([1, 2, 3]) s2 = S([]) self.failUnless(s1.issuperset(s2)) def testSuperset4(self): s1 = S([1, 2, 3]) s2 = S([1]) self.failUnless(s1.issuperset(s2)) def testSuperset5(self): s1 = S([]) s2 = S([]) self.failUnless(s1.issuperset(s2)) def testSuperset6(self): s1 = S([1, 2, 3]) s2 = S([1, 4]) self.failUnless(not s1.issuperset(s2)) def testUpdate1(self): s1 = S([1, 2, 3]) u = (4, 5, 6) e = S([1, 2, 3, 4, 5, 6]) s1.update(u) self.failUnless(s1 == e) def testUpdate2(self): s1 = S([1, 2, 3]) u = [] e = S([1, 2, 3]) s1.update(u) self.failUnless(s1 == e) def testGetitem(self): s1 = S([1, 2, 3]) i0 = s1[0] i1 = s1[1] i2 = s1[2] s2 = S([i0, i1, i2]) self.failUnless(s1 == s2) def testGetslice(self): s1 = S([1, 2, 3]) slice = s1[0:2] self.failUnless(len(slice) == 2) item = s1[2] slice.append(item) s2 = S(slice) self.failUnless(s1 == s2) def testDelitem(self): s1 = S([1, 2, 3]) del s1[0] i1 = s1[0] i2 = s1[1] self.failUnless(i1 != i2) self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) self.failUnless(i2 == 1 or i2 == 2 or i2 == 3) def testDelslice(self): s1 = S([1, 2, 3]) del s1[0:2] i1 = s1[0] self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/rdtypeandclass.py0000644000175000017500000001027411570774060025447 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.rdataclass import dns.rdatatype class RdTypeAndClassTestCase(unittest.TestCase): # Classes def test_class_meta1(self): self.failUnless(dns.rdataclass.is_metaclass(dns.rdataclass.ANY)) def test_class_meta2(self): self.failUnless(not dns.rdataclass.is_metaclass(dns.rdataclass.IN)) def test_class_bytext1(self): self.failUnless(dns.rdataclass.from_text('IN') == dns.rdataclass.IN) def test_class_bytext2(self): self.failUnless(dns.rdataclass.from_text('CLASS1') == dns.rdataclass.IN) def test_class_bytext_bounds1(self): self.failUnless(dns.rdataclass.from_text('CLASS0') == 0) self.failUnless(dns.rdataclass.from_text('CLASS65535') == 65535) def test_class_bytext_bounds2(self): def bad(): junk = dns.rdataclass.from_text('CLASS65536') self.failUnlessRaises(ValueError, bad) def test_class_bytext_unknown(self): def bad(): junk = dns.rdataclass.from_text('XXX') self.failUnlessRaises(dns.rdataclass.UnknownRdataclass, bad) def test_class_totext1(self): self.failUnless(dns.rdataclass.to_text(dns.rdataclass.IN) == 'IN') def test_class_totext1(self): self.failUnless(dns.rdataclass.to_text(999) == 'CLASS999') def test_class_totext_bounds1(self): def bad(): junk = dns.rdataclass.to_text(-1) self.failUnlessRaises(ValueError, bad) def test_class_totext_bounds2(self): def bad(): junk = dns.rdataclass.to_text(65536) self.failUnlessRaises(ValueError, bad) # Types def test_type_meta1(self): self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.ANY)) def test_type_meta2(self): self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.OPT)) def test_type_meta3(self): self.failUnless(not dns.rdatatype.is_metatype(dns.rdatatype.A)) def test_type_singleton1(self): self.failUnless(dns.rdatatype.is_singleton(dns.rdatatype.SOA)) def test_type_singleton2(self): self.failUnless(not dns.rdatatype.is_singleton(dns.rdatatype.A)) def test_type_bytext1(self): self.failUnless(dns.rdatatype.from_text('A') == dns.rdatatype.A) def test_type_bytext2(self): self.failUnless(dns.rdatatype.from_text('TYPE1') == dns.rdatatype.A) def test_type_bytext_bounds1(self): self.failUnless(dns.rdatatype.from_text('TYPE0') == 0) self.failUnless(dns.rdatatype.from_text('TYPE65535') == 65535) def test_type_bytext_bounds2(self): def bad(): junk = dns.rdatatype.from_text('TYPE65536') self.failUnlessRaises(ValueError, bad) def test_type_bytext_unknown(self): def bad(): junk = dns.rdatatype.from_text('XXX') self.failUnlessRaises(dns.rdatatype.UnknownRdatatype, bad) def test_type_totext1(self): self.failUnless(dns.rdatatype.to_text(dns.rdatatype.A) == 'A') def test_type_totext1(self): self.failUnless(dns.rdatatype.to_text(999) == 'TYPE999') def test_type_totext_bounds1(self): def bad(): junk = dns.rdatatype.to_text(-1) self.failUnlessRaises(ValueError, bad) def test_type_totext_bounds2(self): def bad(): junk = dns.rdatatype.to_text(65536) self.failUnlessRaises(ValueError, bad) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/Makefile0000644000175000017500000000171511570774061023516 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # $Id: Makefile,v 1.5 2004/03/19 00:17:27 halley Exp $ PYTHON=python check: test test: @for i in *.py; do \ echo "Running $$i:"; \ PYTHONPATH=.. ${PYTHON} $$i || exit 1; \ done LinkChecker-9.3/third_party/dnspython/tests/zone.py0000644000175000017500000003332411570774060023403 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import filecmp import os import unittest import dns.exception import dns.rdata import dns.rdataclass import dns.rdatatype import dns.rrset import dns.zone example_text = """$TTL 3600 $ORIGIN example. @ soa foo bar 1 2 3 4 5 @ ns ns1 @ ns ns2 ns1 a 10.0.0.1 ns2 a 10.0.0.2 $TTL 300 $ORIGIN foo.example. bar mx 0 blaz """ example_text_output = """@ 3600 IN SOA foo bar 1 2 3 4 5 @ 3600 IN NS ns1 @ 3600 IN NS ns2 bar.foo 300 IN MX 0 blaz.foo ns1 3600 IN A 10.0.0.1 ns2 3600 IN A 10.0.0.2 """ something_quite_similar = """@ 3600 IN SOA foo bar 1 2 3 4 5 @ 3600 IN NS ns1 @ 3600 IN NS ns2 bar.foo 300 IN MX 0 blaz.foo ns1 3600 IN A 10.0.0.1 ns2 3600 IN A 10.0.0.3 """ something_different = """@ 3600 IN SOA fooa bar 1 2 3 4 5 @ 3600 IN NS ns11 @ 3600 IN NS ns21 bar.fooa 300 IN MX 0 blaz.fooa ns11 3600 IN A 10.0.0.11 ns21 3600 IN A 10.0.0.21 """ ttl_example_text = """$TTL 1h $ORIGIN example. @ soa foo bar 1 2 3 4 5 @ ns ns1 @ ns ns2 ns1 1d1s a 10.0.0.1 ns2 1w1D1h1m1S a 10.0.0.2 """ no_soa_text = """$TTL 1h $ORIGIN example. @ ns ns1 @ ns ns2 ns1 1d1s a 10.0.0.1 ns2 1w1D1h1m1S a 10.0.0.2 """ no_ns_text = """$TTL 1h $ORIGIN example. @ soa foo bar 1 2 3 4 5 """ include_text = """$INCLUDE "example" """ bad_directive_text = """$FOO bar $ORIGIN example. @ soa foo bar 1 2 3 4 5 @ ns ns1 @ ns ns2 ns1 1d1s a 10.0.0.1 ns2 1w1D1h1m1S a 10.0.0.2 """ _keep_output = False class ZoneTestCase(unittest.TestCase): def testFromFile1(self): z = dns.zone.from_file('example', 'example') ok = False try: z.to_file('example1.out', nl='\x0a') ok = filecmp.cmp('example1.out', 'example1.good') finally: if not _keep_output: os.unlink('example1.out') self.failUnless(ok) def testFromFile2(self): z = dns.zone.from_file('example', 'example', relativize=False) ok = False try: z.to_file('example2.out', relativize=False, nl='\x0a') ok = filecmp.cmp('example2.out', 'example2.good') finally: if not _keep_output: os.unlink('example2.out') self.failUnless(ok) def testFromText(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) f = cStringIO.StringIO() names = z.nodes.keys() names.sort() for n in names: print >> f, z[n].to_text(n) self.failUnless(f.getvalue() == example_text_output) def testTorture1(self): # # Read a zone containing all our supported RR types, and # for each RR in the zone, convert the rdata into wire format # and then back out, and see if we get equal rdatas. # f = cStringIO.StringIO() o = dns.name.from_text('example.') z = dns.zone.from_file('example', o) for (name, node) in z.iteritems(): for rds in node: for rd in rds: f.seek(0) f.truncate() rd.to_wire(f, origin=o) wire = f.getvalue() rd2 = dns.rdata.from_wire(rds.rdclass, rds.rdtype, wire, 0, len(wire), origin = o) self.failUnless(rd == rd2) def testEqual(self): z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(example_text_output, 'example.', relativize=True) self.failUnless(z1 == z2) def testNotEqual1(self): z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(something_quite_similar, 'example.', relativize=True) self.failUnless(z1 != z2) def testNotEqual2(self): z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(something_different, 'example.', relativize=True) self.failUnless(z1 != z2) def testNotEqual3(self): z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(something_different, 'example2.', relativize=True) self.failUnless(z1 != z2) def testFindRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.find_rdataset('@', 'soa') exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) def testFindRdataset2(self): def bad(): z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.find_rdataset('@', 'loc') self.failUnlessRaises(KeyError, bad) def testFindRRset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.find_rrset('@', 'soa') exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') self.failUnless(rrs == exrrs) def testFindRRset2(self): def bad(): z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.find_rrset('@', 'loc') self.failUnlessRaises(KeyError, bad) def testGetRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.get_rdataset('@', 'soa') exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) def testGetRdataset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.get_rdataset('@', 'loc') self.failUnless(rds == None) def testGetRRset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.get_rrset('@', 'soa') exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') self.failUnless(rrs == exrrs) def testGetRRset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.get_rrset('@', 'loc') self.failUnless(rrs == None) def testReplaceRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rdataset = dns.rdataset.from_text('in', 'ns', 300, 'ns3', 'ns4') z.replace_rdataset('@', rdataset) rds = z.get_rdataset('@', 'ns') self.failUnless(rds is rdataset) def testReplaceRdataset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rdataset = dns.rdataset.from_text('in', 'txt', 300, '"foo"') z.replace_rdataset('@', rdataset) rds = z.get_rdataset('@', 'txt') self.failUnless(rds is rdataset) def testDeleteRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) z.delete_rdataset('@', 'ns') rds = z.get_rdataset('@', 'ns') self.failUnless(rds is None) def testDeleteRdataset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) z.delete_rdataset('ns1', 'a') node = z.get_node('ns1') self.failUnless(node is None) def testNodeFindRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) def testNodeFindRdataset2(self): def bad(): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) self.failUnlessRaises(KeyError, bad) def testNodeGetRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) def testNodeGetRdataset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) self.failUnless(rds == None) def testNodeDeleteRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) self.failUnless(rds == None) def testNodeDeleteRdataset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) self.failUnless(rds == None) def testIterateRdatasets(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) ns = [n for n, r in z.iterate_rdatasets('A')] ns.sort() self.failUnless(ns == [dns.name.from_text('ns1', None), dns.name.from_text('ns2', None)]) def testIterateAllRdatasets(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) ns = [n for n, r in z.iterate_rdatasets()] ns.sort() self.failUnless(ns == [dns.name.from_text('@', None), dns.name.from_text('@', None), dns.name.from_text('bar.foo', None), dns.name.from_text('ns1', None), dns.name.from_text('ns2', None)]) def testIterateRdatas(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) l = list(z.iterate_rdatas('A')) l.sort() exl = [(dns.name.from_text('ns1', None), 3600, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '10.0.0.1')), (dns.name.from_text('ns2', None), 3600, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '10.0.0.2'))] self.failUnless(l == exl) def testIterateAllRdatas(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort() exl = [(dns.name.from_text('@', None), 3600, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns1')), (dns.name.from_text('@', None), 3600, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns2')), (dns.name.from_text('@', None), 3600, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'foo bar 1 2 3 4 5')), (dns.name.from_text('bar.foo', None), 300, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, '0 blaz.foo')), (dns.name.from_text('ns1', None), 3600, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '10.0.0.1')), (dns.name.from_text('ns2', None), 3600, dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '10.0.0.2'))] self.failUnless(l == exl) def testTTLs(self): z = dns.zone.from_text(ttl_example_text, 'example.', relativize=True) n = z['@'] rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) self.failUnless(rds.ttl == 3600) n = z['ns1'] rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) self.failUnless(rds.ttl == 86401) n = z['ns2'] rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) self.failUnless(rds.ttl == 694861) def testNoSOA(self): def bad(): z = dns.zone.from_text(no_soa_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoSOA, bad) def testNoNS(self): def bad(): z = dns.zone.from_text(no_ns_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoNS, bad) def testInclude(self): z1 = dns.zone.from_text(include_text, 'example.', relativize=True, allow_include=True) z2 = dns.zone.from_file('example', 'example.', relativize=True) self.failUnless(z1 == z2) def testBadDirective(self): def bad(): z = dns.zone.from_text(bad_directive_text, 'example.', relativize=True) self.failUnlessRaises(dns.exception.SyntaxError, bad) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/resolver.py0000644000175000017500000001026711570774060024272 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import select import sys import time import unittest import dns.name import dns.message import dns.name import dns.rdataclass import dns.rdatatype import dns.resolver resolv_conf = """ /t/t # comment 1 ; comment 2 domain foo nameserver 10.0.0.1 nameserver 10.0.0.2 """ message_text = """id 1234 opcode QUERY rcode NOERROR flags QR AA RD ;QUESTION example. IN A ;ANSWER example. 1 IN A 10.0.0.1 ;AUTHORITY ;ADDITIONAL """ class BaseResolverTests(object): if sys.platform != 'win32': def testRead(self): f = cStringIO.StringIO(resolv_conf) r = dns.resolver.Resolver(f) self.failUnless(r.nameservers == ['10.0.0.1', '10.0.0.2'] and r.domain == dns.name.from_text('foo')) def testCacheExpiration(self): message = dns.message.from_text(message_text) name = dns.name.from_text('example.') answer = dns.resolver.Answer(name, dns.rdatatype.A, dns.rdataclass.IN, message) cache = dns.resolver.Cache() cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) time.sleep(2) self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) is None) def testCacheCleaning(self): message = dns.message.from_text(message_text) name = dns.name.from_text('example.') answer = dns.resolver.Answer(name, dns.rdatatype.A, dns.rdataclass.IN, message) cache = dns.resolver.Cache(cleaning_interval=1.0) cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) time.sleep(2) self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) is None) def testZoneForName1(self): name = dns.name.from_text('www.dnspython.org.') ezname = dns.name.from_text('dnspython.org.') zname = dns.resolver.zone_for_name(name) self.failUnless(zname == ezname) def testZoneForName2(self): name = dns.name.from_text('a.b.www.dnspython.org.') ezname = dns.name.from_text('dnspython.org.') zname = dns.resolver.zone_for_name(name) self.failUnless(zname == ezname) def testZoneForName3(self): name = dns.name.from_text('dnspython.org.') ezname = dns.name.from_text('dnspython.org.') zname = dns.resolver.zone_for_name(name) self.failUnless(zname == ezname) def testZoneForName4(self): def bad(): name = dns.name.from_text('dnspython.org', None) zname = dns.resolver.zone_for_name(name) self.failUnlessRaises(dns.resolver.NotAbsolute, bad) class PollingMonkeyPatchMixin(object): def setUp(self): self.__native_polling_backend = dns.query._polling_backend dns.query._set_polling_backend(self.polling_backend()) unittest.TestCase.setUp(self) def tearDown(self): dns.query._set_polling_backend(self.__native_polling_backend) unittest.TestCase.tearDown(self) class SelectResolverTestCase(PollingMonkeyPatchMixin, BaseResolverTests, unittest.TestCase): def polling_backend(self): return dns.query._select_for if hasattr(select, 'poll'): class PollResolverTestCase(PollingMonkeyPatchMixin, BaseResolverTests, unittest.TestCase): def polling_backend(self): return dns.query._poll_for if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/ntoaaton.py0000644000175000017500000001211611570774060024247 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.exception import dns.ipv6 class NtoAAtoNTestCase(unittest.TestCase): def test_aton1(self): a = dns.ipv6.inet_aton('::') self.failUnless(a == '\x00' * 16) def test_aton2(self): a = dns.ipv6.inet_aton('::1') self.failUnless(a == '\x00' * 15 + '\x01') def test_aton3(self): a = dns.ipv6.inet_aton('::10.0.0.1') self.failUnless(a == '\x00' * 12 + '\x0a\x00\x00\x01') def test_aton4(self): a = dns.ipv6.inet_aton('abcd::dcba') self.failUnless(a == '\xab\xcd' + '\x00' * 12 + '\xdc\xba') def test_aton5(self): a = dns.ipv6.inet_aton('1:2:3:4:5:6:7:8') self.failUnless(a == \ '00010002000300040005000600070008'.decode('hex_codec')) def test_bad_aton1(self): def bad(): a = dns.ipv6.inet_aton('abcd:dcba') self.failUnlessRaises(dns.exception.SyntaxError, bad) def test_bad_aton2(self): def bad(): a = dns.ipv6.inet_aton('abcd::dcba::1') self.failUnlessRaises(dns.exception.SyntaxError, bad) def test_bad_aton3(self): def bad(): a = dns.ipv6.inet_aton('1:2:3:4:5:6:7:8:9') self.failUnlessRaises(dns.exception.SyntaxError, bad) def test_aton1(self): a = dns.ipv6.inet_aton('::') self.failUnless(a == '\x00' * 16) def test_aton2(self): a = dns.ipv6.inet_aton('::1') self.failUnless(a == '\x00' * 15 + '\x01') def test_aton3(self): a = dns.ipv6.inet_aton('::10.0.0.1') self.failUnless(a == '\x00' * 12 + '\x0a\x00\x00\x01') def test_aton4(self): a = dns.ipv6.inet_aton('abcd::dcba') self.failUnless(a == '\xab\xcd' + '\x00' * 12 + '\xdc\xba') def test_ntoa1(self): b = '00010002000300040005000600070008'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '1:2:3:4:5:6:7:8') def test_ntoa2(self): b = '\x00' * 16 t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::') def test_ntoa3(self): b = '\x00' * 15 + '\x01' t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::1') def test_ntoa4(self): b = '\x80' + '\x00' * 15 t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '8000::') def test_ntoa5(self): b = '\x01\xcd' + '\x00' * 12 + '\x03\xef' t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '1cd::3ef') def test_ntoa6(self): b = 'ffff00000000ffff000000000000ffff'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == 'ffff:0:0:ffff::ffff') def test_ntoa7(self): b = '00000000ffff000000000000ffffffff'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '0:0:ffff::ffff:ffff') def test_ntoa8(self): b = 'ffff0000ffff00000000ffff00000000'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == 'ffff:0:ffff::ffff:0:0') def test_ntoa9(self): b = '0000000000000000000000000a000001'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::10.0.0.1') def test_ntoa10(self): b = '0000000000000000000000010a000001'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::1:a00:1') def test_ntoa11(self): b = '00000000000000000000ffff0a000001'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::ffff:10.0.0.1') def test_ntoa12(self): b = '000000000000000000000000ffffffff'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::255.255.255.255') def test_ntoa13(self): b = '00000000000000000000ffffffffffff'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::ffff:255.255.255.255') def test_ntoa14(self): b = '0000000000000000000000000001ffff'.decode('hex_codec') t = dns.ipv6.inet_ntoa(b) self.failUnless(t == '::0.1.255.255') def test_bad_ntoa1(self): def bad(): a = dns.ipv6.inet_ntoa('') self.failUnlessRaises(ValueError, bad) def test_bad_ntoa2(self): def bad(): a = dns.ipv6.inet_ntoa('\x00' * 17) self.failUnlessRaises(ValueError, bad) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/dnssec.py0000644000175000017500000002220011570774060023676 0ustar calvincalvin00000000000000# Copyright (C) 2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.dnssec import dns.name import dns.rdata import dns.rdataclass import dns.rdatatype import dns.rrset abs_dnspython_org = dns.name.from_text('dnspython.org') abs_keys = { abs_dnspython_org : dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'DNSKEY', '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') } rel_keys = { dns.name.empty : dns.rrset.from_text('@', 3600, 'IN', 'DNSKEY', '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') } when = 1290250287 abs_soa = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'SOA', 'howl.dnspython.org. hostmaster.dnspython.org. 2010020047 3600 1800 604800 3600') abs_other_soa = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'SOA', 'foo.dnspython.org. hostmaster.dnspython.org. 2010020047 3600 1800 604800 3600') abs_soa_rrsig = dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'RRSIG', 'SOA 5 2 3600 20101127004331 20101119213831 61695 dnspython.org. sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDw t6dvM9jAXdIEi03l9H/RAd9xNNW6gvGMHsBGzpvvqFQxIBR2PoiZA1mX /SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd0 8vs=') rel_soa = dns.rrset.from_text('@', 3600, 'IN', 'SOA', 'howl hostmaster 2010020047 3600 1800 604800 3600') rel_other_soa = dns.rrset.from_text('@', 3600, 'IN', 'SOA', 'foo hostmaster 2010020047 3600 1800 604800 3600') rel_soa_rrsig = dns.rrset.from_text('@', 3600, 'IN', 'RRSIG', 'SOA 5 2 3600 20101127004331 20101119213831 61695 @ sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDw t6dvM9jAXdIEi03l9H/RAd9xNNW6gvGMHsBGzpvvqFQxIBR2PoiZA1mX /SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd0 8vs=') sep_key = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNSKEY, '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=') good_ds = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, '57349 5 2 53A79A3E7488AB44FFC56B2D1109F0699D1796DD977E72108B841F96 E47D7013') when2 = 1290425644 abs_example = dns.name.from_text('example') abs_dsa_keys = { abs_example : dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X', '256 3 3 CJE1yb9YRQiw5d2xZrMUMR+cGCTt1bp1KDCefmYKmS+Z1+q9f42ETVhx JRiQwXclYwmxborzIkSZegTNYIV6mrYwbNB27Q44c3UGcspb3PiOw5TC jNPRYEcdwGvDZ2wWy+vkSV/S9tHXY8O6ODiE6abZJDDg/RnITyi+eoDL R3KZ5n/V1f1T1b90rrV6EewhBGQJpQGDogaXb2oHww9Tm6NfXyo7SoMM pbwbzOckXv+GxRPJIQNSF4D4A9E8XCksuzVVdE/0lr37+uoiAiPia38U 5W2QWe/FJAEPLjIp2eTzf0TrADc1pKP1wrA2ASpdzpm/aX3IB5RPp8Ew S9U72eBFZJAUwg635HxJVxH1maG6atzorR566E+e0OZSaxXS9o1o6QqN 3oPlYLGPORDiExilKfez3C/x/yioOupW9K5eKF0gmtaqrHX0oq9s67f/ RIM2xVaKHgG9Vf2cgJIZkhv7sntujr+E4htnRmy9P9BxyFxsItYxPI6Z bzygHAZpGhlI/7ltEGlIwKxyTK3ZKBm67q7B') } abs_dsa_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400') abs_other_dsa_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401') abs_dsa_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', 'SOA 3 1 86400 20101129143231 20101122112731 42088 example. CGul9SuBofsktunV8cJs4eRs6u+3NCS3yaPKvBbD+pB2C76OUXDZq9U=') example_sep_key = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNSKEY, '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X') example_ds_sha1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, '18673 3 1 71b71d4f3e11bbd71b4eff12cde69f7f9215bbe7') example_ds_sha256 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, '18673 3 2 eb8344cbbf07c9d3d3d6c81d10c76653e28d8611a65e639ef8f716e4e4e5d913') class DNSSECValidatorTestCase(unittest.TestCase): def testAbsoluteRSAGood(self): dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when) def testAbsoluteRSABad(self): def bad(): dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None, when) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) def testRelativeRSAGood(self): dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys, abs_dnspython_org, when) def testRelativeRSABad(self): def bad(): dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys, abs_dnspython_org, when) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) def testMakeSHA256DS(self): ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256') self.failUnless(ds == good_ds) def testAbsoluteDSAGood(self): dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, when2) def testAbsoluteDSABad(self): def bad(): dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, when2) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) def testMakeExampleSHA1DS(self): ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA1') self.failUnless(ds == example_ds_sha1) def testMakeExampleSHA256DS(self): ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') self.failUnless(ds == example_ds_sha256) if __name__ == '__main__': import_ok = False try: import Crypto.Util.number import_ok = True except: pass if import_ok: unittest.main() else: print 'skipping DNSSEC tests because pycrypto is not installed' LinkChecker-9.3/third_party/dnspython/tests/rrset.py0000644000175000017500000000434211570774060023565 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.rrset class RRsetTestCase(unittest.TestCase): def testEqual1(self): r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') r2 = dns.rrset.from_text('FOO', 300, 'in', 'a', '10.0.0.2', '10.0.0.1') self.failUnless(r1 == r2) def testEqual2(self): r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') r2 = dns.rrset.from_text('FOO', 600, 'in', 'a', '10.0.0.2', '10.0.0.1') self.failUnless(r1 == r2) def testNotEqual1(self): r1 = dns.rrset.from_text('fooa', 30, 'in', 'a', '10.0.0.1', '10.0.0.2') r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') self.failUnless(r1 != r2) def testNotEqual2(self): r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.3') r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') self.failUnless(r1 != r2) def testNotEqual3(self): r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.2', '10.0.0.3') r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') self.failUnless(r1 != r2) def testNotEqual4(self): r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1') r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') self.failUnless(r1 != r2) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/example1.good0000644000175000017500000001236211570774061024444 0ustar calvincalvin00000000000000@ 300 IN SOA ns1 hostmaster 1 2000 2000 1814400 3600 @ 300 IN NS ns1 @ 300 IN NS ns2 * 300 IN MX 10 mail a 300 IN TXT "foo foo foo" a 300 IN PTR foo.net. a01 3600 IN A 0.0.0.0 a02 3600 IN A 255.255.255.255 aaaa01 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff aaaa02 3600 IN AAAA ::1 afsdb01 3600 IN AFSDB 0 hostname afsdb02 3600 IN AFSDB 65535 . apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28 apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 b 300 IN CNAME foo.net. c 300 IN A 73.80.65.49 cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= cname01 3600 IN CNAME cname-target. cname02 3600 IN CNAME cname-target cname03 3600 IN CNAME . d 300 IN A 73.80.65.49 dhcid01 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= dhcid02 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= dhcid03 3600 IN DHCID AAABxLmlskllE0MVjd57zHcWmEH3pCQ6 VytcKD//7es/deY= dlv01 3600 IN DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 dname01 3600 IN DNAME dname-target. dname02 3600 IN DNAME dname-target dname03 3600 IN DNAME . dnskey01 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= dnskey02 3600 IN DNSKEY 257 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8= ds01 3600 IN DS 12345 3 1 123456789abcdef67890123456789abcdef67890 e 300 IN MX 10 mail e 300 IN TXT "one" e 300 IN TXT "three" e 300 IN TXT "two" e 300 IN A 73.80.65.49 e 300 IN A 73.80.65.50 e 300 IN A 73.80.65.52 e 300 IN A 73.80.65.51 f 300 IN A 73.80.65.52 gpos01 3600 IN GPOS -22.6882 116.8652 250.0 hinfo01 3600 IN HINFO "Generic PC clone" "NetBSD-1.4" hinfo02 3600 IN HINFO "PC" "NetBSD" hip01 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2 ipseckey01 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey02 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey03 3600 IN IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey04 3600 IN IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== ipseckey05 3600 IN IPSECKEY 10 3 2 mygateway2 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ== isdn01 3600 IN ISDN "isdn-address" isdn02 3600 IN ISDN "isdn-address" "subaddress" isdn03 3600 IN ISDN "isdn-address" isdn04 3600 IN ISDN "isdn-address" "subaddress" kx01 3600 IN KX 10 kdc kx02 3600 IN KX 10 . loc01 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m loc02 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m loc03 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m loc04 3600 IN LOC 60 9 1.500 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m loc05 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m mx01 3600 IN MX 10 mail mx02 3600 IN MX 10 . naptr01 3600 IN NAPTR 0 0 "" "" "" . naptr02 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo. ns1 300 IN A 10.53.0.1 ns2 300 IN A 10.53.0.2 nsap-ptr01 3600 IN NSAP-PTR foo. nsap-ptr01 3600 IN NSAP-PTR . nsap01 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 nsap02 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100 nsec01 3600 IN NSEC a.secure. A MX RRSIG NSEC TYPE1234 nsec02 3600 IN NSEC . NSAP-PTR NSEC nsec03 3600 IN NSEC . NSEC TYPE65535 nsec301 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM nsec302 3600 IN NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM nsec3param01 3600 IN NSEC3PARAM 1 1 12 aabbccdd nsec3param02 3600 IN NSEC3PARAM 1 1 12 - ptr01 3600 IN PTR @ px01 3600 IN PX 65535 foo. bar. px02 3600 IN PX 65535 . . rp01 3600 IN RP mbox-dname txt-dname rp02 3600 IN RP . . rrsig01 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= rt01 3600 IN RT 0 intermediate-host rt02 3600 IN RT 65535 . s 300 IN NS ns.s ns.s 300 IN A 73.80.65.49 spf 3600 IN SPF "v=spf1 mx -all" srv01 3600 IN SRV 0 0 0 . srv02 3600 IN SRV 65535 65535 65535 old-slow-box.example.com. sshfp1 3600 IN SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab t 301 IN A 73.80.65.49 txt01 3600 IN TXT "foo" txt02 3600 IN TXT "foo" "bar" txt03 3600 IN TXT "foo" txt04 3600 IN TXT "foo" "bar" txt05 3600 IN TXT "foo bar" txt06 3600 IN TXT "foo bar" txt07 3600 IN TXT "foo bar" txt08 3600 IN TXT "foo\010bar" txt09 3600 IN TXT "foo\010bar" txt10 3600 IN TXT "foo bar" txt11 3600 IN TXT "\"foo\"" txt12 3600 IN TXT "\"foo\"" txt13 3600 IN TXT "foo" u 300 IN TXT "txt-not-in-nxt" a.u 300 IN A 73.80.65.49 b.u 300 IN A 73.80.65.49 unknown2 3600 IN TYPE999 \# 8 0a0000010a000001 unknown3 3600 IN A 127.0.0.2 wks01 3600 IN WKS 10.0.0.1 6 0 1 2 21 23 wks02 3600 IN WKS 10.0.0.1 17 0 1 2 53 wks03 3600 IN WKS 10.0.0.2 6 65535 x2501 3600 IN X25 "123456789" LinkChecker-9.3/third_party/dnspython/tests/example0000644000175000017500000001756611570774061023447 0ustar calvincalvin00000000000000; Copyright (C) 2000, 2001 Internet Software Consortium. ; ; Permission to use, copy, modify, and distribute this software for any ; purpose with or without fee is hereby granted, provided that the above ; copyright notice and this permission notice appear in all copies. ; ; THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM ; DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ; INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, ; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING ; FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, ; NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION ; WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ; $Id: example,v 1.13 2004/03/19 00:06:37 halley Exp $ $ORIGIN . $TTL 300 ; 5 minutes example IN SOA ns1.example. hostmaster.example. ( 1 ; serial 2000 ; refresh (2000 seconds) 2000 ; retry (2000 seconds) 1814400 ; expire (3 weeks) 3600 ; minimum (1 hour) ) example. NS ns1.example. ns1.example. A 10.53.0.1 example. NS ns2.example. ns2.example. A 10.53.0.2 $ORIGIN example. * MX 10 mail a TXT "foo foo foo" PTR foo.net. ;; The next line not starting with ';;' is leading whitespace followed by ;; EOL. We want to treat that as if EOL had appeared alone. ;; The next line not starting with ';;' is leading whitespace followed by ;; a comment followed by EOL. We want to treat that as if EOL had appeared ;; alone. ; foo $TTL 3600 ; 1 hour a01 A 0.0.0.0 a02 A 255.255.255.255 ;; ;; XXXRTH dnspython doesn't currently implement A6, and since ;; A6 records are effectively dead, it may never do so. ;; ;;a601 A6 0 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ;; A6 64 ::ffff:ffff:ffff:ffff foo. ;; A6 127 ::1 foo. ;; A6 128 . aaaa01 AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff aaaa02 AAAA ::1 afsdb01 AFSDB 0 hostname afsdb02 AFSDB 65535 . $TTL 300 ; 5 minutes b CNAME foo.net. c A 73.80.65.49 $TTL 3600 ; 1 hour cert01 CERT 65534 65535 PRIVATEOID ( MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl d80jEeC8aTrO+KKmCaY= ) cname01 CNAME cname-target. cname02 CNAME cname-target cname03 CNAME . $TTL 300 ; 5 minutes d A 73.80.65.49 $TTL 3600 ; 1 hour dhcid01 DHCID ( AAIBY2/AuCccgoJbsaxcQc9TUapptP69l OjxfNuVAA2kjEA= ) dhcid02 DHCID ( AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQdW L3b/NaiUDlW2No= ) dhcid03 DHCID ( AAABxLmlskllE0MVjd57zHcWmEH3pCQ6V ytcKD//7es/deY= ) dname01 DNAME dname-target. dname02 DNAME dname-target dname03 DNAME . $TTL 300 ; 5 minutes e MX 10 mail TXT "one" TXT "three" TXT "two" A 73.80.65.49 A 73.80.65.50 A 73.80.65.52 A 73.80.65.51 f A 73.80.65.52 $TTL 3600 ; 1 hour gpos01 GPOS "-22.6882" "116.8652" "250.0" ;; ;; XXXRTH I have commented out the following line because I don't think ;; it is a valid GPOS record. ;; ;;gpos02 GPOS "" "" "" hinfo01 HINFO "Generic PC clone" "NetBSD-1.4" hinfo02 HINFO "PC" "NetBSD" isdn01 ISDN "isdn-address" isdn02 ISDN "isdn-address" "subaddress" isdn03 ISDN "isdn-address" isdn04 ISDN "isdn-address" "subaddress" ;; dnspython no longer supports old DNSSEC ;;key01 KEY 512 255 1 ( ;; AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR ;; yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 ;; GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o ;; jqf0BaqHT+8= ) ;;key02 KEY HOST|FLAG4 DNSSEC RSAMD5 ( ;; AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR ;; yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 ;; GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o ;; jqf0BaqHT+8= ) kx01 KX 10 kdc kx02 KX 10 . loc01 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20m 2000m 20m loc02 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20m 2000m 20m loc03 LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000m 20m loc04 LOC 60 9 1.5 N 24 39 0.000 E 10.00m 20m 2000m 20m loc05 LOC 60 9 1.51 N 24 39 0.000 E 10.00m 20m 2000m 20m ;; ;; XXXRTH These are all obsolete and unused. dnspython doesn't implement ;; them ;;mb01 MG madname ;;mb02 MG . ;;mg01 MG mgmname ;;mg02 MG . ;;minfo01 MINFO rmailbx emailbx ;;minfo02 MINFO . . ;;mr01 MR mrname ;;mr02 MR . mx01 MX 10 mail mx02 MX 10 . naptr01 NAPTR 0 0 "" "" "" . naptr02 NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo. nsap-ptr01 NSAP-PTR foo. NSAP-PTR . nsap01 NSAP 0x47000580005a0000000001e133ffffff00016100 nsap02 NSAP 0x47.000580005a0000000001e133ffffff000161.00 ;;nxt01 NXT a.secure ( NS SOA MX SIG KEY LOC NXT ) ;;nxt02 NXT . ( NSAP-PTR NXT ) ;;nxt03 NXT . ( A ) ;;nxt04 NXT . ( 127 ) ptr01 PTR example. px01 PX 65535 foo. bar. px02 PX 65535 . . rp01 RP mbox-dname txt-dname rp02 RP . . rt01 RT 0 intermediate-host rt02 RT 65535 . $TTL 300 ; 5 minutes s NS ns.s $ORIGIN s.example. ns A 73.80.65.49 $ORIGIN example. $TTL 3600 ; 1 hour ;;sig01 SIG NXT 1 3 3600 ( ;; 20200101000000 20030101000000 2143 foo ;; MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi ;; WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl ;; d80jEeC8aTrO+KKmCaY= ) srv01 SRV 0 0 0 . srv02 SRV 65535 65535 65535 old-slow-box.example.com. $TTL 301 ; 5 minutes 1 second t A 73.80.65.49 $TTL 3600 ; 1 hour txt01 TXT "foo" txt02 TXT "foo" "bar" txt03 TXT "foo" txt04 TXT "foo" "bar" txt05 TXT "foo bar" txt06 TXT "foo bar" txt07 TXT "foo bar" txt08 TXT "foo\010bar" txt09 TXT "foo\010bar" txt10 TXT "foo bar" txt11 TXT "\"foo\"" txt12 TXT "\"foo\"" txt13 TXT foo $TTL 300 ; 5 minutes u TXT "txt-not-in-nxt" $ORIGIN u.example. a A 73.80.65.49 b A 73.80.65.49 $ORIGIN example. $TTL 3600 ; 1 hour wks01 WKS 10.0.0.1 6 ( 0 1 2 21 23 ) wks02 WKS 10.0.0.1 17 ( 0 1 2 53 ) wks03 WKS 10.0.0.2 6 ( 65535 ) x2501 X25 "123456789" dlv01 DLV 12345 3 1 123456789abcdef67890123456789abcdef67890 ds01 DS 12345 3 1 123456789abcdef67890123456789abcdef67890 apl01 APL 1:192.168.32.0/21 !1:192.168.38.0/28 apl02 APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 unknown2 TYPE999 \# 8 0a0000010a000001 rrsig01 RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/ vILz45IkskceFGgiWCn/GxHhai6V AuHAoNUz4YoU1tVfSCSqQYn6//11 U6Nld80jEeC8aTrO+KKmCaY= nsec01 NSEC a.secure. A MX RRSIG NSEC TYPE1234 nsec02 NSEC . NSAP-PTR NSEC nsec03 NSEC . NSEC TYPE65535 dnskey01 DNSKEY 512 255 1 ( AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o jqf0BaqHT+8= ) dnskey02 DNSKEY 257 3 RSAMD5 ( AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o jqf0BaqHT+8= ) ; ; test known type using unknown RR syntax ; unknown3 A \# 4 7f000002 sshfp1 SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab spf SPF "v=spf1 mx -all" ipseckey01 IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey02 IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey03 IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey04 IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== ipseckey05 IPSECKEY 10 3 2 mygateway2 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== nsec301 NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG nsec302 NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG nsec3param01 NSEC3PARAM 1 1 12 aabbccdd nsec3param02 NSEC3PARAM 1 1 12 - hip01 HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2 LinkChecker-9.3/third_party/dnspython/tests/message.py0000644000175000017500000001273211570774061024055 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import cStringIO import os import unittest import dns.exception import dns.message query_text = """id 1234 opcode QUERY rcode NOERROR flags RD edns 0 eflags DO payload 4096 ;QUESTION wwww.dnspython.org. IN A ;ANSWER ;AUTHORITY ;ADDITIONAL""" goodhex = '04d201000001000000000001047777777709646e73707974686f6e' \ '036f726700000100010000291000000080000000' goodwire = goodhex.decode('hex_codec') answer_text = """id 1234 opcode QUERY rcode NOERROR flags QR AA RD ;QUESTION dnspython.org. IN SOA ;ANSWER dnspython.org. 3600 IN SOA woof.dnspython.org. hostmaster.dnspython.org. 2003052700 3600 1800 604800 3600 ;AUTHORITY dnspython.org. 3600 IN NS ns1.staff.nominum.org. dnspython.org. 3600 IN NS ns2.staff.nominum.org. dnspython.org. 3600 IN NS woof.play-bow.org. ;ADDITIONAL woof.play-bow.org. 3600 IN A 204.152.186.150 """ goodhex2 = '04d2 8500 0001 0001 0003 0001' \ '09646e73707974686f6e036f726700 0006 0001' \ 'c00c 0006 0001 00000e10 0028 ' \ '04776f6f66c00c 0a686f73746d6173746572c00c' \ '7764289c 00000e10 00000708 00093a80 00000e10' \ 'c00c 0002 0001 00000e10 0014' \ '036e7331057374616666076e6f6d696e756dc016' \ 'c00c 0002 0001 00000e10 0006 036e7332c063' \ 'c00c 0002 0001 00000e10 0010 04776f6f6608706c61792d626f77c016' \ 'c091 0001 0001 00000e10 0004 cc98ba96' goodwire2 = goodhex2.replace(' ', '').decode('hex_codec') query_text_2 = """id 1234 opcode QUERY rcode 4095 flags RD edns 0 eflags DO payload 4096 ;QUESTION wwww.dnspython.org. IN A ;ANSWER ;AUTHORITY ;ADDITIONAL""" goodhex3 = '04d2010f0001000000000001047777777709646e73707974686f6e' \ '036f726700000100010000291000ff0080000000' goodwire3 = goodhex3.decode('hex_codec') class MessageTestCase(unittest.TestCase): def test_comparison_eq1(self): q1 = dns.message.from_text(query_text) q2 = dns.message.from_text(query_text) self.failUnless(q1 == q2) def test_comparison_ne1(self): q1 = dns.message.from_text(query_text) q2 = dns.message.from_text(query_text) q2.id = 10 self.failUnless(q1 != q2) def test_comparison_ne2(self): q1 = dns.message.from_text(query_text) q2 = dns.message.from_text(query_text) q2.question = [] self.failUnless(q1 != q2) def test_comparison_ne3(self): q1 = dns.message.from_text(query_text) self.failUnless(q1 != 1) def test_EDNS_to_wire1(self): q = dns.message.from_text(query_text) w = q.to_wire() self.failUnless(w == goodwire) def test_EDNS_from_wire1(self): m = dns.message.from_wire(goodwire) self.failUnless(str(m) == query_text) def test_EDNS_to_wire2(self): q = dns.message.from_text(query_text_2) w = q.to_wire() self.failUnless(w == goodwire3) def test_EDNS_from_wire2(self): m = dns.message.from_wire(goodwire3) self.failUnless(str(m) == query_text_2) def test_TooBig(self): def bad(): q = dns.message.from_text(query_text) for i in xrange(0, 25): rrset = dns.rrset.from_text('foo%d.' % i, 3600, dns.rdataclass.IN, dns.rdatatype.A, '10.0.0.%d' % i) q.additional.append(rrset) w = q.to_wire(max_size=512) self.failUnlessRaises(dns.exception.TooBig, bad) def test_answer1(self): a = dns.message.from_text(answer_text) wire = a.to_wire(want_shuffle=False) self.failUnless(wire == goodwire2) def test_TrailingJunk(self): def bad(): badwire = goodwire + '\x00' m = dns.message.from_wire(badwire) self.failUnlessRaises(dns.message.TrailingJunk, bad) def test_ShortHeader(self): def bad(): badwire = '\x00' * 11 m = dns.message.from_wire(badwire) self.failUnlessRaises(dns.message.ShortHeader, bad) def test_RespondingToResponse(self): def bad(): q = dns.message.make_query('foo', 'A') r1 = dns.message.make_response(q) r2 = dns.message.make_response(r1) self.failUnlessRaises(dns.exception.FormError, bad) def test_ExtendedRcodeSetting(self): m = dns.message.make_query('foo', 'A') m.set_rcode(4095) self.failUnless(m.rcode() == 4095) m.set_rcode(2) self.failUnless(m.rcode() == 2) def test_EDNSVersionCoherence(self): m = dns.message.make_query('foo', 'A') m.use_edns(1) self.failUnless((m.ednsflags >> 16) & 0xFF == 1) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/bugs.py0000644000175000017500000000336611570774061023374 0ustar calvincalvin00000000000000# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.rdata import dns.rdataclass import dns.rdatatype import dns.ttl class BugsTestCase(unittest.TestCase): def test_float_LOC(self): rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.LOC, "30 30 0.000 N 100 30 0.000 W 10.00m 20m 2000m 20m") self.failUnless(rdata.float_latitude == 30.5) self.failUnless(rdata.float_longitude == -100.5) def test_SOA_BIND8_TTL(self): rdata1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, "a b 100 1s 1m 1h 1d") rdata2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, "a b 100 1 60 3600 86400") self.failUnless(rdata1 == rdata2) def test_TTL_bounds_check(self): def bad(): ttl = dns.ttl.from_text("2147483648") self.failUnlessRaises(dns.ttl.BadTTL, bad) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/dnspython/tests/namedict.py0000644000175000017500000000660311570774060024214 0ustar calvincalvin00000000000000# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import unittest import dns.name import dns.namedict class NameTestCase(unittest.TestCase): def setUp(self): self.ndict = dns.namedict.NameDict() n1 = dns.name.from_text('foo.bar.') n2 = dns.name.from_text('bar.') self.ndict[n1] = 1 self.ndict[n2] = 2 self.rndict = dns.namedict.NameDict() n1 = dns.name.from_text('foo.bar', None) n2 = dns.name.from_text('bar', None) self.rndict[n1] = 1 self.rndict[n2] = 2 def testDepth(self): self.failUnless(self.ndict.max_depth == 3) def testLookup1(self): k = dns.name.from_text('foo.bar.') self.failUnless(self.ndict[k] == 1) def testLookup2(self): k = dns.name.from_text('foo.bar.') self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) def testLookup3(self): k = dns.name.from_text('a.b.c.foo.bar.') self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) def testLookup4(self): k = dns.name.from_text('a.b.c.bar.') self.failUnless(self.ndict.get_deepest_match(k)[1] == 2) def testLookup5(self): def bad(): n = dns.name.from_text('a.b.c.') (k, v) = self.ndict.get_deepest_match(n) self.failUnlessRaises(KeyError, bad) def testLookup6(self): def bad(): (k, v) = self.ndict.get_deepest_match(dns.name.empty) self.failUnlessRaises(KeyError, bad) def testLookup7(self): self.ndict[dns.name.empty] = 100 n = dns.name.from_text('a.b.c.') (k, v) = self.ndict.get_deepest_match(n) self.failUnless(v == 100) def testLookup8(self): def bad(): self.ndict['foo'] = 100 self.failUnlessRaises(ValueError, bad) def testRelDepth(self): self.failUnless(self.rndict.max_depth == 2) def testRelLookup1(self): k = dns.name.from_text('foo.bar', None) self.failUnless(self.rndict[k] == 1) def testRelLookup2(self): k = dns.name.from_text('foo.bar', None) self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) def testRelLookup3(self): k = dns.name.from_text('a.b.c.foo.bar', None) self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) def testRelLookup4(self): k = dns.name.from_text('a.b.c.bar', None) self.failUnless(self.rndict.get_deepest_match(k)[1] == 2) def testRelLookup7(self): self.rndict[dns.name.empty] = 100 n = dns.name.from_text('a.b.c', None) (k, v) = self.rndict.get_deepest_match(n) self.failUnless(v == 100) if __name__ == '__main__': unittest.main() LinkChecker-9.3/third_party/miniboa-r42/0000750000175000017500000000000012361541761020676 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/miniboa-r42/handler_demo.py0000755000175000017500000000305711330070073023672 0ustar calvincalvin00000000000000#!/usr/bin/env python #------------------------------------------------------------------------------ # handler_demo.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ """ Example of using on_connect and on_disconnect handlers. """ from miniboa import TelnetServer CLIENTS = [] def my_on_connect(client): """ Example on_connect handler. """ client.send('You connected from %s\n' % client.addrport()) if CLIENTS: client.send('Also connected are:\n') for neighbor in CLIENTS: client.send('%s\n' % neighbor.addrport()) else: client.send('Sadly, you are alone.\n') CLIENTS.append(client) def my_on_disconnect(client): """ Example on_disconnect handler. """ CLIENTS.remove(client) server = TelnetServer() server.on_connect=my_on_connect server.on_disconnect=my_on_disconnect print "\n\nStarting server on port %d. CTRL-C to interrupt.\n" % server.port while True: server.poll() LinkChecker-9.3/third_party/miniboa-r42/chat_demo.py0000755000175000017500000000741611330070073023177 0ustar calvincalvin00000000000000#!/usr/bin/env python #------------------------------------------------------------------------------ # chat_demo.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ """ Chat Room Demo for Miniboa. """ from miniboa import TelnetServer IDLE_TIMEOUT = 300 CLIENT_LIST = [] SERVER_RUN = True def on_connect(client): """ Sample on_connect function. Handles new connections. """ print "++ Opened connection to %s" % client.addrport() broadcast('%s joins the conversation.\n' % client.addrport() ) CLIENT_LIST.append(client) client.send("Welcome to the Chat Server, %s.\n" % client.addrport() ) def on_disconnect(client): """ Sample on_disconnect function. Handles lost connections. """ print "-- Lost connection to %s" % client.addrport() CLIENT_LIST.remove(client) broadcast('%s leaves the conversation.\n' % client.addrport() ) def kick_idle(): """ Looks for idle clients and disconnects them by setting active to False. """ ## Who hasn't been typing? for client in CLIENT_LIST: if client.idle() > IDLE_TIMEOUT: print('-- Kicking idle lobby client from %s' % client.addrport()) client.active = False def process_clients(): """ Check each client, if client.cmd_ready == True then there is a line of input available via client.get_command(). """ for client in CLIENT_LIST: if client.active and client.cmd_ready: ## If the client sends input echo it to the chat room chat(client) def broadcast(msg): """ Send msg to every client. """ for client in CLIENT_LIST: client.send(msg) def chat(client): """ Echo whatever client types to everyone. """ global SERVER_RUN msg = client.get_command() print '%s says, "%s"' % (client.addrport(), msg) for guest in CLIENT_LIST: if guest != client: guest.send('%s says, %s\n' % (client.addrport(), msg)) else: guest.send('You say, %s\n' % msg) cmd = msg.lower() ## bye = disconnect if cmd == 'bye': client.active = False ## shutdown == stop the server elif cmd == 'shutdown': SERVER_RUN = False #------------------------------------------------------------------------------ # Main #------------------------------------------------------------------------------ if __name__ == '__main__': ## Simple chat server to demonstrate connection handling via the ## async and telnet modules. ## Create a telnet server with a port, address, ## a function to call with new connections ## and one to call with lost connections. telnet_server = TelnetServer( port=7777, address='', on_connect=on_connect, on_disconnect=on_disconnect, timeout = .05 ) print(">> Listening for connections on port %d. CTRL-C to break." % telnet_server.port) ## Server Loop while SERVER_RUN: telnet_server.poll() ## Send, Recv, and look for new connections kick_idle() ## Check for idle clients process_clients() ## Check for client input print(">> Server shutdown.") LinkChecker-9.3/third_party/miniboa-r42/LICENSE.txt0000644000175000017500000002420511330070073022515 0ustar calvincalvin00000000000000Apache License, Version 2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and 2. You must cause any modified files to carry prominent notices stating that You changed the files; and 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. LinkChecker-9.3/third_party/miniboa-r42/hello_demo.py0000755000175000017500000000212611330070073023354 0ustar calvincalvin00000000000000#!/usr/bin/env python #------------------------------------------------------------------------------ # hello_demo.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ """ As simple as it gets. Launch the Telnet server on the default port and greet visitors using the placeholder 'on_connect()' function. Does nothing else. """ from miniboa import TelnetServer server = TelnetServer() print "\n\nStarting server on port %d. CTRL-C to interrupt.\n" % server.port while True: server.poll() LinkChecker-9.3/third_party/miniboa-r42/README.txt0000644000175000017500000000221311330070073022363 0ustar calvincalvin00000000000000Hello. This package is the networking modules (async.py and telnet.py) from the Python based MUD I've been working on. I've had a couple folks ask if I would be willing to release them under a more permissive license than the GPL. While I believe in the GPL for growing a community around a project, but I also understand the appeal of non-copyleft for maximum flexibility with regards to support modules. I removed all the non-network dependencies, cleaned up the code a bit, re-licensed it, and added a small chat server to demo it in action. Please note that the Apache 2.0 license only applies to these three files (given the chaotic state of the MUD, you're not missing much). I wanted to use the Python License but, apparently, that is designed for use only by the Python Software Foundation. Their FAQ page listed the Apache 2.0 license as compatible so I'm using that instead. Please note that I have not tested these modules under Windows -- it being all icky and stuff. I would appreciate any fixes you find necessary. Enjoy Miniboa and please let me know if you build anything cool. Regards, Jim Storch 'wvzfgbepu@tznvy.pbz'.encode('rot13') LinkChecker-9.3/third_party/miniboa-r42/miniboa/0000750000175000017500000000000012361541761022314 5ustar calvincalvin00000000000000LinkChecker-9.3/third_party/miniboa-r42/miniboa/xterm.py0000644000175000017500000000750711332275707024044 0ustar calvincalvin00000000000000# -*- coding: utf-8 -*- #------------------------------------------------------------------------------ # mudlib/usr/xterm.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ """ Support for color and formatting for Xterm style clients. """ import re _PARA_BREAK = re.compile(r"(\n\s*\n)", re.MULTILINE) #--[ Caret Code to ANSI TABLE ]------------------------------------------------ _ANSI_CODES = ( ( '^k', '\x1b[22;30m' ), # black ( '^K', '\x1b[1;30m' ), # bright black (grey) ( '^r', '\x1b[22;31m' ), # red ( '^R', '\x1b[1;31m' ), # bright red ( '^g', '\x1b[22;32m' ), # green ( '^G', '\x1b[1;32m' ), # bright green ( '^y', '\x1b[22;33m' ), # yellow ( '^Y', '\x1b[1;33m' ), # bright yellow ( '^b', '\x1b[22;34m' ), # blue ( '^B', '\x1b[1;34m' ), # bright blue ( '^m', '\x1b[22;35m' ), # magenta ( '^M', '\x1b[1;35m' ), # bright magenta ( '^c', '\x1b[22;36m' ), # cyan ( '^C', '\x1b[1;36m' ), # bright cyan ( '^w', '\x1b[22;37m' ), # white ( '^W', '\x1b[1;37m' ), # bright white ( '^0', '\x1b[40m' ), # black background ( '^1', '\x1b[41m' ), # red background ( '^2', '\x1b[42m' ), # green background ( '^3', '\x1b[43m' ), # yellow background ( '^4', '\x1b[44m' ), # blue background ( '^5', '\x1b[45m' ), # magenta background ( '^6', '\x1b[46m' ), # cyan background ( '^d', '\x1b[39m' ), # default (should be white on black) ( '^I', '\x1b[7m' ), # inverse text on ( '^i', '\x1b[27m' ), # inverse text off ( '^~', '\x1b[0m' ), # reset all ( '^U', '\x1b[4m' ), # underline on ( '^u', '\x1b[24m' ), # underline off ( '^!', '\x1b[1m' ), # bold on ( '^.', '\x1b[22m'), # bold off ( '^s', '\x1b[2J'), # clear screen ( '^l', '\x1b[2K'), # clear to end of line ) def strip_caret_codes(text): """ Strip out any caret codes from a string. """ ## temporarily escape out ^^ text = text.replace('^^', '\x00') for token, foo in _ANSI_CODES: text = text.replace(token, '') return text.replace('\x00', '^') def colorize(text, ansi=True): """ If the client wants ansi, replace the tokens with ansi sequences -- otherwise, simply strip them out. """ if ansi: text = text.replace('^^', '\x00') for token, code in _ANSI_CODES: text = text.replace(token, code) text = text.replace('\x00', '^') else: text = strip_caret_codes(text) return text def word_wrap(text, columns=80, indent=4, padding=2): """ Given a block of text, breaks into a list of lines wrapped to length. """ paragraphs = _PARA_BREAK.split(text) lines = [] columns -= padding for para in paragraphs: if para.isspace(): continue line = ' ' * indent for word in para.split(): if (len(line) + 1 + len(word)) > columns: lines.append(line) line = ' ' * padding line += word else: line += ' ' + word if not line.isspace(): lines.append(line) return lines LinkChecker-9.3/third_party/miniboa-r42/miniboa/telnet.py0000644000175000017500000006047211330070073024163 0ustar calvincalvin00000000000000# -*- coding: utf-8 -*- #------------------------------------------------------------------------------ # miniboa/telnet.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ """ Manage one Telnet client connected via a TCP/IP socket. """ import socket import time from miniboa.error import BogConnectionLost from miniboa.xterm import colorize from miniboa.xterm import word_wrap #---[ Telnet Notes ]----------------------------------------------------------- # (See RFC 854 for more information) # # Negotiating a Local Option # -------------------------- # # Side A begins with: # # "IAC WILL/WONT XX" Meaning "I would like to [use|not use] option XX." # # Side B replies with either: # # "IAC DO XX" Meaning "OK, you may use option XX." # "IAC DONT XX" Meaning "No, you cannot use option XX." # # # Negotiating a Remote Option # ---------------------------- # # Side A begins with: # # "IAC DO/DONT XX" Meaning "I would like YOU to [use|not use] option XX." # # Side B replies with either: # # "IAC WILL XX" Meaning "I will begin using option XX" # "IAC WONT XX" Meaning "I will not begin using option XX" # # # The syntax is designed so that if both parties receive simultaneous requests # for the same option, each will see the other's request as a positive # acknowledgement of it's own. # # If a party receives a request to enter a mode that it is already in, the # request should not be acknowledged. ## Where you see DE in my comments I mean 'Distant End', e.g. the client. UNKNOWN = -1 #--[ Telnet Commands ]--------------------------------------------------------- SE = chr(240) # End of subnegotiation parameters NOP = chr(241) # No operation DATMK = chr(242) # Data stream portion of a sync. BREAK = chr(243) # NVT Character BRK IP = chr(244) # Interrupt Process AO = chr(245) # Abort Output AYT = chr(246) # Are you there EC = chr(247) # Erase Character EL = chr(248) # Erase Line GA = chr(249) # The Go Ahead Signal SB = chr(250) # Sub-option to follow WILL = chr(251) # Will; request or confirm option begin WONT = chr(252) # Wont; deny option request DO = chr(253) # Do = Request or confirm remote option DONT = chr(254) # Don't = Demand or confirm option halt IAC = chr(255) # Interpret as Command SEND = chr(001) # Sub-process negotiation SEND command IS = chr(000) # Sub-process negotiation IS command #--[ Telnet Options ]---------------------------------------------------------- BINARY = chr( 0) # Transmit Binary ECHO = chr( 1) # Echo characters back to sender RECON = chr( 2) # Reconnection SGA = chr( 3) # Suppress Go-Ahead TTYPE = chr( 24) # Terminal Type NAWS = chr( 31) # Negotiate About Window Size LINEMO = chr( 34) # Line Mode #-----------------------------------------------------------------Telnet Option class TelnetOption(object): """ Simple class used to track the status of an extended Telnet option. """ def __init__(self): self.local_option = UNKNOWN # Local state of an option self.remote_option = UNKNOWN # Remote state of an option self.reply_pending = False # Are we expecting a reply? #------------------------------------------------------------------------Telnet class TelnetClient(object): """ Represents a client connection via Telnet. First argument is the socket discovered by the Telnet Server. Second argument is the tuple (ip address, port number). """ def __init__(self, sock, addr_tup): self.protocol = 'telnet' self.active = True # Turns False when the connection is lost self.sock = sock # The connection's socket self.fileno = sock.fileno() # The socket's file descriptor self.address = addr_tup[0] # The client's remote TCP/IP address self.port = addr_tup[1] # The client's remote port self.terminal_type = 'unknown client' # set via request_terminal_type() self.use_ansi = True self.columns = 80 self.rows = 24 self.send_pending = False self.send_buffer = '' self.recv_buffer = '' self.bytes_sent = 0 self.bytes_received = 0 self.cmd_ready = False self.command_list = [] self.connect_time = time.time() self.last_input_time = time.time() ## State variables for interpreting incoming telnet commands self.telnet_got_iac = False # Are we inside an IAC sequence? self.telnet_got_cmd = None # Did we get a telnet command? self.telnet_got_sb = False # Are we inside a subnegotiation? self.telnet_opt_dict = {} # Mapping for up to 256 TelnetOptions self.telnet_echo = False # Echo input back to the client? self.telnet_echo_password = False # Echo back '*' for passwords? self.telnet_sb_buffer = '' # Buffer for sub-negotiations # def __del__(self): # print "Telnet destructor called" # pass def get_command(self): """ Get a line of text that was received from the DE. The class's cmd_ready attribute will be true if lines are available. """ cmd = None count = len(self.command_list) if count > 0: cmd = self.command_list.pop(0) ## If that was the last line, turn off lines_pending if count == 1: self.cmd_ready = False return cmd def send(self, text): """ Send raw text to the distant end. """ if text: self.send_buffer += text.replace('\n', '\r\n') self.send_pending = True def send_cc(self, text): """ Send text with caret codes converted to ansi. """ self.send(colorize(text, self.use_ansi)) def send_wrapped(self, text): """ Send text padded and wrapped to the user's screen width. """ lines = word_wrap(text, self.columns) for line in lines: self.send_cc(line + '\n') def deactivate(self): """ Set the client to disconnect on the next server poll. """ self.active = False def addrport(self): """ Return the DE's IP address and port number as a string. """ return "%s:%s" % (self.address, self.port) def idle(self): """ Returns the number of seconds that have elasped since the DE last sent us some input. """ return time.time() - self.last_input_time def duration(self): """ Returns the number of seconds the DE has been connected. """ return time.time() - self.connect_time def request_do_sga(self): """ Request DE to Suppress Go-Ahead. See RFC 858. """ self._iac_do(SGA) self._note_reply_pending(SGA, True) def request_will_echo(self): """ Tell the DE that we would like to echo their text. See RFC 857. """ self._iac_will(ECHO) self._note_reply_pending(ECHO, True) self.telnet_echo = True def request_wont_echo(self): """ Tell the DE that we would like to stop echoing their text. See RFC 857. """ self._iac_wont(ECHO) self._note_reply_pending(ECHO, True) self.telnet_echo = False def password_mode_on(self): """ Tell DE we will echo (but don't) so typed passwords don't show. """ self._iac_will(ECHO) self._note_reply_pending(ECHO, True) def password_mode_off(self): """ Tell DE we are done echoing (we lied) and show typing again. """ self._iac_wont(ECHO) self._note_reply_pending(ECHO, True) def request_naws(self): """ Request to Negotiate About Window Size. See RFC 1073. """ self._iac_do(NAWS) self._note_reply_pending(NAWS, True) def request_terminal_type(self): """ Begins the Telnet negotiations to request the terminal type from the client. See RFC 779. """ self._iac_do(TTYPE) self._note_reply_pending(TTYPE, True) def socket_send(self): """ Called by TelnetServer when send data is ready. """ if len(self.send_buffer): try: sent = self.sock.send(self.send_buffer) except socket.error, err: print("!! SEND error '%d:%s' from %s" % (err[0], err[1], self.addrport())) self.active = False return self.bytes_sent += sent self.send_buffer = self.send_buffer[sent:] else: self.send_pending = False def socket_recv(self): """ Called by TelnetServer when recv data is ready. """ try: data = self.sock.recv(2048) except socket.error, ex: print ("?? socket.recv() error '%d:%s' from %s" % (ex[0], ex[1], self.addrport())) raise BogConnectionLost() ## Did they close the connection? size = len(data) if size == 0: raise BogConnectionLost() ## Update some trackers self.last_input_time = time.time() self.bytes_received += size ## Test for telnet commands for byte in data: self._iac_sniffer(byte) ## Look for newline characters to get whole lines from the buffer while True: mark = self.recv_buffer.find('\n') if mark == -1: break cmd = self.recv_buffer[:mark].strip() self.command_list.append(cmd) self.cmd_ready = True self.recv_buffer = self.recv_buffer[mark+1:] def _recv_byte(self, byte): """ Non-printable filtering currently disabled because it did not play well with extended character sets. """ ## Filter out non-printing characters #if (byte >= ' ' and byte <= '~') or byte == '\n': if self.telnet_echo: self._echo_byte(byte) self.recv_buffer += byte def _echo_byte(self, byte): """ Echo a character back to the client and convert LF into CR\LF. """ if byte == '\n': self.send_buffer += '\r' if self.telnet_echo_password: self.send_buffer += '*' else: self.send_buffer += byte def _iac_sniffer(self, byte): """ Watches incomming data for Telnet IAC sequences. Passes the data, if any, with the IAC commands stripped to _recv_byte(). """ ## Are we not currently in an IAC sequence coming from the DE? if self.telnet_got_iac is False: if byte == IAC: ## Well, we are now self.telnet_got_iac = True return ## Are we currenty in a sub-negotion? elif self.telnet_got_sb is True: ## Sanity check on length if len(self.telnet_sb_buffer) < 64: self.telnet_sb_buffer += byte else: self.telnet_got_sb = False self.telnet_sb_buffer = "" return else: ## Just a normal NVT character self._recv_byte(byte) return ## Byte handling when already in an IAC sequence sent from the DE else: ## Did we get sent a second IAC? if byte == IAC and self.telnet_got_sb is True: ## Must be an escaped 255 (IAC + IAC) self.telnet_sb_buffer += byte self.telnet_got_iac = False return ## Do we already have an IAC + CMD? elif self.telnet_got_cmd: ## Yes, so handle the option self._three_byte_cmd(byte) return ## We have IAC but no CMD else: ## Is this the middle byte of a three-byte command? if byte == DO: self.telnet_got_cmd = DO return elif byte == DONT: self.telnet_got_cmd = DONT return elif byte == WILL: self.telnet_got_cmd = WILL return elif byte == WONT: self.telnet_got_cmd = WONT return else: ## Nope, must be a two-byte command self._two_byte_cmd(byte) def _two_byte_cmd(self, cmd): """ Handle incoming Telnet commands that are two bytes long. """ #print "got two byte cmd %d" % ord(cmd) if cmd == SB: ## Begin capturing a sub-negotiation string self.telnet_got_sb = True self.telnet_sb_buffer = '' elif cmd == SE: ## Stop capturing a sub-negotiation string self.telnet_got_sb = False self._sb_decoder() elif cmd == NOP: pass elif cmd == DATMK: pass elif cmd == IP: pass elif cmd == AO: pass elif cmd == AYT: pass elif cmd == EC: pass elif cmd == EL: pass elif cmd == GA: pass else: print "2BC: Should not be here." self.telnet_got_iac = False self.telnet_got_cmd = None def _three_byte_cmd(self, option): """ Handle incoming Telnet commmands that are three bytes long. """ cmd = self.telnet_got_cmd #print "got three byte cmd %d:%d" % (ord(cmd), ord(option)) ## Incoming DO's and DONT's refer to the status of this end #---[ DO ]------------------------------------------------------------- if cmd == DO: if option == BINARY: if self._check_reply_pending(BINARY): self._note_reply_pending(BINARY, False) self._note_local_option(BINARY, True) elif (self._check_local_option(BINARY) is False or self._check_local_option(BINARY) is UNKNOWN): self._note_local_option(BINARY, True) self._iac_will(BINARY) ## Just nod elif option == ECHO: if self._check_reply_pending(ECHO): self._note_reply_pending(ECHO, False) self._note_local_option(ECHO, True) elif (self._check_local_option(ECHO) is False or self._check_local_option(ECHO) is UNKNOWN): self._note_local_option(ECHO, True) self._iac_will(ECHO) self.telnet_echo = True elif option == SGA: if self._check_reply_pending(SGA): self._note_reply_pending(SGA, False) self._note_local_option(SGA, True) elif (self._check_local_option(SGA) is False or self._check_local_option(SGA) is UNKNOWN): self._note_local_option(SGA, True) self._iac_will(SGA) ## Just nod else: ## ALL OTHER OTHERS = Default to refusing once if self._check_local_option(option) is UNKNOWN: self._note_local_option(option, False) self._iac_wont(option) #---[ DONT ]----------------------------------------------------------- elif cmd == DONT: if option == BINARY: if self._check_reply_pending(BINARY): self._note_reply_pending(BINARY, False) self._note_local_option(BINARY, False) elif (self._check_local_option(BINARY) is True or self._check_local_option(BINARY) is UNKNOWN): self._note_local_option(BINARY, False) self._iac_wont(BINARY) ## Just nod elif option == ECHO: if self._check_reply_pending(ECHO): self._note_reply_pending(ECHO, False) self._note_local_option(ECHO, True) self.telnet_echo = False elif (self._check_local_option(BINARY) is True or self._check_local_option(BINARY) is UNKNOWN): self._note_local_option(ECHO, False) self._iac_wont(ECHO) self.telnet_echo = False elif option == SGA: if self._check_reply_pending(SGA): self._note_reply_pending(SGA, False) self._note_local_option(SGA, False) elif (self._check_remote_option(SGA) is True or self._check_remote_option(SGA) is UNKNOWN): self._note_local_option(SGA, False) self._iac_will(SGA) ## Just nod else: ## ALL OTHER OPTIONS = Default to ignoring pass ## Incoming WILL's and WONT's refer to the status of the DE #---[ WILL ]----------------------------------------------------------- elif cmd == WILL: if option == ECHO: ## Nutjob DE offering to echo the server... if self._check_remote_option(ECHO) is UNKNOWN: self._note_remote_option(ECHO, False) # No no, bad DE! self._iac_dont(ECHO) elif option == NAWS: if self._check_reply_pending(NAWS): self._note_reply_pending(NAWS, False) self._note_remote_option(NAWS, True) ## Nothing else to do, client follow with SB elif (self._check_remote_option(NAWS) is False or self._check_remote_option(NAWS) is UNKNOWN): self._note_remote_option(NAWS, True) self._iac_do(NAWS) ## Client should respond with SB elif option == SGA: if self._check_reply_pending(SGA): self._note_reply_pending(SGA, False) self._note_remote_option(SGA, True) elif (self._check_remote_option(SGA) is False or self._check_remote_option(SGA) is UNKNOWN): self._note_remote_option(SGA, True) self._iac_do(SGA) ## Just nod elif option == TTYPE: if self._check_reply_pending(TTYPE): self._note_reply_pending(TTYPE, False) self._note_remote_option(TTYPE, True) ## Tell them to send their terminal type self.send('%c%c%c%c%c%c' % (IAC, SB, TTYPE, SEND, IAC, SE)) elif (self._check_remote_option(TTYPE) is False or self._check_remote_option(TTYPE) is UNKNOWN): self._note_remote_option(TTYPE, True) self._iac_do(TTYPE) #---[ WONT ]----------------------------------------------------------- elif cmd == WONT: if option == ECHO: ## DE states it wont echo us -- good, they're not suppose to. if self._check_remote_option(ECHO) is UNKNOWN: self._note_remote_option(ECHO, False) self._iac_dont(ECHO) elif option == SGA: if self._check_reply_pending(SGA): self._note_reply_pending(SGA, False) self._note_remote_option(SGA, False) elif (self._check_remote_option(SGA) is True or self._check_remote_option(SGA) is UNKNOWN): self._note_remote_option(SGA, False) self._iac_dont(SGA) if self._check_reply_pending(TTYPE): self._note_reply_pending(TTYPE, False) self._note_remote_option(TTYPE, False) elif (self._check_remote_option(TTYPE) is True or self._check_remote_option(TTYPE) is UNKNOWN): self._note_remote_option(TTYPE, False) self._iac_dont(TTYPE) else: print "3BC: Should not be here." self.telnet_got_iac = False self.telnet_got_cmd = None def _sb_decoder(self): """ Figures out what to do with a received sub-negotiation block. """ #print "at decoder" bloc = self.telnet_sb_buffer if len(bloc) > 2: if bloc[0] == TTYPE and bloc[1] == IS: self.terminal_type = bloc[2:] #print "Terminal type = '%s'" % self.terminal_type if bloc[0] == NAWS: if len(bloc) != 5: print "Bad length on NAWS SB:", len(bloc) else: self.columns = (256 * ord(bloc[1])) + ord(bloc[2]) self.rows = (256 * ord(bloc[3])) + ord(bloc[4]) #print "Screen is %d x %d" % (self.columns, self.rows) self.telnet_sb_buffer = '' #---[ State Juggling for Telnet Options ]---------------------------------- ## Sometimes verbiage is tricky. I use 'note' rather than 'set' here ## because (to me) set infers something happened. def _check_local_option(self, option): """Test the status of local negotiated Telnet options.""" if not self.telnet_opt_dict.has_key(option): self.telnet_opt_dict[option] = TelnetOption() return self.telnet_opt_dict[option].local_option def _note_local_option(self, option, state): """Record the status of local negotiated Telnet options.""" if not self.telnet_opt_dict.has_key(option): self.telnet_opt_dict[option] = TelnetOption() self.telnet_opt_dict[option].local_option = state def _check_remote_option(self, option): """Test the status of remote negotiated Telnet options.""" if not self.telnet_opt_dict.has_key(option): self.telnet_opt_dict[option] = TelnetOption() return self.telnet_opt_dict[option].remote_option def _note_remote_option(self, option, state): """Record the status of local negotiated Telnet options.""" if not self.telnet_opt_dict.has_key(option): self.telnet_opt_dict[option] = TelnetOption() self.telnet_opt_dict[option].remote_option = state def _check_reply_pending(self, option): """Test the status of requested Telnet options.""" if not self.telnet_opt_dict.has_key(option): self.telnet_opt_dict[option] = TelnetOption() return self.telnet_opt_dict[option].reply_pending def _note_reply_pending(self, option, state): """Record the status of requested Telnet options.""" if not self.telnet_opt_dict.has_key(option): self.telnet_opt_dict[option] = TelnetOption() self.telnet_opt_dict[option].reply_pending = state #---[ Telnet Command Shortcuts ]------------------------------------------- def _iac_do(self, option): """Send a Telnet IAC "DO" sequence.""" self.send('%c%c%c' % (IAC, DO, option)) def _iac_dont(self, option): """Send a Telnet IAC "DONT" sequence.""" self.send('%c%c%c' % (IAC, DONT, option)) def _iac_will(self, option): """Send a Telnet IAC "WILL" sequence.""" self.send('%c%c%c' % (IAC, WILL, option)) def _iac_wont(self, option): """Send a Telnet IAC "WONT" sequence.""" self.send('%c%c%c' % (IAC, WONT, option)) LinkChecker-9.3/third_party/miniboa-r42/miniboa/error.py0000644000175000017500000000162611330070073024015 0ustar calvincalvin00000000000000# -*- coding: utf-8 -*- #------------------------------------------------------------------------------ # miniboa/error.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ class BogConnectionLost(Exception): """ Custom exception to signal a lost connection to the Telnet Server. """ pass LinkChecker-9.3/third_party/miniboa-r42/miniboa/__init__.py0000644000175000017500000000147711330070073024427 0ustar calvincalvin00000000000000# -*- coding: utf-8 -*- #------------------------------------------------------------------------------ # miniboa/__init__.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ from miniboa.async import TelnetServer LinkChecker-9.3/third_party/miniboa-r42/miniboa/async.py0000644000175000017500000001530112043507357024010 0ustar calvincalvin00000000000000# -*- coding: utf-8 -*- #------------------------------------------------------------------------------ # miniboa/async.py # Copyright 2009 Jim Storch # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. #------------------------------------------------------------------------------ """ Handle Asynchronous Telnet Connections. """ import socket import select import sys from miniboa.telnet import TelnetClient from miniboa.error import BogConnectionLost ## Cap sockets to 512 on Windows because winsock can only process 512 at time if sys.platform == 'win32': MAX_CONNECTIONS = 512 ## Cap sockets to 1000 on Linux because you can only have 1024 file descriptors else: MAX_CONNECTIONS = 1000 #-----------------------------------------------------Dummy Connection Handlers def _on_connect(client): """ Placeholder new connection handler. """ print "++ Opened connection to %s, sending greeting..." % client.addrport() client.send("Greetings from Miniboa! " " Now it's time to add your code.\n") def _on_disconnect(client): """ Placeholder lost connection handler. """ print "-- Lost connection to %s" % client.addrport() #-----------------------------------------------------------------Telnet Server class TelnetServer(object): """ Poll sockets for new connections and sending/receiving data from clients. """ def __init__(self, port=7777, host='', on_connect=_on_connect, on_disconnect=_on_disconnect, timeout=0.005): """ Create a new Telnet Server. port -- Port to listen for new connection on. On UNIX-like platforms, you made need root access to use ports under 1025. host -- Address of the LOCAL network interface to listen on. You can usually leave this blank unless you want to restrict traffic to a specific network device. This will usually NOT be the same as the Internet address of your server. on_connect -- function to call with new telnet connections on_disconnect -- function to call when a client's connection dies, either through a terminated session or client.active being set to False. timeout -- amount of time that Poll() will wait from user inport before returning. Also frees a slice of CPU time. """ self.port = port self.host = host self.on_connect = on_connect self.on_disconnect = on_disconnect self.timeout = timeout server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((host, port)) self.address = server_socket.getsockname() server_socket.listen(5) self.server_socket = server_socket self.server_fileno = server_socket.fileno() ## Dictionary of active clients, ## key = file descriptor, value = TelnetClient (see miniboa.telnet) self.clients = {} def client_count(self): """ Returns the number of active connections. """ return len(self.clients) def client_list(self): """ Returns a list of connected clients. """ return self.clients.values() def poll(self): """ Perform a non-blocking scan of recv and send states on the server and client connection sockets. Process new connection requests, read incomming data, and send outgoing data. Sends and receives may be partial. """ #print len(self.connections) ## Build a list of connections to test for receive data pending recv_list = [self.server_fileno] # always add the server for client in self.clients.values(): if client.active: recv_list.append(client.fileno) ## Delete inactive connections from the dictionary else: #print "-- Lost connection to %s" % client.addrport() #client.sock.close() self.on_disconnect(client) del self.clients[client.fileno] ## Build a list of connections that need to send data send_list = [] for client in self.clients.values(): if client.send_pending: send_list.append(client.fileno) ## Get active socket file descriptors from select.select() try: rlist, slist, elist = select.select(recv_list, send_list, [], self.timeout) except select.error, err: ## If we can't even use select(), game over man, game over print >> sys.stderr, ("!! FATAL SELECT error '%d:%s'!" % (err[0], err[1])) sys.exit(1) ## Process socket file descriptors with data to recieve for sock_fileno in rlist: ## If it's coming from the server's socket then this is a new ## connection request. if sock_fileno == self.server_fileno: try: sock, addr_tup = self.server_socket.accept() except socket.error, err: print >> sys.stderr, ("!! ACCEPT error '%d:%s'." % (err[0], err[1])) continue ## Check for maximum connections if self.client_count() >= MAX_CONNECTIONS: print '?? Refusing new connection; maximum in use.' sock.close() continue new_client = TelnetClient(sock, addr_tup) #print "++ Opened connection to %s" % new_client.addrport() ## Add the connection to our dictionary and call handler self.clients[new_client.fileno] = new_client self.on_connect(new_client) else: ## Call the connection's recieve method try: self.clients[sock_fileno].socket_recv() except BogConnectionLost: self.clients[sock_fileno].deactivate() ## Process sockets with data to send for sock_fileno in slist: ## Call the connection's send method self.clients[sock_fileno].socket_send() LinkChecker-9.3/third_party/miniboa-r42/CHANGES.txt0000644000175000017500000000030212043704435022503 0ustar calvincalvin00000000000000The following changes have been applied to the original sources. miniboa/async.py: - rename address to host - removed sys.exit() call on errors Note that this module is only used for testing. LinkChecker-9.3/install-rpm.sh0000644000175000017500000000213611741327612017125 0ustar calvincalvin00000000000000python setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES # 'brp-compress' compresses the manpages without distutils knowing. # The sed scripts append ".gz", ".bz2" or ".xz" suffixes to the affected # manpage filenames. RPM_MANDIR=usr/share/man RPM_LOCALMANDIR=usr/local/share/man if [ -n "$( ls $RPM_BUILD_ROOT/$RPM_MANDIR/man*/*.bz2 2>/dev/null )" \ -o -n "$( ls $RPM_BUILD_ROOT/$RPM_LOCALMANDIR/man*/*.bz2 2>/dev/null )" ]; then # add .bz2 suffix sed -i -e 's@man/man\([[:digit:]]\)/\(.\+\.[[:digit:]]\)$@man/man\1/\2.bz2@g' INSTALLED_FILES elif [ -n "$( ls $RPM_BUILD_ROOT/$RPM_MANDIR/man*/*.xz 2>/dev/null )" \ -o -n "$( ls $RPM_BUILD_ROOT/$RPM_LOCALMANDIR/man*/*.xz 2>/dev/null )" ]; then # add .xz suffix sed -i -e 's@man/man\([[:digit:]]\)/\(.\+\.[[:digit:]]\)$@man/man\1/\2.xz@g' INSTALLED_FILES elif [ -n "$( ls $RPM_BUILD_ROOT/$RPM_MANDIR/man*/*.gz 2>/dev/null )" \ -o -n "$( ls $RPM_BUILD_ROOT/$RPM_LOCALMANDIR/man*/*.gz 2>/dev/null )" ]; then # add .gz suffix sed -i -e 's@man/man\([[:digit:]]\)/\(.\+\.[[:digit:]]\)$@man/man\1/\2.gz@g' INSTALLED_FILES fi LinkChecker-9.3/scripts/0000750000175000017500000000000012361541761016011 5ustar calvincalvin00000000000000LinkChecker-9.3/scripts/update_iana_uri_schemes.sh0000755000175000017500000000044412361407402023210 0ustar calvincalvin00000000000000#!/bin/bash # Update the list of unknown and therefore ignored URL schemes. set -o nounset set -o errexit set -o pipefail #set -o xtrace target=linkcheck/checker/unknownurl.py python scripts/removeafter.py "$target" "# DO NOT REMOVE" python scripts/update_iana_uri_schemes.py >> "$target" LinkChecker-9.3/scripts/update_iana_uri_schemes.py0000644000175000017500000000600112361407402023216 0ustar calvincalvin00000000000000import sys import re import csv import requests iana_uri_schemes = "https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml" # CSV format: URI Scheme,Template,Description,Reference csv_iana_uri_schemes_permanent = 'https://www.iana.org/assignments/uri-schemes/uri-schemes-1.csv' csv_iana_uri_schemes_provisional = 'https://www.iana.org/assignments/uri-schemes/uri-schemes-2.csv' csv_iana_uri_schemes_historical = 'https://www.iana.org/assignments/uri-schemes/uri-schemes-3.csv' iana_uri_schemes_permanent = {} iana_uri_schemes_provisional = {} iana_uri_schemes_historical = {} iana_uri_schemes_other = { "clsid": "Microsoft specific", "find" : "Mozilla specific", "isbn" : "ISBN (int. book numbers)", "javascript": "JavaScript", } filter_uri_schemes_permanent = ( "file", "ftp", "http", "https", "mailto", "news", "nntp", ) template = ''' # from %(uri)s ignored_schemes_permanent = r""" %(permanent)s """ ignored_schemes_provisional = r""" %(provisional)s """ ignored_schemes_historical = r""" %(historical)s """ ignored_schemes_other = r""" %(other)s """ ignored_schemes = "^(%%s%%s%%s%%s)$" %% ( ignored_schemes_permanent, ignored_schemes_provisional, ignored_schemes_historical, ignored_schemes_other, ) ignored_schemes_re = re.compile(ignored_schemes, re.VERBOSE) is_unknown_scheme = ignored_schemes_re.match ''' def main(args): parse_csv_file(csv_iana_uri_schemes_permanent, iana_uri_schemes_permanent) parse_csv_file(csv_iana_uri_schemes_provisional, iana_uri_schemes_provisional) parse_csv_file(csv_iana_uri_schemes_historical, iana_uri_schemes_historical) for scheme in iana_uri_schemes_other: if (scheme in iana_uri_schemes_permanent or scheme in iana_uri_schemes_provisional or scheme in iana_uri_schemes_historical): raise ValueError(scheme) for scheme in filter_uri_schemes_permanent: if scheme in iana_uri_schemes_permanent: del iana_uri_schemes_permanent[scheme] args = dict( uri = iana_uri_schemes, permanent = get_regex(iana_uri_schemes_permanent), provisional = get_regex(iana_uri_schemes_provisional), historical = get_regex(iana_uri_schemes_historical), other = get_regex(iana_uri_schemes_other), ) res = template % args print res return 0 def get_regex(schemes): expr = ["|%s # %s" % (re.escape(scheme).ljust(10), description) for scheme, description in sorted(schemes.items())] return "\n".join(expr) def parse_csv_file(url, res): """Parse given URL and write res with {scheme -> description}""" response = requests.get(url, stream=True) reader = csv.reader(response.iter_lines()) first_row = True for row in reader: if first_row: # skip first row first_row = False else: scheme, template, description, reference = row res[scheme] = description if __name__ == '__main__': sys.exit(main(sys.argv[1:])) LinkChecker-9.3/scripts/removeafter.py0000755000175000017500000000072612361407402020710 0ustar calvincalvin00000000000000#!/usr/bin/env python # Copyright (C) 2012-2014 Bastian Kleineidam """Remove all lines after a given marker line. """ from __future__ import print_function import fileinput import sys def main(args): """Remove lines after marker.""" filename = args[0] marker = args[1] for line in fileinput.input(filename, inplace=1): print(line.rstrip()) if line.startswith(marker): break if __name__ == '__main__': main(sys.argv[1:]) LinkChecker-9.3/scripts/viewprof.py0000755000175000017500000000042012361407402020221 0ustar calvincalvin00000000000000#!/usr/bin/env python """ View yappi profiling data. Usage: $0 """ import sys import yappi def main(args): filename = args[0] stats = yappi.YFuncStats() stats.add(filename) stats.print_all() if __name__ == '__main__': main(sys.argv[1:]) LinkChecker-9.3/scripts/nodebug.sh0000755000175000017500000000027212361407402017772 0ustar calvincalvin00000000000000#!/bin/sh # deactivate all debug calls set -e set -u d=$(dirname $0) base=$(readlink -f $d/../linkcheck) find "$base" -type f -print0 | xargs -0 sed -i 's/ log.debug(/ #log.debug(/g' LinkChecker-9.3/scripts/analyze_memdump.py0000755000175000017500000000757112361407402021565 0ustar calvincalvin00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # Copyright (C) 2012-2014 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Analyze a memory dump by the meliae module. """ import sys import os import codecs import cgi from linkcheck import strformat def main (filename): om = print_memorydump(filename) dirname, basename = os.path.split(filename) basename = os.path.splitext(basename)[0] basedir = os.path.join(dirname, basename) if not os.path.isdir(basedir): os.mkdir(basedir) write_htmlfiles(om, basedir) def print_memorydump(filename): from meliae import loader om = loader.load(filename, collapse=True) om.remove_expensive_references() print om.summarize() return om def write_htmlfiles(om, basedir): om.compute_parents() open_files = {} for obj in om.objs.itervalues(): fp = get_file(obj.type_str, open_files, basedir) write_html_obj(fp, obj, om.objs) close_files(open_files) def get_file(type_str, open_files, basedir): """Get already opened file, or open and initialize a new one.""" if type_str not in open_files: filename = type_str+".html" encoding = 'utf-8' fd = codecs.open(os.path.join(basedir, filename), 'w', encoding) open_files[type_str] = fd write_html_header(fd, type_str, encoding) return open_files[type_str] def close_files(open_files): for fp in open_files.values(): write_html_footer(fp) fp.close() HtmlHeader = u""" """ def write_html_header(fp, type_str, encoding): fp.write(HtmlHeader % encoding) fp.write(u"

Type %s

\n" % type_str) fp.write(u"\n") def get_children(obj, objs): res = [] for address in obj.children: if address in objs: child = objs[address] url = u"#%d" % address if child.type_str != obj.type_str: url = child.type_str + u".html" + url entry = u'%d' % (url, address) else: entry = u"%d" % address res.append(entry) return res def get_parents(obj, objs): res = [] for address in obj.parents: if address in objs: parent = objs[address] url = u"#%d" % address if parent.type_str != obj.type_str: url = parent.type_str + u".html" + url entry = u'%d' % (url, address) else: entry = u"%d" % address res.append(entry) return res def write_html_obj(fp, obj, objs): if obj.value is None: value = u"None" else: value = cgi.escape(str(obj.value)) attrs = dict( address=obj.address, size=strformat.strsize(obj.size), children=u",".join(get_children(obj, objs)), parents=u",".join(get_parents(obj, objs)), value=value, ) fp.write(u"\n" % attrs) def write_html_footer(fp): fp.write(u"
AddressNameSizeParentsReferences
%(address)d%(value)s%(size)s%(children)s
") if __name__ == '__main__': filename = sys.argv[1] main(filename) LinkChecker-9.3/scripts/debugparse.py0000755000175000017500000000262512361407402020512 0ustar calvincalvin00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # Copyright (C) 2011-2014 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Parse HTML given as file parameter or piped to stdin. """ import sys import os sys.path.append(os.getcwd()) import linkcheck.HtmlParser.htmlsax import linkcheck.HtmlParser.htmllib def main (text): parser = linkcheck.HtmlParser.htmlsax.parser() handler = linkcheck.HtmlParser.htmllib.HtmlPrinter() parser.handler = handler # debug lexer #parser.debug(1) parser.feed(text) parser.flush() if __name__ == '__main__': if len(sys.argv) <= 1: text = sys.stdin.read() else: filename = sys.argv[1] with open(filename) as fp: text = fp.read() main(text) LinkChecker-9.3/cgi-bin/0000750000175000017500000000000012361541761015632 5ustar calvincalvin00000000000000LinkChecker-9.3/cgi-bin/lconline/0000750000175000017500000000000012361541761017435 5ustar calvincalvin00000000000000LinkChecker-9.3/cgi-bin/lconline/check.js0000644000175000017500000000112211150300124021026 0ustar calvincalvin00000000000000// check url validity function isValid (thisForm) { if (thisForm.url.value=="" || thisForm.url.value=="http://") { alert(gettext("Empty URL was given.")); thisForm.url.select(); thisForm.url.focus(); return false; } if (!checkSyntax(thisForm.url.value)) { alert(gettext("Invalid URL was given.")); thisForm.url.select(); thisForm.url.focus(); return false; } return true; } // check url syntax function checkSyntax (url) { var syntax = /^https?:\/\/[-_a-zA-Z0-9.\/=%?~]+$/; return syntax.test(url); } LinkChecker-9.3/cgi-bin/lconline/index.html0000644000175000017500000000077211551546346021451 0ustar calvincalvin00000000000000 LinkChecker Online Please use a frame capable browser. LinkChecker-9.3/cgi-bin/lconline/favicon.ico0000644000175000017500000000706611551546254021576 0ustar calvincalvin00000000000000h& ( @o$ñmF#v`r߻YˏU='r0šb0_?۬}ESk9nM$w]ư=mAa'T9!UrO#̡OӰy,N]t;yL̷cӄ:ʆfb4͜bg;ⵋ؞rydOFyS4mA^R. _Kl$gz†N9Fund8Z6t[F{Q־xw)\Do5g-ҶkʸOc@pn-乕z:Iw9ӦwÎ\Iu#l,ck*d@_,j.M۾T,}<Y2 \<ŠΧuU:äu3V!T濔^9fOb0vGp*Gò\>"]҉9c<F X;Ҹfd,v]azKտвԶe-[=wIva£\<6A[8-av1b yFg*B?u)DkX$Lc]\(#H`.'~xY{piUoC 3se4OQ@}0TnZ_EI&^ dNP9?( @҄/m;ᶞ~fRUyUnKiL2rE&_*ТwÌVμj~IoL }_WߝTd*ݰW6Ɲt~O S }\:nIn=ͼ\op0iҎBɨf ƍ|<ʪ1ΙbֻdB_2q•u\D٦nSHk;^ʲNxEW2fx!pɀY@Z<sCױoyTx+¯` ȁ;qM'c#fAla!`’dḎϒTh=Ve/\Ξ|V.r>ߢ_U*aV"թүvj&ً7Lw\EշnS֦xOGWОj`jvU5暑[ |Xß}]ĨWӷ̠u3/{FX< i?ِ@gd7 W2 ŶpEkg,yO, Dzj2hȇ@b@(`2]:Gޓii|cJ˘X%c2ȵƩo?™p_D ֠gǢoRuCdw>K)kP7]ײía:zW ~(ܙN[ro'Pac:rYnH!m>\Tш7vJ`D式kOez ^<aӿnM,jސ:id?ǡ[և0tA j,w)șhyP(]U-`+ͧrJɐYֵթΰ٫|Sлq7lWL`jjA="%[AgE%\\\%cT L J 'GJ+lݜezk㺨uS@@DzXX9I9vq@@tߗDM&mMm>@&& !Pd1ۛ㗸~pT.|ӂaizbNU ̒5̗AsW033.4Zd fVs(R;7,;FQvsbFƋ,hы.q@aT{s(HrЉn8.T*vT{bHxY n)H0q9(bFKx)/O BorH9vbǐ?oyOO)U3NfvF?/OC8h,`|f#R*/OرCO/4wʾX5H,/n4CC nZc$X2}ZBזOnקwNQ@^BBC4ZZ3d6:;BB44_|dBC-_]dshħZn`b`^^u;3<<>FTF???LinkChecker-9.3/cgi-bin/lconline/lc_cgi.html.de0000644000175000017500000000351112361407402022130 0ustar calvincalvin00000000000000 LinkChecker Online

LinkChecker Online

(läuft mit Öl vom LinkChecker)
Url:
Optionen: Rekursionstiefe: Prüfe Anker in HTML:
Nur Warnungen und Fehler ausgeben: Ausgabe:
LinkChecker-9.3/cgi-bin/lconline/leer.html.de0000644000175000017500000000060511150300124021624 0ustar calvincalvin00000000000000 Leer
Keine Links geprüft!
LinkChecker-9.3/cgi-bin/lconline/leer.html.en0000644000175000017500000000061011150300124021632 0ustar calvincalvin00000000000000 Empty
No links checked, dude!
LinkChecker-9.3/cgi-bin/lconline/lc_cgi.html.en0000644000175000017500000000322512361407402022144 0ustar calvincalvin00000000000000 LinkChecker Online

LinkChecker Online

(powered by LinkChecker)
Url:
Options: Recursion Level: Check anchors in HTML:
Log only warnings and errors: Output language:
LinkChecker-9.3/cgi-bin/lconline/lc.css0000644000175000017500000000036011150300124020526 0ustar calvincalvin00000000000000h2 { font-family: Verdana,sans-serif; font-size: 22pt; font-weight: bold } body { font-family: Arial,sans-serif; font-size: 11pt } td { font-family:Arial,sans-serif; font-size:11pt } code { font-family: Courier } a:hover { color: #34a4ef } LinkChecker-9.3/cgi-bin/README0000644000175000017500000000026311150300124016475 0ustar calvincalvin00000000000000For the HTML files in the lconline directory to work, your web server must have mod_negotiation enabled. Or you can just remove the .XY suffixes from the language-specific files. LinkChecker-9.3/cgi-bin/lc.wsgi0000644000175000017500000000150311742617070017126 0ustar calvincalvin00000000000000#!/usr/bin/python # -*- coding: iso-8859-1 -*- # Copyright (C) 2012 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from linkcheck.lc_cgi import application LinkChecker-9.3/linkchecker0000755000175000017500000005774012361407402016545 0ustar calvincalvin00000000000000#!/usr/bin/python -Ru # -*- coding: iso-8859-1 -*- # Copyright (C) 2000-2014 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Check HTML pages for broken links. This is the commandline client. Run this file with the -h option to see how it's done. """ import sys import codecs import os import pprint import argparse import getpass # installs _() and _n() gettext functions into global namespace import linkcheck from linkcheck import logconf, LOG_CMDLINE logconf.init_log_config() # override argparse gettext method with the one from linkcheck.init_i18n() #argparse._ = _ # now import the rest of the linkchecker gang from linkcheck.cmdline import print_version, print_usage, aggregate_url, \ LCArgumentParser, print_plugins from linkcheck import log, i18n, strformat import linkcheck.checker import linkcheck.configuration import linkcheck.fileutil import linkcheck.logger import linkcheck.ansicolor from linkcheck.director import console, check_urls, get_aggregate # optional modules has_argcomplete = linkcheck.fileutil.has_module("argcomplete") has_profile = linkcheck.fileutil.has_module("yappi") has_meliae = linkcheck.fileutil.has_module("meliae") # default profiling filename _profile = "linkchecker.prof" _username = None _password = None # usage texts Notes = _("""NOTES o URLs on the command line starting with "ftp." are treated like "ftp://ftp.", URLs starting with "www." are treated like "http://www.". You can also give local files as arguments. o If you have your system configured to automatically establish a connection to the internet (e.g. with diald), it will connect when checking links not pointing to your local system. See the --ignore-url option on how to prevent this. o Javascript links are currently ignored. o If your platform does not support threading, LinkChecker disables it automatically. o You can supply multiple user/password pairs in a configuration file. o When checking 'news:' links the given NNTP host doesn't need to be the same as the host of the user browsing your pages. """) ProxySupport = _("""PROXY SUPPORT To use a proxy on Unix or Windows set $http_proxy, $https_proxy or $ftp_proxy to the proxy URL. The URL should be of the form "http://[:@][:]". LinkChecker also detects manual proxy settings of Internet Explorer under Windows systems, and gconf or KDE on Linux systems. On a Mac use the Internet Config to select a proxy. LinkChecker honors the $no_proxy environment variable. It can be a list of domain names for which no proxy will be used. Setting a HTTP proxy on Unix for example looks like this: export http_proxy="http://proxy.example.com:8080" Proxy authentication is also supported: export http_proxy="http://user1:mypass@proxy.example.org:8081" Setting a proxy on the Windows command prompt: set http_proxy=http://proxy.example.com:8080 """) RegularExpressions = _("""REGULAR EXPRESSIONS Only Python regular expressions are accepted by LinkChecker. See http://www.amk.ca/python/howto/regex/ for an introduction in regular expressions. The only addition is that a leading exclamation mark negates the regular expression. """) CookieFormat = _("""COOKIE FILES A cookie file contains standard RFC 805 header data with the following possible names: Scheme (optional) Sets the scheme the cookies are valid for; default scheme is 'http'. Host (required) Sets the domain the cookies are valid for. Path (optional) Gives the path the cookies are value for; default path is '/'. Set-cookie (optional) Set cookie name/value. Can be given more than once. Multiple entries are separated by a blank line. The example below will send two cookies to all URLs starting with 'http://example.org/hello/' and one to all URLs starting with 'https://example.com/': Host: example.org Path: /hello Set-cookie: ID="smee" Set-cookie: spam="egg" Scheme: https Host: example.com Set-cookie: baggage="elitist"; comment="hologram" """) Retval = _(r"""RETURN VALUE The return value is non-zero when o invalid links were found or o warnings were found warnings are enabled o a program error occurred """) Examples = _(r"""EXAMPLES The most common use checks the given domain recursively, plus any single URL pointing outside of the domain: linkchecker http://www.example.org/ Beware that this checks the whole site which can have several hundred thousands URLs. Use the -r option to restrict the recursion depth. Don't connect to mailto: hosts, only check their URL syntax. All other links are checked as usual: linkchecker --ignore-url=^mailto: www.example.org Checking local HTML files on Unix: linkchecker ../bla.html subdir/blubber.html Checking a local HTML file on Windows: linkchecker c:\temp\test.html You can skip the "http://" url part if the domain starts with "www.": linkchecker www.example.de You can skip the "ftp://" url part if the domain starts with "ftp.": linkchecker -r0 ftp.example.org """) LoggerTypes = _(r"""OUTPUT TYPES Note that by default only errors and warnings are logged. You should use the --verbose option to see valid URLs, and when outputting a sitemap graph format. text Standard text output, logging URLs in keyword: argument fashion. html Log URLs in keyword: argument fashion, formatted as HTML. Additionally has links to the referenced pages. Invalid URLs have HTML and CSS syntax check links appended. csv Log check result in CSV format with one URL per line. gml Log parent-child relations between linked URLs as a GML sitemap graph. dot Log parent-child relations between linked URLs as a DOT sitemap graph. gxml Log check result as a GraphXML sitemap graph. xml Log check result as machine-readable XML. sql Log check result as SQL script with INSERT commands. An example script to create the initial SQL table is included as create.sql. blacklist Suitable for cron jobs. Logs the check result into a file ~/.linkchecker/blacklist which only contains entries with invalid URLs and the number of times they have failed. none Logs nothing. Suitable for debugging or checking the exit code. """) Warnings = _(r"""IGNORE WARNINGS The following warnings are recognized in the 'ignorewarnings' config file entry: """) + \ "\n".join([u" o %s - %s" % (tag, desc) \ for tag, desc in sorted(linkcheck.checker.const.Warnings.items())]) Epilog = u"\n".join((Examples, LoggerTypes, RegularExpressions, CookieFormat, ProxySupport, Notes, Retval, Warnings)) def has_encoding (encoding): """Detect if Python can encode in a certain encoding.""" try: codecs.lookup(encoding) return True except LookupError: return False # instantiate option parser and configure options argparser = LCArgumentParser( epilog=Epilog, formatter_class=argparse.RawDescriptionHelpFormatter ) # build a config object for this check session config = linkcheck.configuration.Configuration() config.set_status_logger(console.StatusLogger()) ################# general options ################## group = argparser.add_argument_group(_("General options")) group.add_argument("-f", "--config", dest="configfile", metavar="FILENAME", help=_( """Use FILENAME as configuration file. Per default LinkChecker uses ~/.linkchecker/linkcheckerrc (under Windows %%HOMEPATH%%\\.linkchecker\\linkcheckerrc).""")) group.add_argument("-t", "--threads", type=int, metavar="NUMBER", help=_( """Generate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non-positive number.""")) group.add_argument("-V", "--version", action="store_true", help=_("""Print version and exit.""")) group.add_argument("--list-plugins", action="store_true", dest="listplugins", help=_( """Print available check plugins and exit.""")) group.add_argument("--stdin", action="store_true", help=_( """Read list of white-space separated URLs to check from stdin.""")) ################# output options ################## group = argparser.add_argument_group(_("Output options")) # XXX deprecated: --check-css moved to plugin CssSyntaxCheck group.add_argument("--check-css", action="store_true", dest="checkcss", help=argparse.SUPPRESS) # XXX deprecated: --check-html moved to plugin HtmlSyntaxCheck group.add_argument("--check-html", action="store_true", dest="checkhtml", help=argparse.SUPPRESS) # XXX deprecated: --complete is removed group.add_argument("--complete", action="store_true", dest="complete", help=argparse.SUPPRESS) group.add_argument("-D", "--debug", action="append", metavar="STRING", help=_("""Print debugging output for the given logger. Available loggers are %(lognamelist)s. Specifying 'all' is an alias for specifying all available loggers. The option can be given multiple times to debug with more than one logger. For accurate results, threading will be disabled during debug runs.""") % \ {"lognamelist": logconf.lognamelist}) group.add_argument("-F", "--file-output", action="append", dest="fileoutput", metavar="TYPE[/ENCODING[/FILENAME]]", help=_( """Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/blacklist for 'blacklist' output, or FILENAME if specified. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at http://docs.python.org/lib/standard-encodings.html. The FILENAME and ENCODING parts of the 'none' output type will be ignored, else if the file already exists, it will be overwritten. You can specify this option more than once. Valid file output types are %(loggertypes)s. You can specify this option multiple times to output to more than one file. Default is no file output. Note that you can suppress all console output with the option '-o none'.""") % \ {'loggertypes': linkcheck.logger.LoggerKeys}) group.add_argument("--no-status", action="store_false", dest="status", default=True, help=_( """Do not print check status messages.""")) group.add_argument("--no-warnings", action="store_false", dest="warnings", help=_("""Don't log warnings. Default is to log warnings.""")) group.add_argument("-o", "--output", dest="output", metavar="TYPE[/ENCODING]", help=_( """Specify output as %(loggertypes)s. Default output type is text. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at """ \ """http://docs.python.org/lib/standard-encodings.html.""") % \ {'loggertypes': linkcheck.logger.LoggerKeys}) group.add_argument("--profile", action="store_true", dest="profile", help=argparse.SUPPRESS) group.add_argument("-q", "--quiet", action="store_true", dest="quiet", help=_( """Quiet operation, an alias for '-o none'. This is only useful with -F.""")) # XXX deprecated: moved to plugin VirusCheck group.add_argument("--scan-virus", action="store_true", dest="scanvirus", help=argparse.SUPPRESS) group.add_argument("--trace", action="store_true", dest="trace", help=argparse.SUPPRESS) group.add_argument("-v", "--verbose", action="store_true", dest="verbose", help=_( """Log all URLs. Default is to log only errors and warnings.""")) # XXX deprecated: moved to plugin RegexCheck group.add_argument("-W", "--warning-regex", dest="warningregex", metavar="REGEX", help=argparse.SUPPRESS) # XXX deprecated: removed group.add_argument("--warning-size-bytes", dest="warningsizebytes", metavar="NUMBER", help=argparse.SUPPRESS) ################# checking options ################## group = argparser.add_argument_group(_("Checking options")) # XXX deprecated: moved to plugin AnchorCheck group.add_argument("-a", "--anchors", action="store_true", dest="anchors", help=argparse.SUPPRESS) # XXX deprecated: replaced with requests session cookie handling group.add_argument("-C", "--cookies", action="store_true", dest="cookies", help=argparse.SUPPRESS) group.add_argument("--cookiefile", dest="cookiefile", metavar="FILENAME", help=_( """Read a file with initial cookie data. The cookie data format is explained below.""")) group.add_argument("--check-extern", action="store_true", dest="checkextern", help=_("""Check external URLs.""")) group.add_argument("--ignore-url", action="append", metavar="REGEX", dest="externstrict", help=_( """Only check syntax of URLs matching the given regular expression. This option can be given multiple times.""")) group.add_argument("--no-follow-url", action="append", metavar="REGEX", dest="extern", help=_( """Check but do not recurse into URLs matching the given regular expression. This option can be given multiple times.""")) group.add_argument("-N", "--nntp-server", dest="nntpserver", metavar="STRING", help=_( """Specify an NNTP server for 'news:...' links. Default is the environment variable NNTP_SERVER. If no host is given, only the syntax of the link is checked.""")) group.add_argument("-p", "--password", action="store_false", dest="password", default=False, help=_( """Read a password from console and use it for HTTP and FTP authorization. For FTP the default password is 'anonymous@'. For HTTP there is no default password. See also -u.""")) # XXX deprecated: replaced with numrequestsperpage group.add_argument("-P", "--pause", type=int, dest="pause", metavar="NUMBER", help=argparse.SUPPRESS) group.add_argument("-r", "--recursion-level", type=int, dest="recursionlevel", metavar="NUMBER", help=_( """Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite.""")) group.add_argument("--timeout", type=int, dest="timeout", metavar="NUMBER", help=_( """Set the timeout for connection attempts in seconds. The default timeout is %d seconds.""") % config["timeout"]) group.add_argument("-u", "--user", dest="username", metavar="STRING", help=_( """Try the given username for HTTP and FTP authorization. For FTP the default username is 'anonymous'. For HTTP there is no default username. See also -p.""")) group.add_argument("--user-agent", dest="useragent", metavar="STRING", help=_( """Specify the User-Agent string to send to the HTTP server, for example "Mozilla/4.0". The default is "LinkChecker/X.Y" where X.Y is the current version of LinkChecker.""")) argparser.add_argument('url', nargs='*') ################# auto completion ##################### if has_argcomplete: import argcomplete argcomplete.autocomplete(argparser) def read_stdin_urls (): """Read list of URLs, separated by white-space, from stdin.""" num = 0 while True: lines = sys.stdin.readlines(8 * 1024) if not lines: break for line in lines: for url in line.split(): num += 1 if num % 10000 == 0: log.info(LOG_CMDLINE, "Read %d URLs from stdin", num) yield url # read and parse command line options and arguments options = argparser.parse_args() # initialize logging if options.debug: allowed_debugs = logconf.lognames.keys() for _name in options.debug: if _name not in allowed_debugs: print_usage(_("Invalid debug level %(level)r") % {'level': _name}) logconf.set_debug(options.debug) log.debug(LOG_CMDLINE, _("Python %(version)s on %(platform)s") % \ {"version": sys.version, "platform": sys.platform}) # read configuration files try: files = [] if options.configfile: path = linkcheck.configuration.normpath(options.configfile) if os.path.isfile(path): files.append(path) else: log.warn(LOG_CMDLINE, _("Unreadable config file: %r"), options.configfile) config.read(files=files) except linkcheck.LinkCheckerError as msg: # config error print_usage(str(msg)) linkcheck.drop_privileges() # test if running with -O if options.debug and not __debug__: log.warn(LOG_CMDLINE, _("Running with python -O disables debugging.")) # apply commandline options and arguments to configuration constructauth = False do_profile = False if not options.warnings: config["warnings"] = options.warnings if options.externstrict: pats = [linkcheck.get_link_pat(arg, strict=True) \ for arg in options.externstrict] config["externlinks"].extend(pats) if options.extern: pats = [linkcheck.get_link_pat(arg) for arg in options.extern] config["externlinks"].extend(pats) if options.checkextern: config["checkextern"] = True elif not config["checkextern"]: log.info(LOG_CMDLINE, "Checking intern URLs only; use --check-extern to check extern URLs.") if options.output: if "/" in options.output: logtype, encoding = options.output.split("/", 1) else: logtype, encoding = options.output, i18n.default_encoding logtype = logtype.lower() if logtype not in linkcheck.logger.LoggerNames: print_usage( _("Unknown logger type %(type)r in %(output)r for option %(option)s") % \ {"type": logtype, "output": options.output, "option": "'-o, --output'"}) if logtype != 'none' and not has_encoding(encoding): print_usage( _("Unknown encoding %(encoding)r in %(output)r for option %(option)s") % \ {"encoding": encoding, "output": options.output, "option": "'-o, --output'"}) config['output'] = logtype config['logger'] = config.logger_new(logtype, encoding=encoding) if options.fileoutput: ns = {'fileoutput': 1} for arg in options.fileoutput: ftype = arg # look for (optional) filename and encoding if '/' in ftype: ftype, suffix = ftype.split('/', 1) if suffix: if has_encoding(suffix): # it was an encoding ns['encoding'] = suffix elif '/' in suffix: # look for (optional) encoding encoding, filename = suffix.split('/', 1) if has_encoding(encoding): ns['encoding'] = encoding ns['filename'] = filename else: ns['filename'] = suffix else: ns['filename'] = suffix if ftype not in linkcheck.logger.LoggerNames: print_usage( _("Unknown logger type %(type)r in %(output)r for option %(option)s") % \ {"type": ftype, "output": options.fileoutput, "option": "'-F, --file-output'"}) if ftype != 'none' and 'encoding' in ns and \ not has_encoding(ns['encoding']): print_usage( _("Unknown encoding %(encoding)r in %(output)r for option %(option)s") % \ {"encoding": ns['encoding'], "output": options.fileoutput, "option": "'-F, --file-output'"}) logger = config.logger_new(ftype, **ns) config['fileoutput'].append(logger) if options.nntpserver: config["nntpserver"] = options.nntpserver if options.username: _username = options.username constructauth = True if options.password: if _username: msg = _("Enter LinkChecker HTTP/FTP password for user %(user)s:") % \ {"user": _username} else: msg = _("Enter LinkChecker HTTP/FTP password:") _password = getpass.getpass(console.encode(msg)) constructauth = True if options.profile: do_profile = options.profile if options.quiet: config['logger'] = config.logger_new('none') if options.recursionlevel is not None: config["recursionlevel"] = options.recursionlevel if options.status: config['status'] = options.status if options.threads is not None: if options.threads < 1: options.threads = 0 config["threads"] = options.threads if options.timeout is not None: if options.timeout > 0: config["timeout"] = options.timeout else: print_usage(_("Illegal argument %(arg)r for option %(option)s") % \ {"arg": options.timeout, "option": "'--timeout'"}) if options.version: print_version() if options.listplugins: print_plugins(config["pluginfolders"]) if options.verbose: if options.verbose: config["verbose"] = True config["warnings"] = True if options.cookiefile is not None: config['cookiefile'] = options.cookiefile if constructauth: config.add_auth(pattern=".+", user=_username, password=_password) # read missing passwords for entry in config["authentication"]: if entry["password"] is None: attrs = entry.copy() attrs["strpattern"] = attrs["pattern"].pattern msg = _("Enter LinkChecker password for user %(user)s" \ " at %(strpattern)s:") % attrs entry["password"] = getpass.getpass(console.encode(msg)) if options.useragent is not None: config["useragent"] = options.useragent if options.cookiefile is not None: if linkcheck.fileutil.is_readable(options.cookiefile): config["cookiefile"] = options.cookiefile else: msg = _("Could not read cookie file %s") % options.cookiefile log.error(LOG_CMDLINE, msg) # now sanitize the configuration config.sanitize() log.debug(LOG_CMDLINE, "configuration: %s", pprint.pformat(sorted(config.items()))) # prepare checking queue aggregate = get_aggregate(config) if options.trace: # enable thread tracing config["trace"] = True # start trace in mainthread import linkcheck.trace linkcheck.trace.trace_filter([r"^linkcheck"]) linkcheck.trace.trace_on() # add urls to queue if options.stdin: for url in read_stdin_urls(): aggregate_url(aggregate, url) elif options.url: for url in options.url: aggregate_url(aggregate, strformat.stripurl(url)) else: log.warn(LOG_CMDLINE, _("no files or URLs given")) # set up profiling if do_profile: if has_profile: if os.path.exists(_profile): question = _("""Overwrite profiling file %(file)r? Press Ctrl-C to cancel, RETURN to continue.""") % {"file": _profile} try: raw_input(question.encode(i18n.default_encoding, 'replace')) except KeyboardInterrupt: print >> sys.stderr print >> sys.stderr, _("Canceled.") sys.exit(1) else: log.warn(LOG_CMDLINE, _("The `yappi' Python module is not installed," " therefore the --profile option is disabled.")) do_profile = False # finally, start checking if do_profile: import yappi yappi.start() check_urls(aggregate) yappi.stop() yappi.get_func_stats().save(_profile) else: check_urls(aggregate) if config["debugmemory"]: import linkcheck.memoryutil if has_meliae: log.info(LOG_CMDLINE, _(u"Dumping memory statistics...")) filename = linkcheck.memoryutil.write_memory_dump() message = _(u"The memory dump has been written to `%(filename)s'.") log.info(LOG_CMDLINE, message % dict(filename=filename)) else: log.warn(LOG_CMDLINE, linkcheck.memoryutil.MemoryDebugMsg) stats = config['logger'].stats # on internal errors, exit with status 2 if stats.internal_errors: sys.exit(2) # on errors or printed warnings, exit with status 1 if stats.errors or (stats.warnings_printed and config['warnings']): sys.exit(1) LinkChecker-9.3/Makefile0000644000175000017500000002012412361407402015757 0ustar calvincalvin00000000000000# This Makefile is only used by developers. PYVER:=2.7 PYTHON?=python$(PYVER) VERSION:=$(shell $(PYTHON) setup.py --version) PLATFORM:=$(shell $(PYTHON) -c "from __future__ import print_function; from distutils.util import get_platform; print(get_platform())") APPNAME:=$(shell $(PYTHON) setup.py --name) AUTHOR:=$(shell $(PYTHON) setup.py --author) MAINTAINER:=$(shell $(PYTHON) setup.py --maintainer) LAPPNAME:=$(shell echo $(APPNAME)|tr "[A-Z]" "[a-z]") ARCHIVE_SOURCE_EXT:=gz ARCHIVE_SOURCE:=$(APPNAME)-$(VERSION).tar.$(ARCHIVE_SOURCE_EXT) ARCHIVE_WIN32:=$(APPNAME)-$(VERSION).exe GITUSER:=wummel GITREPO:=$(LAPPNAME) HOMEPAGE:=$(HOME)/public_html/$(LAPPNAME)-webpage.git WEB_META:=doc/web/app.yaml DEBUILDDIR:=$(HOME)/projects/debian/official DEBORIGFILE:=$(DEBUILDDIR)/$(LAPPNAME)_$(VERSION).orig.tar.$(ARCHIVE_SOURCE_EXT) DEBPACKAGEDIR:=$(DEBUILDDIR)/$(APPNAME)-$(VERSION) FILESCHECK_URL:=http://localhost/~calvin/ SRCDIR:=${HOME}/src PY_FILES_DIRS:=linkcheck tests *.py linkchecker linkchecker-gui cgi-bin config doc/examples scripts MYPY_FILES_DIRS:=linkcheck/HtmlParser linkcheck/checker \ linkcheck/cache linkcheck/configuration linkcheck/director \ linkcheck/htmlutil linkcheck/logger linkcheck/network \ linkcheck/bookmarks linkcheck/plugins linkcheck/parser \ linkcheck/gui/__init__.py \ linkcheck/gui/checker.py \ linkcheck/gui/contextmenu.py \ linkcheck/gui/debug.py \ linkcheck/gui/editor.py \ linkcheck/gui/editor_qsci.py \ linkcheck/gui/editor_qt.py \ linkcheck/gui/lineedit.py \ linkcheck/gui/help.py \ linkcheck/gui/logger.py \ linkcheck/gui/options.py \ linkcheck/gui/properties.py \ linkcheck/gui/settings.py \ linkcheck/gui/statistics.py \ linkcheck/gui/syntax.py \ linkcheck/gui/updater.py \ linkcheck/gui/urlmodel.py \ linkcheck/gui/urlsave.py \ $(filter-out %2.py,$(wildcard linkcheck/*.py)) \ cgi-bin/lc.wsgi \ linkchecker \ linkchecker-gui \ *.py TESTS ?= tests # set test options, eg. to "--verbose" TESTOPTS= PAGER ?= less # original dnspython repository module DNSPYTHON:=$(HOME)/src/dnspython-git # options to run the pep8 utility PEP8OPTS:=--repeat --ignore=E211,E501,E225,E301,E302,E241 \ --exclude="gzip2.py,httplib2.py,robotparser2.py" PY2APPOPTS ?= ifeq ($(shell uname),Darwin) CHMODMINUSMINUS:= else CHMODMINUSMINUS:=-- endif # Pytest options: # - use multiple processes # - write test results in file PYTESTOPTS:=-n 4 --resultlog=testresults.txt all: @echo "Read the file doc/install.txt to see how to build and install this package." clean: -$(PYTHON) setup.py clean --all rm -f $(LAPPNAME)-out.* *-stamp* $(MAKE) -C po clean $(MAKE) -C doc/html clean $(MAKE) -C linkcheck/HtmlParser clean rm -f linkcheck/network/_network*.so find . -name '*.py[co]' -exec rm -f {} \; distclean: clean rm -rf build dist $(APPNAME).egg-info rm -f _$(APPNAME)_configdata.py MANIFEST Packages.gz # clean aborted dist builds and -out files rm -f $(LAPPNAME)-out* $(LAPPNAME).prof rm -f alexa*.log testresults.txt rm -rf $(APPNAME)-$(VERSION) rm -rf coverage dist-stamp python-build-stamp* MANIFEST: MANIFEST.in setup.py $(PYTHON) setup.py sdist --manifest-only locale: $(MAKE) -C po mofiles # to build in the current directory localbuild: MANIFEST locale $(MAKE) -C doc/html $(MAKE) -C linkcheck/HtmlParser $(PYTHON) setup.py build cp -f build/lib.$(PLATFORM)-$(PYVER)*/linkcheck/HtmlParser/htmlsax*.so linkcheck/HtmlParser cp -f build/lib.$(PLATFORM)-$(PYVER)*/linkcheck/network/_network*.so linkcheck/network release: distclean releasecheck filescheck $(MAKE) dist sign register upload homepage tag changelog deb tag: git tag upstream/$(VERSION) git push --tags origin upstream/$(VERSION) upload: upload_source upload_binary upload_source: twine upload dist/$(ARCHIVE_SOURCE) dist/$(ARCHIVE_SOURCE).asc upload_binary: cp dist/$(ARCHIVE_WIN32) dist/$(ARCHIVE_WIN32).asc \ $(HOMEPAGE)/dist homepage: # update metadata @echo "version: \"$(VERSION)\"" > $(WEB_META) @echo "name: \"$(APPNAME)\"" >> $(WEB_META) @echo "lname: \"$(LAPPNAME)\"" >> $(WEB_META) @echo "maintainer: \"$(MAINTAINER)\"" >> $(WEB_META) @echo "author: \"$(AUTHOR)\"" >> $(WEB_META) git add $(WEBMETA) -git commit -m "Updated webpage meta info" # update documentation and man pages $(MAKE) -C doc man $(MAKE) -C doc/web release register: @echo "Register at Python Package Index..." $(PYTHON) setup.py register @echo "done." deb: # build a debian package [ -f $(DEBORIGFILE) ] || cp dist/$(ARCHIVE_SOURCE) $(DEBORIGFILE) sed -i -e 's/VERSION_$(LAPPNAME):=.*/VERSION_$(LAPPNAME):=$(VERSION)/' $(DEBUILDDIR)/$(LAPPNAME).mak [ -d $(DEBPACKAGEDIR) ] || (cd $(DEBUILDDIR); \ patool extract $(DEBORIGFILE); \ cd $(CURDIR); \ git checkout debian; \ cp -r debian $(DEBPACKAGEDIR); \ rm -f $(DEBPACKAGEDIR)/debian/.gitignore; \ git checkout master) $(MAKE) -C $(DEBUILDDIR) $(LAPPNAME)_clean $(LAPPNAME) chmod: -chmod -R a+rX,u+w,go-w $(CHMODMINUSMINUS) * find . -type d -exec chmod 755 {} \; dist: locale MANIFEST chmod rm -f dist/$(ARCHIVE_SOURCE) $(PYTHON) setup.py sdist --formats=tar gzip --best dist/$(APPNAME)-$(VERSION).tar [ ! -f ../$(ARCHIVE_WIN32) ] || cp ../$(ARCHIVE_WIN32) dist # Build OSX installer with py2app app: distclean localbuild chmod $(PYTHON) setup.py py2app $(PY2APPOPTS) # Build RPM installer with cx_Freeze rpm: $(MAKE) -C doc/html $(MAKE) -C linkcheck/HtmlParser $(PYTHON) setup.py bdist_rpm # Build portable Linux app binary: distclean localbuild chmod LINKCHECKER_FREEZE=1 $(PYTHON) setup.py bdist # The check programs used here are mostly local scripts on my private system. # So for other developers there is no need to execute this target. check: check-copyright check-pofiles -v py-tabdaddy $(MYPY_FILES_DIRS) py-unittest2-compat tests/ $(MAKE) -C doc check $(MAKE) doccheck $(MAKE) pyflakes doccheck: py-check-docstrings --force $(MYPY_FILES_DIRS) filescheck: localbuild for out in text html gml sql csv xml gxml dot sitemap; do \ ./$(LAPPNAME) -o$$out -F$$out --complete -r1 -C $(FILESCHECK_URL) || exit 1; \ done update-copyright: update-copyright --holder="Bastian Kleineidam" $(PY_FILES_DIRS) releasecheck: check @if egrep -i "xx\.|xxxx|\.xx" doc/changelog.txt > /dev/null; then \ echo "Could not release: edit doc/changelog.txt release date"; false; \ fi @if [ ! -f ../$(ARCHIVE_WIN32) ]; then \ echo "Missing WIN32 distribution archive at ../$(ARCHIVE_WIN32)"; \ false; \ fi $(PYTHON) setup.py check --restructuredtext sign: for f in $(shell find dist -name *.$(ARCHIVE_SOURCE_EXT) -o -name *.exe -o -name *.zip -o -name *.dmg); do \ [ -f $${f}.asc ] || gpg --detach-sign --armor $$f; \ done test: localbuild env LANG=en_US.utf-8 $(PYTHON) -m pytest $(PYTESTOPTS) $(TESTOPTS) $(TESTS) pyflakes: pyflakes $(PY_FILES_DIRS) 2>&1 | \ grep -v "local variable 'dummy' is assigned to but never used" | \ grep -v -E "'(py2exe|py2app|PyQt4|biplist|setuptools|win32com|find_executable|parse_sitemap|parse_sitemapindex|parse_bookmark_data|parse_bookmark_file|wsgiref|pyftpdlib|linkchecker_rc)' imported but unused" | \ grep -v "undefined name '_'" | \ grep -v "undefined name '_n'" | cat pep8: pep8 $(PEP8OPTS) $(PY_FILES_DIRS) # Compare custom Python files with the originals diff: @for f in gzip robotparser; do \ echo "Comparing $${f}.py"; \ diff -u linkcheck/$${f}2.py $(SRCDIR)/cpython.hg/Lib/$${f}.py | $(PAGER); \ done @diff -u linkcheck/better_exchook.py $(SRCDIR)/py_better_exchook.git/better_exchook.py # Compare dnspython files with the ones from upstream repository dnsdiff: @(for d in dns tests; do \ diff -BurN --exclude=*.pyc third_party/dnspython/$$d $(DNSPYTHON)/$$d; \ done) | $(PAGER) changelog: github-changelog $(DRYRUN) $(GITUSER) $(GITREPO) doc/changelog.txt gui: $(MAKE) -C linkcheck/gui count: @sloccount linkchecker linkchecker-gui linkcheck tests # run eclipse ide ide: eclipse -data $(CURDIR)/.. .PHONY: test changelog gui count pyflakes ide login upload all clean distclean .PHONY: pep8 cleandeb locale localbuild deb diff dnsdiff sign .PHONY: filescheck update-copyright releasecheck check register announce .PHONY: chmod dist app rpm release homepage LinkChecker-9.3/MANIFEST0000644000175000017500000003354612361541761015473 0ustar calvincalvin00000000000000# file GENERATED by distutils, do NOT edit COPYING MANIFEST.in Makefile install-rpm.sh linkchecker linkchecker-gui linkchecker.freecode setup.cfg setup.py cgi-bin/README cgi-bin/lc.wsgi cgi-bin/lconline/check.js cgi-bin/lconline/favicon.ico cgi-bin/lconline/index.html cgi-bin/lconline/lc.css cgi-bin/lconline/lc_cgi.html.de cgi-bin/lconline/lc_cgi.html.en cgi-bin/lconline/leer.html.de cgi-bin/lconline/leer.html.en config/create.sql config/linkchecker-completion config/linkchecker.apache2.conf config/linkcheckerrc doc/Makefile doc/changelog.txt doc/de.po doc/development.txt doc/fr.po doc/install.txt doc/linkchecker-gui.desktop doc/linkchecker.desktop doc/linkchecker.doc.pot doc/po4a.conf doc/python3.txt doc/robots.txt.example doc/upgrading.txt doc/de/linkchecker-gui.1 doc/de/linkchecker.1 doc/de/linkcheckerrc.5 doc/en/linkchecker-gui.1 doc/en/linkchecker.1 doc/en/linkcheckerrc.5 doc/examples/check_blacklist.sh doc/examples/check_for_x_errors.sh doc/examples/check_urls.sh doc/examples/filter_xml_output.py doc/examples/linkcheckerrc_loginurl doc/examples/windows.bat doc/html/Makefile doc/html/favicon.ico doc/html/index.html doc/html/index.txt doc/html/lccollection.qhc doc/html/lccollection.qhcp doc/html/lcdoc.qch doc/html/lcdoc.qhp doc/html/logo128x128.png doc/html/logo16x16.png doc/html/logo32x32.png doc/html/logo48x48.png doc/html/logo64x64.png linkcheck/__init__.py linkcheck/ansicolor.py linkcheck/better_exchook2.py linkcheck/cmdline.py linkcheck/colorama.py linkcheck/containers.py linkcheck/cookies.py linkcheck/decorators.py linkcheck/dummy.py linkcheck/fileutil.py linkcheck/ftpparse.py linkcheck/gzip2.py linkcheck/httputil.py linkcheck/i18n.py linkcheck/lc_cgi.py linkcheck/loader.py linkcheck/lock.py linkcheck/log.py linkcheck/logconf.py linkcheck/mem.py linkcheck/memoryutil.py linkcheck/mimeutil.py linkcheck/robotparser2.py linkcheck/socketutil.py linkcheck/strformat.py linkcheck/threader.py linkcheck/trace.py linkcheck/updater.py linkcheck/url.py linkcheck/winutil.py linkcheck/HtmlParser/Makefile linkcheck/HtmlParser/__init__.py linkcheck/HtmlParser/fixincludes.awk linkcheck/HtmlParser/htmllex.c linkcheck/HtmlParser/htmllex.l linkcheck/HtmlParser/htmllib.py linkcheck/HtmlParser/htmlparse.c linkcheck/HtmlParser/htmlparse.h linkcheck/HtmlParser/htmlparse.y linkcheck/HtmlParser/htmlsax.h linkcheck/HtmlParser/s_util.c linkcheck/HtmlParser/s_util.h linkcheck/bookmarks/__init__.py linkcheck/bookmarks/chrome.py linkcheck/bookmarks/chromium.py linkcheck/bookmarks/firefox.py linkcheck/bookmarks/opera.py linkcheck/bookmarks/safari.py linkcheck/cache/__init__.py linkcheck/cache/results.py linkcheck/cache/robots_txt.py linkcheck/cache/urlqueue.py linkcheck/checker/__init__.py linkcheck/checker/const.py linkcheck/checker/dnsurl.py linkcheck/checker/fileurl.py linkcheck/checker/ftpurl.py linkcheck/checker/httpurl.py linkcheck/checker/ignoreurl.py linkcheck/checker/internpaturl.py linkcheck/checker/mailtourl.py linkcheck/checker/nntpurl.py linkcheck/checker/proxysupport.py linkcheck/checker/telneturl.py linkcheck/checker/unknownurl.py linkcheck/checker/urlbase.py linkcheck/configuration/__init__.py linkcheck/configuration/confparse.py linkcheck/director/__init__.py linkcheck/director/aggregator.py linkcheck/director/checker.py linkcheck/director/console.py linkcheck/director/interrupt.py linkcheck/director/logger.py linkcheck/director/status.py linkcheck/director/task.py linkcheck/gui/Makefile linkcheck/gui/__init__.py linkcheck/gui/checker.py linkcheck/gui/contextmenu.py linkcheck/gui/debug.py linkcheck/gui/editor.py linkcheck/gui/editor_qsci.py linkcheck/gui/editor_qt.py linkcheck/gui/help.py linkcheck/gui/lineedit.py linkcheck/gui/linkchecker_rc.py linkcheck/gui/linkchecker_ui_debug.py linkcheck/gui/linkchecker_ui_editor.py linkcheck/gui/linkchecker_ui_main.py linkcheck/gui/linkchecker_ui_options.py linkcheck/gui/logger.py linkcheck/gui/options.py linkcheck/gui/projects.py linkcheck/gui/properties.py linkcheck/gui/recentdocs.py linkcheck/gui/settings.py linkcheck/gui/statistics.py linkcheck/gui/syntax.py linkcheck/gui/updater.py linkcheck/gui/urlmodel.py linkcheck/gui/urlsave.py linkcheck/gui/validator.py linkcheck/gui/rc/Makefile linkcheck/gui/rc/about.png linkcheck/gui/rc/app.png linkcheck/gui/rc/arrow_down.png linkcheck/gui/rc/cancel.png linkcheck/gui/rc/clear.png linkcheck/gui/rc/copy.png linkcheck/gui/rc/exit.png linkcheck/gui/rc/help.png linkcheck/gui/rc/linkchecker.qrc linkcheck/gui/rc/online.png linkcheck/gui/rc/options.png linkcheck/gui/rc/preferences.png linkcheck/gui/rc/save.png linkcheck/gui/rc/start.png linkcheck/gui/rc/stop.png linkcheck/gui/ui/debug.ui linkcheck/gui/ui/editor.ui linkcheck/gui/ui/main.ui linkcheck/gui/ui/options.ui linkcheck/htmlutil/__init__.py linkcheck/htmlutil/formsearch.py linkcheck/htmlutil/linkname.py linkcheck/htmlutil/linkparse.py linkcheck/logger/__init__.py linkcheck/logger/blacklist.py linkcheck/logger/csvlog.py linkcheck/logger/customxml.py linkcheck/logger/dot.py linkcheck/logger/gml.py linkcheck/logger/graph.py linkcheck/logger/gxml.py linkcheck/logger/html.py linkcheck/logger/none.py linkcheck/logger/sitemapxml.py linkcheck/logger/sql.py linkcheck/logger/text.py linkcheck/logger/xmllog.py linkcheck/network/__init__.py linkcheck/network/_network.c linkcheck/network/iputil.py linkcheck/parser/__init__.py linkcheck/parser/sitemap.py linkcheck/plugins/__init__.py linkcheck/plugins/anchorcheck.py linkcheck/plugins/httpheaderinfo.py linkcheck/plugins/locationinfo.py linkcheck/plugins/parsepdf.py linkcheck/plugins/parseword.py linkcheck/plugins/regexcheck.py linkcheck/plugins/sslcertcheck.py linkcheck/plugins/syntaxchecks.py linkcheck/plugins/viruscheck.py po/Makefile po/de.po po/es.po po/fr.po po/linkchecker.pot po/msgfmt.py scripts/analyze_memdump.py scripts/debugparse.py scripts/nodebug.sh scripts/removeafter.py scripts/update_iana_uri_schemes.py scripts/update_iana_uri_schemes.sh scripts/viewprof.py tests/__init__.py tests/test_cgi.py tests/test_clamav.py tests/test_console.py tests/test_containers.py tests/test_cookies.py tests/test_decorators.py tests/test_dummy.py tests/test_filenames.py tests/test_fileutil.py tests/test_ftpparse.py tests/test_gui.py tests/test_linkchecker.py tests/test_linkname.py tests/test_linkparser.py tests/test_mimeutil.py tests/test_network.py tests/test_parser.py tests/test_po.py tests/test_robotparser.py tests/test_robotstxt.py tests/test_strformat.py tests/test_updater.py tests/test_url.py tests/test_urlbuild.py tests/cache/__init__.py tests/checker/__init__.py tests/checker/ftpserver.py tests/checker/httpserver.py tests/checker/telnetserver.py tests/checker/test_anchor.py tests/checker/test_base.py tests/checker/test_bookmarks.py tests/checker/test_error.py tests/checker/test_file.py tests/checker/test_frames.py tests/checker/test_ftp.py tests/checker/test_http.py tests/checker/test_http_misc.py tests/checker/test_http_redirect.py tests/checker/test_http_robots.py tests/checker/test_httpbin.py tests/checker/test_https.py tests/checker/test_https_redirect.py tests/checker/test_internpat.py tests/checker/test_mail_bad.py tests/checker/test_mail_good.py tests/checker/test_misc.py tests/checker/test_news.py tests/checker/test_noproxy.py tests/checker/test_telnet.py tests/checker/test_unknown.py tests/checker/test_urllen.py tests/checker/test_whitespace.py tests/checker/data/Bookmarks.result tests/checker/data/anchor.html tests/checker/data/archive.html tests/checker/data/archive.html.result tests/checker/data/base1.html tests/checker/data/base1.html.result tests/checker/data/base2.html tests/checker/data/base2.html.result tests/checker/data/base3.html tests/checker/data/base3.html.result tests/checker/data/base4.html tests/checker/data/base4.html.result tests/checker/data/cookies.txt tests/checker/data/dir.result tests/checker/data/dir.zip tests/checker/data/favicon.ico tests/checker/data/file.asc tests/checker/data/file.asc.result tests/checker/data/file.css tests/checker/data/file.css.result tests/checker/data/file.doc.result tests/checker/data/file.html tests/checker/data/file.html.result tests/checker/data/file.pdf.result tests/checker/data/file.php.result tests/checker/data/file.txt tests/checker/data/file.txt.result tests/checker/data/file.wml.result tests/checker/data/frames.html tests/checker/data/frames.html.result tests/checker/data/html5.html tests/checker/data/html5.html.result tests/checker/data/http.html tests/checker/data/http.html.result tests/checker/data/http.xhtml tests/checker/data/http.xhtml.result tests/checker/data/http_file.html tests/checker/data/http_file.html.result tests/checker/data/http_lowercase.html tests/checker/data/http_lowercase.html.result tests/checker/data/http_quotes.html tests/checker/data/http_quotes.html.result tests/checker/data/http_slash.html tests/checker/data/http_slash.html.result tests/checker/data/misc.html tests/checker/data/misc.html.result tests/checker/data/newurl.html tests/checker/data/norobots.html tests/checker/data/norobots.html.result tests/checker/data/opera6.adr tests/checker/data/opera6.adr.result tests/checker/data/places.sqlite tests/checker/data/places.sqlite.result tests/checker/data/redir.html tests/checker/data/redir.html.result tests/checker/data/test.swf tests/checker/data/urllist.txt tests/checker/data/urllist.txt.result tests/checker/data/Мошкова.bin.result tests/checker/data/a b/el.html tests/checker/data/a b/t.txt tests/checker/data/base/test.txt tests/checker/data/plist_binary/Bookmarks.plist.result tests/checker/data/plist_xml/Bookmarks.plist.result tests/configuration/__init__.py tests/configuration/test_config.py tests/logger/__init__.py tests/logger/test_csvlog.py third_party/dnspython/changelog.txt third_party/dnspython/dns/__init__.py third_party/dnspython/dns/dnssec.py third_party/dnspython/dns/e164.py third_party/dnspython/dns/edns.py third_party/dnspython/dns/entropy.py third_party/dnspython/dns/exception.py third_party/dnspython/dns/flags.py third_party/dnspython/dns/hash.py third_party/dnspython/dns/inet.py third_party/dnspython/dns/ipv4.py third_party/dnspython/dns/ipv6.py third_party/dnspython/dns/message.py third_party/dnspython/dns/name.py third_party/dnspython/dns/namedict.py third_party/dnspython/dns/node.py third_party/dnspython/dns/opcode.py third_party/dnspython/dns/query.py third_party/dnspython/dns/rcode.py third_party/dnspython/dns/rdata.py third_party/dnspython/dns/rdataclass.py third_party/dnspython/dns/rdataset.py third_party/dnspython/dns/rdatatype.py third_party/dnspython/dns/renderer.py third_party/dnspython/dns/resolver.py third_party/dnspython/dns/reversename.py third_party/dnspython/dns/rrset.py third_party/dnspython/dns/set.py third_party/dnspython/dns/tokenizer.py third_party/dnspython/dns/tsig.py third_party/dnspython/dns/tsigkeyring.py third_party/dnspython/dns/ttl.py third_party/dnspython/dns/update.py third_party/dnspython/dns/version.py third_party/dnspython/dns/wiredata.py third_party/dnspython/dns/zone.py third_party/dnspython/dns/rdtypes/__init__.py third_party/dnspython/dns/rdtypes/dsbase.py third_party/dnspython/dns/rdtypes/mxbase.py third_party/dnspython/dns/rdtypes/nsbase.py third_party/dnspython/dns/rdtypes/txtbase.py third_party/dnspython/dns/rdtypes/ANY/AFSDB.py third_party/dnspython/dns/rdtypes/ANY/CERT.py third_party/dnspython/dns/rdtypes/ANY/CNAME.py third_party/dnspython/dns/rdtypes/ANY/DLV.py third_party/dnspython/dns/rdtypes/ANY/DNAME.py third_party/dnspython/dns/rdtypes/ANY/DNSKEY.py third_party/dnspython/dns/rdtypes/ANY/DS.py third_party/dnspython/dns/rdtypes/ANY/GPOS.py third_party/dnspython/dns/rdtypes/ANY/HINFO.py third_party/dnspython/dns/rdtypes/ANY/HIP.py third_party/dnspython/dns/rdtypes/ANY/ISDN.py third_party/dnspython/dns/rdtypes/ANY/LOC.py third_party/dnspython/dns/rdtypes/ANY/MX.py third_party/dnspython/dns/rdtypes/ANY/NS.py third_party/dnspython/dns/rdtypes/ANY/NSEC.py third_party/dnspython/dns/rdtypes/ANY/NSEC3.py third_party/dnspython/dns/rdtypes/ANY/NSEC3PARAM.py third_party/dnspython/dns/rdtypes/ANY/PTR.py third_party/dnspython/dns/rdtypes/ANY/RP.py third_party/dnspython/dns/rdtypes/ANY/RRSIG.py third_party/dnspython/dns/rdtypes/ANY/RT.py third_party/dnspython/dns/rdtypes/ANY/SOA.py third_party/dnspython/dns/rdtypes/ANY/SPF.py third_party/dnspython/dns/rdtypes/ANY/SSHFP.py third_party/dnspython/dns/rdtypes/ANY/TXT.py third_party/dnspython/dns/rdtypes/ANY/X25.py third_party/dnspython/dns/rdtypes/ANY/__init__.py third_party/dnspython/dns/rdtypes/IN/A.py third_party/dnspython/dns/rdtypes/IN/AAAA.py third_party/dnspython/dns/rdtypes/IN/APL.py third_party/dnspython/dns/rdtypes/IN/DHCID.py third_party/dnspython/dns/rdtypes/IN/IPSECKEY.py third_party/dnspython/dns/rdtypes/IN/KX.py third_party/dnspython/dns/rdtypes/IN/NAPTR.py third_party/dnspython/dns/rdtypes/IN/NSAP.py third_party/dnspython/dns/rdtypes/IN/NSAP_PTR.py third_party/dnspython/dns/rdtypes/IN/PX.py third_party/dnspython/dns/rdtypes/IN/SRV.py third_party/dnspython/dns/rdtypes/IN/WKS.py third_party/dnspython/dns/rdtypes/IN/__init__.py third_party/dnspython/tests/Makefile third_party/dnspython/tests/bugs.py third_party/dnspython/tests/dnssec.py third_party/dnspython/tests/example third_party/dnspython/tests/example1.good third_party/dnspython/tests/example2.good third_party/dnspython/tests/flags.py third_party/dnspython/tests/message.py third_party/dnspython/tests/name.py third_party/dnspython/tests/namedict.py third_party/dnspython/tests/ntoaaton.py third_party/dnspython/tests/rdtypeandclass.py third_party/dnspython/tests/resolver.py third_party/dnspython/tests/rrset.py third_party/dnspython/tests/set.py third_party/dnspython/tests/tokenizer.py third_party/dnspython/tests/update.py third_party/dnspython/tests/zone.py third_party/miniboa-r42/CHANGES.txt third_party/miniboa-r42/LICENSE.txt third_party/miniboa-r42/README.txt third_party/miniboa-r42/chat_demo.py third_party/miniboa-r42/handler_demo.py third_party/miniboa-r42/hello_demo.py third_party/miniboa-r42/miniboa/__init__.py third_party/miniboa-r42/miniboa/async.py third_party/miniboa-r42/miniboa/error.py third_party/miniboa-r42/miniboa/telnet.py third_party/miniboa-r42/miniboa/xterm.py LinkChecker-9.3/linkchecker-gui0000755000175000017500000000565112361407402017321 0ustar calvincalvin00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # Copyright (C) 2008-2014 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Check HTML pages for broken links. This is the GUI client. """ import sys import signal from linkcheck import configuration, drop_privileges, i18n from linkcheck.loader import is_frozen if is_frozen(): # Let Python find the C++ runtime DLLs for PyQt. import os from linkcheck import get_install_data sys.path.append(os.path.join(get_install_data(), 'Microsoft.VC90.CRT')) from PyQt4.QtGui import QApplication from linkcheck.fileutil import is_readable from linkcheck.gui import LinkCheckerMain, get_app_style from linkcheck.gui.projects import ProjectExt def excepthook (window, etype, evalue, tb): """Catch unhandled exceptions.""" from cStringIO import StringIO from linkcheck.director.console import internal_error out = i18n.get_encoded_writer(out=StringIO(), encoding="utf-8") internal_error(out=out, etype=etype, evalue=evalue, tb=tb) # signal main window to be thread-safe window.error_signal.emit(out.getvalue()) def main (argv=None): """Initialize the Qt application, handle commandline arguments and show the main window.""" if argv is None: argv = sys.argv app = QApplication(argv) app.setApplicationName(configuration.AppName) app.setApplicationVersion(configuration.Version) app.setOrganizationName(configuration.Author) QApplication.setStyle(get_app_style()) QApplication.setPalette(QApplication.style().standardPalette()) args = app.arguments() mainkwargs = {} if len(args) > 1: fileorurl = unicode(args[1]) if is_readable(fileorurl) and fileorurl.lower().endswith(ProjectExt): mainkwargs["project"] = fileorurl else: mainkwargs["url"] = fileorurl signal.signal(signal.SIGINT, signal.SIG_DFL) # use local variable here to avoid garbage collection of the main # window before app.exec_() finishes window = LinkCheckerMain(**mainkwargs) window.show() window.raise_() # this will raise the window on Mac OS X drop_privileges() sys.excepthook = \ lambda etype, evalue, tb: excepthook(window, etype, evalue, tb) sys.exit(app.exec_()) if __name__ == "__main__": main() LinkChecker-9.3/tests/0000750000175000017500000000000012361541761015464 5ustar calvincalvin00000000000000LinkChecker-9.3/tests/test_cgi.py0000644000175000017500000000543411745050672017653 0ustar calvincalvin00000000000000# -*- coding: iso-8859-1 -*- # Copyright (C) 2004-2012 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Test cgi form routines. """ import unittest import wsgiref import urllib from StringIO import StringIO from wsgiref.util import setup_testing_defaults from linkcheck.lc_cgi import checkform, checklink, LCFormError, application from linkcheck.strformat import limit class TestWsgi (unittest.TestCase): """Test wsgi application.""" def test_form_valid_url (self): # Check url validity. env = dict() form = dict(url="http://www.example.com/", level="1") checkform(form, env) def test_form_empty_url (self): # Check with empty url. env = dict() form = dict(url="", level="0") self.assertRaises(LCFormError, checkform, form, env) def test_form_default_url (self): # Check with default url. env = dict() form = dict(url="http://", level="0") self.assertRaises(LCFormError, checkform, form, env) def test_form_invalid_url (self): # Check url (in)validity. env = dict() form = dict(url="http://www.foo bar/", level="0") self.assertRaises(LCFormError, checkform, form, env) def test_checklink (self): form = dict(url="http://www.example.com/", level="0") checklink(form) def test_application (self): form = dict(url="http://www.example.com/", level="0") formdata = urllib.urlencode(form) environ = {'wsgi.input': StringIO(formdata)} setup_testing_defaults(environ) test_response = "" test_headers = [None] test_status = [None] def start_response(status, headers): test_status[0] = status test_headers[0] = headers for str_data in application(environ, start_response): if not isinstance(str_data, str): err = "answer is not a byte string: %r" % limit(str_data, 30) self.assertTrue(False, err) test_response += str_data self.assertEqual(test_status[0], '200 OK') self.assertTrue("Generated by LinkChecker" in test_response) LinkChecker-9.3/tests/test_linkname.py0000644000175000017500000000420711232427131020671 0ustar calvincalvin00000000000000# -*- coding: iso-8859-1 -*- # Copyright (C) 2004-2009 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Test linkname routines. """ import unittest from linkcheck.htmlutil import linkname class TestLinkname (unittest.TestCase): """ Test href and image name parsing. """ def image_name_test (self, txt, expected): """ Helper function calling linkname.image_name(). """ self.assertEqual(linkname.image_name(txt), expected) def href_name_test (self, txt, expected): """ Helper function calling linkname.href_name(). """ self.assertEqual(linkname.href_name(txt), expected) def test_image_name (self): """ Test image name parsing. """ self.image_name_test("", '') self.image_name_test("abc", 'abc') def test_href_name (self): """ Test href name parsing. """ self.href_name_test("guru guru", 'guru guru') self.href_name_test("a\njo", "a\njo") self.href_name_test("test<", "test<") self.href_name_test("test", "test", "test"foo', '"') self.href_name_test("", '') self.href_name_test("abc", 'abc') LinkChecker-9.3/tests/test_parser.py0000644000175000017500000003075111734567611020411 0ustar calvincalvin00000000000000# -*- coding: iso-8859-1 -*- # Copyright (C) 2004-2012 Bastian Kleineidam # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Test html parsing. """ import linkcheck.HtmlParser.htmlsax import linkcheck.HtmlParser.htmllib from cStringIO import StringIO import unittest # list of tuples # (, ) parsetests = [ # start tags ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""< a>""", """"""), ("""< a >""", """"""), ("""<>""", """<>"""), ("""< >""", """< >"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), # multiple attribute names should be ignored... ("""""", """"""), # ... but which one wins - in our implementation the last one ("""""", """"""), # reduce test ("""<""", """<"""), ("""d>""", """d>"""), # numbers in tag ("""

bla

""", """

bla

"""), # more start tags ("""
""", """"""), ("""
""", """
"""), ("""
""", """
"""), ("""
""", """

"""), # comments ("""< 1>""", """<1>"""), ("""< 2>""", """<2>"""), ("""< 3>""", """<3>"""), ("""< 4>""", """<4>"""), ("""< 5>""", """<5>"""), ("""< 7>""", """<7>"""), ("""""", """"""), ("""< 9>""", """<9>"""), ("""< 10>""", """<10>"""), ("""""", """"""), # empty comment # invalid comments ("""<8>"""), ("""<6>"""), ("""""", """"""), ("""""", """"""), (""""""), ("""< a>""", """
"""), ("""< a>""", """"""), # end tags ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""< / a>""", """"""), ("""< /a>""", """"""), ("""""", """"""), # start and end tag (HTML doctype assumed) ("""""", """"""), ("""""", """"""), ("""""", """"""), # declaration tags ("""""", """"""), # misc ("""""", """"""), # javascript ("""""", """"""), ("""""", """"""), ("""""", """"""), # line continuation (Dr. Fun webpage) ("""""", """"""), ("""""", """"""), ("""""", """"""), # href with $ ("""""", """"""), # quoting ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), # entity resolving ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), # note that \u8156 is not valid encoding and therefore gets removed ("""""", """"""), # non-ascii characters (""" fahr {""", """ fahr {"""), # mailto link ("""1""", """1"""), # doctype XHTML ("""""", """"""), # meta tag with charset encoding ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), ("""""", """"""), # CDATA ("""hallo]]>""", """hallo]]>"""), # missing > in end tag ("""""", """"""), ("""""", """"""), # missing beginning quote ("""""", """"""), # stray < before start tag ("""<0.""", """<0."""), # stray < before end tag ("""<0.""", """<0."""), # missing end quote (XXX TODO) #("""\n"""), #("""\na"""), #("""\n""", """\n"""), #("""\n""", """\n"""), # HTML5 tags ("""