[hipl-dev] [Branch ~hipl-core/hipl/trunk] Rev 6381: Merge lp:~ptman/hipl/tests.

  • From: noreply@xxxxxxxxxxxxx
  • To: HIPL core team <hipl-dev@xxxxxxxxxxxxx>
  • Date: Sat, 28 Apr 2012 17:36:12 -0000

Merge authors:
  Paul Tötterman (ptman)
Related merge proposals:
  https://code.launchpad.net/~ptman/hipl/tests/+merge/103985
  proposed by: Paul Tötterman (ptman)
  review: Approve - Miika Komu (miika-iki)
------------------------------------------------------------
revno: 6381 [merge]
committer: Paul Tötterman <paul.totterman@xxxxxx>
branch nick: trunk
timestamp: Sat 2012-04-28 20:32:20 +0300
message:
  Merge lp:~ptman/hipl/tests.
  
  Modularize hipdnsproxy to ease testing.
  Remove dead code with unreliable test.
  Replace getopt with optparse. (and remove unused options)
  Replace homegrown Logger with stdlib module logging.
added:
  tools/hipdnsproxy/dnsproxy.py
modified:
  Makefile.am
  tools/hipdnsproxy/hipdnsproxy.in
  tools/hipdnsproxy/util.py


--
lp:hipl
https://code.launchpad.net/~hipl-core/hipl/trunk

Your team HIPL core team is subscribed to branch lp:hipl.
To unsubscribe from this branch go to 
https://code.launchpad.net/~hipl-core/hipl/trunk/+edit-subscription
=== modified file 'Makefile.am'
--- Makefile.am 2012-04-27 21:01:44 +0000
+++ Makefile.am 2012-04-28 15:51:10 +0000
@@ -272,7 +272,8 @@
 
 tools_hipdnskeyparse_PYTHON = tools/hipdnskeyparse/myasn.py
 
-tools_hipdnsproxy_PYTHON = tools/hipdnsproxy/hosts.py                   \
+tools_hipdnsproxy_PYTHON = tools/hipdnsproxy/dnsproxy.py                \
+                           tools/hipdnsproxy/hosts.py                   \
                            tools/hipdnsproxy/util.py
 
 tools_hipdnskeyparsedir = $(pythondir)/hipdnskeyparse

=== added file 'tools/hipdnsproxy/dnsproxy.py'
--- tools/hipdnsproxy/dnsproxy.py       1970-01-01 00:00:00 +0000
+++ tools/hipdnsproxy/dnsproxy.py       2012-04-28 15:58:42 +0000
@@ -0,0 +1,1024 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Aalto University and RWTH Aachen University.
+#
+# 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.
+
+"""HIP name look-up daemon for HIPL hosts file and DNS servers."""
+
+# Usage: Basic usage without any command line options.
+#        See getopt() for the options.
+#
+# Working test cases with hipdnsproxy
+# - Interoperates with libc and dnsmasq
+# - Resolvconf(on/off) + dnsmasq (on/off)
+#    - initial look up (check HIP and non-hip look up)
+#      - check that ctrl+c restores /etc/resolv.conf
+#    - change access network (check HIP and non-hip look up)
+#      - check that ctrl+c restores /etc/resolv.conf
+# - Watch out for cached entries! Restart dnmasq and hipdnsproxy after
+#   each test.
+# - Test name resolution with following methods:
+#   - Non-HIP records
+#   - Hostname to HIT resolution
+#     - HITs and LSIs from /etc/hip/hosts
+#     - On-the-fly generated LSI; HIT either from from DNS or hosts
+#     - HI records from DNS
+#   - PTR records: maps HITs to hostnames from /etc/hip/hosts
+#
+# Actions to resolv.conf files and dnsproxy hooking:
+# - Dnsmasq=on, revolvconf=on: only hooks dnsmasq
+# - Dnsmasq=off, revolvconf=on: rewrites /etc/resolvconf/run/resolv.conf
+# - Dnsmasq=on, revolvconf=off: hooks dnsmasq and rewrites /etc/resolv.conf
+# - Dnsmasq=off, revolvconf=off: rewrites /etc/resolv.conf
+#
+# TBD:
+# - rewrite the code to more object oriented
+# - the use of alternative (multiple) dns servers
+# - implement TTLs for cache
+#   - applicable to HITs, LSIs and IP addresses
+#   - host files: forever (purged when the file is changed)
+#   - dns records: follow DNS TTL
+# - bind to ::1, not 127.0.0.1 (setsockopt blah blah)
+# - remove hardcoded addresses from ifconfig commands
+# - compatibility with "unbound"
+
+import copy
+import errno
+import fileinput
+import logging
+import logging.handlers
+import os
+import re
+import select
+import signal
+import socket
+import subprocess
+import sys
+import time
+
+#local imports
+
+# prepending (instead of appending) to make sure hosts.py does not
+# collide with the system default
+import hosts
+import util
+from DNS import Serialize, DeSerialize
+
+
+DEFAULT_HOSTS = '/etc/hosts'
+LSI_RE = re.compile(r'(?P<lsi>1\.\d+\.\d+\.\d+)')
+
+
+def usage(unused_utyp, *msg):
+    """Print usage instructions and exit."""
+    sys.stderr.write('Usage: %s\n' % os.path.split(sys.argv[0])[1])
+    if msg:
+        sys.stderr.write('Error: %r\n' % msg)
+    sys.exit(1)
+
+
+# Done: forking affects this. Fixed in forkme
+MYID = '%d-%d' % (time.time(), os.getpid())
+
+
+def add_hit_ip_map(hit, addr):
+    """Add IP for HIT."""
+    logging.info('Associating HIT %s with IP %s', hit, addr)
+    subprocess.check_call(['hipconf', 'daemon', 'add', 'map', hit, addr],
+                          stdout=open(os.devnull, 'w'),
+                          stderr=subprocess.STDOUT)
+
+
+def hit_to_lsi(hit):
+    """Return LSI for HIT if found."""
+    output = subprocess.Popen(['hipconf', 'daemon', 'hit-to-lsi', hit],
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.STDOUT).stdout
+
+    for line in output:
+        match = LSI_RE.search(line)
+        if match:
+            return match.group('lsi')
+
+
+def lsi_to_hit(lsi):
+    """Return HIT for LSI if found."""
+    output = subprocess.Popen(['hipconf', 'daemon', 'lsi-to-hit', lsi],
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.STDOUT).stdout
+
+    for line in output:
+        match = hosts.HIT_RE.search(line)
+        if match:
+            return match.group('hit')
+
+
+def is_reverse_hit_query(name):
+    """Check if the query is a reverse query to a HIT.
+
+    >>> is_reverse_hit_query('::1')
+    False
+    >>> is_reverse_hit_query('8.e.b.8.b.3.c.9.1.a.0.c.e.e.2.c.c.e.d.0.9.c.'
+    ...                      '9.a.e.1.0.0.1.0.0.2.hit-to-ip.infrahip.net')
+    True
+    """
+    if (name.endswith('.1.0.0.1.0.0.2.hit-to-ip.infrahip.net') and
+        len(name) == 86):
+        return True
+    return False
+
+
+class ResolvConf:
+    """Handle resolv.conf."""
+    re_nameserver = re.compile(r'nameserver\s+(\S+)$')
+
+    def __init__(self, dnsp, filetowatch=None):
+        self.dnsmasq_initd_script = '/etc/init.d/dnsmasq'
+        if os.path.exists('/etc/redhat-release'):
+            self.distro = 'redhat'
+            self.rh_before = '# See how we were called.'
+            self.rh_inject = '. /etc/sysconfig/dnsmasq # Added by hipdnsproxy'
+        elif os.path.exists('/etc/debian_version'):
+            self.distro = 'debian'
+        else:
+            self.distro = 'unknown'
+
+        if self.distro == 'redhat':
+            self.dnsmasq_defaults = '/etc/sysconfig/dnsmasq'
+            if not os.path.exists(self.dnsmasq_defaults):
+                open(self.dnsmasq_defaults, 'w').close()
+        else:
+            self.dnsmasq_defaults = '/etc/default/dnsmasq'
+
+        self.dnsmasq_defaults_backup = (self.dnsmasq_defaults +
+                                        '.backup.hipdnsproxy')
+
+        if (os.path.isdir('/etc/resolvconf/.') and
+            os.path.exists('/sbin/resolvconf') and
+            os.path.exists('/etc/resolvconf/run/resolv.conf')):
+            self.use_resolvconf = True
+        else:
+            self.use_resolvconf = False
+        self.use_dnsmasq_hook = False
+        self.resolvconfd = None
+        self.dnsmasq_hook = None
+        self.alt_port = None
+
+        self.dnsmasq_resolv = '/var/run/dnsmasq/resolv.conf'
+        self.resolvconf_run = '/etc/resolvconf/run/resolv.conf'
+        if self.use_resolvconf:
+            self.resolvconf_towrite = '/etc/resolvconf/run/resolv.conf'
+        else:
+            self.resolvconf_towrite = '/etc/resolv.conf'
+
+        self.dnsmasq_restart = [self.dnsmasq_initd_script, 'restart']
+        if filetowatch is None:
+            self.filetowatch = self.guess_resolvconf()
+        self.resolvconf_orig = self.filetowatch
+        self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
+        self.resolvconf_bkname = '%s-%s' % (self.resolvconf_towrite, MYID)
+        self.overwrite_resolv_conf = dnsp.overwrite_resolv_conf
+
+    def guess_resolvconf(self):
+        """Guess the location of the correct resolv.conf file."""
+        if self.use_dnsmasq_hook and self.use_resolvconf:
+            return self.dnsmasq_resolv
+        elif self.use_resolvconf:
+            return self.resolvconf_run
+        else:
+            return '/etc/resolv.conf'
+
+    def reread_old_rc(self):
+        """Re-read the old resolv.conf."""
+        self.resolvconfd = {}
+        ifile = open(self.filetowatch)
+        for line in ifile.xreadlines():
+            line = line.strip()
+            if 'nameserver' not in self.resolvconfd:
+                match = self.re_nameserver.match(line)
+                if match:
+                    self.resolvconfd['nameserver'] = match.group(1)
+        return self.resolvconfd
+
+    def set_dnsmasq_hook(self, dnsp):
+        """Set the dnsmasq hook."""
+        self.alt_port = dnsp.bind_alt_port
+        self.use_dnsmasq_hook = True
+        logging.info('Dnsmasq-resolvconf installation detected')
+        if self.distro == 'redhat':
+            self.dnsmasq_hook = ('OPTIONS+="--no-hosts --no-resolv '
+                                 '--cache-size=0 --server=%s#%s"\n' % (
+                                     dnsp.bind_ip, self.alt_port))
+        else:
+            self.dnsmasq_hook = ('DNSMASQ_OPTS="--no-hosts --no-resolv '
+                                 '--cache-size=0 --server=%s#%s"\n' % (
+                                     dnsp.bind_ip, self.alt_port))
+        return
+
+    def old_has_changed(self):
+        """Return true if the old resolv.conf file has changed."""
+        old_rc_mtime = os.stat(self.filetowatch).st_mtime
+        if old_rc_mtime != self.old_rc_mtime:
+            self.reread_old_rc()
+            self.old_rc_mtime = old_rc_mtime
+            return True
+        else:
+            return False
+
+    def save_resolvconf_dnsmasq(self):
+        """Inject the dnsmasq hook and restart dnsmasq if necessary."""
+        if self.use_dnsmasq_hook:
+            if os.path.exists(self.dnsmasq_defaults):
+                ifile = open(self.dnsmasq_defaults, 'r')
+                line = ifile.readline()
+                ifile.close()
+                if (line.find('server=127') != -1 and
+                    line[:line.find('server=')] ==
+                    self.dnsmasq_hook[:self.dnsmasq_hook.find('server=')]):
+                    logging.info('Dnsmasq configuration file seems to be '
+                                 'written by dnsproxy. Zeroing.')
+                    ofile = open(self.dnsmasq_defaults, 'w')
+                    ofile.write('')
+                    ofile.close()
+                os.rename(self.dnsmasq_defaults,
+                          self.dnsmasq_defaults_backup)
+            dmd = open(self.dnsmasq_defaults, 'w')
+            dmd.write(self.dnsmasq_hook)
+            dmd.close()
+            if self.distro == 'redhat':
+                for line in fileinput.input(self.dnsmasq_initd_script,
+                                            inplace=1):
+                    if line.find(self.rh_before) == 0:
+                        print self.rh_inject
+                    print line,
+            subprocess.check_call(self.dnsmasq_restart,
+                                  stdout=open(os.devnull, 'w'),
+                                  stderr=subprocess.STDOUT)
+            logging.info('Hooked with dnsmasq')
+            # Restarting of dnsproxy changes also resolv conf. Reset timer
+            # to make sure that we don't load dnsproxy's IP address. Otherwise
+            # all DNS requests are blocked when running dnsproxy in
+            # combination with dnsmasq.
+            self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
+        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
+            self.overwrite_resolv_conf):
+            os.link(self.resolvconf_towrite, self.resolvconf_bkname)
+        return
+
+    def restore_resolvconf_dnsmasq(self):
+        """Restore old dnsmasq config and restart dnsmasq if necessary."""
+        if self.use_dnsmasq_hook:
+            logging.info('Removing dnsmasq hooks')
+            if os.path.exists(self.dnsmasq_defaults_backup):
+                os.rename(self.dnsmasq_defaults_backup,
+                          self.dnsmasq_defaults)
+            if self.distro == 'redhat':
+                for line in fileinput.input(self.dnsmasq_initd_script,
+                                            inplace=1):
+                    if line.find(self.rh_inject) == -1:
+                        print line,
+            subprocess.check_call(self.dnsmasq_restart,
+                                  stdout=open(os.devnull, 'w'),
+                                  stderr=subprocess.STDOUT)
+        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
+            self.overwrite_resolv_conf):
+            os.rename(self.resolvconf_bkname, self.resolvconf_towrite)
+            logging.info('resolv.conf restored')
+        return
+
+    def write(self, params):
+        """Write resolv.conf."""
+        tmp = '%s.tmp-%s' % (self.resolvconf_towrite, MYID)
+        ofile = open(tmp, 'w')
+        ofile.write('# This is written by hipdnsproxy\n')
+        for key, value in params.iteritems():
+            if type(value) is str:
+                value = (value,)
+            for val in value:
+                ofile.write('%-10s %s\n' % (key, val))
+        ofile.close()
+        os.rename(tmp, self.resolvconf_towrite)
+        self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
+
+    def overwrite_resolvconf(self):
+        """Rewrite the contents of resolv.conf.
+
+        TODO(ptman): would just changing the mtime suffice?
+        """
+        tmp = '%s.tmp-%s' % (self.resolvconf_towrite, MYID)
+        ifile = open(self.resolvconf_towrite, 'r')
+        ofile = open(tmp, 'w')
+        while True:
+            buf = ifile.read(16384)
+            if not buf:
+                break
+            ofile.write(buf)
+        ifile.close()
+        ofile.close()
+        os.rename(tmp, self.resolvconf_towrite)
+        logging.info('Rewrote resolv.conf')
+
+    def start(self):
+        """Perform startup routines."""
+        self.save_resolvconf_dnsmasq()
+        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
+            self.overwrite_resolv_conf):
+            self.overwrite_resolvconf()
+
+    def restart(self):
+        """Perform restart routines."""
+        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
+            self.overwrite_resolv_conf):
+            self.overwrite_resolvconf()
+        self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
+
+    def stop(self):
+        """Perform shutdown routines."""
+        self.restore_resolvconf_dnsmasq()
+        subprocess.check_call(['ifconfig', 'lo:53', 'down'])
+        # Sometimes hipconf processes get stuck, particularly when
+        # hipd is busy or unresponsive. This is a workaround.
+        subprocess.call(['killall', '--quiet', 'hipconf'],
+                        stderr=open(os.devnull, 'w'))
+
+
+class DNSProxy:
+    """HIP DNS proxy main class."""
+    re_nameserver = re.compile(r'nameserver\s+(\S+)$')
+
+    def __init__(self, bind_ip=None, bind_port=None, disable_lsi=False,
+                 dns_timeout=2.0, fork=False, hiphosts=None, hostsnames=None,
+                 overwrite_resolv_conf=True, pidfile=None, prefix=None,
+                 resolv_conf=None, server_ip=None, server_port=None):
+        self.bind_ip = bind_ip
+        self.bind_port = bind_port
+        self.disable_lsi = disable_lsi
+        self.dns_timeout = dns_timeout
+        self.fork = fork
+        self.hiphosts = hiphosts
+        self.hostsnames = hostsnames
+        self.overwrite_resolv_conf = overwrite_resolv_conf
+        self.pidfile = pidfile
+        self.prefix = prefix
+        self.resolv_conf = resolv_conf
+        self.server_ip = server_ip
+        self.server_port = server_port
+
+        if self.hostsnames is None:
+            self.hostsnames = []
+
+        self.bind_alt_port = None
+        self.use_alt_port = False
+        self.app_timeout = 1
+        self.hosts_ttl = 122
+        self.sent_queue = []
+        self.rc1 = None
+        self.resolvconfd = None
+        self.hosts = None
+        # Keyed by ('server_ip',server_port,query_id) tuple
+        self.sent_queue_d = {}
+        # required for ifconfig and hipconf in Fedora
+        # (rpm and "make install" targets)
+        os.environ['PATH'] += ':/sbin:/usr/sbin:/usr/local/sbin'
+
+    def add_query(self, server_ip, server_port, query_id, query):
+        """Add a pending DNS query"""
+        key = (server_ip, server_port, query_id)
+        value = (key, time.time(), query)
+        self.sent_queue.append(value)
+        self.sent_queue_d[key] = value
+
+    def find_query(self, server_ip, server_port, query_id):
+        """Find a pending DNS query"""
+        key = (server_ip, server_port, query_id)
+        query = self.sent_queue_d.get(key)
+        if query:
+            idx = self.sent_queue.index(query)
+            self.sent_queue.pop(idx)
+            del self.sent_queue_d[key]
+            return query[2]
+        return None
+
+    def clean_queries(self):
+        """Clean old unanswered queries"""
+        texp = time.time() - 30
+        while self.sent_queue:
+            if self.sent_queue[0][1] < texp:
+                # TODO(ptman): test that key is used properly in del
+                key = self.sent_queue[0][0]
+                self.sent_queue.pop(0)
+                del self.sent_queue_d[key]
+            else:
+                break
+        return
+
+    def read_resolv_conf(self, cfile=None):
+        """Read resolv.conf."""
+        if cfile is None:
+            cfile = self.resolv_conf
+
+        options = {}
+
+        ifile = open(cfile)
+        for line in ifile.xreadlines():
+            line = line.strip()
+            if 'nameserver' not in options:
+                match = self.re_nameserver.match(line)
+                if match:
+                    options['nameserver'] = match.group(1)
+
+        if self.server_ip is None:
+            nameserver = options.get('nameserver', None)
+            self.server_ip = nameserver
+
+        self.resolvconfd = options
+        return options
+
+    def parameter_defaults(self):
+        """Missing default parameters."""
+        env = os.environ
+        if self.server_ip is None:
+            self.server_ip = env.get('SERVER', None)
+        if self.server_port is None:
+            server_port = env.get('SERVERPORT', None)
+            if server_port is not None:
+                self.server_port = int(server_port)
+        if self.server_port is None:
+            self.server_port = 53
+        if self.bind_ip is None:
+            self.bind_ip = env.get('IP', None)
+        if self.bind_ip is None:
+            self.bind_ip = '127.0.0.53'
+        if self.bind_port is None:
+            bind_port = env.get('PORT', None)
+            if bind_port is not None:
+                self.bind_port = int(bind_port)
+        if self.bind_port is None:
+            self.bind_port = 53
+        if self.bind_alt_port is None:
+            self.bind_alt_port = 60600
+
+    def hosts_recheck(self):
+        """Recheck all hosts files."""
+        for hostsdb in self.hosts:
+            hostsdb.recheck()
+        return
+
+    def getaddr(self, ahn):
+        """Get a hostname matching address."""
+        for hostsdb in self.hosts:
+            result = hostsdb.getaddr(ahn)
+            if result:
+                return result
+
+    def getaaaa(self, ahn):
+        """Get an AAAA record from the hosts files."""
+        for hostsdb in self.hosts:
+            result = hostsdb.getaaaa(ahn)
+            if result:
+                return result
+
+    def getaaaa_hit(self, ahn):
+        """Get and HIT record from the hosts files."""
+        for hostsdb in self.hosts:
+            result = hostsdb.getaaaa_hit(ahn)
+            if result:
+                return result
+
+    def cache_name(self, name, addr, ttl):
+        """Cache the name-address mapping with ttl in all hosts files."""
+        for hostsdb in self.hosts:
+            hostsdb.cache_name(name, addr, ttl)
+
+    def geta(self, ahn):
+        """Get an A record from the hosts files."""
+        for hostsdb in self.hosts:
+            result = hostsdb.geta(ahn)
+            if result:
+                return result
+
+    def forkme(self):
+        """Daemonize current process."""
+        pid = os.fork()
+        if pid:
+            return False
+        else:
+            # we are the child
+            global MYID
+            MYID = '%d-%d' % (time.time(), os.getpid())
+            loghandler = logging.handlers.SysLogHandler(address='/dev/log',
+                facility=logging.handlers.SysLogHandler.LOG_DAEMON)
+            loghandler.setFormatter(logging.Formatter(
+                'hipdnsproxy[%(process)s] %(levelname)-8s %(message)s'))
+            logging.getLogger().addHandler(loghandler)
+            stdin = file(os.devnull, 'r')
+            stdout = file(os.devnull, 'a+')
+            stderr = file(os.devnull, 'a+', 0)
+            os.dup2(stdin.fileno(), sys.stdin.fileno())
+            os.dup2(stdout.fileno(), sys.stdout.fileno())
+            os.dup2(stderr.fileno(), sys.stderr.fileno())
+            return True
+
+    def killold(self):
+        """Kill process with PID from pidfile."""
+        try:
+            ifile = open(self.pidfile, 'r')
+        except IOError, ioe:
+            if ioe[0] == errno.ENOENT:
+                return
+            else:
+                logging.error('Error opening pid file: %s', ioe)
+                sys.exit(1)
+        try:
+            os.kill(int(ifile.readline().rstrip()), signal.SIGTERM)
+        except OSError, ose:
+            if ose[0] == errno.ESRCH:
+                ifile.close()
+                return
+            else:
+                logging.error('Error terminating old process: %s', ose)
+                sys.exit(1)
+        time.sleep(3)
+        ifile.close()
+
+    def recovery(self):
+        """Recover from being harshly killed."""
+        try:
+            ifile = open(self.pidfile, 'r')
+        except IOError, ioe:
+            if ioe[0] == errno.ENOENT:
+                return
+            else:
+                logging.error('Error opening pid file: %s', ioe)
+                sys.exit(1)
+        ifile.readline()
+        bk_path = '%s-%s' % (self.rc1.resolvconf_towrite,
+                             ifile.readline().rstrip())
+        if os.path.exists(bk_path):
+            logging.info('resolv.conf backup found. Restoring.')
+            tmp = self.rc1.resolvconf_bkname
+            self.rc1.resolvconf_bkname = bk_path
+            self.rc1.restore_resolvconf_dnsmasq()
+            self.rc1.resolvconf_bkname = tmp
+        ifile.close()
+
+    def savepid(self):
+        """Write PID and MYID to pidfile."""
+        try:
+            ofile = open(self.pidfile, 'w')
+        except IOError, ioe:
+            logging.error('Error opening pid file for writing: %s', ioe)
+            sys.exit(1)
+        ofile.write('%d\n' % (os.getpid(),))
+        ofile.write('%s\n' % MYID)
+        ofile.close()
+
+    def write_local_hits_to_hosts(self):
+        """Add local HITs to the hosts files.
+
+        Otherwise certain services (sendmail, cups, httpd) timeout when they
+        are started and they query the local HITs from the DNS.
+
+        FIXME: should we really write the local hits to a file rather than just
+        adding them to the cache?
+        """
+        localhit = []
+        proc = subprocess.Popen(['ifconfig', 'dummy0'],
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT).stdout
+        result = proc.readline()
+        while result:
+            start = result.find('2001:1')
+            end = result.find('/28')
+            if start != -1 and end != -1:
+                hit = result[start:end]
+                if not self.getaddr(hit):
+                    localhit.append(hit)
+            result = proc.readline()
+        proc.close()
+        ofile = open(self.hiphosts, 'a')
+        for i in range(len(localhit)):
+            ofile.write('%s\tlocalhit%s\n' % (localhit[i], i + 1))
+        ofile.close()
+
+    def hip_cache_lookup(self, packet):
+        """Make a cache lookup."""
+        result = None
+        qname = packet['questions'][0][0]
+        qtype = packet['questions'][0][1]
+
+        if self.prefix and qname.startswith(self.prefix):
+            qname = qname[len(self.prefix):]
+
+        # convert 1.2....1.0.0.1.0.0.2.ip6.arpa to a HIT and
+        # map host name to address from cache
+        if qtype == 12:
+            lr_ptr = None
+            addr_str = hosts.ptr_to_addr(qname)
+            if (not self.disable_lsi and addr_str is not None and
+                hosts.valid_lsi(addr_str)):
+                addr_str = lsi_to_hit(addr_str)
+            lr_ptr = self.getaddr(addr_str)
+            lr_aaaa_hit = None
+        else:
+            lr_a = self.geta(qname)
+            lr_aaaa = self.getaaaa(qname)
+            lr_aaaa_hit = self.getaaaa_hit(qname)
+
+        if (lr_aaaa_hit is not None and
+            (not self.prefix or
+             packet['questions'][0][0].startswith(self.prefix))):
+            if lr_a is not None:
+                add_hit_ip_map(lr_aaaa_hit[0], lr_a[0])
+            if lr_aaaa is not None:
+                add_hit_ip_map(lr_aaaa_hit[0], lr_aaaa[0])
+            if qtype == 28:               # 28: AAAA
+                result = lr_aaaa_hit
+            elif qtype == 1 and not self.disable_lsi:  # 1: A
+                lsi = hit_to_lsi(lr_aaaa_hit[0])
+                if lsi is not None:
+                    result = (lsi, lr_aaaa_hit[1])
+        elif self.prefix and packet['questions'][0][0].startswith(self.prefix):
+            result = None
+        elif qtype == 28:
+            result = lr_aaaa
+        elif qtype == 1:
+            result = lr_a
+        elif qtype == 12 and lr_ptr is not None:  # 12: PTR
+            result = (lr_ptr, self.hosts_ttl)
+
+        if result is not None:
+            packet['answers'].append([packet['questions'][0][0], qtype, 1,
+                                     result[1], result[0]])
+            packet['ancount'] = len(packet['answers'])
+            packet['qr'] = 1
+            return True
+
+        return False
+
+    def hip_lookup(self, packet):
+        """Make a lookup."""
+        qname = packet['questions'][0][0]
+        qtype = packet['questions'][0][1]
+
+        dns_hit_found = False
+        for answer in packet['answers']:
+            if answer[1] == 55:
+                dns_hit_found = True
+                break
+
+        lsi = None
+        hit_found = dns_hit_found is not None
+        if hit_found:
+            hit_ans = []
+            lsi_ans = []
+
+            for answer in packet['answers']:
+                if answer[1] != 55:
+                    continue
+
+                hit = socket.inet_ntop(socket.AF_INET6, answer[7])
+                hit_ans.append([qname, 28, 1, answer[3], hit])
+
+                if qtype == 1 and not self.disable_lsi:
+                    lsi = hit_to_lsi(hit)
+                    if lsi is not None:
+                        lsi_ans.append([qname, 1, 1, self.hosts_ttl, lsi])
+
+                self.cache_name(qname, hit, answer[3])
+
+        if qtype == 28 and hit_found:
+            packet['answers'] = hit_ans
+        elif lsi is not None:
+            packet['answers'] = lsi_ans
+        else:
+            packet['answers'] = []
+
+        packet['ancount'] = len(packet['answers'])
+
+    def mainloop(self, unused_args):
+        """HIP DNS proxy main loop."""
+        connected = False
+
+        logging.info('Dns proxy for HIP started')
+
+        self.parameter_defaults()
+
+        # Default virtual interface and address for dnsproxy to
+        # avoid problems with other dns forwarders (e.g. dnsmasq)
+        os.system("ifconfig lo:53 %s" % (self.bind_ip,))
+
+        servsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        try:
+            servsock.bind((self.bind_ip, self.bind_port))
+        except socket.error:
+            logging.info('Port %d occupied, falling back to port %d',
+                         self.bind_port, self.bind_alt_port)
+            servsock.bind((self.bind_ip, self.bind_alt_port))
+            self.use_alt_port = True
+
+        servsock.settimeout(self.app_timeout)
+
+        rc1 = self.rc1
+        if self.use_alt_port and os.path.exists(rc1.dnsmasq_defaults):
+            rc1.set_dnsmasq_hook(self)
+
+        if rc1.use_dnsmasq_hook and rc1.use_resolvconf:
+            conf_file = rc1.guess_resolvconf()
+        else:
+            conf_file = None
+
+        if conf_file is not None:
+            logging.info('Using conf file %s', conf_file)
+
+        self.read_resolv_conf(conf_file)
+        if self.server_ip is not None:
+            logging.info('DNS server is %s', self.server_ip)
+
+        self.hosts = []
+        if self.hostsnames:
+            for hostsname in self.hostsnames:
+                self.hosts.append(hosts.Hosts(hostsname))
+        else:
+            if os.path.exists(self.hiphosts):
+                self.hosts.append(hosts.Hosts(self.hiphosts))
+
+        if os.path.exists(DEFAULT_HOSTS):
+            self.hosts.append(hosts.Hosts(DEFAULT_HOSTS))
+
+        self.write_local_hits_to_hosts()
+
+        util.init_wantdown()
+        util.init_wantdown_int()        # Keyboard interrupts
+
+        rc1.start()
+
+        if (not (rc1.use_dnsmasq_hook and rc1.use_resolvconf) and
+            self.overwrite_resolv_conf):
+            rc1.write({'nameserver': self.bind_ip})
+
+        if self.server_ip is not None:
+            if self.server_ip.find(':') == -1:
+                server_family = socket.AF_INET
+            else:
+                server_family = socket.AF_INET6
+            clisock = socket.socket(server_family, socket.SOCK_DGRAM)
+            clisock.settimeout(self.dns_timeout)
+            try:
+                clisock.connect((self.server_ip, self.server_port))
+                connected = True
+            except socket.error:
+                connected = False
+
+        query_id = 1
+
+        while not util.wantdown():
+            try:
+                self.hosts_recheck()
+                if rc1.old_has_changed():
+                    connected = False
+                    self.server_ip = rc1.resolvconfd.get('nameserver')
+                    if self.server_ip is not None:
+                        if self.server_ip.find(':') == -1:
+                            server_family = socket.AF_INET
+                        else:
+                            server_family = socket.AF_INET6
+                        clisock = socket.socket(server_family,
+                                                socket.SOCK_DGRAM)
+                        clisock.settimeout(self.dns_timeout)
+                        try:
+                            clisock.connect((self.server_ip, self.server_port))
+                            connected = True
+                            logging.info('DNS server is %s', self.server_ip)
+                        except socket.error:
+                            connected = False
+
+                    rc1.restart()
+                    if (not (rc1.use_dnsmasq_hook and rc1.use_resolvconf) and
+                        self.overwrite_resolv_conf):
+                        rc1.write({'nameserver': self.bind_ip})
+
+                if connected:
+                    rlist, _, _ = select.select([servsock, clisock], [], [],
+                                                5.0)
+                else:
+                    rlist, _, _ = select.select([servsock], [], [], 5.0)
+                self.clean_queries()
+                if servsock in rlist:          # Incoming DNS request
+                    inbuf, from_a = servsock.recvfrom(2048)
+
+                    packet = DeSerialize(inbuf).get_dict()
+                    qtype = packet['questions'][0][1]
+
+                    sent_answer = False
+
+                    if qtype in (1, 28, 12):
+                        if self.hip_cache_lookup(packet):
+                            try:
+                                outbuf = Serialize(packet).get_packet()
+                                servsock.sendto(outbuf, from_a)
+                                sent_answer = True
+                            except socket.error:
+                                logging.exception('Exception:')
+                    elif (self.prefix and
+                          packet['questions'][0][0].startswith(self.prefix)):
+                        # Query with HIP prefix for unsupported RR type.
+                        # Send empty response.
+                        packet['qr'] = 1
+                        try:
+                            outbuf = Serialize(packet).get_packet()
+                            servsock.sendto(outbuf, from_a)
+                            sent_answer = True
+                        except socket.error:
+                            logging.exception('Exception:')
+
+                    if connected and not sent_answer:
+                        logging.info('Query type %d for %s from %s',
+                            qtype, packet['questions'][0][0],
+                            (self.server_ip, self.server_port))
+
+                        query = (packet, from_a[0], from_a[1], qtype)
+                        # FIXME: Should randomize for security
+                        query_id = (query_id % 65535) + 1
+                        pckt = copy.copy(packet)
+                        pckt['id'] = query_id
+                        if ((qtype == 28 or
+                             (qtype == 1 and not self.disable_lsi)) and not
+                            is_reverse_hit_query(packet['questions'][0][0])):
+
+                            if not self.prefix:
+                                pckt['questions'][0][1] = 55
+                            if (self.prefix and
+                                pckt['questions'][0][0].startswith(
+                                    self.prefix)):
+                                pckt['questions'][0][0] = pckt[
+                                    'questions'][0][0][len(self.prefix):]
+                                pckt['questions'][0][1] = 55
+
+                        if qtype == 12 and not self.disable_lsi:
+                            qname = packet['questions'][0][0]
+                            addr_str = hosts.ptr_to_addr(qname)
+                            if (addr_str is not None and
+                                hosts.valid_lsi(addr_str)):
+                                query = (packet, from_a[0], from_a[1], qname)
+                                hit_str = lsi_to_hit(addr_str)
+                                if hit_str is not None:
+                                    pckt['questions'][0][0] = \
+                                            hosts.addr_to_ptr(hit_str)
+
+                        outbuf = Serialize(pckt).get_packet()
+                        clisock.sendto(outbuf, (self.server_ip,
+                                                self.server_port))
+
+                        self.add_query(self.server_ip, self.server_port,
+                                       query_id, query)
+
+                if connected and clisock in rlist:   # Incoming DNS reply
+                    inbuf, from_a = clisock.recvfrom(2048)
+                    logging.info('Packet from DNS server %d bytes from %s',
+                        len(inbuf), from_a)
+                    packet = DeSerialize(inbuf).get_dict()
+
+                    # Find original query
+                    query_id_o = packet['id']
+                    query_o = self.find_query(from_a[0], from_a[1], query_id_o)
+                    if query_o:
+                        qname = packet['questions'][0][0]
+                        qtype = packet['questions'][0][1]
+                        send_reply = True
+                        query_again = False
+                        hit_found = False
+                        packet_o = query_o[0]
+                        # Replace with the original query id
+                        packet['id'] = packet_o['id']
+
+                        if qtype == 55 and query_o[3] in (1, 28):
+                            # Restore qtype
+                            packet['questions'][0][1] = query_o[3]
+                            self.hip_lookup(packet)
+                            if packet['ancount'] > 0:
+                                hit_found = True
+                            if (not self.prefix or
+                                (hit_found and not (self.getaaaa(qname) or
+                                                    self.geta(qname)))):
+                                query_again = True
+                                send_reply = False
+                            elif self.prefix:
+                                hit_found = True
+                                packet['questions'][0][0] = (
+                                    self.prefix + packet['questions'][0][0])
+                                for answer in packet['answers']:
+                                    answer[0] = self.prefix + answer[0]
+
+                        elif qtype in (1, 28):
+                            hit = self.getaaaa_hit(qname)
+                            ip6 = self.getaaaa(qname)
+                            ip4 = self.geta(qname)
+                            for answer in packet['answers']:
+                                if answer[1] in (1, 28):
+                                    self.cache_name(qname, answer[4],
+                                                    answer[3])
+                            if hit is not None:
+                                for answer in packet['answers']:
+                                    if (answer[1] == 1 or
+                                        (answer[1] == 28 and not
+                                         hosts.valid_hit(answer[4]))):
+                                        add_hit_ip_map(hit[0], answer[4])
+                                # Reply with HIT/LSI once it's been mapped to
+                                # an IP
+                                if ip6 is None and ip4 is None:
+                                    if (packet_o['ancount'] == 0 and
+                                        not self.prefix):
+                                        # No LSI available. Return IPv4
+                                        tmp = packet['answers']
+                                        packet = packet_o
+                                        packet['answers'] = tmp
+                                        packet['ancount'] = len(
+                                            packet['answers'])
+                                    else:
+                                        packet = packet_o
+                                        if self.prefix:
+                                            packet['questions'][0][0] = \
+                                                    (self.prefix +
+                                                     packet['questions'][0][0])
+                                            for answer in packet['answers']:
+                                                answer[0] = (self.prefix +
+                                                             answer[0])
+                                else:
+                                    send_reply = False
+                            elif query_o[3] == 0:
+                                # Prefix is in use
+                                # IP was queried for cache only
+                                send_reply = False
+
+                        elif qtype == 12 and isinstance(query_o[3], str):
+                            packet['questions'][0][0] = query_o[3]
+                            for answer in packet['answers']:
+                                answer[0] = query_o[3]
+
+                        if query_again:
+                            if hit_found:
+                                qtypes = [28, 1]
+                                pckt = copy.deepcopy(packet)
+                            else:
+                                qtypes = [query_o[3]]
+                                pckt = copy.copy(packet)
+                            pckt['qr'] = 0
+                            pckt['answers'] = []
+                            pckt['ancount'] = 0
+                            pckt['nslist'] = []
+                            pckt['nscount'] = 0
+                            pckt['additional'] = []
+                            pckt['arcount'] = 0
+                            for qtype in qtypes:
+                                if self.prefix:
+                                    query = (packet, query_o[1], query_o[2], 0)
+                                else:
+                                    query = (packet, query_o[1], query_o[2],
+                                             qtype)
+                                query_id = (query_id % 65535) + 1
+                                pckt['id'] = query_id
+                                pckt['questions'][0][1] = qtype
+                                outbuf = Serialize(pckt).get_packet()
+                                clisock.sendto(outbuf, (self.server_ip,
+                                                        self.server_port))
+                                self.add_query(self.server_ip,
+                                               self.server_port,
+                                               query_id, query)
+                            packet['questions'][0][1] = query_o[3]
+
+                        if send_reply:
+                            outbuf = Serialize(packet).get_packet()
+                            servsock.sendto(outbuf, (query_o[1], query_o[2]))
+            except (select.error, OSError), exc:
+                if exc[0] == errno.EINTR:
+                    pass
+                else:
+                    logging.exception('Exception:')
+
+        logging.info('Wants down')
+        rc1.stop()
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod(raise_on_error=True)

=== modified file 'tools/hipdnsproxy/hipdnsproxy.in'
--- tools/hipdnsproxy/hipdnsproxy.in    2012-04-28 09:15:20 +0000
+++ tools/hipdnsproxy/hipdnsproxy.in    2012-04-28 15:58:42 +0000
@@ -1,1112 +1,103 @@
 #! /usr/bin/env python
 
-# Copyright (c) 2012 Aalto University and RWTH Aachen University.
-#
-# 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.
-
-"""HIP name look-up daemon for HIPL hosts file and DNS servers."""
-
-# Usage: Basic usage without any command line options.
-#        See getopt() for the options.
-#
-# Working test cases with hipdnsproxy
-# - Interoperates with libc and dnsmasq
-# - Resolvconf(on/off) + dnsmasq (on/off)
-#    - initial look up (check HIP and non-hip look up)
-#      - check that ctrl+c restores /etc/resolv.conf
-#    - change access network (check HIP and non-hip look up)
-#      - check that ctrl+c restores /etc/resolv.conf
-# - Watch out for cached entries! Restart dnmasq and hipdnsproxy after
-#   each test.
-# - Test name resolution with following methods:
-#   - Non-HIP records
-#   - Hostname to HIT resolution
-#     - HITs and LSIs from @sysconfdir@/hosts
-#     - On-the-fly generated LSI; HIT either from from DNS or hosts
-#     - HI records from DNS
-#   - PTR records: maps HITs to hostnames from @sysconfdir@/hosts
-#
-# Actions to resolv.conf files and dnsproxy hooking:
-# - Dnsmasq=on, revolvconf=on: only hooks dnsmasq
-# - Dnsmasq=off, revolvconf=on: rewrites /etc/resolvconf/run/resolv.conf
-# - Dnsmasq=on, revolvconf=off: hooks dnsmasq and rewrites /etc/resolv.conf
-# - Dnsmasq=off, revolvconf=off: rewrites /etc/resolv.conf
-#
-# TBD:
-# - rewrite the code to more object oriented
-# - the use of alternative (multiple) dns servers
-# - implement TTLs for cache
-#   - applicable to HITs, LSIs and IP addresses
-#   - host files: forever (purged when the file is changed)
-#   - dns records: follow DNS TTL
-# - bind to ::1, not 127.0.0.1 (setsockopt blah blah)
-# - remove hardcoded addresses from ifconfig commands
-# - compatibility with "unbound"
-
-import copy
-import errno
-import fileinput
-import getopt
-import os
-import re
-import select
-import signal
-import socket
-import subprocess
+"""HIP DNS Proxy launcher."""
+
+import logging
+import optparse
 import sys
-import syslog
-import time
-import traceback
-
-#local imports
-
-# prepending (instead of appending) to make sure hosts.py does not
-# collide with the system default
+
 sys.path.insert(0, '@pythondir@/hipdnsproxy')
-import hosts
-import util
-from DNS import Serialize, DeSerialize
-
-
-LSI_RE = re.compile(r'(?P<lsi>1\.\d+\.\d+\.\d+)')
-
-
-def usage(unused_utyp, *msg):
-    """Print usage instructions and exit."""
-    sys.stderr.write('Usage: %s\n' % os.path.split(sys.argv[0])[1])
-    if msg:
-        sys.stderr.write('Error: %r\n' % msg)
-    sys.exit(1)
-
-
-# Done: forking affects this. Fixed in forkme
-MYID = '%d-%d' % (time.time(), os.getpid())
-
-
-def hit_to_lsi(hit):
-    """Return LSI for HIT if found."""
-    output = subprocess.Popen(['hipconf', 'daemon', 'hit-to-lsi', hit],
-                              stdout=subprocess.PIPE,
-                              stderr=subprocess.STDOUT).stdout
-
-    for line in output:
-        match = LSI_RE.search(line)
-        if match:
-            return match.group('lsi')
-
-
-def lsi_to_hit(lsi):
-    """Return HIT for LSI if found."""
-    output = subprocess.Popen(['hipconf', 'daemon', 'lsi-to-hit', lsi],
-                              stdout=subprocess.PIPE,
-                              stderr=subprocess.STDOUT).stdout
-
-    for line in output:
-        match = hosts.HIT_RE.search(line)
-        if match:
-            return match.group('hit')
-
-
-def is_reverse_hit_query(name):
-    """Check if the query is a reverse query to a HIT.
-
-    >>> is_reverse_hit_query('::1')
-    False
-    >>> is_reverse_hit_query('8.e.b.8.b.3.c.9.1.a.0.c.e.e.2.c.c.e.d.0.9.c.'
-    ...                      '9.a.e.1.0.0.1.0.0.2.hit-to-ip.infrahip.net')
-    True
-    """
-    if (name.endswith('.1.0.0.1.0.0.2.hit-to-ip.infrahip.net') and
-        len(name) == 86):
-        return True
-    return False
-
-
-class Logger:
-    """Logging to stdout or syslog.
-
-    TODO(ptman): replace with stdlib module logging.
-    """
-    def __init__(self):
-        self._write = sys.stdout.write
-        self.flush = sys.stdout.flush
-
-    def setsyslog(self):
-        """Direct writes to syslog instead of stdout."""
-        syslog.openlog('dnsproxy', syslog.LOG_PID)
-        self._write = syslog.syslog
-        self.flush = lambda *x: None
-
-    def write(self, msg):
-        """Log message using selected logging backend."""
-        self._write(msg)
-        self.flush()
-
-
-class ResolvConf:
-    """Handle resolv.conf."""
-    re_nameserver = re.compile(r'nameserver\s+(\S+)$')
-
-    def __init__(self, dnsp, filetowatch=None):
-        self.fout = dnsp.fout
-        self.dnsmasq_initd_script = '/etc/init.d/dnsmasq'
-        if os.path.exists('/etc/redhat-release'):
-            self.distro = 'redhat'
-            self.rh_before = '# See how we were called.'
-            self.rh_inject = '. /etc/sysconfig/dnsmasq # Added by hipdnsproxy'
-        elif os.path.exists('/etc/debian_version'):
-            self.distro = 'debian'
-        else:
-            self.distro = 'unknown'
-
-        if self.distro == 'redhat':
-            self.dnsmasq_defaults = '/etc/sysconfig/dnsmasq'
-            if not os.path.exists(self.dnsmasq_defaults):
-                open(self.dnsmasq_defaults, 'w').close()
-        else:
-            self.dnsmasq_defaults = '/etc/default/dnsmasq'
-
-        self.dnsmasq_defaults_backup = (self.dnsmasq_defaults +
-                                        '.backup.hipdnsproxy')
-
-        if (os.path.isdir('/etc/resolvconf/.') and
-            os.path.exists('/sbin/resolvconf') and
-            os.path.exists('/etc/resolvconf/run/resolv.conf')):
-            self.use_resolvconf = True
-        else:
-            self.use_resolvconf = False
-        self.use_dnsmasq_hook = False
-        self.resolvconfd = None
-        self.dnsmasq_hook = None
-        self.alt_port = None
-
-        self.dnsmasq_resolv = '/var/run/dnsmasq/resolv.conf'
-        self.resolvconf_run = '/etc/resolvconf/run/resolv.conf'
-        if self.use_resolvconf:
-            self.resolvconf_towrite = '/etc/resolvconf/run/resolv.conf'
-        else:
-            self.resolvconf_towrite = '/etc/resolv.conf'
-
-        self.dnsmasq_restart = [self.dnsmasq_initd_script, 'restart']
-        if filetowatch is None:
-            self.filetowatch = self.guess_resolvconf()
-        self.resolvconf_orig = self.filetowatch
-        self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
-        self.resolvconf_bkname = '%s-%s' % (self.resolvconf_towrite, MYID)
-        self.overwrite_resolv_conf = dnsp.overwrite_resolv_conf
-
-    def guess_resolvconf(self):
-        """Guess the location of the correct resolv.conf file."""
-        if self.use_dnsmasq_hook and self.use_resolvconf:
-            return self.dnsmasq_resolv
-        elif self.use_resolvconf:
-            return self.resolvconf_run
-        else:
-            return '/etc/resolv.conf'
-
-    def reread_old_rc(self):
-        """Re-read the old resolv.conf."""
-        self.resolvconfd = {}
-        ifile = open(self.filetowatch)
-        for line in ifile.xreadlines():
-            line = line.strip()
-            if 'nameserver' not in self.resolvconfd:
-                match = self.re_nameserver.match(line)
-                if match:
-                    self.resolvconfd['nameserver'] = match.group(1)
-        return self.resolvconfd
-
-    def set_dnsmasq_hook(self, dnsp):
-        """Set the dnsmasq hook."""
-        self.alt_port = dnsp.bind_alt_port
-        self.use_dnsmasq_hook = True
-        self.fout.write('Dnsmasq-resolvconf installation detected\n')
-        if self.distro == 'redhat':
-            self.dnsmasq_hook = ('OPTIONS+="--no-hosts --no-resolv '
-                                 '--cache-size=0 --server=%s#%s"\n' % (
-                                     dnsp.bind_ip, self.alt_port))
-        else:
-            self.dnsmasq_hook = ('DNSMASQ_OPTS="--no-hosts --no-resolv '
-                                 '--cache-size=0 --server=%s#%s"\n' % (
-                                     dnsp.bind_ip, self.alt_port))
-        return
-
-    def old_has_changed(self):
-        """Return true if the old resolv.conf file has changed."""
-        old_rc_mtime = os.stat(self.filetowatch).st_mtime
-        if old_rc_mtime != self.old_rc_mtime:
-            self.reread_old_rc()
-            self.old_rc_mtime = old_rc_mtime
-            return True
-        else:
-            return False
-
-    def save_resolvconf_dnsmasq(self):
-        """Inject the dnsmasq hook and restart dnsmasq if necessary."""
-        if self.use_dnsmasq_hook:
-            if os.path.exists(self.dnsmasq_defaults):
-                ifile = open(self.dnsmasq_defaults, 'r')
-                line = ifile.readline()
-                ifile.close()
-                if (line.find('server=127') != -1 and
-                    line[:line.find('server=')] ==
-                    self.dnsmasq_hook[:self.dnsmasq_hook.find('server=')]):
-                    self.fout.write('Dnsmasq configuration file seems to be '
-                                    'written by dnsproxy. Zeroing.\n')
-                    ofile = open(self.dnsmasq_defaults, 'w')
-                    ofile.write('')
-                    ofile.close()
-                os.rename(self.dnsmasq_defaults,
-                          self.dnsmasq_defaults_backup)
-            dmd = open(self.dnsmasq_defaults, 'w')
-            dmd.write(self.dnsmasq_hook)
-            dmd.close()
-            if self.distro == 'redhat':
-                for line in fileinput.input(self.dnsmasq_initd_script,
-                                            inplace=1):
-                    if line.find(self.rh_before) == 0:
-                        print self.rh_inject
-                    print line,
-            subprocess.check_call(self.dnsmasq_restart,
-                                  stdout=open(os.devnull, 'wb'),
-                                  stderr=subprocess.STDOUT)
-            self.fout.write('Hooked with dnsmasq\n')
-            # Restarting of dnsproxy changes also resolv conf. Reset timer
-            # to make sure that we don't load dnsproxy's IP address. Otherwise
-            # all DNS requests are blocked when running dnsproxy in
-            # combination with dnsmasq.
-            self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
-        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
-            self.overwrite_resolv_conf):
-            os.link(self.resolvconf_towrite, self.resolvconf_bkname)
-        return
-
-    def restore_resolvconf_dnsmasq(self):
-        """Restore old dnsmasq config and restart dnsmasq if necessary."""
-        if self.use_dnsmasq_hook:
-            self.fout.write('Removing dnsmasq hooks\n')
-            if os.path.exists(self.dnsmasq_defaults_backup):
-                os.rename(self.dnsmasq_defaults_backup,
-                          self.dnsmasq_defaults)
-            if self.distro == 'redhat':
-                for line in fileinput.input(self.dnsmasq_initd_script,
-                                            inplace=1):
-                    if line.find(self.rh_inject) == -1:
-                        print line,
-            subprocess.check_call(self.dnsmasq_restart,
-                                  stdout=open(os.devnull, 'wb'),
-                                  stderr=subprocess.STDOUT)
-        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
-            self.overwrite_resolv_conf):
-            os.rename(self.resolvconf_bkname, self.resolvconf_towrite)
-            self.fout.write('resolv.conf restored\n')
-        return
-
-    def write(self, params):
-        """Write resolv.conf."""
-        tmp = '%s.tmp-%s' % (self.resolvconf_towrite, MYID)
-        ofile = open(tmp, 'w')
-        ofile.write('# This is written by hipdnsproxy\n')
-        for key, value in params.iteritems():
-            if type(value) is str:
-                value = (value,)
-            for val in value:
-                ofile.write('%-10s %s\n' % (key, val))
-        ofile.close()
-        os.rename(tmp, self.resolvconf_towrite)
-        self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
-
-    def overwrite_resolvconf(self):
-        """Rewrite the contents of resolv.conf.
-
-        TODO(ptman): would just changing the mtime suffice?
-        """
-        tmp = '%s.tmp-%s' % (self.resolvconf_towrite, MYID)
-        ifile = open(self.resolvconf_towrite, 'r')
-        ofile = open(tmp, 'w')
-        while True:
-            buf = ifile.read(16384)
-            if not buf:
-                break
-            ofile.write(buf)
-        ifile.close()
-        ofile.close()
-        os.rename(tmp, self.resolvconf_towrite)
-        self.fout.write('Rewrote resolv.conf\n')
-
-    def start(self):
-        """Perform startup routines."""
-        self.save_resolvconf_dnsmasq()
-        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
-            self.overwrite_resolv_conf):
-            self.overwrite_resolvconf()
-
-    def restart(self):
-        """Perform restart routines."""
-        if (not (self.use_dnsmasq_hook and self.use_resolvconf) and
-            self.overwrite_resolv_conf):
-            self.overwrite_resolvconf()
-        self.old_rc_mtime = os.stat(self.filetowatch).st_mtime
-
-    def stop(self):
-        """Perform shutdown routines."""
-        self.restore_resolvconf_dnsmasq()
-        subprocess.check_call(['ifconfig', 'lo:53', 'down'])
-        # Sometimes hipconf processes get stuck, particularly when
-        # hipd is busy or unresponsive. This is a workaround.
-        subprocess.call(['killall', '--quiet', 'hipconf'],
-                        stderr=open(os.devnull, 'wb'))
-
-
-class DNSProxy:
-    """HIP DNS proxy main class."""
-    default_hiphosts = "@sysconfdir@/hosts"
-    default_hosts = "/etc/hosts"
-    re_nameserver = re.compile(r'nameserver\s+(\S+)$')
-
-    def __init__(self):
-        self.resolv_conf = '/etc/resolv.conf'
-        self.hostsnames = []
-        self.server_ip = None
-        self.server_port = None
-        self.bind_ip = None
-        self.bind_port = None
-        self.bind_alt_port = None
-        self.use_alt_port = False
-        self.disable_lsi = False
-        self.fork = False
-        self.pidfile = '/var/run/hipdnsproxy.pid'
-        self.kill = False
-        self.overwrite_resolv_conf = True
-        self.logger = Logger()
-        self.fout = self.logger
-        self.app_timeout = 1
-        self.dns_timeout = 2
-        self.hosts_ttl = 122
-        self.sent_queue = []
-        self.prefix = None
-        self.tarfilename = None
-        self.fetchcount = None
-        self.rc1 = None
-        self.resolvconfd = None
-        self.hosts = None
-        # Keyed by ('server_ip',server_port,query_id) tuple
-        self.sent_queue_d = {}
-        # required for ifconfig and hipconf in Fedora
-        # (rpm and "make install" targets)
-        os.environ['PATH'] += ':/sbin:/usr/sbin:/usr/local/sbin'
-
-    def add_query(self, server_ip, server_port, query_id, query):
-        """Add a pending DNS query"""
-        key = (server_ip, server_port, query_id)
-        value = (key, time.time(), query)
-        self.sent_queue.append(value)
-        self.sent_queue_d[key] = value
-
-    def find_query(self, server_ip, server_port, query_id):
-        """Find a pending DNS query"""
-        key = (server_ip, server_port, query_id)
-        query = self.sent_queue_d.get(key)
-        if query:
-            idx = self.sent_queue.index(query)
-            self.sent_queue.pop(idx)
-            del self.sent_queue_d[key]
-            return query[2]
-        return None
-
-    def clean_queries(self):
-        """Clean old unanswered queries"""
-        texp = time.time() - 30
-        while self.sent_queue:
-            if self.sent_queue[0][1] < texp:
-                # TODO(ptman): test that key is used properly in del
-                key = self.sent_queue[0][0]
-                self.sent_queue.pop(0)
-                del self.sent_queue_d[key]
-            else:
-                break
-        return
-
-    def read_resolv_conf(self, cfile=None):
-        """Read resolv.conf."""
-        if cfile is None:
-            cfile = self.resolv_conf
-
-        options = {}
-
-        ifile = open(cfile)
-        for line in ifile.xreadlines():
-            line = line.strip()
-            if 'nameserver' not in options:
-                match = self.re_nameserver.match(line)
-                if match:
-                    options['nameserver'] = match.group(1)
-
-        if self.server_ip is None:
-            nameserver = options.get('nameserver', None)
-            self.server_ip = nameserver
-
-        self.resolvconfd = options
-        return options
-
-    def parameter_defaults(self):
-        """Missing default parameters."""
-        env = os.environ
-        if self.server_ip is None:
-            self.server_ip = env.get('SERVER', None)
-        if self.server_port is None:
-            server_port = env.get('SERVERPORT', None)
-            if server_port is not None:
-                self.server_port = int(server_port)
-        if self.server_port is None:
-            self.server_port = 53
-        if self.bind_ip is None:
-            self.bind_ip = env.get('IP', None)
-        if self.bind_ip is None:
-            self.bind_ip = '127.0.0.53'
-        if self.bind_port is None:
-            bind_port = env.get('PORT', None)
-            if bind_port is not None:
-                self.bind_port = int(bind_port)
-        if self.bind_port is None:
-            self.bind_port = 53
-        if self.bind_alt_port is None:
-            self.bind_alt_port = 60600
-
-    def hosts_recheck(self):
-        """Recheck all hosts files."""
-        for hostsdb in self.hosts:
-            hostsdb.recheck()
-        return
-
-    def getaddr(self, ahn):
-        """Get a hostname matching address."""
-        for hostsdb in self.hosts:
-            result = hostsdb.getaddr(ahn)
-            if result:
-                return result
-
-    def getaaaa(self, ahn):
-        """Get an AAAA record from the hosts files."""
-        for hostsdb in self.hosts:
-            result = hostsdb.getaaaa(ahn)
-            if result:
-                return result
-
-    def getaaaa_hit(self, ahn):
-        """Get and HIT record from the hosts files."""
-        for hostsdb in self.hosts:
-            result = hostsdb.getaaaa_hit(ahn)
-            if result:
-                return result
-
-    def cache_name(self, name, addr, ttl):
-        """Cache the name-address mapping with ttl in all hosts files."""
-        for hostsdb in self.hosts:
-            hostsdb.cache_name(name, addr, ttl)
-
-    def geta(self, ahn):
-        """Get an A record from the hosts files."""
-        for hostsdb in self.hosts:
-            result = hostsdb.geta(ahn)
-            if result:
-                return result
-
-    def forkme(self):
-        """Daemonize current process."""
-        pid = os.fork()
-        if pid:
-            return False
-        else:
-            # we are the child
-            global MYID
-            MYID = '%d-%d' % (time.time(), os.getpid())
-            self.logger.setsyslog()
-            return True
-
-    def killold(self):
-        """Kill process with PID from pidfile."""
-        try:
-            ifile = open(self.pidfile, 'r')
-        except IOError, ioe:
-            if ioe[0] == errno.ENOENT:
-                return
-            else:
-                self.fout.write('Error opening pid file: %s\n' % ioe)
-                sys.exit(1)
-        try:
-            os.kill(int(ifile.readline().rstrip()), signal.SIGTERM)
-        except OSError, ose:
-            if ose[0] == errno.ESRCH:
-                ifile.close()
-                return
-            else:
-                self.fout.write('Error terminating old process: %s\n' % ose)
-                sys.exit(1)
-        time.sleep(3)
-        ifile.close()
-
-    def recovery(self):
-        """Recover from being harshly killed."""
-        try:
-            ifile = open(self.pidfile, 'r')
-        except IOError, ioe:
-            if ioe[0] == errno.ENOENT:
-                return
-            else:
-                self.fout.write('Error opening pid file: %s\n' % ioe)
-                sys.exit(1)
-        ifile.readline()
-        bk_path = '%s-%s' % (self.rc1.resolvconf_towrite,
-                             ifile.readline().rstrip())
-        if os.path.exists(bk_path):
-            self.fout.write('resolv.conf backup found. Restoring.\n')
-            tmp = self.rc1.resolvconf_bkname
-            self.rc1.resolvconf_bkname = bk_path
-            self.rc1.restore_resolvconf_dnsmasq()
-            self.rc1.resolvconf_bkname = tmp
-        ifile.close()
-
-    def savepid(self):
-        """Write PID and MYID to pidfile."""
-        try:
-            ofile = open(self.pidfile, 'w')
-        except IOError, ioe:
-            self.fout.write('Error opening pid file for writing: %s' % ioe)
-            sys.exit(1)
-        ofile.write('%d\n' % (os.getpid(),))
-        ofile.write('%s\n' % MYID)
-        ofile.close()
-
-    def write_local_hits_to_hosts(self):
-        """Add local HITs to the hosts files.
-
-        Otherwise certain services (sendmail, cups, httpd) timeout when they
-        are started and they query the local HITs from the DNS.
-
-        FIXME: should we really write the local hits to a file rather than just
-        adding them to the cache?
-        """
-        localhit = []
-        proc = subprocess.Popen(['ifconfig', 'dummy0'],
-                                stdout=subprocess.PIPE,
-                                stderr=subprocess.STDOUT).stdout
-        result = proc.readline()
-        while result:
-            start = result.find('2001:1')
-            end = result.find('/28')
-            if start != -1 and end != -1:
-                hit = result[start:end]
-                if not self.getaddr(hit):
-                    localhit.append(hit)
-            result = proc.readline()
-        proc.close()
-        ofile = open(self.default_hiphosts, 'a')
-        for i in range(len(localhit)):
-            ofile.write('%s\tlocalhit%s\n' % (localhit[i], i + 1))
-        ofile.close()
-
-    def add_hit_ip_map(self, hit, addr):
-        """Add IP for HIT."""
-        self.fout.write('Associating HIT %s with IP %s\n' % (hit, addr))
-        subprocess.check_call(['hipconf', 'daemon', 'add', 'map', hit, addr],
-                              stdout=open(os.devnull, 'wb'),
-                              stderr=subprocess.STDOUT)
-
-    def hip_cache_lookup(self, packet):
-        """Make a cache lookup."""
-        result = None
-        qname = packet['questions'][0][0]
-        qtype = packet['questions'][0][1]
-
-        if self.prefix and qname.startswith(self.prefix):
-            qname = qname[len(self.prefix):]
-
-        # convert 1.2....1.0.0.1.0.0.2.ip6.arpa to a HIT and
-        # map host name to address from cache
-        if qtype == 12:
-            lr_ptr = None
-            addr_str = hosts.ptr_to_addr(qname)
-            if (not self.disable_lsi and addr_str is not None and
-                hosts.valid_lsi(addr_str)):
-                addr_str = lsi_to_hit(addr_str)
-            lr_ptr = self.getaddr(addr_str)
-            lr_aaaa_hit = None
-        else:
-            lr_a = self.geta(qname)
-            lr_aaaa = self.getaaaa(qname)
-            lr_aaaa_hit = self.getaaaa_hit(qname)
-
-        if (lr_aaaa_hit is not None and
-            (not self.prefix or
-             packet['questions'][0][0].startswith(self.prefix))):
-            if lr_a is not None:
-                self.add_hit_ip_map(lr_aaaa_hit[0], lr_a[0])
-            if lr_aaaa is not None:
-                self.add_hit_ip_map(lr_aaaa_hit[0], lr_aaaa[0])
-            if qtype == 28:               # 28: AAAA
-                result = lr_aaaa_hit
-            elif qtype == 1 and not self.disable_lsi:  # 1: A
-                lsi = hit_to_lsi(lr_aaaa_hit[0])
-                if lsi is not None:
-                    result = (lsi, lr_aaaa_hit[1])
-        elif self.prefix and packet['questions'][0][0].startswith(self.prefix):
-            result = None
-        elif qtype == 28:
-            result = lr_aaaa
-        elif qtype == 1:
-            result = lr_a
-        elif qtype == 12 and lr_ptr is not None:  # 12: PTR
-            result = (lr_ptr, self.hosts_ttl)
-
-        if result is not None:
-            packet['answers'].append([packet['questions'][0][0], qtype, 1,
-                                     result[1], result[0]])
-            packet['ancount'] = len(packet['answers'])
-            packet['qr'] = 1
-            return True
-
-        return False
-
-    def hip_lookup(self, packet):
-        """Make a lookup."""
-        qname = packet['questions'][0][0]
-        qtype = packet['questions'][0][1]
-
-        dns_hit_found = False
-        for answer in packet['answers']:
-            if answer[1] == 55:
-                dns_hit_found = True
-                break
-
-        lsi = None
-        hit_found = dns_hit_found is not None
-        if hit_found:
-            hit_ans = []
-            lsi_ans = []
-
-            for answer in packet['answers']:
-                if answer[1] != 55:
-                    continue
-
-                hit = socket.inet_ntop(socket.AF_INET6, answer[7])
-                hit_ans.append([qname, 28, 1, answer[3], hit])
-
-                if qtype == 1 and not self.disable_lsi:
-                    lsi = hit_to_lsi(hit)
-                    if lsi is not None:
-                        lsi_ans.append([qname, 1, 1, self.hosts_ttl, lsi])
-
-                self.cache_name(qname, hit, answer[3])
-
-        if qtype == 28 and hit_found:
-            packet['answers'] = hit_ans
-        elif lsi is not None:
-            packet['answers'] = lsi_ans
-        else:
-            packet['answers'] = []
-
-        packet['ancount'] = len(packet['answers'])
-
-    def mainloop(self, unused_args):
-        """HIP DNS proxy main loop."""
-        connected = False
-        fout = self.fout
-
-        fout.write('Dns proxy for HIP started\n')
-
-        self.parameter_defaults()
-
-        # Default virtual interface and address for dnsproxy to
-        # avoid problems with other dns forwarders (e.g. dnsmasq)
-        os.system("ifconfig lo:53 %s" % (self.bind_ip,))
-
-        servsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-        try:
-            servsock.bind((self.bind_ip, self.bind_port))
-        except socket.error:
-            fout.write('Port %d occupied, falling back to port %d\n' %
-                       (self.bind_port, self.bind_alt_port))
-            servsock.bind((self.bind_ip, self.bind_alt_port))
-            self.use_alt_port = True
-
-        servsock.settimeout(self.app_timeout)
-
-        rc1 = self.rc1
-        if self.use_alt_port and os.path.exists(rc1.dnsmasq_defaults):
-            rc1.set_dnsmasq_hook(self)
-
-        if rc1.use_dnsmasq_hook and rc1.use_resolvconf:
-            conf_file = rc1.guess_resolvconf()
-        else:
-            conf_file = None
-
-        if conf_file is not None:
-            fout.write("Using conf file %s\n" % conf_file)
-
-        self.read_resolv_conf(conf_file)
-        if self.server_ip is not None:
-            fout.write("DNS server is %s\n" % self.server_ip)
-
-        self.hosts = []
-        if self.hostsnames:
-            for hostsname in self.hostsnames:
-                self.hosts.append(hosts.Hosts(hostsname))
-        else:
-            if os.path.exists(self.default_hiphosts):
-                self.hosts.append(hosts.Hosts(self.default_hiphosts))
-
-        if os.path.exists(self.default_hosts):
-            self.hosts.append(hosts.Hosts(self.default_hosts))
-
-        self.write_local_hits_to_hosts()
-
-        util.init_wantdown()
-        util.init_wantdown_int()        # Keyboard interrupts
-
-        rc1.start()
-
-        if (not (rc1.use_dnsmasq_hook and rc1.use_resolvconf) and
-            self.overwrite_resolv_conf):
-            rc1.write({'nameserver': self.bind_ip})
-
-        if self.server_ip is not None:
-            if self.server_ip.find(':') == -1:
-                server_family = socket.AF_INET
-            else:
-                server_family = socket.AF_INET6
-            clisock = socket.socket(server_family, socket.SOCK_DGRAM)
-            clisock.settimeout(self.dns_timeout)
-            try:
-                clisock.connect((self.server_ip, self.server_port))
-                connected = True
-            except socket.error:
-                connected = False
-
-        query_id = 1
-
-        while not util.wantdown():
-            try:
-                self.hosts_recheck()
-                if rc1.old_has_changed():
-                    connected = False
-                    self.server_ip = rc1.resolvconfd.get('nameserver')
-                    if self.server_ip is not None:
-                        if self.server_ip.find(':') == -1:
-                            server_family = socket.AF_INET
-                        else:
-                            server_family = socket.AF_INET6
-                        clisock = socket.socket(server_family,
-                                                socket.SOCK_DGRAM)
-                        clisock.settimeout(self.dns_timeout)
-                        try:
-                            clisock.connect((self.server_ip, self.server_port))
-                            connected = True
-                            fout.write("DNS server is %s\n" % self.server_ip)
-                        except socket.error:
-                            connected = False
-
-                    rc1.restart()
-                    if (not (rc1.use_dnsmasq_hook and rc1.use_resolvconf) and
-                        self.overwrite_resolv_conf):
-                        rc1.write({'nameserver': self.bind_ip})
-
-                if connected:
-                    rlist, _, _ = select.select([servsock, clisock], [], [],
-                                                5.0)
-                else:
-                    rlist, _, _ = select.select([servsock], [], [], 5.0)
-                self.clean_queries()
-                if servsock in rlist:          # Incoming DNS request
-                    inbuf, from_a = servsock.recvfrom(2048)
-
-                    packet = DeSerialize(inbuf).get_dict()
-                    qtype = packet['questions'][0][1]
-
-                    sent_answer = False
-
-                    if qtype in (1, 28, 12):
-                        if self.hip_cache_lookup(packet):
-                            try:
-                                outbuf = Serialize(packet).get_packet()
-                                servsock.sendto(outbuf, from_a)
-                                sent_answer = True
-                            except socket.error, socke:
-                                tbstr = traceback.format_exc()
-                                fout.write('Exception: %s %s\n' % (socke,
-                                                                   tbstr))
-                    elif (self.prefix and
-                          packet['questions'][0][0].startswith(self.prefix)):
-                        # Query with HIP prefix for unsupported RR type.
-                        # Send empty response.
-                        packet['qr'] = 1
-                        try:
-                            outbuf = Serialize(packet).get_packet()
-                            servsock.sendto(outbuf, from_a)
-                            sent_answer = True
-                        except socket.error, socke:
-                            tbstr = traceback.format_exc()
-                            fout.write('Exception: %s %s\n' % (socke, tbstr))
-
-                    if connected and not sent_answer:
-                        self.fout.write('Query type %d for %s from %s\n' % (
-                            qtype, packet['questions'][0][0],
-                            (self.server_ip, self.server_port)))
-
-                        query = (packet, from_a[0], from_a[1], qtype)
-                        # FIXME: Should randomize for security
-                        query_id = (query_id % 65535) + 1
-                        pckt = copy.copy(packet)
-                        pckt['id'] = query_id
-                        if ((qtype == 28 or
-                             (qtype == 1 and not self.disable_lsi)) and not
-                            is_reverse_hit_query(packet['questions'][0][0])):
-
-                            if not self.prefix:
-                                pckt['questions'][0][1] = 55
-                            if (self.prefix and
-                                pckt['questions'][0][0].startswith(
-                                    self.prefix)):
-                                pckt['questions'][0][0] = pckt[
-                                    'questions'][0][0][len(self.prefix):]
-                                pckt['questions'][0][1] = 55
-
-                        if qtype == 12 and not self.disable_lsi:
-                            qname = packet['questions'][0][0]
-                            addr_str = hosts.ptr_to_addr(qname)
-                            if (addr_str is not None and
-                                hosts.valid_lsi(addr_str)):
-                                query = (packet, from_a[0], from_a[1], qname)
-                                hit_str = lsi_to_hit(addr_str)
-                                if hit_str is not None:
-                                    pckt['questions'][0][0] = \
-                                            hosts.addr_to_ptr(hit_str)
-
-                        outbuf = Serialize(pckt).get_packet()
-                        clisock.sendto(outbuf, (self.server_ip,
-                                                self.server_port))
-
-                        self.add_query(self.server_ip, self.server_port,
-                                       query_id, query)
-
-                if connected and clisock in rlist:   # Incoming DNS reply
-                    inbuf, from_a = clisock.recvfrom(2048)
-                    fout.write('Packet from DNS server %d bytes from %s\n' % (
-                        len(inbuf), from_a))
-                    packet = DeSerialize(inbuf).get_dict()
-
-                    # Find original query
-                    query_id_o = packet['id']
-                    query_o = self.find_query(from_a[0], from_a[1], query_id_o)
-                    if query_o:
-                        qname = packet['questions'][0][0]
-                        qtype = packet['questions'][0][1]
-                        send_reply = True
-                        query_again = False
-                        hit_found = False
-                        packet_o = query_o[0]
-                        # Replace with the original query id
-                        packet['id'] = packet_o['id']
-
-                        if qtype == 55 and query_o[3] in (1, 28):
-                            # Restore qtype
-                            packet['questions'][0][1] = query_o[3]
-                            self.hip_lookup(packet)
-                            if packet['ancount'] > 0:
-                                hit_found = True
-                            if (not self.prefix or
-                                (hit_found and not (self.getaaaa(qname) or
-                                                    self.geta(qname)))):
-                                query_again = True
-                                send_reply = False
-                            elif self.prefix:
-                                hit_found = True
-                                packet['questions'][0][0] = (
-                                    self.prefix + packet['questions'][0][0])
-                                for answer in packet['answers']:
-                                    answer[0] = self.prefix + answer[0]
-
-                        elif qtype in (1, 28):
-                            hit = self.getaaaa_hit(qname)
-                            ip6 = self.getaaaa(qname)
-                            ip4 = self.geta(qname)
-                            for answer in packet['answers']:
-                                if answer[1] in (1, 28):
-                                    self.cache_name(qname, answer[4],
-                                                    answer[3])
-                            if hit is not None:
-                                for answer in packet['answers']:
-                                    if (answer[1] == 1 or
-                                        (answer[1] == 28 and not
-                                         hosts.valid_hit(answer[4]))):
-                                        self.add_hit_ip_map(hit[0], answer[4])
-                                # Reply with HIT/LSI once it's been mapped to
-                                # an IP
-                                if ip6 is None and ip4 is None:
-                                    if (packet_o['ancount'] == 0 and
-                                        not self.prefix):
-                                        # No LSI available. Return IPv4
-                                        tmp = packet['answers']
-                                        packet = packet_o
-                                        packet['answers'] = tmp
-                                        packet['ancount'] = len(
-                                            packet['answers'])
-                                    else:
-                                        packet = packet_o
-                                        if self.prefix:
-                                            packet['questions'][0][0] = \
-                                                    (self.prefix +
-                                                     packet['questions'][0][0])
-                                            for answer in packet['answers']:
-                                                answer[0] = (self.prefix +
-                                                             answer[0])
-                                else:
-                                    send_reply = False
-                            elif query_o[3] == 0:
-                                # Prefix is in use
-                                # IP was queried for cache only
-                                send_reply = False
-
-                        elif qtype == 12 and isinstance(query_o[3], str):
-                            packet['questions'][0][0] = query_o[3]
-                            for answer in packet['answers']:
-                                answer[0] = query_o[3]
-
-                        if query_again:
-                            if hit_found:
-                                qtypes = [28, 1]
-                                pckt = copy.deepcopy(packet)
-                            else:
-                                qtypes = [query_o[3]]
-                                pckt = copy.copy(packet)
-                            pckt['qr'] = 0
-                            pckt['answers'] = []
-                            pckt['ancount'] = 0
-                            pckt['nslist'] = []
-                            pckt['nscount'] = 0
-                            pckt['additional'] = []
-                            pckt['arcount'] = 0
-                            for qtype in qtypes:
-                                if self.prefix:
-                                    query = (packet, query_o[1], query_o[2], 0)
-                                else:
-                                    query = (packet, query_o[1], query_o[2],
-                                             qtype)
-                                query_id = (query_id % 65535) + 1
-                                pckt['id'] = query_id
-                                pckt['questions'][0][1] = qtype
-                                outbuf = Serialize(pckt).get_packet()
-                                clisock.sendto(outbuf, (self.server_ip,
-                                                        self.server_port))
-                                self.add_query(self.server_ip,
-                                               self.server_port,
-                                               query_id, query)
-                            packet['questions'][0][1] = query_o[3]
-
-                        if send_reply:
-                            outbuf = Serialize(packet).get_packet()
-                            servsock.sendto(outbuf, (query_o[1], query_o[2]))
-            except (select.error, OSError), exc:
-                if exc[0] == errno.EINTR:
-                    pass
-                else:
-                    tbstr = traceback.format_exc()
-                    fout.write('Exception: %s\n%s\n' % (os.errno, tbstr))
-
-        fout.write('Wants down\n')
-        rc1.stop()
-
-
-def main(argv):
+
+import dnsproxy
+
+HIPHOSTS = '@sysconfdir@/hosts'
+RESOLV_CONF = '/etc/resolv.conf'
+PIDFILE = '/var/run/hipdnsproxy.pid'
+
+
+def main():
     """The main function."""
-    dnsp = DNSProxy()
-    try:
-        opts, args = getopt.getopt(argv[1:],
-                                   'bkhLf:c:H:s:p:l:i:P:',
-                                   ['background',
-                                    'kill',
-                                    'help',
-                                    'disable-lsi',
-                                    'file=',
-                                    'count=',
-                                    'hosts=',
-                                    'server=',
-                                    'serverport=',
-                                    'ip=',
-                                    'port=',
-                                    'pidfile='
-                                    'resolv-conf=',
-                                    'dns-timeout=',
-                                    'leave-resolv-conf',
-                                    'hip-domain-prefix=',
-                                    ])
-    except getopt.error, msg:
-        usage(1, msg)
-
-    for opt, arg in opts:
-        if opt in ('-k', '--kill'):
-            dnsp.kill = True
-        elif opt in ('-b', '--background'):
-            dnsp.fork = True
-        elif opt in ('-L', '--disable-lsi'):
-            dnsp.disable_lsi = True
-        elif opt in ('-f', '--file'):
-            dnsp.tarfilename = arg
-        elif opt in ('-c', '--count'):
-            dnsp.fetchcount = int(arg)
-        elif opt in ('-H', '--hosts'):
-            dnsp.hostsnames.append(arg)
-        elif opt in ('--resolv-conf',):
-            dnsp.resolv_conf = arg
-        elif opt in ('-s', '--server'):
-            dnsp.server_ip = arg
-        elif opt in ('-p', '--serverport'):
-            dnsp.server_port = int(arg)
-        elif opt in ('-i', '--ip'):
-            dnsp.bind_ip = arg
-        elif opt in ('-l', '--port'):
-            dnsp.bind_port = int(arg)
-        elif opt in ('--dns-timeout',):
-            dnsp.dns_timeout = float(arg)
-        elif opt in ('-P', '--pidfile'):
-            dnsp.pidfile = arg
-        elif opt in ('--leave-resolv-conf'):
-            dnsp.overwrite_resolv_conf = False
-        elif opt == '--hip-domain-prefix':
-            dnsp.prefix = arg + '.'
+    optparser = optparse.OptionParser()
+    optparser.add_option('-b', '--background', dest='background',
+                         action='store_true', default=False,
+                         help='Fork into background')
+    optparser.add_option('-H', '--hosts', dest='hosts', action='append',
+                         help='hosts file')
+    optparser.add_option('-i', '--ip', dest='bind_ip', action='store',
+                         default=None, help='Bind IP address')
+    optparser.add_option('-k', '--kill', dest='kill', action='store_true',
+                         default=False, help='Kill old instance')
+    optparser.add_option('-l', '--port', dest='bind_port', action='store',
+                         type='int', default=None, help='Bind port')
+    optparser.add_option('-L', '--disable-lsi', dest='disable_lsi',
+                         default=False, action='store_true',
+                         help='Disable LSI')
+    optparser.add_option('-P', '--pidfile', dest='pidfile', action='store',
+                         default=PIDFILE, help='PID file location')
+    optparser.add_option('-s', '--server', dest='server_ip', action='store',
+                         default=None, help='DNS server IP address')
+    optparser.add_option('-p', '--serverport', dest='server_port',
+                         action='store', type='int', default=None,
+                         help='DNS server port')
+    optparser.add_option('-r', '--resolv-conf', dest='resolv_conf',
+                         action='store', default=RESOLV_CONF,
+                         help='resolv.conf location')
+    optparser.add_option('-t', '--dns-timeout', dest='dns_timeout',
+                         action='store', type='float', default=2.0,
+                         help='DNS timeout')
+    optparser.add_option('-d', '--debug', dest='loglevel',
+                         action='store_const', const=logging.DEBUG,
+                         help='Debug logging')
+    optparser.add_option('-v', '--verbose', dest='loglevel',
+                         action='store_const', const=logging.INFO,
+                         help='Verbose logging')
+    optparser.add_option('-q', '--quiet', dest='loglevel',
+                         action='store_const', const=logging.ERROR,
+                         help='Less logging', default=logging.WARNING)
+    optparser.add_option('--leave-resolv-conf', dest='overwrite_rc',
+                         action='store_false', default=True,
+                         help='Leave resolv.conf')
+    optparser.add_option('--hip-hosts', dest='hiphosts', action='store',
+                         default=HIPHOSTS, help='HIP hosts file')
+    optparser.add_option('--hip-domain-prefix', dest='prefix', default=None,
+                         action='store', help='HIP domain prefix')
+
+    (options, args) = optparser.parse_args()
+
+    logging.getLogger().setLevel(options.loglevel)
+    loghandler = logging.StreamHandler(sys.stderr)
+    loghandler.setFormatter(logging.Formatter(
+        '%(asctime)s %(levelname)-8s %(message)s'))
+    logging.getLogger().addHandler(loghandler)
+
+    dnsp = dnsproxy.DNSProxy(bind_ip=options.bind_ip,
+                             bind_port=options.bind_port,
+                             disable_lsi=options.disable_lsi,
+                             dns_timeout=options.dns_timeout,
+                             fork=options.background,
+                             hiphosts=options.hiphosts,
+                             hostsnames=options.hosts,
+                             overwrite_resolv_conf=options.overwrite_rc,
+                             pidfile=options.pidfile,
+                             prefix=options.prefix,
+                             resolv_conf=options.resolv_conf,
+                             server_ip=options.server_ip,
+                             server_port=options.server_port)
 
     child = False
-    if (dnsp.fork):
+    if (options.background):
+        logging.getLogger().removeHandler(loghandler)
         child = dnsp.forkme()
 
-    if child or not dnsp.fork:
-        dnsp.rc1 = ResolvConf(dnsp)
-        if dnsp.kill:
+    if child or not options.background:
+        dnsp.rc1 = dnsproxy.ResolvConf(dnsp)
+        if options.kill:
             dnsp.killold()
-            if dnsp.overwrite_resolv_conf:
+            if options.overwrite_rc:
                 dnsp.recovery()
         dnsp.savepid()
         dnsp.mainloop(args)
 
 
 if __name__ == '__main__':
-    main(sys.argv)
+    main()

=== modified file 'tools/hipdnsproxy/util.py'
--- tools/hipdnsproxy/util.py   2012-04-23 20:14:51 +0000
+++ tools/hipdnsproxy/util.py   2012-04-28 15:51:10 +0000
@@ -28,7 +28,6 @@
 import re
 import signal
 import struct
-import time
 
 __FLAGS = {'down': False,
            'alarm': False}
@@ -63,20 +62,6 @@
     return random.random()
 
 
-def tstamp(when=None):
-    """Return a timestamp formatted as 'YYYY-MM-DD-hh.mm.ss.musmus'.
-
-    >>> tstamp(1000000000)
-    '2001-09-09-04.46.40.000000'
-    """
-    if when is None:
-        when = time.time()
-    date_time, sec_fract = [int(x) for x in ('%.6f' % when).split('.')]
-    time_st = time.localtime(date_time)
-    return '%04d-%02d-%02d-%02d.%02d.%02d.%06d' % (
-        time_st[:6] + (sec_fract,))
-
-
 def sighandler(signum, unused_frame):
     """A signal handler that toggles flags about received signals."""
     if signum == signal.SIGTERM:

Other related posts:

  • » [hipl-dev] [Branch ~hipl-core/hipl/trunk] Rev 6381: Merge lp:~ptman/hipl/tests. - noreply