Your IP : 216.73.216.86


Current Path : /home/emeraadmin/public_html/4d695/
Upload File :
Current File : /home/emeraadmin/public_html/4d695/python3-unbound.tar

async-lookup.py000064400000004244151702565550007561 0ustar00#!/usr/bin/python
'''
 async-lookup.py : This example shows how to use asynchronous lookups

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import unbound
import time

ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")

def call_back(my_data,status,result):
    print("Call_back:", sorted(my_data))
    if status == 0 and result.havedata:
        print("Result:", sorted(result.data.address_list))
        my_data['done_flag'] = True


my_data = {'done_flag':False,'arbitrary':"object"}
status, async_id = ctx.resolve_async("www.nic.cz", my_data, call_back, unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
        
while (status == 0) and (not my_data['done_flag']):
    status = ctx.process()
    time.sleep(0.1)

if (status != 0):
    print("Resolve error:", unbound.ub_strerror(status))
avahi-resolver.py000064400000043207151702565550010066 0ustar00#!/usr/bin/env python3
#
# A plugin for the Unbound DNS resolver to resolve DNS records in
# multicast DNS [RFC 6762] via Avahi.
#
# Copyright (C) 2018-2019 Internet Real-Time Lab, Columbia University
# http://www.cs.columbia.edu/irt/
#
# Written by Jan Janak <janakj@cs.columbia.edu>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#
# Dependendies:
#   Unbound with pythonmodule configured for Python 3
#   dnspython [http://www.dnspython.org]
#   pydbus [https://github.com/LEW21/pydbus]
#
# To enable Python 3 support, configure Unbound as follows:
#   PYTHON_VERSION=3 ./configure --with-pythonmodule
#
# The plugin in meant to be used as a fallback resolver that resolves
# records in multicast DNS if the upstream server cannot be reached or
# provides no answer (NXDOMAIN).
#
# mDNS requests for negative records, i.e., records for which Avahi
# returns no answer (NXDOMAIN), are expensive. Since there is no
# single authoritative server in mDNS, such requests terminate only
# via a timeout. The timeout is about a second (if MDNS_TIMEOUT is not
# configured), or the value configured via MDNS_TIMEOUT. The
# corresponding Unbound thread will be blocked for this amount of
# time. For this reason, it is important to configure an appropriate
# number of threads in unbound.conf and limit the RR types and names
# that will be resolved via Avahi via the environment variables
# described later.
#
# An example unbound.conf with the plugin enabled:
#
# | server:
# |   module-config: "validator python iterator"
# |   num-threads: 32
# |   cache-max-negative-ttl: 60
# |   cache-max-ttl: 60
# | python:
# |   python-script: path/to/this/file
#
#
# The plugin can also be run interactively. Provide the name and
# record type to be resolved as command line arguments and the
# resolved record will be printed to standard output:
#
#   $ ./avahi-resolver.py voip-phx4.phxnet.org A
#   voip-phx4.phxnet.org. 120 IN A 10.4.3.2
#
#
# The behavior of the plugin can be controlled via the following
# environment variables:
#
# DBUS_SYSTEM_BUS_ADDRESS
#
# The address of the system DBus bus, in the format expected by DBus,
# e.g., unix:path=/run/avahi/system-bus.sock
#
#
# DEBUG
#
# Set this environment variable to "yes", "true", "on", or "1" to
# enable debugging. In debugging mode, the plugin will output a lot
# more information about what it is doing either to the standard
# output (when run interactively) or to Unbound via log_info and
# log_error.
#
# By default debugging is disabled.
#
#
# MDNS_TTL
#
# Avahi does not provide the TTL value for the records it returns.
# This environment variable can be used to configure the TTL value for
# such records.
#
# The default value is 120 seconds.
#
#
# MDNS_TIMEOUT
#
# The maximum amount of time (in milliseconds) an Avahi request is
# allowed to run. This value sets the time it takes to resolve
# negative (non-existent) records in Avahi. If unset, the request
# terminates when Avahi sends the "AllForNow" signal, telling the
# client that more records are unlikely to arrive. This takes roughly
# about one second. You may need to configure a longer value here on
# slower networks, e.g., networks that relay mDNS packets such as
# MANETs.
#
#
# MDNS_GETONE
#
# If set to "true", "1", or "on", an Avahi request will terminate as
# soon as at least one record has been found. If there are multiple
# nodes in the mDNS network publishing the same record, only one (or
# subset) will be returned.
#
# If set to "false", "0", or "off", the plugin will gather records for
# MDNS_TIMEOUT and return all records found. This is only useful in
# networks where multiple nodes are known to publish different records
# under the same name and the client needs to be able to obtain them
# all. When configured this way, all Avahi requests will always take
# MDNS_TIMEOUT to complete!
#
# This option is set to true by default.
#
#
# MDNS_REJECT_TYPES
#
# A comma-separated list of record types that will NOT be resolved in
# mDNS via Avahi. Use this environment variable to prevent specific
# record types from being resolved via Avahi. For example, if your
# network does not support IPv6, you can put AAAA on this list.
#
# The default value is an empty list.
#
# Example: MDNS_REJECT_TYPES=aaaa,mx,soa
#
#
# MDNS_ACCEPT_TYPES
#
# If set, a record type will be resolved via Avahi if and only if it
# is present on this comma-separated list. In other words, this is a
# whitelist.
#
# The default value is an empty list which means all record types will
# be resolved via Avahi.
#
# Example: MDNS_ACCEPT_TYPES=a,ptr,txt,srv,aaaa,cname
#
#
# MDNS_REJECT_NAMES
#
# If the name being resolved matches the regular expression in this
# environment variable, the name will NOT be resolved via Avahi. In
# other words, this environment variable provides a blacklist.
#
# The default value is empty--no names will be reject.
#
# Example: MDNS_REJECT_NAMES=(^|\.)example\.com\.$
#
#
# MDNS_ACCEPT_NAMES
#
# If set to a regular expression, a name will be resolved via Avahi if
# and only if it matches the regular expression. In other words, this
# variable provides a whitelist.
#
# The default value is empty--all names will be resolved via Avahi.
#
# Example: MDNS_ACCEPT_NAMES=^.*\.example\.com\.$
#

import os
import re
import array
import threading
import traceback
import dns.rdata
import dns.rdatatype
import dns.rdataclass
from queue import Queue
from gi.repository import GLib
from pydbus import SystemBus


IF_UNSPEC    = -1
PROTO_UNSPEC = -1

sysbus = None
avahi = None
trampoline = dict()
thread_local = threading.local()
dbus_thread = None
dbus_loop = None


def str2bool(v):
    if v.lower() in ['false', 'no', '0', 'off', '']:
        return False
    return True


def dbg(msg):
    if DEBUG != False:
        log_info('avahi-resolver: %s' % msg)


#
# Although pydbus has an internal facility for handling signals, we
# cannot use that with Avahi. When responding from an internal cache,
# Avahi sends the first signal very quickly, before pydbus has had a
# chance to subscribe for the signal. This will result in lost signal
# and missed data:
#
# https://github.com/LEW21/pydbus/issues/87
#
# As a workaround, we subscribe to all signals before creating a
# record browser and do our own signal matching and dispatching via
# the following function.
#
def signal_dispatcher(connection, sender, path, interface, name, args):
    o = trampoline.get(path, None)
    if o is None:
        return

    if   name == 'ItemNew':    o.itemNew(*args)
    elif name == 'ItemRemove': o.itemRemove(*args)
    elif name == 'AllForNow':  o.allForNow(*args)
    elif name == 'Failure':    o.failure(*args)


class RecordBrowser:
    def __init__(self, callback, name, type_, timeout=None, getone=True):
        self.callback = callback
        self.records = []
        self.error = None
        self.getone = getone

        self.timer = None if timeout is None else GLib.timeout_add(timeout, self.timedOut)

        self.browser_path = avahi.RecordBrowserNew(IF_UNSPEC, PROTO_UNSPEC, name, dns.rdataclass.IN, type_, 0)
        trampoline[self.browser_path] = self
        self.browser = sysbus.get('.Avahi', self.browser_path)
        self.dbg('Created RecordBrowser(name=%s, type=%s, getone=%s, timeout=%s)'
                   % (name, dns.rdatatype.to_text(type_), getone, timeout))

    def dbg(self, msg):
        dbg('[%s] %s' % (self.browser_path, msg))

    def _done(self):
        del trampoline[self.browser_path]
        self.dbg('Freeing')
        self.browser.Free()

        if self.timer is not None:
            self.dbg('Removing timer')
            GLib.source_remove(self.timer)

        self.callback(self.records, self.error)

    def itemNew(self, interface, protocol, name, class_, type_, rdata, flags):
        self.dbg('Got signal ItemNew')
        self.records.append((name, class_, type_, rdata))
        if self.getone:
            self._done()

    def itemRemove(self, interface, protocol, name, class_, type_, rdata, flags):
        self.dbg('Got signal ItemRemove')
        self.records.remove((name, class_, type_, rdata))

    def failure(self, error):
        self.dbg('Got signal Failure')
        self.error = Exception(error)
        self._done()

    def allForNow(self):
        self.dbg('Got signal AllForNow')
        if self.timer is None:
            self._done()

    def timedOut(self):
        self.dbg('Timed out')
        self._done()
        return False


#
# This function runs the main event loop for DBus (GLib). This
# function must be run in a dedicated worker thread.
#
def dbus_main():
    global sysbus, avahi, dbus_loop

    dbg('Connecting to system DBus')
    sysbus = SystemBus()

    dbg('Subscribing to .Avahi.RecordBrowser signals')
    sysbus.con.signal_subscribe('org.freedesktop.Avahi',
        'org.freedesktop.Avahi.RecordBrowser',
        None, None, None, 0, signal_dispatcher)

    avahi = sysbus.get('.Avahi', '/')

    dbg("Connected to Avahi Daemon: %s (API %s) [%s]"
             % (avahi.GetVersionString(), avahi.GetAPIVersion(), avahi.GetHostNameFqdn()))

    dbg('Starting DBus main loop')
    dbus_loop = GLib.MainLoop()
    dbus_loop.run()


#
# This function must be run in the DBus worker thread. It creates a
# new RecordBrowser instance and once it has finished doing it thing,
# it will send the result back to the original thread via the queue.
#
def start_resolver(queue, *args, **kwargs):
    try:
        RecordBrowser(lambda *v: queue.put_nowait(v), *args, **kwargs)
    except Exception as e:
        queue.put_nowait((None, e))

    return False


#
# To resolve a request, we setup a queue, post a task to the DBus
# worker thread, and wait for the result (or error) to arrive over the
# queue. If the worker thread reports an error, raise the error as an
# exception.
#
def resolve(*args, **kwargs):
    try:
        queue = thread_local.queue
    except AttributeError:
        dbg('Creating new per-thread queue')
        queue = Queue()
        thread_local.queue = queue

    GLib.idle_add(lambda: start_resolver(queue, *args, **kwargs))

    records, error = queue.get()
    queue.task_done()

    if error is not None:
        raise error

    return records


def parse_type_list(lst):
    return list(map(dns.rdatatype.from_text, [v.strip() for v in lst.split(',') if len(v)]))


def init(*args, **kwargs):
    global dbus_thread, DEBUG
    global MDNS_TTL, MDNS_GETONE, MDNS_TIMEOUT
    global MDNS_REJECT_TYPES, MDNS_ACCEPT_TYPES
    global MDNS_REJECT_NAMES, MDNS_ACCEPT_NAMES

    DEBUG = str2bool(os.environ.get('DEBUG', str(False)))

    MDNS_TTL = int(os.environ.get('MDNS_TTL', 120))
    dbg("TTL for records from Avahi: %d" % MDNS_TTL)

    MDNS_REJECT_TYPES = parse_type_list(os.environ.get('MDNS_REJECT_TYPES', ''))
    if MDNS_REJECT_TYPES:
        dbg('Types NOT resolved via Avahi: %s' % MDNS_REJECT_TYPES)

    MDNS_ACCEPT_TYPES = parse_type_list(os.environ.get('MDNS_ACCEPT_TYPES', ''))
    if MDNS_ACCEPT_TYPES:
        dbg('ONLY resolving the following types via Avahi: %s' % MDNS_ACCEPT_TYPES)

    v = os.environ.get('MDNS_REJECT_NAMES', None)
    MDNS_REJECT_NAMES = re.compile(v, flags=re.I | re.S) if v is not None else None
    if MDNS_REJECT_NAMES is not None:
        dbg('Names NOT resolved via Avahi: %s' % MDNS_REJECT_NAMES.pattern)

    v = os.environ.get('MDNS_ACCEPT_NAMES', None)
    MDNS_ACCEPT_NAMES = re.compile(v, flags=re.I | re.S) if v is not None else None
    if MDNS_ACCEPT_NAMES is not None:
        dbg('ONLY resolving the following names via Avahi: %s' % MDNS_ACCEPT_NAMES.pattern)

    v = os.environ.get('MDNS_TIMEOUT', None)
    MDNS_TIMEOUT = int(v) if v is not None else None
    if MDNS_TIMEOUT is not None:
        dbg('Avahi request timeout: %s' % MDNS_TIMEOUT)

    MDNS_GETONE = str2bool(os.environ.get('MDNS_GETONE', str(True)))
    dbg('Terminate Avahi requests on first record: %s' % MDNS_GETONE)

    dbus_thread = threading.Thread(target=dbus_main)
    dbus_thread.daemon = True
    dbus_thread.start()


def deinit(*args, **kwargs):
    dbus_loop.quit()
    dbus_thread.join()
    return True


def inform_super(id, qstate, superqstate, qdata):
    return True


def get_rcode(msg):
    if not msg:
        return RCODE_SERVFAIL

    return msg.rep.flags & 0xf


def rr2text(rec, ttl):
    name, class_, type_, rdata = rec
    wire = array.array('B', rdata).tostring()
    return '%s. %d %s %s %s' % (
        name,
        ttl,
        dns.rdataclass.to_text(class_),
        dns.rdatatype.to_text(type_),
        dns.rdata.from_wire(class_, type_, wire, 0, len(wire), None))


def operate(id, event, qstate, qdata):
    qi = qstate.qinfo
    name = qi.qname_str
    type_ = qi.qtype
    type_str = dns.rdatatype.to_text(type_)
    class_ = qi.qclass
    class_str = dns.rdataclass.to_text(class_)
    rc = get_rcode(qstate.return_msg)

    if event == MODULE_EVENT_NEW or event == MODULE_EVENT_PASS:
        qstate.ext_state[id] = MODULE_WAIT_MODULE
        return True

    if event != MODULE_EVENT_MODDONE:
        log_err("avahi-resolver: Unexpected event %d" % event)
        qstate.ext_state[id] = MODULE_ERROR
        return True

    qstate.ext_state[id] = MODULE_FINISHED

    # Only resolve via Avahi if we got NXDOMAIn from the upstream DNS
    # server, or if we could not reach the upstream DNS server. If we
    # got some records for the name from the upstream DNS server
    # already, do not resolve the record in Avahi.
    if rc != RCODE_NXDOMAIN and rc != RCODE_SERVFAIL:
        return True

    dbg("Got request for '%s %s %s'" % (name, class_str, type_str))

    # Avahi only supports the IN class
    if class_ != RR_CLASS_IN:
        dbg('Rejected, Avahi only supports the IN class')
        return True

    # Avahi does not support meta queries (e.g., ANY)
    if dns.rdatatype.is_metatype(type_):
        dbg('Rejected, Avahi does not support the type %s' % type_str)
        return True

    # If we have a type blacklist and the requested type is on the
    # list, reject it.
    if MDNS_REJECT_TYPES and type_ in MDNS_REJECT_TYPES:
        dbg('Rejected, type %s is on the blacklist' % type_str)
        return True

    # If we have a type whitelist and if the requested type is not on
    # the list, reject it.
    if MDNS_ACCEPT_TYPES and type_ not in MDNS_ACCEPT_TYPES:
        dbg('Rejected, type %s is not on the whitelist' % type_str)
        return True

    # If we have a name blacklist and if the requested name matches
    # the blacklist, reject it.
    if MDNS_REJECT_NAMES is not None:
        if MDNS_REJECT_NAMES.search(name):
            dbg('Rejected, name %s is on the blacklist' % name)
            return True

    # If we have a name whitelist and if the requested name does not
    # match the whitelist, reject it.
    if MDNS_ACCEPT_NAMES is not None:
        if not MDNS_ACCEPT_NAMES.search(name):
            dbg('Rejected, name %s is not on the whitelist' % name)
            return True

    dbg("Resolving '%s %s %s' via Avahi" % (name, class_str, type_str))

    recs = resolve(name, type_, getone=MDNS_GETONE, timeout=MDNS_TIMEOUT)

    if not recs:
        dbg('Result: Not found (NXDOMAIN)')
        qstate.return_rcode = RCODE_NXDOMAIN
        return True

    m = DNSMessage(name, type_, class_, PKT_QR | PKT_RD | PKT_RA)
    for r in recs:
        s = rr2text(r, MDNS_TTL)
        dbg('Result: %s' % s)
        m.answer.append(s)

    if not m.set_return_msg(qstate):
        raise Exception("Error in set_return_msg")

    if not storeQueryInCache(qstate, qstate.return_msg.qinfo, qstate.return_msg.rep, 0):
        raise Exception("Error in storeQueryInCache")

    qstate.return_msg.rep.security = 2
    qstate.return_rcode = RCODE_NOERROR
    return True


#
# It does not appear to be sufficient to check __name__ to determine
# whether we are being run in interactive mode. As a workaround, try
# to import module unboundmodule and if that fails, assume we're being
# run in interactive mode.
#
try:
    import unboundmodule
    embedded = True
except ImportError:
    embedded = False

if __name__ == '__main__' and not embedded:
    import sys

    def log_info(msg):
        print(msg)

    def log_err(msg):
        print('ERROR: %s' % msg, file=sys.stderr)

    if len(sys.argv) != 3:
        print('Usage: %s <name> <rr_type>' % sys.argv[0])
        sys.exit(2)

    name = sys.argv[1]
    type_str = sys.argv[2]

    try:
        type_ = dns.rdatatype.from_text(type_str)
    except dns.rdatatype.UnknownRdatatype:
        log_err('Unsupported DNS record type "%s"' % type_str)
        sys.exit(2)

    if dns.rdatatype.is_metatype(type_):
        log_err('Meta record type "%s" cannot be resolved via Avahi' % type_str)
        sys.exit(2)

    init()
    try:
        recs = resolve(name, type_, getone=MDNS_GETONE, timeout=MDNS_TIMEOUT)
        if not len(recs):
            print('%s not found (NXDOMAIN)' % name)
            sys.exit(1)

        for r in recs:
            print(rr2text(r, MDNS_TTL))
    finally:
        deinit()
calc.py000064400000006426151702565550006043 0ustar00# -*- coding: utf-8 -*-
'''
 calc.py: DNS-based calculator 

 Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
 
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
 
    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''

#Try: dig @localhost 1*25._calc_.cz.

def init(id, cfg): return True
def deinit(id): return True
def inform_super(id, qstate, superqstate, qdata): return True

def operate(id, event, qstate, qdata):

    if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):

        if qstate.qinfo.qname_str.endswith("._calc_.cz.") and not ("__" in qstate.qinfo.qname_str):
            try:
                # the second and third argument to eval attempt to restrict
                # functions and variables available to stop code execution
                # but it may not be safe either.  This is why __ substrings
                # are excluded from evaluation.
                res = eval(''.join(qstate.qinfo.qname_list[0:-3]),{"__builtins__":None},{})
            except:
                res = "exception"

            msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_QR | PKT_RA | PKT_AA) #, 300)
            msg.answer.append("%s 300 IN TXT \"%s\"" % (qstate.qinfo.qname_str,res))
            if not msg.set_return_msg(qstate):
               qstate.ext_state[id] = MODULE_ERROR 
               return True

            qstate.return_rcode = RCODE_NOERROR
            qstate.ext_state[id] = MODULE_FINISHED 
            return True

        else: 
            #Pass on the unknown query to the iterator
            qstate.ext_state[id] = MODULE_WAIT_MODULE 
            return True

    elif event == MODULE_EVENT_MODDONE: 
        #the iterator has finished
        qstate.ext_state[id] = MODULE_FINISHED
        return True

    log_err("pythonmod: Unknown event")
    qstate.ext_state[id] = MODULE_ERROR
    return True

dict.py000064400000010207151702565550006054 0ustar00# -*- coding: utf-8 -*-
'''
 calc.py: DNS-based czech-english dictionary

 Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
 
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
 
    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
import os
cz_dict = {}
en_dict = {}

def init(id, cfg):
   log_info("pythonmod: dict init")
   f = open("examples/dict_data.txt", "r")
   try:
      for line in f:
         if line.startswith('#'):
            continue
         itm = line.split("\t", 3)
         if len(itm) < 2: 
            continue
         en,cs = itm[0:2]

         if not (cs in cz_dict):
            cz_dict[cs] = [en]     # [cs] = en
         else:
            cz_dict[cs].append(en) # [cs] = en

         if not (en in en_dict):
            en_dict[en] = [cs]     # [en] = cs
         else:
            en_dict[en].append(cs) # [en] = cs

   finally:
      f.close()
   return True

def deinit(id):
   log_info("pythonmod: dict deinit")
   return True

def operate(id, event, qstate, qdata):
    if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):

       if qstate.qinfo.qname_str.endswith("._dict_.cz."):
        
         aword = ' '.join(qstate.qinfo.qname_list[0:-4])
         adict = qstate.qinfo.qname_list[-4]

         log_info("pythonmod: dictionary look up; word:%s dict:%s" % (aword,adict))

         words = []
         if (adict == "en") and (aword in en_dict):
            words = en_dict[aword] # EN -> CS
         if (adict == "cs") and (aword in cz_dict):
            words = cz_dict[aword] # CS -> EN

         if len(words) and ((qstate.qinfo.qtype == RR_TYPE_TXT) or (qstate.qinfo.qtype == RR_TYPE_ANY)):

            msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_RD | PKT_RA | PKT_AA)
            for w in words:
                msg.answer.append("%s 300 IN TXT \"%s\"" % (qstate.qinfo.qname_str,w.replace("\"","\\\"")))

            if not msg.set_return_msg(qstate):
               qstate.ext_state[id] = MODULE_ERROR 
               return True

            qstate.return_rcode = RCODE_NOERROR
            qstate.ext_state[id] = MODULE_FINISHED 
            return True

         else:
            qstate.return_rcode = RCODE_SERVFAIL
            qstate.ext_state[id] = MODULE_FINISHED 
            return True

       else: #Pass on the unknown query to the iterator
         qstate.ext_state[id] = MODULE_WAIT_MODULE 
         return True

    elif event == MODULE_EVENT_MODDONE: #the iterator has finished
         #we don't need modify result
         qstate.ext_state[id] = MODULE_FINISHED
         return True

    log_err("pythonmod: Unknown event")
    qstate.ext_state[id] = MODULE_ERROR
    return True

def inform_super(id, qstate, superqstate, qdata):
   return True

dict_data.txt000064400000000243151702565550007233 0ustar00*	*			web
computer	po��ta�ov�	adj:		Zden�k Bro�
computer	po��ta�	n:		
domain	dom�na	n:		Zden�k Bro�
query	otazn�k	n:		Zden�k Bro�
network	s�	n: [it.]	po��ta�ov�	
dns-lookup.py000064400000003517151702565550007232 0ustar00#!/usr/bin/python
'''
 dns-lookup.py : This example shows how to resolve IP address

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import unbound

ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")

status, result = ctx.resolve("www.nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:", sorted(result.data.address_list))
elif status != 0:
    print("Error:", unbound.ub_strerror(status))
dnssec-valid.py000064400000004121151702565550007503 0ustar00#!/usr/bin/python
'''
 dnssec-valid.py:  DNSSEC validation

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import os
from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN

ctx = ub_ctx()
ctx.resolvconf("/etc/resolv.conf")

fw = open("dnssec-valid.txt","wb")
ctx.debugout(fw)
ctx.debuglevel(2)

if os.path.isfile("keys"):
    ctx.add_ta_file("keys") #read public keys for DNSSEC verification

status, result = ctx.resolve("www.nic.cz", RR_TYPE_A, RR_CLASS_IN)
if status == 0 and result.havedata:

    print("Result:", sorted(result.data.address_list))

    if result.secure:
        print("Result is secure")
    elif result.bogus:
        print("Result is bogus")
    else:
        print("Result is insecure")

dnssec_test.py000064400000002560151702565550007452 0ustar00#!/usr/bin/env python
from __future__ import print_function
from unbound import ub_ctx, RR_TYPE_A, RR_TYPE_RRSIG, RR_TYPE_NSEC, RR_TYPE_NSEC3
import ldns

def dnssecParse(domain, rrType=RR_TYPE_A):
    print("Resolving domain", domain)
    s, r = resolver.resolve(domain)
    print("status: %s, secure: %s, rcode: %s, havedata: %s, answer_len; %s" % (s, r.secure, r.rcode_str, r.havedata, r.answer_len))
    
    s, pkt = ldns.ldns_wire2pkt(r.packet)
    if s != 0:
        raise RuntimeError("Error parsing DNS packet")

    rrsigs = pkt.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_ANSWER)
    print("RRSIGs from answer:", sorted(rrsigs))
    
    rrsigs = pkt.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_AUTHORITY)
    print("RRSIGs from authority:", sorted(rrsigs))
    
    nsecs = pkt.rr_list_by_type(RR_TYPE_NSEC, ldns.LDNS_SECTION_AUTHORITY)
    print("NSECs:", sorted(nsecs))
    
    nsec3s = pkt.rr_list_by_type(RR_TYPE_NSEC3, ldns.LDNS_SECTION_AUTHORITY)
    print("NSEC3s:", sorted(nsec3s))
    
    print("---")


resolver = ub_ctx()
resolver.add_ta(".   IN DS   19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5")
resolver.add_ta(".   IN DS   20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D")

dnssecParse("nic.cz")
dnssecParse("nonexistent-domain-blablabla.cz")
dnssecParse("nonexistent-domain-blablabla.root.cz")

edns.py000064400000021220151702565550006057 0ustar00# -*- coding: utf-8 -*-
'''
 edns.py: python module showcasing EDNS option functionality.

 Copyright (c) 2016, NLnet Labs.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
 
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
 
    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
#Try:
# - dig @localhost nlnetlabs.nl +ednsopt=65001:c001
#       This query will always reach the modules stage as EDNS option 65001 is
#       registered to bypass the cache response stage. It will also be handled
#       as a unique query because of the no_aggregation flag. This means that
#       it will not be aggregated with other queries for the same qinfo.
#       For demonstration purposes when option 65001 with hexdata 'c001' is
#       sent from the client side this module will reply with the same code and
#       data 'deadbeef'.

# Useful functions:
#   edns_opt_list_is_empty(edns_opt_list):
#       Check if the option list is empty.
#       Return True if empty, False otherwise.
#
#   edns_opt_list_append(edns_opt_list, code, data_bytearray, region): 
#       Append the EDNS option with code and data_bytearray to the given
#           edns_opt_list.
#       NOTE: data_bytearray MUST be a Python bytearray.
#       Return True on success, False on failure.
#
#   edns_opt_list_remove(edns_opt_list, code):
#       Remove all occurrences of the given EDNS option code from the
#           edns_opt_list.
#       Return True when at least one EDNS option was removed, False otherwise.
#
#   register_edns_option(env, code, bypass_cache_stage=True,
#                        no_aggregation=True):
#       Register EDNS option code as a known EDNS option.
#       bypass_cache_stage:
#           bypasses answering from cache and allows the query to reach the
#           modules for further EDNS handling.
#       no_aggregation:
#           makes every query with the said EDNS option code unique.
#       Return True on success, False on failure.
#
# Examples on how to use the functions are given in this file.


def init_standard(id, env):
    """New version of the init function.
    The function's signature is the same as the C counterpart and allows for
    extra functionality during init.
    ..note:: This function is preferred by unbound over the old init function.
    ..note:: The previously accessible configuration options can now be found in
             env.cfg.
    """
    log_info("python: inited script {}".format(env.cfg.python_script))

    # Register EDNS option 65001 as a known EDNS option.
    if not register_edns_option(env, 65001, bypass_cache_stage=True,
                                no_aggregation=True):
        return False

    return True


def init(id, cfg):
    """Previous version init function.
    ..note:: This function is still supported for backwards compatibility when
             the init_standard function is missing. When init_standard is
             present this function SHOULD be omitted to avoid confusion to the
             reader.
    """
    return True


def deinit(id): return True


def inform_super(id, qstate, superqstate, qdata): return True


def operate(id, event, qstate, qdata):
    if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
        # Detect if EDNS option code 56001 is present from the client side. If
        # so turn on the flags for cache management.
        if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
            log_info("python: searching for EDNS option code 65001 during NEW "
                     "or PASS event ")
            for o in qstate.edns_opts_front_in_iter:
                if o.code == 65001:
                    log_info("python: found EDNS option code 65001")
                    # Instruct other modules to not lookup for an
                    # answer in the cache.
                    qstate.no_cache_lookup = 1
                    log_info("python: enabled no_cache_lookup")

                    # Instruct other modules to not store the answer in
                    # the cache.
                    qstate.no_cache_store = 1
                    log_info("python: enabled no_cache_store")

        #Pass on the query
        qstate.ext_state[id] = MODULE_WAIT_MODULE 
        return True

    elif event == MODULE_EVENT_MODDONE:
        # If the client sent EDNS option code 65001 and data 'c001' reply
        # with the same code and data 'deadbeef'.
        if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
            log_info("python: searching for EDNS option code 65001 during "
                     "MODDONE")
            for o in qstate.edns_opts_front_in_iter:
                if o.code == 65001 and o.data == bytearray.fromhex("c001"):
                    b = bytearray.fromhex("deadbeef")
                    if not edns_opt_list_append(qstate.edns_opts_front_out,
                                           o.code, b, qstate.region):
                        qstate.ext_state[id] = MODULE_ERROR
                        return False

        # List every EDNS option in all lists.
        # The available lists are:
        #   - qstate.edns_opts_front_in:  EDNS options that came from the
        #                                 client side. SHOULD NOT be changed;
        #
        #   - qstate.edns_opts_back_out:  EDNS options that will be sent to the
        #                                 server side. Can be populated by
        #                                 EDNS literate modules;
        #
        #   - qstate.edns_opts_back_in:   EDNS options that came from the
        #                                 server side. SHOULD NOT be changed;
        #
        #   - qstate.edns_opts_front_out: EDNS options that will be sent to the
        #                                 client side. Can be populated by
        #                                 EDNS literate modules;
        #
        # The lists' contents can be accessed in python by their _iter
        # counterpart as an iterator.
        if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
            log_info("python: EDNS options in edns_opts_front_in:")
            for o in qstate.edns_opts_front_in_iter:
                log_info("python:    Code: {}, Data: '{}'".format(o.code,
                                "".join('{:02x}'.format(x) for x in o.data)))

        if not edns_opt_list_is_empty(qstate.edns_opts_back_out):
            log_info("python: EDNS options in edns_opts_back_out:")
            for o in qstate.edns_opts_back_out_iter:
                log_info("python:    Code: {}, Data: '{}'".format(o.code,
                                "".join('{:02x}'.format(x) for x in o.data)))

        if not edns_opt_list_is_empty(qstate.edns_opts_back_in):
            log_info("python: EDNS options in edns_opts_back_in:")
            for o in qstate.edns_opts_back_in_iter:
                log_info("python:    Code: {}, Data: '{}'".format(o.code,
                                "".join('{:02x}'.format(x) for x in o.data)))

        if not edns_opt_list_is_empty(qstate.edns_opts_front_out):
            log_info("python: EDNS options in edns_opts_front_out:")
            for o in qstate.edns_opts_front_out_iter:
                log_info("python:    Code: {}, Data: '{}'".format(o.code,
                                "".join('{:02x}'.format(x) for x in o.data)))

        qstate.ext_state[id] = MODULE_FINISHED
        return True

    log_err("pythonmod: Unknown event")
    qstate.ext_state[id] = MODULE_ERROR
    return True
example8-1.py000064400000004631151702565550007016 0ustar00#!/usr/bin/python
# vim:fileencoding=utf-8
'''
 example8-1.py: Example shows how to lookup for MX and NS records

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import unbound

ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")

status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.mx_list):
        print("      priority:%d address:%s" % k)

status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.address_list):
        print("      address:%s" % k)

status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_NS, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.domain_list):
        print("      host: %s" % k)

idn-lookup.py000064400000005145151702565550007217 0ustar00#!/usr/bin/python
# vim:fileencoding=utf-8
'''
 idn-lookup.py: IDN (Internationalized Domain Name) lookup support 

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import unbound
import locale

ctx = unbound.ub_ctx()
ctx.set_option("module-config:","iterator") #We don't need validation
ctx.resolvconf("/etc/resolv.conf")

#The unicode IDN string is automatically converted (if necessary)
status, result = ctx.resolve(u"www.háčkyčárky.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.address_list):
        print("      address:%s" % k)

status, result = ctx.resolve(u"háčkyčárky.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.mx_list_idn):
        print("      priority:%d address:%s" % k)

status, result = ctx.resolve(unbound.reverse('217.31.204.66')+'.in-addr.arpa', unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result.data:", result.data)
    for k in sorted(result.data.domain_list_idn):
        print("      dname:%s" % k)
inplace_callbacks.py000064400000031567151702565550010557 0ustar00# -*- coding: utf-8 -*-
'''
 inplace_callbacks.py: python module showcasing inplace callback function
                       registration and functionality.

 Copyright (c) 2016, NLnet Labs.

 This software is open source.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
#Try:
# - dig @localhost nlnetlabs.nl +ednsopt=65002:
#       This query *could* be answered from cache. If so, unbound will reply
#       with the same EDNS option 65002, but with hexdata 'deadbeef' as data.
#
# - dig @localhost bogus.nlnetlabs.nl txt:
#       This query returns SERVFAIL as the txt record of bogus.nlnetlabs.nl is
#       intentionally bogus. The reply will contain an empty EDNS option
#       with option code 65003.
#       Unbound will also log the source address of the client that made
#       the request.
#       (unbound needs to be validating for this example to work)

# Useful functions:
#   register_inplace_cb_reply(inplace_reply_callback, env, id):
#       Register the reply_callback function as an inplace callback function
#       when answering with a resolved query.
#       Return True on success, False on failure.
#
#   register_inplace_cb_reply_cache(inplace_reply_cache_callback, env, id):
#       Register the reply_cache_callback function as an inplace callback
#       function when answering from cache.
#       Return True on success, False on failure.
#
#   register_inplace_cb_reply_local(inplace_reply_local_callback, env, id):
#       Register the reply_local_callback function as an inplace callback
#       function when answering from local data or chaos reply.
#       Return True on success, False on failure.
#
#   register_inplace_cb_reply_servfail(inplace_reply_servfail_callback, env, id):
#       Register the reply_servfail_callback function as an inplace callback
#       function when answering with servfail.
#       Return True on success, False on failure.
#
# Examples on how to use the functions are given in this file.


def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
                           region, **kwargs):
    """
    Function that will be registered as an inplace callback function.
    It will be called when answering with a resolved query.

    :param qinfo: query_info struct;
    :param qstate: module qstate. It contains the available opt_lists; It
                   SHOULD NOT be altered;
    :param rep: reply_info struct;
    :param rcode: return code for the query;
    :param edns: edns_data to be sent to the client side. It SHOULD NOT be
                 altered;
    :param opt_list_out: the list with the EDNS options that will be sent as a
                         reply. It can be populated with EDNS options;
    :param region: region to allocate temporary data. Needs to be used when we
                   want to append a new option to opt_list_out.
    :param **kwargs: Dictionary that may contain parameters added in a future
                     release. Current parameters:
        ``repinfo``: Reply information for a communication point (comm_reply).

    :return: True on success, False on failure.

    """
    log_info("python: called back while replying.")
    return True


def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
                           region, **kwargs):
    """
    Function that will be registered as an inplace callback function.
    It will be called when answering from the cache.

    :param qinfo: query_info struct;
    :param qstate: module qstate. None;
    :param rep: reply_info struct;
    :param rcode: return code for the query;
    :param edns: edns_data sent from the client side. The list with the EDNS
                 options is accessible through edns.opt_list. It SHOULD NOT be
                 altered;
    :param opt_list_out: the list with the EDNS options that will be sent as a
                         reply. It can be populated with EDNS options;
    :param region: region to allocate temporary data. Needs to be used when we
                   want to append a new option to opt_list_out.
    :param **kwargs: Dictionary that may contain parameters added in a future
                     release. Current parameters:
        ``repinfo``: Reply information for a communication point (comm_reply).

    :return: True on success, False on failure.

    For demonstration purposes we want to see if EDNS option 65002 is present
    and reply with a new value.

    """
    log_info("python: called back while answering from cache.")
    # Inspect the incoming EDNS options.
    if not edns_opt_list_is_empty(edns.opt_list):
        log_info("python: available EDNS options:")
        for o in edns.opt_list_iter:
            log_info("python:    Code: {}, Data: '{}'".format(o.code,
                "".join('{:02x}'.format(x) for x in o.data)))
            if o.code == 65002:
                log_info("python: *found option code 65002*")

                # add to opt_list
                # Data MUST be represented in a bytearray.
                b = bytearray.fromhex("deadbeef")
                if edns_opt_list_append(opt_list_out, o.code, b, region):
                    log_info("python: *added new option code 65002*")
                else:
                    log_info("python: *failed to add new option code 65002*")
                    return False
                break

    return True


def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
                           region, **kwargs):
    """
    Function that will be registered as an inplace callback function.
    It will be called when answering from local data.

    :param qinfo: query_info struct;
    :param qstate: module qstate. None;
    :param rep: reply_info struct;
    :param rcode: return code for the query;
    :param edns: edns_data sent from the client side. The list with the
                 EDNS options is accessible through edns.opt_list. It
                 SHOULD NOT be altered;
    :param opt_list_out: the list with the EDNS options that will be sent as a
                         reply. It can be populated with EDNS options;
    :param region: region to allocate temporary data. Needs to be used when we
                   want to append a new option to opt_list_out.
    :param **kwargs: Dictionary that may contain parameters added in a future
                     release. Current parameters:
        ``repinfo``: Reply information for a communication point (comm_reply).

    :return: True on success, False on failure.

    """
    log_info("python: called back while replying with local data or chaos"
             " reply.")
    return True


def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
                              region, **kwargs):
    """
    Function that will be registered as an inplace callback function.
    It will be called when answering with SERVFAIL.

    :param qinfo: query_info struct;
    :param qstate: module qstate. If not None the relevant opt_lists are
                   available here;
    :param rep: reply_info struct. None;
    :param rcode: return code for the query. LDNS_RCODE_SERVFAIL;
    :param edns: edns_data to be sent to the client side. If qstate is None
                 edns.opt_list contains the EDNS options sent from the client
                 side. It SHOULD NOT be altered;
    :param opt_list_out: the list with the EDNS options that will be sent as a
                         reply. It can be populated with EDNS options;
    :param region: region to allocate temporary data. Needs to be used when we
                   want to append a new option to opt_list_out.
    :param **kwargs: Dictionary that may contain parameters added in a future
                     release. Current parameters:
        ``repinfo``: Reply information for a communication point (comm_reply).

    :return: True on success, False on failure.

    For demonstration purposes we want to reply with an empty EDNS code '65003'
    and log the IP address of the client.

    """
    log_info("python: called back while servfail.")
    # Append the example EDNS option
    b = bytearray.fromhex("")
    edns_opt_list_append(opt_list_out, 65003, b, region)

    # Log the client's IP address
    comm_reply = kwargs['repinfo']
    if comm_reply:
        addr = comm_reply.addr
        port = comm_reply.port
        addr_family = comm_reply.family
        log_info("python: Client IP: {}({}), port: {}"
                 "".format(addr, addr_family, port))

    return True


def inplace_query_callback(qinfo, flags, qstate, addr, zone, region, **kwargs):
    """
    Function that will be registered as an inplace callback function.
    It will be called before sending a query to a backend server.

    :param qinfo: query_info struct;
    :param flags: flags of the query;
    :param qstate: module qstate. opt_lists are available here;
    :param addr: struct sockaddr_storage. Address of the backend server;
    :param zone: zone name in binary;
    :param region: region to allocate temporary data. Needs to be used when we
                   want to append a new option to opt_lists.
    :param **kwargs: Dictionary that may contain parameters added in a future
                     release.
    """
    log_info("python: outgoing query to {}@{}".format(addr.addr, addr.port))
    return True


def init_standard(id, env):
    """
    New version of the init function.

    The function's signature is the same as the C counterpart and allows for
    extra functionality during init.

    ..note:: This function is preferred by unbound over the old init function.
    ..note:: The previously accessible configuration options can now be found in
             env.cfg.

    """
    log_info("python: inited script {}".format(env.cfg.python_script))

    # Register the inplace_reply_callback function as an inplace callback
    # function when answering a resolved query.
    if not register_inplace_cb_reply(inplace_reply_callback, env, id):
        return False

    # Register the inplace_cache_callback function as an inplace callback
    # function when answering from cache.
    if not register_inplace_cb_reply_cache(inplace_cache_callback, env, id):
        return False

    # Register the inplace_local_callback function as an inplace callback
    # function when answering from local data.
    if not register_inplace_cb_reply_local(inplace_local_callback, env, id):
        return False

    # Register the inplace_servfail_callback function as an inplace callback
    # function when answering with SERVFAIL.
    if not register_inplace_cb_reply_servfail(inplace_servfail_callback, env, id):
        return False

    # Register the inplace_query_callback function as an inplace callback
    # before sending a query to a backend server.
    if not register_inplace_cb_query(inplace_query_callback, env, id):
        return False

    return True


def init(id, cfg):
    """
    Previous version of the init function.

    ..note:: This function is still supported for backwards compatibility when
             the init_standard function is missing. When init_standard is
             present this function SHOULD be omitted to avoid confusion to the
             reader.

    """
    return True


def deinit(id): return True


def inform_super(id, qstate, superqstate, qdata): return True


def operate(id, event, qstate, qdata):
    if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
        qstate.ext_state[id] = MODULE_WAIT_MODULE 
        return True

    elif event == MODULE_EVENT_MODDONE:
        qstate.ext_state[id] = MODULE_FINISHED
        return True

    log_err("pythonmod: Unknown event")
    qstate.ext_state[id] = MODULE_ERROR
    return True
log.py000064400000010371151702565550005714 0ustar00import os
'''
 calc.py: Response packet logger

 Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
 
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
 
    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''

def dataHex(data, prefix=""):
    """Converts binary string data to display representation form"""
    res = ""
    for i in range(0, (len(data)+15)/16):
        res += "%s0x%02X | " % (prefix, i*16)
        d = map(lambda x:ord(x), data[i*16:i*16+17])
        for ch in d:
            res += "%02X " % ch
        for i in range(0,17-len(d)):
            res += "   "
        res += "| "
        for ch in d:
            if (ch < 32) or (ch > 127):
                res += ". "
            else:
                res += "%c " % ch
        res += "\n"
    return res

def logDnsMsg(qstate):
    """Logs response"""

    r  = qstate.return_msg.rep
    q  = qstate.return_msg.qinfo

    print "-"*100
    print("Query: %s, type: %s (%d), class: %s (%d) " % (
            qstate.qinfo.qname_str, qstate.qinfo.qtype_str, qstate.qinfo.qtype,
            qstate.qinfo.qclass_str, qstate.qinfo.qclass))
    print "-"*100
    print "Return    reply :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (r.flags, r.qdcount, r.security, r.ttl)
    print "          qinfo :: qname: %s %s, qtype: %s, qclass: %s" % (str(q.qname_list), q.qname_str, q.qtype_str, q.qclass_str)

    if (r):
        print "Reply:"
        for i in range(0, r.rrset_count):
            rr = r.rrsets[i]

            rk = rr.rk
            print i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags,
            print "type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class)

            d = rr.entry.data
            for j in range(0,d.count+d.rrsig_count):
                print "  ",j,":","TTL=",d.rr_ttl[j],
                if (j >= d.count): print "rrsig",
                print 
                print dataHex(d.rr_data[j],"       ")

    print "-"*100

def init(id, cfg):
   log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
   return True

def deinit(id):
   log_info("pythonmod: deinit called, module id is %d" % id)
   return True

def inform_super(id, qstate, superqstate, qdata):
   return True

def operate(id, event, qstate, qdata):
   log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
  
   if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
      #Pass on the new event to the iterator
      qstate.ext_state[id] = MODULE_WAIT_MODULE 
      return True

   if event == MODULE_EVENT_MODDONE:
      #Iterator finished, show response (if any)

      if (qstate.return_msg):
          logDnsMsg(qstate)

      qstate.ext_state[id] = MODULE_FINISHED 
      return True

   qstate.ext_state[id] = MODULE_ERROR
   return True

mx-lookup.py000064400000004165151702565550007072 0ustar00#!/usr/bin/python
# vim:fileencoding=utf-8
'''
 mx-lookup.py: Lookup for MX records

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import unbound

ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")

status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.mx_list):
        print("      priority:%d address:%s" % k)

status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.address_list):
        print("      address:%s" % k)
ns-lookup.py000064400000003574151702565550007071 0ustar00#!/usr/bin/python
# vim:fileencoding=utf-8
'''
 ns-lookup.py: Example shows how to lookup for NS records 

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import unbound

ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")

status, result = ctx.resolve("vutbr.cz", unbound.RR_TYPE_NS, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result:")
    print("      raw data:", result.data)
    for k in sorted(result.data.domain_list):
        print("      host: %s" % k)

resgen.py000064400000006177151702565550006427 0ustar00'''
 resgen.py: This example shows how to generate authoritative response

 Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
 
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
 
    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
def init(id, cfg): return True

def deinit(id): return True

def inform_super(id, qstate, superqstate, qdata): return True

def operate(id, event, qstate, qdata):
    if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
        if (qstate.qinfo.qname_str.endswith(".localdomain.")): #query name ends with localdomain
            #create instance of DNS message (packet) with given parameters
            msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_A, RR_CLASS_IN, PKT_QR | PKT_RA | PKT_AA)
            #append RR
            if (qstate.qinfo.qtype == RR_TYPE_A) or (qstate.qinfo.qtype == RR_TYPE_ANY):
                msg.answer.append("%s 10 IN A 127.0.0.1" % qstate.qinfo.qname_str)
            #set qstate.return_msg 
            if not msg.set_return_msg(qstate):
                qstate.ext_state[id] = MODULE_ERROR 
                return True

            #we don't need validation, result is valid
            qstate.return_msg.rep.security = 2

            qstate.return_rcode = RCODE_NOERROR
            qstate.ext_state[id] = MODULE_FINISHED 
            return True
        else:
            #pass the query to validator
            qstate.ext_state[id] = MODULE_WAIT_MODULE 
            return True

    if event == MODULE_EVENT_MODDONE:
        log_info("pythonmod: iterator module done")
        qstate.ext_state[id] = MODULE_FINISHED 
        return True
      
    log_err("pythonmod: bad event")
    qstate.ext_state[id] = MODULE_ERROR
    return True
resip.py000064400000007711151702565550006261 0ustar00'''
 resip.py: This example shows how to generate authoritative response
           and how to find out the IP address of a client

 Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
 
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
 
    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.


 Usage:

   dig @127.0.0.1 -t TXT what.is.my.ip.
'''

def init(id, cfg): return True

def deinit(id): return True

def inform_super(id, qstate, superqstate, qdata): return True

def operate(id, event, qstate, qdata):
    print("Operate {} state: {}".format(event, qstate))

    # Please note that if this module blocks, by moving to the validator
    # to validate or iterator to lookup or spawn a subquery to look up,
    # then, other incoming queries are queued up onto this module and
    # all of them receive the same reply.
    # You can inspect the cache.

    if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
        if (qstate.qinfo.qname_str.endswith("what.is.my.ip.")): #query name ends with localdomain
            #create instance of DNS message (packet) with given parameters
            msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_QR | PKT_RA | PKT_AA)
            #append RR
            if (qstate.qinfo.qtype == RR_TYPE_TXT) or (qstate.qinfo.qtype == RR_TYPE_ANY):
                rl = qstate.mesh_info.reply_list
                while (rl):
                    if rl.query_reply:
                        q = rl.query_reply
                        # The TTL of 0 is mandatory, otherwise it ends up in
                        # the cache, and is returned to other IP addresses.
                        msg.answer.append("%s 0 IN TXT \"%s %d (%s)\"" % (qstate.qinfo.qname_str, q.addr,q.port,q.family))
                    rl = rl.next

            #set qstate.return_msg 
            if not msg.set_return_msg(qstate):
                qstate.ext_state[id] = MODULE_ERROR 
                return True

            #we don't need validation, result is valid
            qstate.return_msg.rep.security = 2

            qstate.return_rcode = RCODE_NOERROR
            qstate.ext_state[id] = MODULE_FINISHED 
            return True
        else:
            #pass the query to validator
            qstate.ext_state[id] = MODULE_WAIT_MODULE 
            return True

    if event == MODULE_EVENT_MODDONE:
        log_info("pythonmod: iterator module done")
        qstate.ext_state[id] = MODULE_FINISHED 
        return True

    log_err("pythonmod: bad event")
    qstate.ext_state[id] = MODULE_ERROR
    return True
resmod.py000064400000006677151702565550006442 0ustar00'''
 resmod.py: This example shows how to modify the response from iterator 

 Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
 
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
 
    * Neither the name of the organization nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''

def init(id, cfg): return True

def deinit(id): return True

def inform_super(id, qstate, superqstate, qdata): return True

def setTTL(qstate, ttl):
    """Updates return_msg TTL and the TTL of all the RRs"""
    if qstate.return_msg:
        qstate.return_msg.rep.ttl = ttl
        if (qstate.return_msg.rep):
            for i in range(0,qstate.return_msg.rep.rrset_count):
                d = qstate.return_msg.rep.rrsets[i].entry.data
                for j in range(0,d.count+d.rrsig_count):
                    d.rr_ttl[j] = ttl

def operate(id, event, qstate, qdata):
    if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
        #pass the query to validator
        qstate.ext_state[id] = MODULE_WAIT_MODULE 
        return True

    if event == MODULE_EVENT_MODDONE:
        log_info("pythonmod: iterator module done")

        if not qstate.return_msg:
            qstate.ext_state[id] = MODULE_FINISHED 
            return True

        #modify the response

        qdn = qstate.qinfo.qname_str
        if qdn.endswith(".nic.cz."):
            #invalidate response in cache added by iterator
            #invalidateQueryInCache(qstate, qstate.return_msg.qinfo)

            #modify TTL to 10 secs and store response in cache
            #setTTL(qstate, 5)
            #if not storeQueryInCache(qstate, qstate.return_msg.qinfo, qstate.return_msg.rep, 0):
            #    qstate.ext_state[id] = MODULE_ERROR
            #    return False

            #modify TTL of response, which will be send to a) validator and then b) client
            setTTL(qstate, 10)
            qstate.return_rcode = RCODE_NOERROR

        qstate.ext_state[id] = MODULE_FINISHED 
        return True
      
    log_err("pythonmod: bad event")
    qstate.ext_state[id] = MODULE_ERROR
    return True
reverse-lookup.py000064400000003512151702565550010114 0ustar00#!/usr/bin/python
'''
 reverse-lookup.py: Example shows how to resolve reverse record 

 Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
          Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)

 Copyright (c) 2008. All rights reserved.

 This software is open source.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
'''
from __future__ import print_function
import unbound

ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")

status, result = ctx.resolve(unbound.reverse("74.125.43.147") + ".in-addr.arpa.", unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
    print("Result.data:", result.data, sorted(result.data.domain_list))