BIND 10 master, updated. 7ad41d91b28fa38bfa5dc07458da24b8459fdc2a [992] ChangeLog update.

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Dec 14 11:50:27 UTC 2011


The branch, master has been updated
       via  7ad41d91b28fa38bfa5dc07458da24b8459fdc2a (commit)
       via  5749a7ada244fbb7113883b4150c94b20d20d1e6 (commit)
       via  d6e33479365c8f8f62ef2b9aa5548efe6b194601 (commit)
       via  64546f4f97bf4032f7b97f768649ba1024503fc0 (commit)
       via  d8cd199a66645341270081a7f409c557e596099b (commit)
       via  0f4dd0cf9c1ca4cc397954d639692a8946edb284 (commit)
       via  eb2e8615ae2ed35f9d70e632e970c42729853a19 (commit)
       via  ea709c77cdab1d2d91a923b913af869f865477bd (commit)
       via  7e2204f4a69fe0f1ce24ce36152577828c8ded79 (commit)
      from  53bc298c40ab5386e88d751cf4c997df7c0eec96 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 7ad41d91b28fa38bfa5dc07458da24b8459fdc2a
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Wed Dec 14 12:48:26 2011 +0100

    [992] ChangeLog update.

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |    6 +
 configure.ac                                       |    3 +
 src/bin/Makefile.am                                |    2 +-
 src/bin/dhcp4/Makefile.am                          |   42 +++++
 src/bin/{dhcp6/b10-dhcp6.8 => dhcp4/b10-dhcp4.8}   |   27 +++-
 .../{dhcp6/b10-dhcp6.xml => dhcp4/b10-dhcp4.xml}   |   16 +-
 src/bin/{dhcp6/dhcp6.spec => dhcp4/dhcp4.spec}     |    4 +-
 src/bin/dhcp4/dhcp4_srv.cc                         |  154 +++++++++++++++++++
 src/bin/dhcp4/dhcp4_srv.h                          |  137 +++++++++++++++++
 src/bin/{dhcp6 => dhcp4}/main.cc                   |   20 ++--
 src/bin/{dhcp6 => dhcp4}/spec_config.h.pre.in      |    2 +-
 src/bin/dhcp4/tests/Makefile.am                    |   46 ++++++
 src/bin/dhcp4/tests/dhcp4_srv_unittest.cc          |  161 ++++++++++++++++++++
 .../dhcp4/tests/dhcp4_unittests.cc}                |    5 +-
 src/bin/dhcp6/Makefile.am                          |    3 +-
 src/bin/dhcp6/dhcp6.spec                           |    2 +-
 src/bin/dhcp6/dhcp6_srv.cc                         |    2 +-
 src/bin/dhcp6/tests/Makefile.am                    |    4 +-
 src/lib/dhcp/Makefile.am                           |    1 +
 src/{bin/dhcp6 => lib/dhcp}/iface_mgr.cc           |    2 +-
 src/{bin/dhcp6 => lib/dhcp}/iface_mgr.h            |    3 +-
 src/lib/dhcp/pkt4.h                                |   82 +++++++++--
 src/lib/dhcp/tests/Makefile.am                     |    5 +
 .../dhcp6 => lib/dhcp}/tests/iface_mgr_unittest.cc |   17 +-
 src/lib/dhcp/tests/pkt4_unittest.cc                |   18 ++-
 25 files changed, 696 insertions(+), 68 deletions(-)
 create mode 100644 src/bin/dhcp4/Makefile.am
 copy src/bin/{dhcp6/b10-dhcp6.8 => dhcp4/b10-dhcp4.8} (55%)
 copy src/bin/{dhcp6/b10-dhcp6.xml => dhcp4/b10-dhcp4.xml} (84%)
 copy src/bin/{dhcp6/dhcp6.spec => dhcp4/dhcp4.spec} (72%)
 create mode 100644 src/bin/dhcp4/dhcp4_srv.cc
 create mode 100644 src/bin/dhcp4/dhcp4_srv.h
 copy src/bin/{dhcp6 => dhcp4}/main.cc (83%)
 copy src/bin/{dhcp6 => dhcp4}/spec_config.h.pre.in (92%)
 create mode 100644 src/bin/dhcp4/tests/Makefile.am
 create mode 100644 src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
 copy src/{lib/dhcp/tests/run_unittests.cc => bin/dhcp4/tests/dhcp4_unittests.cc} (91%)
 rename src/{bin/dhcp6 => lib/dhcp}/iface_mgr.cc (99%)
 rename src/{bin/dhcp6 => lib/dhcp}/iface_mgr.h (99%)
 rename src/{bin/dhcp6 => lib/dhcp}/tests/iface_mgr_unittest.cc (97%)

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index df5adbd..1628ba5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+345.	[func]		tomek
+	dhcp4: Dummy DHCPv4 component implemented. Currently it does
+	nothing useful, except providing skeleton implementation that can
+	be expanded in the future.
+	(Trac #992, git d6e33479365c8f8f62ef2b9aa5548efe6b194601)
+
 344.	[func]		y-aharen
 	src/lib/statistics: Added statistics counter library for entire server
 	items and per zone items. Also, modified b10-auth to use it. It is
diff --git a/configure.ac b/configure.ac
index 4c1d9cf..5dab45b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -892,6 +892,8 @@ AC_CONFIG_FILES([Makefile
                  src/bin/auth/benchmarks/Makefile
                  src/bin/dhcp6/Makefile
                  src/bin/dhcp6/tests/Makefile
+		 src/bin/dhcp4/Makefile
+		 src/bin/dhcp4/tests/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
                  src/bin/sockcreator/Makefile
@@ -1033,6 +1035,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/msgq/run_msgq.sh
            src/bin/auth/auth.spec.pre
            src/bin/auth/spec_config.h.pre
+           src/bin/dhcp4/spec_config.h.pre
            src/bin/dhcp6/spec_config.h.pre
            src/bin/tests/process_rename_test.py
            src/lib/config/tests/data_def_unittests_config.h
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index 06d8df2..ba7ae81 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -1,4 +1,4 @@
 SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout \
-	usermgr zonemgr stats tests resolver sockcreator dhcp6 
+	usermgr zonemgr stats tests resolver sockcreator dhcp6 dhcp4
 
 check-recursive: all-recursive
diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am
new file mode 100644
index 0000000..71a4531
--- /dev/null
+++ b/src/bin/dhcp4/Makefile.am
@@ -0,0 +1,42 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+
+man_MANS = b10-dhcp4.8
+EXTRA_DIST = $(man_MANS) dhcp4.spec
+
+if ENABLE_MAN
+
+b10-dhcp4.8: b10-dhcp4.xml
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-dhcp4.xml
+
+endif
+
+spec_config.h: spec_config.h.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
+
+BUILT_SOURCES = spec_config.h
+pkglibexec_PROGRAMS = b10-dhcp4
+
+b10_dhcp4_SOURCES = main.cc dhcp4_srv.cc dhcp4_srv.h
+
+b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/log/liblog.la
+
+# TODO: config.h.in is wrong because doesn't honor pkgdatadir
+# and can't use @datadir@ because doesn't expand default ${prefix}
+b10_dhcp4dir = $(pkgdatadir)
+b10_dhcp4_DATA = dhcp4.spec
+
diff --git a/src/bin/dhcp4/b10-dhcp4.8 b/src/bin/dhcp4/b10-dhcp4.8
new file mode 100644
index 0000000..97bdeb8
--- /dev/null
+++ b/src/bin/dhcp4/b10-dhcp4.8
@@ -0,0 +1,60 @@
+'\" t
+.\"     Title: b10-dhcp4
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: October 27, 2011
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-DHCP4" "8" "October 27, 2011" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-dhcp4 \- DHCPv4 server in BIND 10 architecture
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-dhcp4\fR\ 'u
+\fBb10\-dhcp4\fR [\fB\-v\fR]
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-dhcp4\fR
+daemon will provide the DHCPv4 server implementation when it becomes functional\&.
+.SH "ARGUMENTS"
+.PP
+The arguments are as follows:
+.PP
+\fB\-v\fR
+.RS 4
+Enable verbose mode\&.
+.RE
+.SH "SEE ALSO"
+.PP
+
+\fBbind10\fR(8)\&.
+.SH "HISTORY"
+.PP
+The
+\fBb10\-dhcp4\fR
+daemon was first coded in November 2011 by Tomek Mrugalski\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/dhcp4/b10-dhcp4.xml b/src/bin/dhcp4/b10-dhcp4.xml
new file mode 100644
index 0000000..370fa04
--- /dev/null
+++ b/src/bin/dhcp4/b10-dhcp4.xml
@@ -0,0 +1,98 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "—">]>
+<!--
+ - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<refentry>
+
+  <refentryinfo>
+    <date>October 27, 2011</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-dhcp4</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-dhcp4</refname>
+    <refpurpose>DHCPv4 server in BIND 10 architecture</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2011</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-dhcp4</command>
+      <arg><option>-v</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      The <command>b10-dhcp4</command> daemon will provide the
+       DHCPv4 server implementation when it becomes functional.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>ARGUMENTS</title>
+
+    <para>The arguments are as follows:</para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term><option>-v</option></term>
+        <listitem><para>
+          Enable verbose mode.
+<!-- TODO: what does this do? -->
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>b10-dhcp4</command> daemon was first coded in
+      November 2011 by Tomek Mrugalski.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/dhcp4/dhcp4.spec b/src/bin/dhcp4/dhcp4.spec
new file mode 100644
index 0000000..8061fd2
--- /dev/null
+++ b/src/bin/dhcp4/dhcp4.spec
@@ -0,0 +1,14 @@
+{
+  "module_spec": {
+    "module_name": "dhcp4",
+    "module_description": "DHCPv4 server daemon",
+    "config_data": [
+      { "item_name": "interface",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "eth0"
+      }
+    ],
+    "commands": []
+  }
+}
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
new file mode 100644
index 0000000..9686a35
--- /dev/null
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -0,0 +1,154 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcp/dhcp4.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcp4/dhcp4_srv.h>
+#include <asiolink/io_address.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
+    cout << "Initialization: opening sockets on port " << port << endl;
+
+    // first call to instance() will create IfaceMgr (it's a singleton)
+    // it may throw something if things go wrong
+    IfaceMgr::instance();
+
+    /// @todo: instantiate LeaseMgr here once it is imlpemented.
+
+    setServerID();
+
+    shutdown_ = false;
+}
+
+Dhcpv4Srv::~Dhcpv4Srv() {
+    cout << "DHCPv4 server shutdown." << endl;
+}
+
+bool
+Dhcpv4Srv::run() {
+    while (!shutdown_) {
+        boost::shared_ptr<Pkt4> query; // client's message
+        boost::shared_ptr<Pkt4> rsp;   // server's response
+
+#if 0
+        // uncomment this once ticket 1239 is merged.
+        query = IfaceMgr::instance().receive4();
+#endif
+
+        if (query) {
+            if (!query->unpack()) {
+                cout << "Failed to parse incoming packet" << endl;
+                continue;
+            }
+            switch (query->getType()) {
+            case DHCPDISCOVER:
+                rsp = processDiscover(query);
+                break;
+            case DHCPREQUEST:
+                rsp = processRequest(query);
+                break;
+            case DHCPRELEASE:
+                processRelease(query);
+                break;
+            case DHCPDECLINE:
+                processDecline(query);
+                break;
+            case DHCPINFORM:
+                processInform(query);
+                break;
+            default:
+                cout << "Unknown pkt type received:"
+                     << query->getType() << endl;
+            }
+
+            cout << "Received " << query->len() << " bytes packet type="
+                 << query->getType() << endl;
+
+            // TODO: print out received packets only if verbose (or debug)
+            // mode is enabled
+            cout << query->toText();
+
+            if (rsp) {
+                rsp->setRemoteAddr(query->getRemoteAddr());
+                rsp->setLocalAddr(query->getLocalAddr());
+                rsp->setRemotePort(DHCP4_CLIENT_PORT);
+                rsp->setLocalPort(DHCP4_SERVER_PORT);
+                rsp->setIface(query->getIface());
+                rsp->setIndex(query->getIndex());
+
+                cout << "Replying with:" << rsp->getType() << endl;
+                cout << rsp->toText();
+                cout << "----" << endl;
+                if (rsp->pack()) {
+                    cout << "Packet assembled correctly." << endl;
+                }
+#if 0
+                // uncomment this once ticket 1240 is merged.
+                IfaceMgr::instance().send4(rsp);
+#endif
+            }
+        }
+
+        // TODO add support for config session (see src/bin/auth/main.cc)
+        //      so this daemon can be controlled from bob
+    }
+
+    return (true);
+}
+
+void
+Dhcpv4Srv::setServerID() {
+    /// TODO implement this for real once interface detection (ticket 1237)
+    /// is done. Use hardcoded server-id for now.
+
+#if 0
+    // uncomment this once ticket 1350 is merged.
+    IOAddress srvId("127.0.0.1");
+    serverid_ = boost::shared_ptr<Option>(
+      new Option4AddrLst(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, srvId));
+#endif
+}
+
+boost::shared_ptr<Pkt4>
+Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
+    /// TODO: Currently implemented echo mode. Implement this for real
+    return (discover);
+}
+
+boost::shared_ptr<Pkt4>
+Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
+    /// TODO: Currently implemented echo mode. Implement this for real
+    return (request);
+}
+
+void Dhcpv4Srv::processRelease(boost::shared_ptr<Pkt4>& release) {
+    /// TODO: Implement this.
+    cout << "Received RELEASE on " << release->getIface() << " interface." << endl;
+}
+
+void Dhcpv4Srv::processDecline(boost::shared_ptr<Pkt4>& decline) {
+    /// TODO: Implement this.
+    cout << "Received DECLINE on " << decline->getIface() << " interface." << endl;
+}
+
+boost::shared_ptr<Pkt4> Dhcpv4Srv::processInform(boost::shared_ptr<Pkt4>& inform) {
+    /// TODO: Currently implemented echo mode. Implement this for real
+    return (inform);
+}
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
new file mode 100644
index 0000000..033ac5a
--- /dev/null
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -0,0 +1,137 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DHCPV4_SRV_H
+#define DHCPV4_SRV_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <dhcp/dhcp4.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/option.h>
+#include <iostream>
+
+namespace isc {
+
+namespace dhcp {
+/// @brief DHCPv4 server service.
+///
+/// This singleton class represents DHCPv4 server. It contains all
+/// top-level methods and routines necessary for server operation.
+/// In particular, it instantiates IfaceMgr, loads or generates DUID
+/// that is going to be used as server-identifier, receives incoming
+/// packets, processes them, manages leases assignment and generates
+/// appropriate responses.
+class Dhcpv4Srv : public boost::noncopyable {
+
+    public:
+    /// @brief Default constructor.
+    ///
+    /// Instantiates necessary services, required to run DHCPv6 server.
+    /// In particular, creates IfaceMgr that will be responsible for
+    /// network interaction. Will instantiate lease manager, and load
+    /// old or create new DUID. It is possible to specify alternate
+    /// port on which DHCPv4 server will listen on. That is mostly useful
+    /// for testing purposes.
+    ///
+    /// @param port specifies port number to listen on
+    Dhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT);
+
+    /// @brief Destructor. Used during DHCPv6 service shutdown.
+    ~Dhcpv4Srv();
+
+    /// @brief Main server processing loop.
+    ///
+    /// Main server processing loop. Receives incoming packets, verifies
+    /// their correctness, generates appropriate answer (if needed) and
+    /// transmits respones.
+    ///
+    /// @return true, if being shut down gracefully, fail if experienced
+    ///         critical error.
+    bool run();
+
+protected:
+    /// @brief Processes incoming DISCOVER and returns response.
+    ///
+    /// Processes received DISCOVER message and verifies that its sender
+    /// should be served. In particular, a lease is selected and sent
+    /// as an offer to a client if it should be served.
+    ///
+    /// @param solicit DISCOVER message received from client
+    ///
+    /// @return OFFER message or NULL
+    boost::shared_ptr<Pkt4>
+    processDiscover(boost::shared_ptr<Pkt4>& discover);
+
+    /// @brief Processes incoming REQUEST and returns REPLY response.
+    ///
+    /// Processes incoming REQUEST message and verifies that its sender
+    /// should be served. In particular, verifies that requested lease
+    /// is valid, not expired, not reserved, not used by other client and
+    /// that requesting client is allowed to use it.
+    ///
+    /// Returns ACK message, NACK message, or NULL
+    ///
+    /// @param request a message received from client
+    ///
+    /// @return ACK or NACK message
+    boost::shared_ptr<Pkt4> processRequest(boost::shared_ptr<Pkt4>& request);
+
+    /// @brief Stub function that will handle incoming RELEASE messages.
+    ///
+    /// In DHCPv4, server does not respond to RELEASE messages, therefore
+    /// this function does not return anything.
+    ///
+    /// @param release message received from client
+    void processRelease(boost::shared_ptr<Pkt4>& release);
+
+    /// @brief Stub function that will handle incoming DHCPDECLINE messages.
+    ///
+    /// @param decline message received from client
+    void processDecline(boost::shared_ptr<Pkt4>& decline);
+
+    /// @brief Stub function that will handle incoming INFORM messages.
+    ///
+    /// @param infRequest message received from client
+    boost::shared_ptr<Pkt4> processInform(boost::shared_ptr<Pkt4>& inform);
+
+    /// @brief Returns server-intentifier option
+    ///
+    /// @return server-id option
+    boost::shared_ptr<isc::dhcp::Option>
+    getServerID() { return serverid_; }
+
+    /// @brief Sets server-identifier.
+    ///
+    /// This method attempts to set server-identifier DUID. It tries to
+    /// load previously stored IP from configuration. If there is no previously
+    /// stored server identifier, it will pick up one address from configured
+    /// and supported network interfaces.
+    ///
+    /// @throws isc::Unexpected Failed to obtain server identifier (i.e. no
+    //          previously stored configuration and no network interfaces available)
+    void setServerID();
+
+    /// server DUID (to be sent in server-identifier option)
+    boost::shared_ptr<isc::dhcp::Option> serverid_;
+
+    /// indicates if shutdown is in progress. Setting it to true will
+    /// initiate server shutdown procedure.
+    volatile bool shutdown_;
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif // DHCP4_SRV_H
diff --git a/src/bin/dhcp4/main.cc b/src/bin/dhcp4/main.cc
new file mode 100644
index 0000000..ee40295
--- /dev/null
+++ b/src/bin/dhcp4/main.cc
@@ -0,0 +1,112 @@
+// Copyright (C) 2009-2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <cassert>
+#include <iostream>
+
+#include <exceptions/exceptions.h>
+#if 0
+// TODO cc is not used yet. It should be eventually
+#include <cc/session.h>
+#include <config/ccsession.h>
+#endif
+
+#include <util/buffer.h>
+#include <log/dummylog.h>
+
+#include <dhcp4/spec_config.h>
+#include <dhcp4/dhcp4_srv.h>
+
+using namespace std;
+using namespace isc::util;
+
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+bool verbose_mode = false;
+
+void
+usage() {
+    cerr << "Usage:  b10-dhcp4 [-v]"
+         << endl;
+    cerr << "\t-v: verbose output" << endl;
+    exit(1);
+}
+} // end of anonymous namespace
+
+int
+main(int argc, char* argv[]) {
+    int ch;
+
+    while ((ch = getopt(argc, argv, ":v")) != -1) {
+        switch (ch) {
+        case 'v':
+            verbose_mode = true;
+            isc::log::denabled = true;
+            break;
+        case ':':
+        default:
+            usage();
+        }
+    }
+
+    cout << "My pid=" << getpid() << endl;
+
+    if (argc - optind > 0) {
+        usage();
+    }
+
+    int ret = 0;
+
+    // TODO remainder of auth to dhcp4 code copy. We need to enable this in
+    //      dhcp4 eventually
+#if 0
+    Session* cc_session = NULL;
+    Session* statistics_session = NULL;
+    ModuleCCSession* config_session = NULL;
+#endif
+    try {
+        string specfile;
+        if (getenv("B10_FROM_BUILD")) {
+            specfile = string(getenv("B10_FROM_BUILD")) +
+                "/src/bin/auth/dhcp4.spec";
+        } else {
+            specfile = string(DHCP4_SPECFILE_LOCATION);
+        }
+
+        cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl;
+
+        Dhcpv4Srv* srv = new Dhcpv4Srv();
+
+        srv->run();
+
+    } catch (const std::exception& ex) {
+        cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl;
+        ret = 1;
+    }
+
+    return (ret);
+}
diff --git a/src/bin/dhcp4/spec_config.h.pre.in b/src/bin/dhcp4/spec_config.h.pre.in
new file mode 100644
index 0000000..17623ed
--- /dev/null
+++ b/src/bin/dhcp4/spec_config.h.pre.in
@@ -0,0 +1,15 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#define DHCP4_SPECFILE_LOCATION "@prefix@/share/@PACKAGE@/dhcp4.spec"
diff --git a/src/bin/dhcp4/tests/Makefile.am b/src/bin/dhcp4/tests/Makefile.am
new file mode 100644
index 0000000..5367c5c
--- /dev/null
+++ b/src/bin/dhcp4/tests/Makefile.am
@@ -0,0 +1,46 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+LIBRARY_PATH_PLACEHOLDER =
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$(abs_top_builddir)/src/lib/datasrc/.libs:$$$(ENV_LIBRARY_PATH)
+endif
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
+AM_CPPFLAGS += -I$(top_srcdir)/src/bin
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/dhcp6/tests\"
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
+CLEANFILES = $(builddir)/interfaces.txt
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+TESTS =
+if HAVE_GTEST
+
+TESTS += dhcp4_unittests
+
+dhcp4_unittests_SOURCES == ../dhcp4_srv.h ../dhcp4_srv.cc
+dhcp4_unittests_SOURCES += dhcp4_unittests.cc
+dhcp4_unittests_SOURCES += dhcp4_srv_unittest.cc
+
+dhcp4_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+dhcp4_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+dhcp4_unittests_LDADD = $(GTEST_LDADD)
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
new file mode 100644
index 0000000..c20e983
--- /dev/null
+++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <dhcp/dhcp4.h>
+#include <dhcp4/dhcp4_srv.h>
+#include <dhcp/option.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+class NakedDhcpv4Srv: public Dhcpv4Srv {
+    // "naked" DHCPv4 server, exposes internal fields
+public:
+    NakedDhcpv4Srv() { }
+
+    boost::shared_ptr<Pkt4> processDiscover(boost::shared_ptr<Pkt4>& discover) {
+        return Dhcpv4Srv::processDiscover(discover);
+    }
+    boost::shared_ptr<Pkt4> processRequest(boost::shared_ptr<Pkt4>& request) {
+        return Dhcpv4Srv::processRequest(request);
+    }
+    void processRelease(boost::shared_ptr<Pkt4>& release) {
+        return Dhcpv4Srv::processRelease(release);
+    }
+    void processDecline(boost::shared_ptr<Pkt4>& decline) {
+        Dhcpv4Srv::processDecline(decline);
+    }
+    boost::shared_ptr<Pkt4> processInform(boost::shared_ptr<Pkt4>& inform) {
+        return Dhcpv4Srv::processInform(inform);
+    }
+};
+
+class Dhcpv4SrvTest : public ::testing::Test {
+public:
+    Dhcpv4SrvTest() {
+    }
+
+    ~Dhcpv4SrvTest() {
+    };
+};
+
+TEST_F(Dhcpv4SrvTest, basic) {
+    // nothing to test. DHCPv4_srv instance is created
+    // in test fixture. It is destroyed in destructor
+
+    Dhcpv4Srv* srv = 0;
+    ASSERT_NO_THROW({
+        srv = new Dhcpv4Srv();
+    });
+
+    delete srv;
+}
+
+TEST_F(Dhcpv4SrvTest, processDiscover) {
+    NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
+
+    boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDISCOVER, 1234));
+
+    // should not throw
+    EXPECT_NO_THROW(
+        srv->processDiscover(pkt);
+    );
+
+    // should return something
+    EXPECT_TRUE(srv->processDiscover(pkt));
+
+    // TODO: Implement more reasonable tests before starting
+    // work on processSomething() method.
+    delete srv;
+}
+
+TEST_F(Dhcpv4SrvTest, processRequest) {
+    NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
+
+    boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPREQUEST, 1234));
+
+    // should not throw
+    EXPECT_NO_THROW(
+        srv->processRequest(pkt);
+    );
+
+    // should return something
+    EXPECT_TRUE(srv->processRequest(pkt));
+
+    // TODO: Implement more reasonable tests before starting
+    // work on processSomething() method.
+    delete srv;
+}
+
+TEST_F(Dhcpv4SrvTest, processRelease) {
+    NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
+
+    boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPRELEASE, 1234));
+
+    // should not throw
+    EXPECT_NO_THROW(
+        srv->processRelease(pkt);
+    );
+
+    // TODO: Implement more reasonable tests before starting
+    // work on processSomething() method.
+
+    delete srv;
+}
+
+TEST_F(Dhcpv4SrvTest, processDecline) {
+    NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
+
+    boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDECLINE, 1234));
+
+    // should not throw
+    EXPECT_NO_THROW(
+        srv->processDecline(pkt);
+    );
+
+    // TODO: Implement more reasonable tests before starting
+    // work on processSomething() method.
+    delete srv;
+}
+
+TEST_F(Dhcpv4SrvTest, processInform) {
+    NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
+
+    boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPINFORM, 1234));
+
+    // should not throw
+    EXPECT_NO_THROW(
+        srv->processInform(pkt);
+    );
+
+    // should return something
+    EXPECT_TRUE(srv->processInform(pkt));
+
+    // TODO: Implement more reasonable tests before starting
+    // work on processSomething() method.
+
+    delete srv;
+}
+
+} // end of anonymous namespace
diff --git a/src/bin/dhcp4/tests/dhcp4_unittests.cc b/src/bin/dhcp4/tests/dhcp4_unittests.cc
new file mode 100644
index 0000000..ebc72fb
--- /dev/null
+++ b/src/bin/dhcp4/tests/dhcp4_unittests.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdio.h>
+#include <gtest/gtest.h>
+#include <log/logger_support.h>
+
+int
+main(int argc, char* argv[]) {
+
+    ::testing::InitGoogleTest(&argc, argv);
+    isc::log::initLogger();
+
+    int result = RUN_ALL_TESTS();
+
+    return (result);
+}
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index b0f8cd9..7967515 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -32,8 +32,7 @@ spec_config.h: spec_config.h.pre
 BUILT_SOURCES = spec_config.h
 pkglibexec_PROGRAMS = b10-dhcp6
 
-b10_dhcp6_SOURCES = main.cc iface_mgr.cc dhcp6_srv.cc
-b10_dhcp6_SOURCES += iface_mgr.h dhcp6_srv.h
+b10_dhcp6_SOURCES = main.cc dhcp6_srv.cc dhcp6_srv.h
 
 b10_dhcp6_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
index 0e7e852..05c3529 100644
--- a/src/bin/dhcp6/dhcp6.spec
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -1,7 +1,7 @@
 {
   "module_spec": {
     "module_name": "dhcp6",
-    "module_description": "DHCPv6 daemon",
+    "module_description": "DHCPv6 server daemon",
     "config_data": [
       { "item_name": "interface",
         "item_type": "string",
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index d5a969f..6bc7194 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -14,7 +14,7 @@
 
 #include <dhcp/dhcp6.h>
 #include <dhcp/pkt6.h>
-#include <dhcp6/iface_mgr.h>
+#include <dhcp/iface_mgr.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
diff --git a/src/bin/dhcp6/iface_mgr.cc b/src/bin/dhcp6/iface_mgr.cc
deleted file mode 100644
index de2b93c..0000000
--- a/src/bin/dhcp6/iface_mgr.cc
+++ /dev/null
@@ -1,725 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <sstream>
-#include <fstream>
-#include <string.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <dhcp/dhcp6.h>
-#include <dhcp6/iface_mgr.h>
-#include <exceptions/exceptions.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-
-namespace isc {
-
-/// IfaceMgr is a singleton implementation
-IfaceMgr* IfaceMgr::instance_ = 0;
-
-void
-IfaceMgr::instanceCreate() {
-    if (instance_) {
-        // no need to do anything. Instance is already created.
-        // Who called it again anyway? Uh oh. Had to be us, as
-        // this is private method.
-        return;
-    }
-    instance_ = new IfaceMgr();
-}
-
-IfaceMgr&
-IfaceMgr::instance() {
-    if (instance_ == 0) {
-        instanceCreate();
-    }
-    return (*instance_);
-}
-
-IfaceMgr::Iface::Iface(const std::string& name, int ifindex)
-    :name_(name), ifindex_(ifindex), mac_len_(0) {
-
-    memset(mac_, 0, sizeof(mac_));
-}
-
-std::string
-IfaceMgr::Iface::getFullName() const {
-    ostringstream tmp;
-    tmp << name_ << "/" << ifindex_;
-    return (tmp.str());
-}
-
-std::string
-IfaceMgr::Iface::getPlainMac() const {
-    ostringstream tmp;
-    tmp.fill('0');
-    tmp << hex;
-    for (int i = 0; i < mac_len_; i++) {
-        tmp.width(2);
-        tmp << mac_[i];
-        if (i < mac_len_-1) {
-            tmp << ":";
-        }
-    }
-    return (tmp.str());
-}
-
-bool IfaceMgr::Iface::delAddress(const isc::asiolink::IOAddress& addr) {
-
-    // Let's delete all addresses that match. It really shouldn't matter
-    // if we delete first or all, as the OS should allow to add a single
-    // address to an interface only once. If OS allows multiple instances
-    // of the same address added, we are in deep problems anyway.
-    size_t size = addrs_.size();
-    addrs_.erase(remove(addrs_.begin(), addrs_.end(), addr), addrs_.end());
-    return (addrs_.size() < size);
-}
-
-bool IfaceMgr::Iface::delSocket(uint16_t sockfd) {
-    list<SocketInfo>::iterator sock = sockets_.begin();
-    while (sock!=sockets_.end()) {
-        if (sock->sockfd_ == sockfd) {
-            close(sockfd);
-            sockets_.erase(sock);
-            return (true); //socket found
-        }
-        ++sock;
-    }
-    return (false); // socket not found
-}
-
-IfaceMgr::IfaceMgr()
-    :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
-     control_buf_(new char[control_buf_len_])
-{
-
-    cout << "IfaceMgr initialization." << endl;
-
-    try {
-        // required for sending/receiving packets
-        // let's keep it in front, just in case someone
-        // wants to send anything during initialization
-
-        // control_buf_ = boost::scoped_array<char>();
-
-        detectIfaces();
-
-    } catch (const std::exception& ex) {
-        cout << "IfaceMgr creation failed:" << ex.what() << endl;
-
-        // TODO Uncomment this (or call LOG_FATAL) once
-        // interface detection is implemented. Otherwise
-        // it is not possible to run tests in a portable
-        // way (see detectIfaces() method).
-        // throw ex;
-    }
-}
-
-void IfaceMgr::closeSockets() {
-    for (IfaceCollection::iterator iface = ifaces_.begin();
-         iface != ifaces_.end(); ++iface) {
-
-        for (SocketCollection::iterator sock = iface->sockets_.begin();
-             sock != iface->sockets_.end(); ++sock) {
-            cout << "Closing socket " << sock->sockfd_ << endl;
-            close(sock->sockfd_);
-        }
-        iface->sockets_.clear();
-    }
-
-}
-
-IfaceMgr::~IfaceMgr() {
-    closeSockets();
-
-    // control_buf_ is deleted automatically (scoped_ptr)
-    control_buf_len_ = 0;
-}
-
-void
-IfaceMgr::detectIfaces() {
-    string ifaceName, linkLocal;
-
-    // TODO do the actual detection. Currently interface detection is faked
-    //      by reading a text file.
-
-    cout << "Interface detection is not implemented yet. "
-         << "Reading interfaces.txt file instead." << endl;
-    cout << "Please use format: interface-name link-local-address" << endl;
-
-    try {
-        ifstream interfaces("interfaces.txt");
-
-        if (!interfaces.good()) {
-            cout << "Failed to read interfaces.txt file." << endl;
-            isc_throw(Unexpected, "Failed to read interfaces.txt");
-        }
-        interfaces >> ifaceName;
-        interfaces >> linkLocal;
-
-        cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
-
-        Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
-        IOAddress addr(linkLocal);
-        iface.addAddress(addr);
-        addInterface(iface);
-        interfaces.close();
-    } catch (const std::exception& ex) {
-        // TODO: deallocate whatever memory we used
-        // not that important, since this function is going to be
-        // thrown away as soon as we get proper interface detection
-        // implemented
-
-        // TODO Do LOG_FATAL here
-        std::cerr << "Interface detection failed." << std::endl;
-        throw ex;
-    }
-}
-
-void
-IfaceMgr::openSockets(uint16_t port) {
-    int sock1, sock2;
-
-    for (IfaceCollection::iterator iface = ifaces_.begin();
-         iface != ifaces_.end(); ++iface) {
-
-        AddressCollection addrs = iface->getAddresses();
-
-        for (AddressCollection::iterator addr = addrs.begin();
-             addr != addrs.end();
-             ++addr) {
-
-            sock1 = openSocket(iface->getName(), *addr, port);
-            if (sock1 < 0) {
-                isc_throw(Unexpected, "Failed to open unicast socket on "
-                          << " interface " << iface->getFullName());
-            }
-
-            if ( !joinMcast(sock1, iface->getName(),
-                             string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
-                close(sock1);
-                isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
-                          << " multicast group.");
-            }
-
-            // this doesn't work too well on NetBSD
-            sock2 = openSocket(iface->getName(),
-                               IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
-                               port);
-            if (sock2 < 0) {
-                isc_throw(Unexpected, "Failed to open multicast socket on "
-                          << " interface " << iface->getFullName());
-                iface->delSocket(sock1); // delete previously opened socket
-            }
-        }
-    }
-}
-
-void
-IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
-    for (IfaceCollection::const_iterator iface = ifaces_.begin();
-         iface != ifaces_.end(); ++iface) {
-        out << "Detected interface " << iface->getFullName() << endl;
-        out << "  " << iface->getAddresses().size() << " addr(s):" << endl;
-        const AddressCollection addrs = iface->getAddresses();
-
-        for (AddressCollection::const_iterator addr = addrs.begin();
-             addr != addrs.end(); ++addr) {
-            out << "  " << addr->toText() << endl;
-        }
-        out << "  mac: " << iface->getPlainMac() << endl;
-    }
-}
-
-IfaceMgr::Iface*
-IfaceMgr::getIface(int ifindex) {
-    for (IfaceCollection::iterator iface = ifaces_.begin();
-         iface != ifaces_.end(); ++iface) {
-        if (iface->getIndex() == ifindex) {
-            return (&(*iface));
-        }
-    }
-
-    return (NULL); // not found
-}
-
-IfaceMgr::Iface*
-IfaceMgr::getIface(const std::string& ifname) {
-    for (IfaceCollection::iterator iface = ifaces_.begin();
-         iface != ifaces_.end(); ++iface) {
-        if (iface->getName() == ifname) {
-            return (&(*iface));
-        }
-    }
-
-    return (NULL); // not found
-}
-
-int
-IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
-                     int port) {
-    Iface* iface = getIface(ifname);
-    if (!iface) {
-        isc_throw(BadValue, "There is no " << ifname << " interface present.");
-    }
-    switch (addr.getFamily()) {
-    case AF_INET:
-        return openSocket4(*iface, addr, port);
-    case AF_INET6:
-        return openSocket6(*iface, addr, port);
-    default:
-        isc_throw(BadValue, "Failed to detect family of address: "
-                  << addr.toText());
-    }
-}
-
-int
-IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
-
-    cout << "Creating UDP4 socket on " << iface.getFullName()
-         << " " << addr.toText() << "/port=" << port << endl;
-
-    struct sockaddr_in addr4;
-    memset(&addr4, 0, sizeof(sockaddr));
-    addr4.sin_family = AF_INET;
-    addr4.sin_port = htons(port);
-    memcpy(&addr4.sin_addr, addr.getAddress().to_v4().to_bytes().data(),
-           sizeof(addr4.sin_addr));
-
-    int sock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sock < 0) {
-        isc_throw(Unexpected, "Failed to create UDP6 socket.");
-    }
-
-    if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
-        close(sock);
-        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
-                  << "/port=" << port);
-    }
-
-    // If there is no support for IP_PKTINFO, we are really out of luck.
-    // It will be difficult to understand, where this packet came from.
-#if defined(IP_PKTINFO)
-    int flag = 1;
-    if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
-        close(sock);
-        isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
-    }
-#endif
-
-    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
-        addr.toText() << "/port=" << port << endl;
-
-    iface.addSocket(SocketInfo(sock, addr, port));
-
-    return (sock);
-}
-
-int
-IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
-
-    cout << "Creating UDP6 socket on " << iface.getFullName()
-         << " " << addr.toText() << "/port=" << port << endl;
-
-    struct sockaddr_in6 addr6;
-    memset(&addr6, 0, sizeof(addr6));
-    addr6.sin6_family = AF_INET6;
-    addr6.sin6_port = htons(port);
-    if (addr.toText() != "::1")
-      addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str());
-
-    memcpy(&addr6.sin6_addr,
-           addr.getAddress().to_v6().to_bytes().data(),
-           sizeof(addr6.sin6_addr));
-#ifdef HAVE_SA_LEN
-    addr6->sin6_len = sizeof(addr6);
-#endif
-
-    // TODO: use sockcreator once it becomes available
-
-    // make a socket
-    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
-    if (sock < 0) {
-        isc_throw(Unexpected, "Failed to create UDP6 socket.");
-    }
-
-    // Set the REUSEADDR option so that we don't fail to start if
-    // we're being restarted.
-    int flag = 1;
-    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-                   (char *)&flag, sizeof(flag)) < 0) {
-        close(sock);
-        isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
-    }
-
-    if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
-        close(sock);
-        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
-                  << "/port=" << port);
-    }
-#ifdef IPV6_RECVPKTINFO
-    // RFC3542 - a new way
-    if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
-                   &flag, sizeof(flag)) != 0) {
-        close(sock);
-        isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
-    }
-#else
-    // RFC2292 - an old way
-    if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
-                   &flag, sizeof(flag)) != 0) {
-        close(sock);
-        isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
-    }
-#endif
-
-    // multicast stuff
-    if (addr.getAddress().to_v6().is_multicast()) {
-        // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
-        // are link and site-scoped, so there is no sense to join those groups
-        // with global addresses.
-
-        if ( !joinMcast( sock, iface.getName(),
-                         string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
-            close(sock);
-            isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
-                      << " multicast group.");
-        }
-    }
-
-    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
-        addr.toText() << "/port=" << port << endl;
-
-    iface.addSocket(SocketInfo(sock, addr, port));
-
-    return (sock);
-}
-
-bool
-IfaceMgr::joinMcast(int sock, const std::string& ifname,
-const std::string & mcast) {
-
-    struct ipv6_mreq mreq;
-
-    if (inet_pton(AF_INET6, mcast.c_str(),
-                  &mreq.ipv6mr_multiaddr) <= 0) {
-        cout << "Failed to convert " << ifname
-             << " to IPv6 multicast address." << endl;
-        return (false);
-    }
-
-    mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
-    if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
-                   &mreq, sizeof(mreq)) < 0) {
-        cout << "Failed to join " << mcast << " multicast group." << endl;
-        return (false);
-    }
-
-    cout << "Joined multicast " << mcast << " group." << endl;
-
-    return (true);
-}
-
-bool
-IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
-    struct msghdr m;
-    struct iovec v;
-    int result;
-    struct in6_pktinfo *pktinfo;
-    struct cmsghdr *cmsg;
-
-    Iface* iface = getIface(pkt->iface_);
-    if (!iface) {
-        isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
-                  << pkt->iface_ << ") specified.");
-    }
-
-    memset(&control_buf_[0], 0, control_buf_len_);
-
-    // Initialize our message header structure.
-    memset(&m, 0, sizeof(m));
-
-    // Set the target address we're sending to.
-    sockaddr_in6 to;
-    memset(&to, 0, sizeof(to));
-    to.sin6_family = AF_INET6;
-    to.sin6_port = htons(pkt->remote_port_);
-    memcpy(&to.sin6_addr,
-           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
-           16);
-    to.sin6_scope_id = pkt->ifindex_;
-
-    m.msg_name = &to;
-    m.msg_namelen = sizeof(to);
-
-    // Set the data buffer we're sending. (Using this wacky
-    // "scatter-gather" stuff... we only have a single chunk
-    // of data to send, so we declare a single vector entry.)
-    v.iov_base = (char *) &pkt->data_[0];
-    v.iov_len = pkt->data_len_;
-    m.msg_iov = &v;
-    m.msg_iovlen = 1;
-
-    // Setting the interface is a bit more involved.
-    //
-    // We have to create a "control message", and set that to
-    // define the IPv6 packet information. We could set the
-    // source address if we wanted, but we can safely let the
-    // kernel decide what that should be.
-    m.msg_control = &control_buf_[0];
-    m.msg_controllen = control_buf_len_;
-    cmsg = CMSG_FIRSTHDR(&m);
-    cmsg->cmsg_level = IPPROTO_IPV6;
-    cmsg->cmsg_type = IPV6_PKTINFO;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
-    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
-    memset(pktinfo, 0, sizeof(*pktinfo));
-    pktinfo->ipi6_ifindex = pkt->ifindex_;
-    m.msg_controllen = cmsg->cmsg_len;
-
-    result = sendmsg(getSocket(*pkt), &m, 0);
-    if (result < 0) {
-        cout << "Send packet failed." << endl;
-    }
-    cout << "Sent " << pkt->data_len_ << " bytes over socket " << getSocket(*pkt)
-         << " on " << iface->getFullName() << " interface: "
-         << " dst=" << pkt->remote_addr_.toText()
-         << ", src=" << pkt->local_addr_.toText()
-         << endl;
-
-    return (result);
-}
-
-bool
-IfaceMgr::send(boost::shared_ptr<Pkt4>& )
-{
-    /// TODO: Implement this (ticket #1240)
-    isc_throw(NotImplemented, "Pkt4 send not implemented yet.");
-}
-
-
-boost::shared_ptr<Pkt4>
-IfaceMgr::receive4() {
-    isc_throw(NotImplemented, "Pkt4 reception not implemented yet.");
-
-    // TODO: To be implemented (ticket #1239)
-    return (boost::shared_ptr<Pkt4>()); // NULL
-}
-
-boost::shared_ptr<Pkt6>
-IfaceMgr::receive6() {
-    struct msghdr m;
-    struct iovec v;
-    int result;
-    struct cmsghdr* cmsg;
-    struct in6_pktinfo* pktinfo;
-    struct sockaddr_in6 from;
-    struct in6_addr to_addr;
-    boost::shared_ptr<Pkt6> pkt;
-    char addr_str[INET6_ADDRSTRLEN];
-
-    try {
-        // RFC3315 states that server responses may be
-        // fragmented if they are over MTU. There is no
-        // text whether client's packets may be larger
-        // than 1500. Nevertheless to be on the safe side
-        // we use larger buffer. This buffer limit is checked
-        // during reception (see iov_len below), so we are
-        // safe
-        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
-    } catch (const std::exception& ex) {
-        cout << "Failed to create new packet." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
-
-    memset(&control_buf_[0], 0, control_buf_len_);
-
-    memset(&from, 0, sizeof(from));
-    memset(&to_addr, 0, sizeof(to_addr));
-
-    // Initialize our message header structure.
-    memset(&m, 0, sizeof(m));
-
-    // Point so we can get the from address.
-    m.msg_name = &from;
-    m.msg_namelen = sizeof(from);
-
-    // Set the data buffer we're receiving. (Using this wacky
-    // "scatter-gather" stuff... but we that doesn't really make
-    // sense for us, so we use a single vector entry.)
-    v.iov_base = (void*)&pkt->data_[0];
-    v.iov_len = pkt->data_len_;
-    m.msg_iov = &v;
-    m.msg_iovlen = 1;
-
-    // Getting the interface is a bit more involved.
-    //
-    // We set up some space for a "control message". We have
-    // previously asked the kernel to give us packet
-    // information (when we initialized the interface), so we
-    // should get the destination address from that.
-    m.msg_control = &control_buf_[0];
-    m.msg_controllen = control_buf_len_;
-
-    /// TODO: Need to move to select() and pool over
-    /// all available sockets. For now, we just take the
-    /// first interface and use first socket from it.
-    IfaceCollection::const_iterator iface = ifaces_.begin();
-    if (iface == ifaces_.end()) {
-        isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
-    }
-    SocketCollection::const_iterator s = iface->sockets_.begin();
-    const SocketInfo* candidate = 0;
-    while (s != iface->sockets_.end()) {
-        if (s->addr_.getAddress().to_v6().is_multicast()) {
-            candidate = &(*s);
-            break;
-        }
-        if (!candidate) {
-            candidate = &(*s); // it's not multicast, but it's better than none
-        }
-        ++s;
-    }
-    if (!candidate) {
-        isc_throw(Unexpected, "Interface " << iface->getFullName()
-                  << " does not have any sockets open.");
-    }
-
-    cout << "Trying to receive over socket " << candidate->sockfd_ << " bound to "
-         << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
-         << iface->getFullName() << endl;
-    result = recvmsg(candidate->sockfd_, &m, 0);
-
-    if (result >= 0) {
-        // If we did read successfully, then we need to loop
-        // through the control messages we received and
-        // find the one with our destination address.
-        //
-        // We also keep a flag to see if we found it. If we
-        // didn't, then we consider this to be an error.
-        int found_pktinfo = 0;
-        cmsg = CMSG_FIRSTHDR(&m);
-        while (cmsg != NULL) {
-            if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
-                (cmsg->cmsg_type == IPV6_PKTINFO)) {
-                pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
-                to_addr = pktinfo->ipi6_addr;
-                pkt->ifindex_ = pktinfo->ipi6_ifindex;
-                found_pktinfo = 1;
-            }
-            cmsg = CMSG_NXTHDR(&m, cmsg);
-        }
-        if (!found_pktinfo) {
-            cout << "Unable to find pktinfo" << endl;
-            return (boost::shared_ptr<Pkt6>()); // NULL
-        }
-    } else {
-        cout << "Failed to receive data." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
-
-    // That's ugly.
-    // TODO add IOAddress constructor that will take struct in6_addr*
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
-    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
-    pkt->local_addr_ = IOAddress(string(addr_str));
-
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
-    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
-    pkt->remote_addr_ = IOAddress(string(addr_str));
-
-    pkt->remote_port_ = ntohs(from.sin6_port);
-
-    Iface* received = getIface(pkt->ifindex_);
-    if (received) {
-        pkt->iface_ = received->getName();
-    } else {
-        cout << "Received packet over unknown interface (ifindex="
-             << pkt->ifindex_ << ")." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
-
-    pkt->data_len_ = result;
-
-    // TODO Move this to LOG_DEBUG
-    cout << "Received " << pkt->data_len_ << " bytes over "
-         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
-         << " src=" << pkt->remote_addr_.toText()
-         << ", dst=" << pkt->local_addr_.toText()
-         << endl;
-
-    return (pkt);
-}
-
-uint16_t
-IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
-    Iface* iface = getIface(pkt.iface_);
-    if (!iface) {
-        isc_throw(BadValue, "Tried to find socket for non-existent interface "
-                  << pkt.iface_);
-    }
-
-    SocketCollection::const_iterator s;
-    for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
-        if (s->family_ != AF_INET6) {
-            // don't use IPv4 sockets
-            continue;
-        }
-        if (s->addr_.getAddress().to_v6().is_multicast()) {
-            // don't use IPv6 sockets bound to multicast address
-            continue;
-        }
-        /// TODO: Add more checks here later. If remote address is
-        /// not link-local, we can't use link local bound socket
-        /// to send data.
-
-        return (s->sockfd_);
-    }
-
-    isc_throw(Unexpected, "Interface " << iface->getFullName()
-              << " does not have any suitable IPv6 sockets open.");
-}
-
-uint16_t
-IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
-    Iface* iface = getIface(pkt.getIface());
-    if (!iface) {
-        isc_throw(BadValue, "Tried to find socket for non-existent interface "
-                  << pkt.getIface());
-    }
-
-    SocketCollection::const_iterator s;
-    for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
-        if (s->family_ != AF_INET) {
-            // don't use IPv4 sockets
-            continue;
-        }
-        /// TODO: Add more checks here later. If remote address is
-        /// not link-local, we can't use link local bound socket
-        /// to send data.
-
-        return (s->sockfd_);
-    }
-
-    isc_throw(Unexpected, "Interface " << iface->getFullName()
-              << " does not have any suitable IPv4 sockets open.");
-}
-
-
-
-}
diff --git a/src/bin/dhcp6/iface_mgr.h b/src/bin/dhcp6/iface_mgr.h
deleted file mode 100644
index 0aa2592..0000000
--- a/src/bin/dhcp6/iface_mgr.h
+++ /dev/null
@@ -1,414 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef IFACE_MGR_H
-#define IFACE_MGR_H
-
-#include <list>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_array.hpp>
-#include <boost/noncopyable.hpp>
-#include <asiolink/io_address.h>
-#include <dhcp/pkt4.h>
-#include <dhcp/pkt6.h>
-
-namespace isc {
-
-namespace dhcp {
-/// @brief handles network interfaces, transmission and reception
-///
-/// IfaceMgr is an interface manager class that detects available network
-/// interfaces, configured addresses, link-local addresses, and provides
-/// API for using sockets.
-///
-class IfaceMgr : public boost::noncopyable {
-public:
-    /// type that defines list of addresses
-    typedef std::vector<isc::asiolink::IOAddress> AddressCollection;
-
-    /// maximum MAC address length (Infiniband uses 20 bytes)
-    static const unsigned int MAX_MAC_LEN = 20;
-
-    /// Holds information about socket.
-    struct SocketInfo {
-        uint16_t sockfd_; /// socket descriptor
-        isc::asiolink::IOAddress addr_; /// bound address
-        uint16_t port_;   /// socket port
-        uint16_t family_; /// IPv4 or IPv6
-
-        /// @brief SocketInfo constructor.
-        ///
-        /// @param sockfd socket descriptor
-        /// @param addr an address the socket is bound to
-        /// @param port a port the socket is bound to
-        SocketInfo(uint16_t sockfd, const isc::asiolink::IOAddress& addr,
-                   uint16_t port)
-        :sockfd_(sockfd), addr_(addr), port_(port), family_(addr.getFamily()) { }
-    };
-
-    /// type that holds a list of socket informations
-    typedef std::list<SocketInfo> SocketCollection;
-
-    /// @brief represents a single network interface
-    ///
-    /// Iface structure represents network interface with all useful
-    /// information, like name, interface index, MAC address and
-    /// list of assigned addresses
-    class Iface {
-    public:
-        /// @brief Iface constructor.
-        ///
-        /// Creates Iface object that represents network interface.
-        ///
-        /// @param name name of the interface
-        /// @param ifindex interface index (unique integer identifier)
-        Iface(const std::string& name, int ifindex);
-
-        /// @brief Returns full interface name as "ifname/ifindex" string.
-        ///
-        /// @return string with interface name
-        std::string getFullName() const;
-
-        /// @brief Returns link-layer address a plain text.
-        ///
-        /// @return MAC address as a plain text (string)
-        std::string getPlainMac() const;
-
-        /// @brief Returns interface index.
-        ///
-        /// @return interface index
-        uint16_t getIndex() const { return ifindex_; }
-
-        /// @brief Returns interface name.
-        ///
-        /// @return interface name
-        std::string getName() const { return name_; };
-
-        /// @brief Returns all interfaces available on an interface.
-        ///
-        /// Care should be taken to not use this collection after Iface object
-        /// ceases to exist. That is easy in most cases as Iface objects are
-        /// created by IfaceMgr that is a singleton an is expected to be
-        /// available at all time. We may revisit this if we ever decide to
-        /// implement dynamic interface detection, but such fancy feature would
-        /// mostly be useful for clients with wifi/vpn/virtual interfaces.
-        ///
-        /// @return collection of addresses
-        const AddressCollection& getAddresses() const { return addrs_; }
-
-        /// @brief Adds an address to an interface.
-        ///
-        /// This only adds an address to collection, it does not physically
-        /// configure address on actual network interface.
-        ///
-        /// @param addr address to be added
-        void addAddress(const isc::asiolink::IOAddress& addr) {
-            addrs_.push_back(addr);
-        }
-
-        /// @brief Deletes an address from an interface.
-        ///
-        /// This only deletes address from collection, it does not physically
-        /// remove address configuration from actual network interface.
-        ///
-        /// @param addr address to be removed.
-        ///
-        /// @return true if removal was successful (address was in collection),
-        ///         false otherwise
-        bool delAddress(const isc::asiolink::IOAddress& addr);
-
-        /// @brief Adds socket descriptor to an interface.
-        ///
-        /// @param socket SocketInfo structure that describes socket.
-        void addSocket(const SocketInfo& sock)
-            { sockets_.push_back(sock); }
-
-        /// @brief Closes socket.
-        ///
-        /// Closes socket and removes corresponding SocketInfo structure
-        /// from an interface.
-        ///
-        /// @param socket descriptor to be closed/removed.
-        /// @return true if there was such socket, false otherwise
-        bool delSocket(uint16_t sockfd);
-
-        /// socket used to sending data
-        /// TODO: this should be protected
-        SocketCollection sockets_;
-
-    protected:
-        /// network interface name
-        std::string name_;
-
-        /// interface index (a value that uniquely indentifies an interface)
-        int ifindex_;
-
-        /// list of assigned addresses
-        AddressCollection addrs_;
-
-        /// link-layer address
-        uint8_t mac_[MAX_MAC_LEN];
-
-        /// length of link-layer address (usually 6)
-        int mac_len_;
-    };
-
-    // TODO performance improvement: we may change this into
-    //      2 maps (ifindex-indexed and name-indexed) and
-    //      also hide it (make it public make tests easier for now)
-
-    /// type that holds a list of interfaces
-    typedef std::list<Iface> IfaceCollection;
-
-    /// IfaceMgr is a singleton class. This method returns reference
-    /// to its sole instance.
-    ///
-    /// @return the only existing instance of interface manager
-    static IfaceMgr& instance();
-
-    /// @brief Returns interface with specified interface index
-    ///
-    /// @param ifindex index of searched interface
-    ///
-    /// @return interface with requested index (or NULL if no such
-    ///         interface is present)
-    ///
-    Iface*
-    getIface(int ifindex);
-
-    /// @brief Returns interface with specified interface name
-    ///
-    /// @param ifname name of searched interface
-    ///
-    /// @return interface with requested name (or NULL if no such
-    ///         interface is present)
-    ///
-    Iface*
-    getIface(const std::string& ifname);
-
-    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
-    ///
-    /// This method takes Pkt6 (see overloaded implementation that takes
-    /// Pkt4) and chooses appropriate socket to send it. This method
-    /// may throw BadValue if specified packet does not have outbound
-    /// interface specified, no such interface exists, or specified
-    /// interface does not have any appropriate sockets open.
-    ///
-    /// @param pkt a packet to be transmitted
-    ///
-    /// @return a socket descriptor
-    uint16_t getSocket(const isc::dhcp::Pkt6& pkt);
-
-    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
-    ///
-    /// This method takes Pkt4 (see overloaded implementation that takes
-    /// Pkt6) and chooses appropriate socket to send it. This method
-    /// may throw BadValue if specified packet does not have outbound
-    /// interface specified, no such interface exists, or specified
-    /// interface does not have any appropriate sockets open.
-    ///
-    /// @param pkt a packet to be transmitted
-    ///
-    /// @return a socket descriptor
-    uint16_t getSocket(const isc::dhcp::Pkt4& pkt);
-
-    /// debugging method that prints out all available interfaces
-    ///
-    /// @param out specifies stream to print list of interfaces to
-    void
-    printIfaces(std::ostream& out = std::cout);
-
-    /// @brief Sends an IPv6 packet.
-    ///
-    /// Sends an IPv6 packet. All parameters for actual transmission are specified in
-    /// Pkt6 structure itself. That includes destination address, src/dst port
-    /// and interface over which data will be sent.
-    ///
-    /// @param pkt packet to be sent
-    ///
-    /// @return true if sending was successful
-    bool send(boost::shared_ptr<Pkt6>& pkt);
-
-    /// @brief Sends an IPv4 packet.
-    ///
-    /// Sends an IPv4 packet. All parameters for actual transmission are specified
-    /// in Pkt4 structure itself. That includes destination address, src/dst
-    /// port and interface over which data will be sent.
-    ///
-    /// @param pkt a packet to be sent
-    ///
-    /// @return true if sending was successful
-    bool send(boost::shared_ptr<Pkt4>& pkt);
-
-    /// @brief Tries to receive IPv6 packet over open IPv6 sockets.
-    ///
-    /// Attempts to receive a single IPv6 packet of any of the open IPv6 sockets.
-    /// If reception is successful and all information about its sender
-    /// are obtained, Pkt6 object is created and returned.
-    ///
-    /// TODO Start using select() and add timeout to be able
-    /// to not wait infinitely, but rather do something useful
-    /// (e.g. remove expired leases)
-    ///
-    /// @return Pkt6 object representing received packet (or NULL)
-    boost::shared_ptr<Pkt6> receive6();
-
-    /// @brief Tries to receive IPv4 packet over open IPv4 sockets.
-    ///
-    /// Attempts to receive a single IPv4 packet of any of the open IPv4 sockets.
-    /// If reception is successful and all information about its sender
-    /// are obtained, Pkt4 object is created and returned.
-    ///
-    /// TODO Start using select() and add timeout to be able
-    /// to not wait infinitely, but rather do something useful
-    /// (e.g. remove expired leases)
-    ///
-    /// @return Pkt4 object representing received packet (or NULL)
-    boost::shared_ptr<Pkt4> receive4();
-
-    /// Opens UDP/IP socket and binds it to address, interface and port.
-    ///
-    /// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr
-    /// family.
-    ///
-    /// @param ifname name of the interface
-    /// @param addr address to be bound.
-    /// @param port UDP port.
-    ///
-    /// Method will throw if socket creation, socket binding or multicast
-    /// join fails.
-    ///
-    /// @return socket descriptor, if socket creation, binding and multicast
-    /// group join were all successful.
-    int openSocket(const std::string& ifname,
-                   const isc::asiolink::IOAddress& addr, int port);
-
-    /// Opens IPv6 sockets on detected interfaces.
-    ///
-    /// Will throw exception if socket creation fails.
-    ///
-    /// @param port specifies port number (usually DHCP6_SERVER_PORT)
-    void openSockets(uint16_t port);
-
-
-    /// @brief Closes all open sockets.
-    /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
-    void closeSockets();
-
-    // don't use private, we need derived classes in tests
-protected:
-
-    /// @brief Protected constructor.
-    ///
-    /// Protected constructor. This is a singleton class. We don't want
-    /// anyone to create instances of IfaceMgr. Use instance() method instead.
-    IfaceMgr();
-
-    ~IfaceMgr();
-
-    /// @brief Opens IPv4 socket.
-    ///
-    /// Please do not use this method directly. Use openSocket instead.
-    ///
-    /// This method may throw exception if socket creation fails.
-    ///
-    /// @param iface reference to interface structure.
-    /// @param addr an address the created socket should be bound to
-    /// @param port a port that created socket should be bound to
-    ///
-    /// @return socket descriptor
-    int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
-
-    /// @brief Opens IPv6 socket.
-    ///
-    /// Please do not use this method directly. Use openSocket instead.
-    ///
-    /// This method may throw exception if socket creation fails.
-    ///
-    /// @param iface reference to interface structure.
-    /// @param addr an address the created socket should be bound to
-    /// @param port a port that created socket should be bound to
-    ///
-    /// @return socket descriptor
-    int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
-
-    /// @brief Adds an interface to list of known interfaces.
-    ///
-    /// @param iface reference to Iface object.
-    void addInterface(const Iface& iface) {
-        ifaces_.push_back(iface);
-    }
-
-    /// @brief Detects network interfaces.
-    ///
-    /// This method will eventually detect available interfaces. For now
-    /// it offers stub implementation. First interface name and link-local
-    /// IPv6 address is read from intefaces.txt file.
-    void
-    detectIfaces();
-
-    // TODO: having 2 maps (ifindex->iface and ifname->iface would)
-    //      probably be better for performance reasons
-
-    /// List of available interfaces
-    IfaceCollection ifaces_;
-
-    /// a pointer to a sole instance of this class (a singleton)
-    static IfaceMgr * instance_;
-
-    // TODO: Also keep this interface on Iface once interface detection
-    // is implemented. We may need it e.g. to close all sockets on
-    // specific interface
-    //int recvsock_; // TODO: should be fd_set eventually, but we have only
-    //int sendsock_; // 2 sockets for now. Will do for until next release
-
-    // we can't use the same socket, as receiving socket
-    // is bound to multicast address. And we all know what happens
-    // to people who try to use multicast as source address.
-
-    /// length of the control_buf_ array
-    int control_buf_len_;
-
-    /// control-buffer, used in transmission and reception
-    boost::scoped_array<char> control_buf_;
-
-private:
-
-    /// creates a single instance of this class (a singleton implementation)
-    static void
-    instanceCreate();
-
-    /// @brief Joins IPv6 multicast group on a socket.
-    ///
-    /// Socket must be created and bound to an address. Note that this
-    /// address is different than the multicast address. For example DHCPv6
-    /// server should bind its socket to link-local address (fe80::1234...)
-    /// and later join ff02::1:2 multicast group.
-    ///
-    /// @param sock socket fd (socket must be bound)
-    /// @param ifname interface name (for link-scoped multicast groups)
-    /// @param mcast multicast address to join (e.g. "ff02::1:2")
-    ///
-    /// @return true if multicast join was successful
-    ///
-    bool
-    joinMcast(int sock, const std::string& ifname,
-              const std::string& mcast);
-
-};
-
-}; // namespace isc::dhcp
-}; // namespace isc
-
-#endif
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index f37194c..de0256c 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -43,10 +43,8 @@ if HAVE_GTEST
 
 TESTS += dhcp6_unittests
 
-dhcp6_unittests_SOURCES = ../iface_mgr.h ../iface_mgr.cc
-dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc
+dhcp6_unittests_SOURCES = ../dhcp6_srv.h ../dhcp6_srv.cc
 dhcp6_unittests_SOURCES += dhcp6_unittests.cc
-dhcp6_unittests_SOURCES += iface_mgr_unittest.cc
 dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
 
 dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/bin/dhcp6/tests/iface_mgr_unittest.cc b/src/bin/dhcp6/tests/iface_mgr_unittest.cc
deleted file mode 100644
index 0c54780..0000000
--- a/src/bin/dhcp6/tests/iface_mgr_unittest.cc
+++ /dev/null
@@ -1,518 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <fstream>
-#include <sstream>
-
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-
-#include <asiolink/io_address.h>
-#include <dhcp/pkt6.h>
-#include <dhcp6/iface_mgr.h>
-#include <dhcp/dhcp4.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-
-// name of loopback interface detection
-char LOOPBACK[32] = "lo";
-
-namespace {
-const char* const INTERFACE_FILE = TEST_DATA_BUILDDIR "/interfaces.txt";
-
-class NakedIfaceMgr: public IfaceMgr {
-    // "naked" Interface Manager, exposes internal fields
-public:
-    NakedIfaceMgr() { }
-    IfaceCollection & getIfacesLst() { return ifaces_; }
-};
-
-// dummy class for now, but this will be expanded when needed
-class IfaceMgrTest : public ::testing::Test {
-public:
-    IfaceMgrTest() {
-    }
-
-    void createLoInterfacesTxt() {
-        unlink(INTERFACE_FILE);
-        fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
-        fakeifaces << LOOPBACK << " ::1";
-        fakeifaces.close();
-    }
-};
-
-// We need some known interface to work reliably. Loopback interface
-// is named lo on Linux and lo0 on BSD boxes. We need to find out
-// which is available. This is not a real test, but rather a workaround
-// that will go away when interface detection is implemented.
-
-// NOTE: At this stage of development, write access to current directory
-// during running tests is required.
-TEST_F(IfaceMgrTest, loDetect) {
-
-    // poor man's interface detection
-    // it will go away as soon as proper interface detection
-    // is implemented
-    if (if_nametoindex("lo")>0) {
-        cout << "This is Linux, using lo as loopback." << endl;
-        sprintf(LOOPBACK, "lo");
-    } else if (if_nametoindex("lo0")>0) {
-        cout << "This is BSD, using lo0 as loopback." << endl;
-        sprintf(LOOPBACK, "lo0");
-    } else {
-        cout << "Failed to detect loopback interface. Neither "
-             << "lo or lo0 worked. I give up." << endl;
-        ASSERT_TRUE(false);
-    }
-}
-
-// uncomment this test to create packet writer. It will
-// write incoming DHCPv6 packets as C arrays. That is useful
-// for generating test sequences based on actual traffic
-//
-// TODO: this potentially should be moved to a separate tool
-//
-
-#if 0
-TEST_F(IfaceMgrTest, dhcp6Sniffer) {
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-
-    unlink("interfaces.txt");
-
-    ofstream interfaces("interfaces.txt", ios::ate);
-    interfaces << "eth0 fe80::21e:8cff:fe9b:7349";
-    interfaces.close();
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    Pkt6 * pkt = 0;
-    int cnt = 0;
-    cout << "---8X-----------------------------------------" << endl;
-    while (true) {
-        pkt = ifacemgr->receive();
-
-        cout << "// this code is autogenerated. Do NOT edit." << endl;
-        cout << "// Received " << pkt->data_len_ << " bytes packet:" << endl;
-        cout << "Pkt6 *capture" << cnt++ << "() {" << endl;
-        cout << "    Pkt6* pkt;" << endl;
-        cout << "    pkt = new Pkt6(" << pkt->data_len_ << ");" << endl;
-        cout << "    pkt->remote_port_ = " << pkt-> remote_port_ << ";" << endl;
-        cout << "    pkt->remote_addr_ = IOAddress(\""
-             << pkt->remote_addr_.toText() << "\");" << endl;
-        cout << "    pkt->local_port_ = " << pkt-> local_port_ << ";" << endl;
-        cout << "    pkt->local_addr_ = IOAddress(\""
-             << pkt->local_addr_.toText() << "\");" << endl;
-        cout << "    pkt->ifindex_ = " << pkt->ifindex_ << ";" << endl;
-        cout << "    pkt->iface_ = \"" << pkt->iface_ << "\";" << endl;
-
-        // TODO it is better to declare an array and then memcpy it to
-        // packet.
-        for (int i=0; i< pkt->data_len_; i++) {
-            cout << "    pkt->data_[" << i << "]="
-                 << (int)(unsigned char)pkt->data_[i] << "; ";
-            if (!(i%4))
-                cout << endl;
-        }
-        cout << endl;
-        cout << "    return (pkt);" << endl;
-        cout << "}" << endl << endl;
-
-        delete pkt;
-    }
-    cout << "---8X-----------------------------------------" << endl;
-
-    // never happens. Infinite loop is infinite
-    delete pkt;
-    delete ifacemgr;
-}
-#endif
-
-TEST_F(IfaceMgrTest, basic) {
-    // checks that IfaceManager can be instantiated
-
-    IfaceMgr & ifacemgr = IfaceMgr::instance();
-    ASSERT_TRUE(&ifacemgr != 0);
-}
-
-TEST_F(IfaceMgrTest, ifaceClass) {
-    // basic tests for Iface inner class
-
-    IfaceMgr::Iface * iface = new IfaceMgr::Iface("eth5", 7);
-
-    EXPECT_STREQ("eth5/7", iface->getFullName().c_str());
-
-    delete iface;
-
-}
-
-// TODO: Implement getPlainMac() test as soon as interface detection
-// is implemented.
-TEST_F(IfaceMgrTest, getIface) {
-
-    cout << "Interface checks. Please ignore socket binding errors." << endl;
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    // interface name, ifindex
-    IfaceMgr::Iface iface1("lo1", 1);
-    IfaceMgr::Iface iface2("eth5", 2);
-    IfaceMgr::Iface iface3("en3", 5);
-    IfaceMgr::Iface iface4("e1000g0", 3);
-
-    // note: real interfaces may be detected as well
-    ifacemgr->getIfacesLst().push_back(iface1);
-    ifacemgr->getIfacesLst().push_back(iface2);
-    ifacemgr->getIfacesLst().push_back(iface3);
-    ifacemgr->getIfacesLst().push_back(iface4);
-
-    cout << "There are " << ifacemgr->getIfacesLst().size()
-         << " interfaces." << endl;
-    for (IfaceMgr::IfaceCollection::iterator iface=ifacemgr->getIfacesLst().begin();
-         iface != ifacemgr->getIfacesLst().end();
-         ++iface) {
-        cout << "  " << iface->getFullName() << endl;
-    }
-
-
-    // check that interface can be retrieved by ifindex
-    IfaceMgr::Iface * tmp = ifacemgr->getIface(5);
-    // ASSERT_NE(NULL, tmp); is not supported. hmmmm.
-    ASSERT_TRUE( tmp != NULL );
-
-    EXPECT_EQ( "en3", tmp->getName() );
-    EXPECT_EQ(5, tmp->getIndex());
-
-    // check that interface can be retrieved by name
-    tmp = ifacemgr->getIface("lo1");
-    ASSERT_TRUE( tmp != NULL );
-
-    EXPECT_EQ( "lo1", tmp->getName() );
-    EXPECT_EQ(1, tmp->getIndex());
-
-    // check that non-existing interfaces are not returned
-    EXPECT_EQ(static_cast<void*>(NULL), ifacemgr->getIface("wifi0") );
-
-    delete ifacemgr;
-}
-
-TEST_F(IfaceMgrTest, detectIfaces) {
-
-    // test detects that interfaces can be detected
-    // there is no code for that now, but interfaces are
-    // read from file
-    fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
-    fakeifaces << "eth0 fe80::1234";
-    fakeifaces.close();
-
-    // this is not usable on systems that don't have eth0
-    // interfaces. Nevertheless, this fake interface should
-    // be on list, but if_nametoindex() will fail.
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    ASSERT_TRUE( ifacemgr->getIface("eth0") != NULL );
-
-    IfaceMgr::Iface * eth0 = ifacemgr->getIface("eth0");
-
-    // there should be one address
-    IfaceMgr::AddressCollection addrs = eth0->getAddresses();
-    ASSERT_EQ(1, addrs.size());
-
-    IOAddress addr = *addrs.begin();
-
-    EXPECT_STREQ( "fe80::1234", addr.toText().c_str() );
-
-    delete ifacemgr;
-}
-
-TEST_F(IfaceMgrTest, sockets6) {
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-
-    createLoInterfacesTxt();
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    IOAddress loAddr("::1");
-
-    Pkt6 pkt6(128);
-    pkt6.iface_ = LOOPBACK;
-
-    // bind multicast socket to port 10547
-    int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
-    EXPECT_GT(socket1, 0); // socket > 0
-
-    EXPECT_EQ(socket1, ifacemgr->getSocket(pkt6));
-
-    // bind unicast socket to port 10548
-    int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10548);
-    EXPECT_GT(socket2, 0);
-
-    // removed code for binding socket twice to the same address/port
-    // as it caused problems on some platforms (e.g. Mac OS X)
-
-    close(socket1);
-    close(socket2);
-
-    delete ifacemgr;
-}
-
-// TODO: disabled due to other naming on various systems
-// (lo in Linux, lo0 in BSD systems)
-TEST_F(IfaceMgrTest, DISABLED_sockets6Mcast) {
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    IOAddress loAddr("::1");
-    IOAddress mcastAddr("ff02::1:2");
-
-    // bind multicast socket to port 10547
-    int socket1 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
-    EXPECT_GT(socket1, 0); // socket > 0
-
-    // expect success. This address/port is already bound, but
-    // we are using SO_REUSEADDR, so we can bind it twice
-    int socket2 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
-    EXPECT_GT(socket2, 0);
-
-    // there's no good way to test negative case here.
-    // we would need non-multicast interface. We will be able
-    // to iterate thru available interfaces and check if there
-    // are interfaces without multicast-capable flag.
-
-    close(socket1);
-    close(socket2);
-
-    delete ifacemgr;
-}
-
-TEST_F(IfaceMgrTest, sendReceive6) {
-
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-    createLoInterfacesTxt();
-
-    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
-
-    // let's assume that every supported OS have lo interface
-    IOAddress loAddr("::1");
-    int socket1 = 0, socket2 = 0;
-    EXPECT_NO_THROW(
-        socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
-        socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
-    );
-
-    EXPECT_GT(socket1, 0);
-    EXPECT_GT(socket2, 0);
-
-    boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
-
-    // prepare dummy payload
-    for (int i=0;i<128; i++) {
-        sendPkt->data_[i] = i;
-    }
-
-    sendPkt->remote_port_ = 10547;
-    sendPkt->remote_addr_ = IOAddress("::1");
-    sendPkt->ifindex_ = 1;
-    sendPkt->iface_ = LOOPBACK;
-
-    boost::shared_ptr<Pkt6> rcvPkt;
-
-    EXPECT_EQ(true, ifacemgr->send(sendPkt));
-
-    rcvPkt = ifacemgr->receive6();
-
-    ASSERT_TRUE( rcvPkt ); // received our own packet
-
-    // let's check that we received what was sent
-    EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
-    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
-                        rcvPkt->data_len_) );
-
-    EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
-
-    // since we opened 2 sockets on the same interface and none of them is multicast,
-    // none is preferred over the other for sending data, so we really should not
-    // assume the one or the other will always be choosen for sending data. Therefore
-    // we should accept both values as source ports.
-    EXPECT_TRUE( (rcvPkt->remote_port_ == 10546) || (rcvPkt->remote_port_ == 10547) );
-
-    delete ifacemgr;
-}
-
-TEST_F(IfaceMgrTest, socket4) {
-
-    createLoInterfacesTxt();
-    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
-
-    // Let's assume that every supported OS have lo interface.
-    IOAddress loAddr("127.0.0.1");
-    // Use unprivileged port (it's convenient for running tests as non-root).
-    int socket1 = 0;
-
-    EXPECT_NO_THROW(
-        socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000);
-    );
-
-    EXPECT_GT(socket1, 0);
-
-    Pkt4 pkt(DHCPDISCOVER, 1234);
-    pkt.setIface(LOOPBACK);
-
-    // Expect that we get the socket that we just opened.
-    EXPECT_EQ(socket1, ifacemgr->getSocket(pkt));
-
-    close(socket1);
-
-    delete ifacemgr;
-}
-
-// Test the Iface structure itself
-TEST_F(IfaceMgrTest, iface) {
-    IfaceMgr::Iface* iface = 0;
-    EXPECT_NO_THROW(
-        iface = new IfaceMgr::Iface("eth0",1);
-    );
-
-    EXPECT_EQ("eth0", iface->getName());
-    EXPECT_EQ(1, iface->getIndex());
-    EXPECT_EQ("eth0/1", iface->getFullName());
-
-    // Let's make a copy of this address collection.
-    IfaceMgr::AddressCollection addrs = iface->getAddresses();
-
-    EXPECT_EQ(0, addrs.size());
-
-    IOAddress addr1("192.0.2.6");
-    iface->addAddress(addr1);
-
-    addrs = iface->getAddresses();
-    ASSERT_EQ(1, addrs.size());
-    EXPECT_EQ("192.0.2.6", addrs.at(0).toText());
-
-    // No such address, should return false.
-    EXPECT_FALSE(iface->delAddress(IOAddress("192.0.8.9")));
-
-    // This address is present, delete it!
-    EXPECT_TRUE(iface->delAddress(IOAddress("192.0.2.6")));
-
-    // Not really necessary, previous reference still points to the same
-    // collection. Let's do it anyway, as test code may serve as example
-    // usage code as well.
-    addrs = iface->getAddresses();
-
-    EXPECT_EQ(0, addrs.size());
-
-    EXPECT_NO_THROW(
-        delete iface;
-    );
-}
-
-TEST_F(IfaceMgrTest, socketInfo) {
-
-    // check that socketinfo for IPv4 socket is functional
-    IfaceMgr::SocketInfo sock1(7, IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7);
-    EXPECT_EQ(7, sock1.sockfd_);
-    EXPECT_EQ("192.0.2.56", sock1.addr_.toText());
-    EXPECT_EQ(AF_INET, sock1.family_);
-    EXPECT_EQ(DHCP4_SERVER_PORT + 7, sock1.port_);
-
-    // check that socketinfo for IPv6 socket is functional
-    IfaceMgr::SocketInfo sock2(9, IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9);
-    EXPECT_EQ(9, sock2.sockfd_);
-    EXPECT_EQ("2001:db8:1::56", sock2.addr_.toText());
-    EXPECT_EQ(AF_INET6, sock2.family_);
-    EXPECT_EQ(DHCP4_SERVER_PORT + 9, sock2.port_);
-
-    // now let's test if IfaceMgr handles socket info properly
-    createLoInterfacesTxt();
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-    IfaceMgr::Iface* loopback = ifacemgr->getIface(LOOPBACK);
-    ASSERT_TRUE(loopback);
-    loopback->addSocket(sock1);
-    loopback->addSocket(sock2);
-
-    Pkt6 pkt6(100);
-
-    // pkt6 dos not have interface set yet
-    EXPECT_THROW(
-        ifacemgr->getSocket(pkt6),
-        BadValue
-    );
-
-    // try to send over non-existing interface
-    pkt6.iface_ = "nosuchinterface45";
-    EXPECT_THROW(
-        ifacemgr->getSocket(pkt6),
-        BadValue
-    );
-
-    // this will work
-    pkt6.iface_ = LOOPBACK;
-    EXPECT_EQ(9, ifacemgr->getSocket(pkt6));
-
-    bool deleted = false;
-    EXPECT_NO_THROW(
-        deleted = ifacemgr->getIface(LOOPBACK)->delSocket(9);
-    );
-    EXPECT_EQ(true, deleted);
-
-    // it should throw again, there's no usable socket anymore
-    EXPECT_THROW(
-        ifacemgr->getSocket(pkt6),
-        Unexpected
-    );
-
-    // repeat for pkt4
-    Pkt4 pkt4(DHCPDISCOVER, 1);
-
-    // pkt4 does not have interface set yet.
-    EXPECT_THROW(
-        ifacemgr->getSocket(pkt4),
-        BadValue
-    );
-
-    // Try to send over non-existing interface.
-    pkt4.setIface("nosuchinterface45");
-    EXPECT_THROW(
-        ifacemgr->getSocket(pkt4),
-        BadValue
-    );
-
-    // Socket info is set, packet has well defined interface. It should work.
-    pkt4.setIface(LOOPBACK);
-    EXPECT_EQ(7, ifacemgr->getSocket(pkt4));
-
-    EXPECT_NO_THROW(
-        ifacemgr->getIface(LOOPBACK)->delSocket(7);
-    );
-
-    // It should throw again, there's no usable socket anymore.
-    EXPECT_THROW(
-        ifacemgr->getSocket(pkt4),
-        Unexpected
-    );
-
-    delete ifacemgr;
-}
-
-}
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 3991033..1cb5556 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -10,6 +10,7 @@ CLEANFILES = *.gcno *.gcda
 lib_LTLIBRARIES = libdhcp.la
 libdhcp_la_SOURCES  =
 libdhcp_la_SOURCES += libdhcp.cc libdhcp.h
+libdhcp_la_SOURCES += iface_mgr.cc iface_mgr.h
 libdhcp_la_SOURCES += option.cc option.h
 libdhcp_la_SOURCES += option6_ia.cc option6_ia.h
 libdhcp_la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
new file mode 100644
index 0000000..25999a0
--- /dev/null
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -0,0 +1,725 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <sstream>
+#include <fstream>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp/iface_mgr.h>
+#include <exceptions/exceptions.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+namespace isc {
+
+/// IfaceMgr is a singleton implementation
+IfaceMgr* IfaceMgr::instance_ = 0;
+
+void
+IfaceMgr::instanceCreate() {
+    if (instance_) {
+        // no need to do anything. Instance is already created.
+        // Who called it again anyway? Uh oh. Had to be us, as
+        // this is private method.
+        return;
+    }
+    instance_ = new IfaceMgr();
+}
+
+IfaceMgr&
+IfaceMgr::instance() {
+    if (instance_ == 0) {
+        instanceCreate();
+    }
+    return (*instance_);
+}
+
+IfaceMgr::Iface::Iface(const std::string& name, int ifindex)
+    :name_(name), ifindex_(ifindex), mac_len_(0) {
+
+    memset(mac_, 0, sizeof(mac_));
+}
+
+std::string
+IfaceMgr::Iface::getFullName() const {
+    ostringstream tmp;
+    tmp << name_ << "/" << ifindex_;
+    return (tmp.str());
+}
+
+std::string
+IfaceMgr::Iface::getPlainMac() const {
+    ostringstream tmp;
+    tmp.fill('0');
+    tmp << hex;
+    for (int i = 0; i < mac_len_; i++) {
+        tmp.width(2);
+        tmp << mac_[i];
+        if (i < mac_len_-1) {
+            tmp << ":";
+        }
+    }
+    return (tmp.str());
+}
+
+bool IfaceMgr::Iface::delAddress(const isc::asiolink::IOAddress& addr) {
+
+    // Let's delete all addresses that match. It really shouldn't matter
+    // if we delete first or all, as the OS should allow to add a single
+    // address to an interface only once. If OS allows multiple instances
+    // of the same address added, we are in deep problems anyway.
+    size_t size = addrs_.size();
+    addrs_.erase(remove(addrs_.begin(), addrs_.end(), addr), addrs_.end());
+    return (addrs_.size() < size);
+}
+
+bool IfaceMgr::Iface::delSocket(uint16_t sockfd) {
+    list<SocketInfo>::iterator sock = sockets_.begin();
+    while (sock!=sockets_.end()) {
+        if (sock->sockfd_ == sockfd) {
+            close(sockfd);
+            sockets_.erase(sock);
+            return (true); //socket found
+        }
+        ++sock;
+    }
+    return (false); // socket not found
+}
+
+IfaceMgr::IfaceMgr()
+    :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
+     control_buf_(new char[control_buf_len_])
+{
+
+    cout << "IfaceMgr initialization." << endl;
+
+    try {
+        // required for sending/receiving packets
+        // let's keep it in front, just in case someone
+        // wants to send anything during initialization
+
+        // control_buf_ = boost::scoped_array<char>();
+
+        detectIfaces();
+
+    } catch (const std::exception& ex) {
+        cout << "IfaceMgr creation failed:" << ex.what() << endl;
+
+        // TODO Uncomment this (or call LOG_FATAL) once
+        // interface detection is implemented. Otherwise
+        // it is not possible to run tests in a portable
+        // way (see detectIfaces() method).
+        // throw ex;
+    }
+}
+
+void IfaceMgr::closeSockets() {
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end(); ++iface) {
+
+        for (SocketCollection::iterator sock = iface->sockets_.begin();
+             sock != iface->sockets_.end(); ++sock) {
+            cout << "Closing socket " << sock->sockfd_ << endl;
+            close(sock->sockfd_);
+        }
+        iface->sockets_.clear();
+    }
+
+}
+
+IfaceMgr::~IfaceMgr() {
+    closeSockets();
+
+    // control_buf_ is deleted automatically (scoped_ptr)
+    control_buf_len_ = 0;
+}
+
+void
+IfaceMgr::detectIfaces() {
+    string ifaceName, linkLocal;
+
+    // TODO do the actual detection. Currently interface detection is faked
+    //      by reading a text file.
+
+    cout << "Interface detection is not implemented yet. "
+         << "Reading interfaces.txt file instead." << endl;
+    cout << "Please use format: interface-name link-local-address" << endl;
+
+    try {
+        ifstream interfaces("interfaces.txt");
+
+        if (!interfaces.good()) {
+            cout << "Failed to read interfaces.txt file." << endl;
+            isc_throw(Unexpected, "Failed to read interfaces.txt");
+        }
+        interfaces >> ifaceName;
+        interfaces >> linkLocal;
+
+        cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
+
+        Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
+        IOAddress addr(linkLocal);
+        iface.addAddress(addr);
+        addInterface(iface);
+        interfaces.close();
+    } catch (const std::exception& ex) {
+        // TODO: deallocate whatever memory we used
+        // not that important, since this function is going to be
+        // thrown away as soon as we get proper interface detection
+        // implemented
+
+        // TODO Do LOG_FATAL here
+        std::cerr << "Interface detection failed." << std::endl;
+        throw ex;
+    }
+}
+
+void
+IfaceMgr::openSockets(uint16_t port) {
+    int sock1, sock2;
+
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end(); ++iface) {
+
+        AddressCollection addrs = iface->getAddresses();
+
+        for (AddressCollection::iterator addr = addrs.begin();
+             addr != addrs.end();
+             ++addr) {
+
+            sock1 = openSocket(iface->getName(), *addr, port);
+            if (sock1 < 0) {
+                isc_throw(Unexpected, "Failed to open unicast socket on "
+                          << " interface " << iface->getFullName());
+            }
+
+            if ( !joinMcast(sock1, iface->getName(),
+                             string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
+                close(sock1);
+                isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
+                          << " multicast group.");
+            }
+
+            // this doesn't work too well on NetBSD
+            sock2 = openSocket(iface->getName(),
+                               IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
+                               port);
+            if (sock2 < 0) {
+                isc_throw(Unexpected, "Failed to open multicast socket on "
+                          << " interface " << iface->getFullName());
+                iface->delSocket(sock1); // delete previously opened socket
+            }
+        }
+    }
+}
+
+void
+IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
+    for (IfaceCollection::const_iterator iface = ifaces_.begin();
+         iface != ifaces_.end(); ++iface) {
+        out << "Detected interface " << iface->getFullName() << endl;
+        out << "  " << iface->getAddresses().size() << " addr(s):" << endl;
+        const AddressCollection addrs = iface->getAddresses();
+
+        for (AddressCollection::const_iterator addr = addrs.begin();
+             addr != addrs.end(); ++addr) {
+            out << "  " << addr->toText() << endl;
+        }
+        out << "  mac: " << iface->getPlainMac() << endl;
+    }
+}
+
+IfaceMgr::Iface*
+IfaceMgr::getIface(int ifindex) {
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end(); ++iface) {
+        if (iface->getIndex() == ifindex) {
+            return (&(*iface));
+        }
+    }
+
+    return (NULL); // not found
+}
+
+IfaceMgr::Iface*
+IfaceMgr::getIface(const std::string& ifname) {
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end(); ++iface) {
+        if (iface->getName() == ifname) {
+            return (&(*iface));
+        }
+    }
+
+    return (NULL); // not found
+}
+
+int
+IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
+                     int port) {
+    Iface* iface = getIface(ifname);
+    if (!iface) {
+        isc_throw(BadValue, "There is no " << ifname << " interface present.");
+    }
+    switch (addr.getFamily()) {
+    case AF_INET:
+        return openSocket4(*iface, addr, port);
+    case AF_INET6:
+        return openSocket6(*iface, addr, port);
+    default:
+        isc_throw(BadValue, "Failed to detect family of address: "
+                  << addr.toText());
+    }
+}
+
+int
+IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
+
+    cout << "Creating UDP4 socket on " << iface.getFullName()
+         << " " << addr.toText() << "/port=" << port << endl;
+
+    struct sockaddr_in addr4;
+    memset(&addr4, 0, sizeof(sockaddr));
+    addr4.sin_family = AF_INET;
+    addr4.sin_port = htons(port);
+    memcpy(&addr4.sin_addr, addr.getAddress().to_v4().to_bytes().data(),
+           sizeof(addr4.sin_addr));
+
+    int sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) {
+        isc_throw(Unexpected, "Failed to create UDP6 socket.");
+    }
+
+    if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
+        close(sock);
+        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
+                  << "/port=" << port);
+    }
+
+    // If there is no support for IP_PKTINFO, we are really out of luck.
+    // It will be difficult to understand, where this packet came from.
+#if defined(IP_PKTINFO)
+    int flag = 1;
+    if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
+        close(sock);
+        isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
+    }
+#endif
+
+    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
+        addr.toText() << "/port=" << port << endl;
+
+    iface.addSocket(SocketInfo(sock, addr, port));
+
+    return (sock);
+}
+
+int
+IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
+
+    cout << "Creating UDP6 socket on " << iface.getFullName()
+         << " " << addr.toText() << "/port=" << port << endl;
+
+    struct sockaddr_in6 addr6;
+    memset(&addr6, 0, sizeof(addr6));
+    addr6.sin6_family = AF_INET6;
+    addr6.sin6_port = htons(port);
+    if (addr.toText() != "::1")
+      addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str());
+
+    memcpy(&addr6.sin6_addr,
+           addr.getAddress().to_v6().to_bytes().data(),
+           sizeof(addr6.sin6_addr));
+#ifdef HAVE_SA_LEN
+    addr6->sin6_len = sizeof(addr6);
+#endif
+
+    // TODO: use sockcreator once it becomes available
+
+    // make a socket
+    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (sock < 0) {
+        isc_throw(Unexpected, "Failed to create UDP6 socket.");
+    }
+
+    // Set the REUSEADDR option so that we don't fail to start if
+    // we're being restarted.
+    int flag = 1;
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                   (char *)&flag, sizeof(flag)) < 0) {
+        close(sock);
+        isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
+    }
+
+    if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
+        close(sock);
+        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
+                  << "/port=" << port);
+    }
+#ifdef IPV6_RECVPKTINFO
+    // RFC3542 - a new way
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        close(sock);
+        isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
+    }
+#else
+    // RFC2292 - an old way
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        close(sock);
+        isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
+    }
+#endif
+
+    // multicast stuff
+    if (addr.getAddress().to_v6().is_multicast()) {
+        // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
+        // are link and site-scoped, so there is no sense to join those groups
+        // with global addresses.
+
+        if ( !joinMcast( sock, iface.getName(),
+                         string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
+            close(sock);
+            isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
+                      << " multicast group.");
+        }
+    }
+
+    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
+        addr.toText() << "/port=" << port << endl;
+
+    iface.addSocket(SocketInfo(sock, addr, port));
+
+    return (sock);
+}
+
+bool
+IfaceMgr::joinMcast(int sock, const std::string& ifname,
+const std::string & mcast) {
+
+    struct ipv6_mreq mreq;
+
+    if (inet_pton(AF_INET6, mcast.c_str(),
+                  &mreq.ipv6mr_multiaddr) <= 0) {
+        cout << "Failed to convert " << ifname
+             << " to IPv6 multicast address." << endl;
+        return (false);
+    }
+
+    mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                   &mreq, sizeof(mreq)) < 0) {
+        cout << "Failed to join " << mcast << " multicast group." << endl;
+        return (false);
+    }
+
+    cout << "Joined multicast " << mcast << " group." << endl;
+
+    return (true);
+}
+
+bool
+IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
+    struct msghdr m;
+    struct iovec v;
+    int result;
+    struct in6_pktinfo *pktinfo;
+    struct cmsghdr *cmsg;
+
+    Iface* iface = getIface(pkt->iface_);
+    if (!iface) {
+        isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
+                  << pkt->iface_ << ") specified.");
+    }
+
+    memset(&control_buf_[0], 0, control_buf_len_);
+
+    // Initialize our message header structure.
+    memset(&m, 0, sizeof(m));
+
+    // Set the target address we're sending to.
+    sockaddr_in6 to;
+    memset(&to, 0, sizeof(to));
+    to.sin6_family = AF_INET6;
+    to.sin6_port = htons(pkt->remote_port_);
+    memcpy(&to.sin6_addr,
+           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
+           16);
+    to.sin6_scope_id = pkt->ifindex_;
+
+    m.msg_name = &to;
+    m.msg_namelen = sizeof(to);
+
+    // Set the data buffer we're sending. (Using this wacky
+    // "scatter-gather" stuff... we only have a single chunk
+    // of data to send, so we declare a single vector entry.)
+    v.iov_base = (char *) &pkt->data_[0];
+    v.iov_len = pkt->data_len_;
+    m.msg_iov = &v;
+    m.msg_iovlen = 1;
+
+    // Setting the interface is a bit more involved.
+    //
+    // We have to create a "control message", and set that to
+    // define the IPv6 packet information. We could set the
+    // source address if we wanted, but we can safely let the
+    // kernel decide what that should be.
+    m.msg_control = &control_buf_[0];
+    m.msg_controllen = control_buf_len_;
+    cmsg = CMSG_FIRSTHDR(&m);
+    cmsg->cmsg_level = IPPROTO_IPV6;
+    cmsg->cmsg_type = IPV6_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
+    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+    memset(pktinfo, 0, sizeof(*pktinfo));
+    pktinfo->ipi6_ifindex = pkt->ifindex_;
+    m.msg_controllen = cmsg->cmsg_len;
+
+    result = sendmsg(getSocket(*pkt), &m, 0);
+    if (result < 0) {
+        cout << "Send packet failed." << endl;
+    }
+    cout << "Sent " << pkt->data_len_ << " bytes over socket " << getSocket(*pkt)
+         << " on " << iface->getFullName() << " interface: "
+         << " dst=" << pkt->remote_addr_.toText()
+         << ", src=" << pkt->local_addr_.toText()
+         << endl;
+
+    return (result);
+}
+
+bool
+IfaceMgr::send(boost::shared_ptr<Pkt4>& )
+{
+    /// TODO: Implement this (ticket #1240)
+    isc_throw(NotImplemented, "Pkt4 send not implemented yet.");
+}
+
+
+boost::shared_ptr<Pkt4>
+IfaceMgr::receive4() {
+    isc_throw(NotImplemented, "Pkt4 reception not implemented yet.");
+
+    // TODO: To be implemented (ticket #1239)
+    return (boost::shared_ptr<Pkt4>()); // NULL
+}
+
+boost::shared_ptr<Pkt6>
+IfaceMgr::receive6() {
+    struct msghdr m;
+    struct iovec v;
+    int result;
+    struct cmsghdr* cmsg;
+    struct in6_pktinfo* pktinfo;
+    struct sockaddr_in6 from;
+    struct in6_addr to_addr;
+    boost::shared_ptr<Pkt6> pkt;
+    char addr_str[INET6_ADDRSTRLEN];
+
+    try {
+        // RFC3315 states that server responses may be
+        // fragmented if they are over MTU. There is no
+        // text whether client's packets may be larger
+        // than 1500. Nevertheless to be on the safe side
+        // we use larger buffer. This buffer limit is checked
+        // during reception (see iov_len below), so we are
+        // safe
+        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
+    } catch (const std::exception& ex) {
+        cout << "Failed to create new packet." << endl;
+        return (boost::shared_ptr<Pkt6>()); // NULL
+    }
+
+    memset(&control_buf_[0], 0, control_buf_len_);
+
+    memset(&from, 0, sizeof(from));
+    memset(&to_addr, 0, sizeof(to_addr));
+
+    // Initialize our message header structure.
+    memset(&m, 0, sizeof(m));
+
+    // Point so we can get the from address.
+    m.msg_name = &from;
+    m.msg_namelen = sizeof(from);
+
+    // Set the data buffer we're receiving. (Using this wacky
+    // "scatter-gather" stuff... but we that doesn't really make
+    // sense for us, so we use a single vector entry.)
+    v.iov_base = (void*)&pkt->data_[0];
+    v.iov_len = pkt->data_len_;
+    m.msg_iov = &v;
+    m.msg_iovlen = 1;
+
+    // Getting the interface is a bit more involved.
+    //
+    // We set up some space for a "control message". We have
+    // previously asked the kernel to give us packet
+    // information (when we initialized the interface), so we
+    // should get the destination address from that.
+    m.msg_control = &control_buf_[0];
+    m.msg_controllen = control_buf_len_;
+
+    /// TODO: Need to move to select() and pool over
+    /// all available sockets. For now, we just take the
+    /// first interface and use first socket from it.
+    IfaceCollection::const_iterator iface = ifaces_.begin();
+    if (iface == ifaces_.end()) {
+        isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
+    }
+    SocketCollection::const_iterator s = iface->sockets_.begin();
+    const SocketInfo* candidate = 0;
+    while (s != iface->sockets_.end()) {
+        if (s->addr_.getAddress().to_v6().is_multicast()) {
+            candidate = &(*s);
+            break;
+        }
+        if (!candidate) {
+            candidate = &(*s); // it's not multicast, but it's better than none
+        }
+        ++s;
+    }
+    if (!candidate) {
+        isc_throw(Unexpected, "Interface " << iface->getFullName()
+                  << " does not have any sockets open.");
+    }
+
+    cout << "Trying to receive over socket " << candidate->sockfd_ << " bound to "
+         << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
+         << iface->getFullName() << endl;
+    result = recvmsg(candidate->sockfd_, &m, 0);
+
+    if (result >= 0) {
+        // If we did read successfully, then we need to loop
+        // through the control messages we received and
+        // find the one with our destination address.
+        //
+        // We also keep a flag to see if we found it. If we
+        // didn't, then we consider this to be an error.
+        int found_pktinfo = 0;
+        cmsg = CMSG_FIRSTHDR(&m);
+        while (cmsg != NULL) {
+            if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
+                (cmsg->cmsg_type == IPV6_PKTINFO)) {
+                pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+                to_addr = pktinfo->ipi6_addr;
+                pkt->ifindex_ = pktinfo->ipi6_ifindex;
+                found_pktinfo = 1;
+            }
+            cmsg = CMSG_NXTHDR(&m, cmsg);
+        }
+        if (!found_pktinfo) {
+            cout << "Unable to find pktinfo" << endl;
+            return (boost::shared_ptr<Pkt6>()); // NULL
+        }
+    } else {
+        cout << "Failed to receive data." << endl;
+        return (boost::shared_ptr<Pkt6>()); // NULL
+    }
+
+    // That's ugly.
+    // TODO add IOAddress constructor that will take struct in6_addr*
+    // TODO: there's from_bytes() method added in IOAddress. Use it!
+    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
+    pkt->local_addr_ = IOAddress(string(addr_str));
+
+    // TODO: there's from_bytes() method added in IOAddress. Use it!
+    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
+    pkt->remote_addr_ = IOAddress(string(addr_str));
+
+    pkt->remote_port_ = ntohs(from.sin6_port);
+
+    Iface* received = getIface(pkt->ifindex_);
+    if (received) {
+        pkt->iface_ = received->getName();
+    } else {
+        cout << "Received packet over unknown interface (ifindex="
+             << pkt->ifindex_ << ")." << endl;
+        return (boost::shared_ptr<Pkt6>()); // NULL
+    }
+
+    pkt->data_len_ = result;
+
+    // TODO Move this to LOG_DEBUG
+    cout << "Received " << pkt->data_len_ << " bytes over "
+         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
+         << " src=" << pkt->remote_addr_.toText()
+         << ", dst=" << pkt->local_addr_.toText()
+         << endl;
+
+    return (pkt);
+}
+
+uint16_t
+IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
+    Iface* iface = getIface(pkt.iface_);
+    if (!iface) {
+        isc_throw(BadValue, "Tried to find socket for non-existent interface "
+                  << pkt.iface_);
+    }
+
+    SocketCollection::const_iterator s;
+    for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
+        if (s->family_ != AF_INET6) {
+            // don't use IPv4 sockets
+            continue;
+        }
+        if (s->addr_.getAddress().to_v6().is_multicast()) {
+            // don't use IPv6 sockets bound to multicast address
+            continue;
+        }
+        /// TODO: Add more checks here later. If remote address is
+        /// not link-local, we can't use link local bound socket
+        /// to send data.
+
+        return (s->sockfd_);
+    }
+
+    isc_throw(Unexpected, "Interface " << iface->getFullName()
+              << " does not have any suitable IPv6 sockets open.");
+}
+
+uint16_t
+IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
+    Iface* iface = getIface(pkt.getIface());
+    if (!iface) {
+        isc_throw(BadValue, "Tried to find socket for non-existent interface "
+                  << pkt.getIface());
+    }
+
+    SocketCollection::const_iterator s;
+    for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
+        if (s->family_ != AF_INET) {
+            // don't use IPv4 sockets
+            continue;
+        }
+        /// TODO: Add more checks here later. If remote address is
+        /// not link-local, we can't use link local bound socket
+        /// to send data.
+
+        return (s->sockfd_);
+    }
+
+    isc_throw(Unexpected, "Interface " << iface->getFullName()
+              << " does not have any suitable IPv4 sockets open.");
+}
+
+
+
+}
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
new file mode 100644
index 0000000..759d657
--- /dev/null
+++ b/src/lib/dhcp/iface_mgr.h
@@ -0,0 +1,413 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef IFACE_MGR_H
+#define IFACE_MGR_H
+
+#include <list>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/noncopyable.hpp>
+#include <asiolink/io_address.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/pkt6.h>
+
+namespace isc {
+
+namespace dhcp {
+/// @brief handles network interfaces, transmission and reception
+///
+/// IfaceMgr is an interface manager class that detects available network
+/// interfaces, configured addresses, link-local addresses, and provides
+/// API for using sockets.
+///
+class IfaceMgr : public boost::noncopyable {
+public:
+    /// type that defines list of addresses
+    typedef std::vector<isc::asiolink::IOAddress> AddressCollection;
+
+    /// maximum MAC address length (Infiniband uses 20 bytes)
+    static const unsigned int MAX_MAC_LEN = 20;
+
+    /// Holds information about socket.
+    struct SocketInfo {
+        uint16_t sockfd_; /// socket descriptor
+        isc::asiolink::IOAddress addr_; /// bound address
+        uint16_t port_;   /// socket port
+        uint16_t family_; /// IPv4 or IPv6
+
+        /// @brief SocketInfo constructor.
+        ///
+        /// @param sockfd socket descriptor
+        /// @param addr an address the socket is bound to
+        /// @param port a port the socket is bound to
+        SocketInfo(uint16_t sockfd, const isc::asiolink::IOAddress& addr,
+                   uint16_t port)
+        :sockfd_(sockfd), addr_(addr), port_(port), family_(addr.getFamily()) { }
+    };
+
+    /// type that holds a list of socket informations
+    typedef std::list<SocketInfo> SocketCollection;
+
+    /// @brief represents a single network interface
+    ///
+    /// Iface structure represents network interface with all useful
+    /// information, like name, interface index, MAC address and
+    /// list of assigned addresses
+    class Iface {
+    public:
+        /// @brief Iface constructor.
+        ///
+        /// Creates Iface object that represents network interface.
+        ///
+        /// @param name name of the interface
+        /// @param ifindex interface index (unique integer identifier)
+        Iface(const std::string& name, int ifindex);
+
+        /// @brief Returns full interface name as "ifname/ifindex" string.
+        ///
+        /// @return string with interface name
+        std::string getFullName() const;
+
+        /// @brief Returns link-layer address a plain text.
+        ///
+        /// @return MAC address as a plain text (string)
+        std::string getPlainMac() const;
+
+        /// @brief Returns interface index.
+        ///
+        /// @return interface index
+        uint16_t getIndex() const { return ifindex_; }
+
+        /// @brief Returns interface name.
+        ///
+        /// @return interface name
+        std::string getName() const { return name_; };
+
+        /// @brief Returns all interfaces available on an interface.
+        ///
+        /// Care should be taken to not use this collection after Iface object
+        /// ceases to exist. That is easy in most cases as Iface objects are
+        /// created by IfaceMgr that is a singleton an is expected to be
+        /// available at all time. We may revisit this if we ever decide to
+        /// implement dynamic interface detection, but such fancy feature would
+        /// mostly be useful for clients with wifi/vpn/virtual interfaces.
+        ///
+        /// @return collection of addresses
+        const AddressCollection& getAddresses() const { return addrs_; }
+
+        /// @brief Adds an address to an interface.
+        ///
+        /// This only adds an address to collection, it does not physically
+        /// configure address on actual network interface.
+        ///
+        /// @param addr address to be added
+        void addAddress(const isc::asiolink::IOAddress& addr) {
+            addrs_.push_back(addr);
+        }
+
+        /// @brief Deletes an address from an interface.
+        ///
+        /// This only deletes address from collection, it does not physically
+        /// remove address configuration from actual network interface.
+        ///
+        /// @param addr address to be removed.
+        ///
+        /// @return true if removal was successful (address was in collection),
+        ///         false otherwise
+        bool delAddress(const isc::asiolink::IOAddress& addr);
+
+        /// @brief Adds socket descriptor to an interface.
+        ///
+        /// @param socket SocketInfo structure that describes socket.
+        void addSocket(const SocketInfo& sock)
+            { sockets_.push_back(sock); }
+
+        /// @brief Closes socket.
+        ///
+        /// Closes socket and removes corresponding SocketInfo structure
+        /// from an interface.
+        ///
+        /// @param socket descriptor to be closed/removed.
+        /// @return true if there was such socket, false otherwise
+        bool delSocket(uint16_t sockfd);
+
+        /// socket used to sending data
+        /// TODO: this should be protected
+        SocketCollection sockets_;
+
+    protected:
+        /// network interface name
+        std::string name_;
+
+        /// interface index (a value that uniquely indentifies an interface)
+        int ifindex_;
+
+        /// list of assigned addresses
+        AddressCollection addrs_;
+
+        /// link-layer address
+        uint8_t mac_[MAX_MAC_LEN];
+
+        /// length of link-layer address (usually 6)
+        int mac_len_;
+    };
+
+    // TODO performance improvement: we may change this into
+    //      2 maps (ifindex-indexed and name-indexed) and
+    //      also hide it (make it public make tests easier for now)
+
+    /// type that holds a list of interfaces
+    typedef std::list<Iface> IfaceCollection;
+
+    /// IfaceMgr is a singleton class. This method returns reference
+    /// to its sole instance.
+    ///
+    /// @return the only existing instance of interface manager
+    static IfaceMgr& instance();
+
+    /// @brief Returns interface with specified interface index
+    ///
+    /// @param ifindex index of searched interface
+    ///
+    /// @return interface with requested index (or NULL if no such
+    ///         interface is present)
+    ///
+    Iface* getIface(int ifindex);
+
+    /// @brief Returns interface with specified interface name
+    ///
+    /// @param ifname name of searched interface
+    ///
+    /// @return interface with requested name (or NULL if no such
+    ///         interface is present)
+    ///
+    Iface*
+    getIface(const std::string& ifname);
+
+    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
+    ///
+    /// This method takes Pkt6 (see overloaded implementation that takes
+    /// Pkt4) and chooses appropriate socket to send it. This method
+    /// may throw BadValue if specified packet does not have outbound
+    /// interface specified, no such interface exists, or specified
+    /// interface does not have any appropriate sockets open.
+    ///
+    /// @param pkt a packet to be transmitted
+    ///
+    /// @return a socket descriptor
+    uint16_t getSocket(const isc::dhcp::Pkt6& pkt);
+
+    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
+    ///
+    /// This method takes Pkt4 (see overloaded implementation that takes
+    /// Pkt6) and chooses appropriate socket to send it. This method
+    /// may throw BadValue if specified packet does not have outbound
+    /// interface specified, no such interface exists, or specified
+    /// interface does not have any appropriate sockets open.
+    ///
+    /// @param pkt a packet to be transmitted
+    ///
+    /// @return a socket descriptor
+    uint16_t getSocket(const isc::dhcp::Pkt4& pkt);
+
+    /// debugging method that prints out all available interfaces
+    ///
+    /// @param out specifies stream to print list of interfaces to
+    void
+    printIfaces(std::ostream& out = std::cout);
+
+    /// @brief Sends an IPv6 packet.
+    ///
+    /// Sends an IPv6 packet. All parameters for actual transmission are specified in
+    /// Pkt6 structure itself. That includes destination address, src/dst port
+    /// and interface over which data will be sent.
+    ///
+    /// @param pkt packet to be sent
+    ///
+    /// @return true if sending was successful
+    bool send(boost::shared_ptr<Pkt6>& pkt);
+
+    /// @brief Sends an IPv4 packet.
+    ///
+    /// Sends an IPv4 packet. All parameters for actual transmission are specified
+    /// in Pkt4 structure itself. That includes destination address, src/dst
+    /// port and interface over which data will be sent.
+    ///
+    /// @param pkt a packet to be sent
+    ///
+    /// @return true if sending was successful
+    bool send(boost::shared_ptr<Pkt4>& pkt);
+
+    /// @brief Tries to receive IPv6 packet over open IPv6 sockets.
+    ///
+    /// Attempts to receive a single IPv6 packet of any of the open IPv6 sockets.
+    /// If reception is successful and all information about its sender
+    /// are obtained, Pkt6 object is created and returned.
+    ///
+    /// TODO Start using select() and add timeout to be able
+    /// to not wait infinitely, but rather do something useful
+    /// (e.g. remove expired leases)
+    ///
+    /// @return Pkt6 object representing received packet (or NULL)
+    boost::shared_ptr<Pkt6> receive6();
+
+    /// @brief Tries to receive IPv4 packet over open IPv4 sockets.
+    ///
+    /// Attempts to receive a single IPv4 packet of any of the open IPv4 sockets.
+    /// If reception is successful and all information about its sender
+    /// are obtained, Pkt4 object is created and returned.
+    ///
+    /// TODO Start using select() and add timeout to be able
+    /// to not wait infinitely, but rather do something useful
+    /// (e.g. remove expired leases)
+    ///
+    /// @return Pkt4 object representing received packet (or NULL)
+    boost::shared_ptr<Pkt4> receive4();
+
+    /// Opens UDP/IP socket and binds it to address, interface and port.
+    ///
+    /// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr
+    /// family.
+    ///
+    /// @param ifname name of the interface
+    /// @param addr address to be bound.
+    /// @param port UDP port.
+    ///
+    /// Method will throw if socket creation, socket binding or multicast
+    /// join fails.
+    ///
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful.
+    int openSocket(const std::string& ifname,
+                   const isc::asiolink::IOAddress& addr, int port);
+
+    /// Opens IPv6 sockets on detected interfaces.
+    ///
+    /// Will throw exception if socket creation fails.
+    ///
+    /// @param port specifies port number (usually DHCP6_SERVER_PORT)
+    void openSockets(uint16_t port);
+
+
+    /// @brief Closes all open sockets.
+    /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
+    void closeSockets();
+
+    // don't use private, we need derived classes in tests
+protected:
+
+    /// @brief Protected constructor.
+    ///
+    /// Protected constructor. This is a singleton class. We don't want
+    /// anyone to create instances of IfaceMgr. Use instance() method instead.
+    IfaceMgr();
+
+    ~IfaceMgr();
+
+    /// @brief Opens IPv4 socket.
+    ///
+    /// Please do not use this method directly. Use openSocket instead.
+    ///
+    /// This method may throw exception if socket creation fails.
+    ///
+    /// @param iface reference to interface structure.
+    /// @param addr an address the created socket should be bound to
+    /// @param port a port that created socket should be bound to
+    ///
+    /// @return socket descriptor
+    int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
+
+    /// @brief Opens IPv6 socket.
+    ///
+    /// Please do not use this method directly. Use openSocket instead.
+    ///
+    /// This method may throw exception if socket creation fails.
+    ///
+    /// @param iface reference to interface structure.
+    /// @param addr an address the created socket should be bound to
+    /// @param port a port that created socket should be bound to
+    ///
+    /// @return socket descriptor
+    int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
+
+    /// @brief Adds an interface to list of known interfaces.
+    ///
+    /// @param iface reference to Iface object.
+    void addInterface(const Iface& iface) {
+        ifaces_.push_back(iface);
+    }
+
+    /// @brief Detects network interfaces.
+    ///
+    /// This method will eventually detect available interfaces. For now
+    /// it offers stub implementation. First interface name and link-local
+    /// IPv6 address is read from intefaces.txt file.
+    void
+    detectIfaces();
+
+    // TODO: having 2 maps (ifindex->iface and ifname->iface would)
+    //      probably be better for performance reasons
+
+    /// List of available interfaces
+    IfaceCollection ifaces_;
+
+    /// a pointer to a sole instance of this class (a singleton)
+    static IfaceMgr * instance_;
+
+    // TODO: Also keep this interface on Iface once interface detection
+    // is implemented. We may need it e.g. to close all sockets on
+    // specific interface
+    //int recvsock_; // TODO: should be fd_set eventually, but we have only
+    //int sendsock_; // 2 sockets for now. Will do for until next release
+
+    // we can't use the same socket, as receiving socket
+    // is bound to multicast address. And we all know what happens
+    // to people who try to use multicast as source address.
+
+    /// length of the control_buf_ array
+    int control_buf_len_;
+
+    /// control-buffer, used in transmission and reception
+    boost::scoped_array<char> control_buf_;
+
+private:
+
+    /// creates a single instance of this class (a singleton implementation)
+    static void
+    instanceCreate();
+
+    /// @brief Joins IPv6 multicast group on a socket.
+    ///
+    /// Socket must be created and bound to an address. Note that this
+    /// address is different than the multicast address. For example DHCPv6
+    /// server should bind its socket to link-local address (fe80::1234...)
+    /// and later join ff02::1:2 multicast group.
+    ///
+    /// @param sock socket fd (socket must be bound)
+    /// @param ifname interface name (for link-scoped multicast groups)
+    /// @param mcast multicast address to join (e.g. "ff02::1:2")
+    ///
+    /// @return true if multicast join was successful
+    ///
+    bool
+    joinMcast(int sock, const std::string& ifname,
+              const std::string& mcast);
+
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif
diff --git a/src/lib/dhcp/pkt4.h b/src/lib/dhcp/pkt4.h
index 189d95d..9b6f726 100644
--- a/src/lib/dhcp/pkt4.h
+++ b/src/lib/dhcp/pkt4.h
@@ -302,17 +302,79 @@ public:
     boost::shared_ptr<Option>
     getOption(uint8_t opt_type);
 
+    /// @brief Returns interface name.
+    ///
+    /// Returns interface name over which packet was received or is
+    /// going to be transmitted.
+    ///
+    /// @return interface name
+    std::string getIface() const { return iface_; };
+
+    /// @brief Sets interface name.
+    ///
+    /// Sets interface name over which packet was received or is
+    /// going to be transmitted.
+    ///
+    /// @return interface name
+    void setIface(const std::string& iface ) { iface_ = iface; };
+
+    /// @brief Sets interface index.
+    ///
+    /// @param ifindex specifies interface index.
+    void setIndex(uint32_t ifindex) { ifindex_ = ifindex; };
+
+    /// @brief Returns interface index.
+    ///
+    /// @return interface index
+    uint32_t getIndex() const { return (ifindex_); };
+
+    /// @brief Sets remote address.
+    ///
+    /// @params remote specifies remote address
+    void setRemoteAddr(const isc::asiolink::IOAddress& remote) {
+        remote_addr_ = remote;
+    }
+
+    /// @brief Returns remote address
+    ///
+    /// @return remote address
+    const isc::asiolink::IOAddress& getRemoteAddr() {
+        return (remote_addr_);
+    }
+
+    /// @brief Sets local address.
+    ///
+    /// @params local specifies local address
+    void setLocalAddr(const isc::asiolink::IOAddress& local) {
+        local_addr_ = local;
+    }
+
+    /// @brief Returns local address.
+    ///
+    /// @return local address
+    const isc::asiolink::IOAddress& getLocalAddr() {
+        return (local_addr_);
+    }
+
+    /// @brief Sets local port.
+    ///
+    /// @params local specifies local port
+    void setLocalPort(uint16_t local) { local_port_ = local; }
+
+    /// @brief Returns local port.
+    ///
+    /// @return local port
+    uint16_t getLocalPort() { return (local_port_); }
 
-    /// @brief set interface over which packet should be sent
+    /// @brief Sets remote port.
     ///
-    /// @param interface defines outbound interface
-    void setIface(const std::string& interface){ iface_ = interface; }
+    /// @params remote specifies remote port
+    void setRemotePort(uint16_t remote) { remote_port_ = remote; }
 
-    /// @brief gets interface over which packet was received or
-    ///        will be transmitted
+    /// @brief Returns remote port.
     ///
-    /// @return name of the interface
-    std::string getIface() const { return iface_; }
+    /// @return remote port
+    uint16_t getRemotePort() { return (remote_port_); }
 
 protected:
 
@@ -338,13 +400,13 @@ protected:
     /// Each network interface has assigned unique ifindex. It is functional
     /// equvalent of name, but sometimes more useful, e.g. when using crazy
     /// systems that allow spaces in interface names e.g. MS Windows)
-    int ifindex_;
+    uint32_t ifindex_;
 
     /// local UDP port
-    int local_port_;
+    uint16_t local_port_;
 
     /// remote UDP port
-    int remote_port_;
+    uint16_t remote_port_;
 
     /// @brief message operation code
     ///
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 176992f..c1e87f5 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -2,6 +2,10 @@ SUBDIRS = .
 
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dhcp/tests\"
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 if USE_STATIC_LINK
@@ -15,6 +19,7 @@ if HAVE_GTEST
 TESTS += libdhcp_unittests
 libdhcp_unittests_SOURCES  = run_unittests.cc
 libdhcp_unittests_SOURCES += ../libdhcp.h ../libdhcp.cc libdhcp_unittest.cc
+libdhcp_unittests_SOURCES += ../iface_mgr.cc ../iface_mgr.h iface_mgr_unittest.cc
 libdhcp_unittests_SOURCES += ../option6_iaaddr.h ../option6_iaaddr.cc option6_iaaddr_unittest.cc
 libdhcp_unittests_SOURCES += ../option6_ia.h ../option6_ia.cc option6_ia_unittest.cc
 libdhcp_unittests_SOURCES += ../option6_addrlst.h ../option6_addrlst.cc option6_addrlst_unittest.cc
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
new file mode 100644
index 0000000..088f177
--- /dev/null
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -0,0 +1,519 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcp/dhcp4.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+// name of loopback interface detection
+const size_t buf_size = 32;
+char LOOPBACK[buf_size] = "lo";
+
+namespace {
+const char* const INTERFACE_FILE = TEST_DATA_BUILDDIR "/interfaces.txt";
+
+class NakedIfaceMgr: public IfaceMgr {
+    // "naked" Interface Manager, exposes internal fields
+public:
+    NakedIfaceMgr() { }
+    IfaceCollection & getIfacesLst() { return ifaces_; }
+};
+
+// dummy class for now, but this will be expanded when needed
+class IfaceMgrTest : public ::testing::Test {
+public:
+    IfaceMgrTest() {
+    }
+
+    void createLoInterfacesTxt() {
+        unlink(INTERFACE_FILE);
+        fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
+        fakeifaces << LOOPBACK << " ::1";
+        fakeifaces.close();
+    }
+};
+
+// We need some known interface to work reliably. Loopback interface
+// is named lo on Linux and lo0 on BSD boxes. We need to find out
+// which is available. This is not a real test, but rather a workaround
+// that will go away when interface detection is implemented.
+
+// NOTE: At this stage of development, write access to current directory
+// during running tests is required.
+TEST_F(IfaceMgrTest, loDetect) {
+
+    // poor man's interface detection
+    // it will go away as soon as proper interface detection
+    // is implemented
+    if (if_nametoindex("lo") > 0) {
+        cout << "This is Linux, using lo as loopback." << endl;
+        snprintf(LOOPBACK, buf_size - 1, "lo");
+    } else if (if_nametoindex("lo0") > 0) {
+        cout << "This is BSD, using lo0 as loopback." << endl;
+        snprintf(LOOPBACK, buf_size - 1, "lo0");
+    } else {
+        cout << "Failed to detect loopback interface. Neither "
+             << "lo nor lo0 worked. I give up." << endl;
+        FAIL();
+    }
+}
+
+// uncomment this test to create packet writer. It will
+// write incoming DHCPv6 packets as C arrays. That is useful
+// for generating test sequences based on actual traffic
+//
+// TODO: this potentially should be moved to a separate tool
+//
+
+#if 0
+TEST_F(IfaceMgrTest, dhcp6Sniffer) {
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+
+    unlink("interfaces.txt");
+
+    ofstream interfaces("interfaces.txt", ios::ate);
+    interfaces << "eth0 fe80::21e:8cff:fe9b:7349";
+    interfaces.close();
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    Pkt6 * pkt = 0;
+    int cnt = 0;
+    cout << "---8X-----------------------------------------" << endl;
+    while (true) {
+        pkt = ifacemgr->receive();
+
+        cout << "// this code is autogenerated. Do NOT edit." << endl;
+        cout << "// Received " << pkt->data_len_ << " bytes packet:" << endl;
+        cout << "Pkt6 *capture" << cnt++ << "() {" << endl;
+        cout << "    Pkt6* pkt;" << endl;
+        cout << "    pkt = new Pkt6(" << pkt->data_len_ << ");" << endl;
+        cout << "    pkt->remote_port_ = " << pkt-> remote_port_ << ";" << endl;
+        cout << "    pkt->remote_addr_ = IOAddress(\""
+             << pkt->remote_addr_.toText() << "\");" << endl;
+        cout << "    pkt->local_port_ = " << pkt-> local_port_ << ";" << endl;
+        cout << "    pkt->local_addr_ = IOAddress(\""
+             << pkt->local_addr_.toText() << "\");" << endl;
+        cout << "    pkt->ifindex_ = " << pkt->ifindex_ << ";" << endl;
+        cout << "    pkt->iface_ = \"" << pkt->iface_ << "\";" << endl;
+
+        // TODO it is better to declare an array and then memcpy it to
+        // packet.
+        for (int i=0; i< pkt->data_len_; i++) {
+            cout << "    pkt->data_[" << i << "]="
+                 << (int)(unsigned char)pkt->data_[i] << "; ";
+            if (!(i%4))
+                cout << endl;
+        }
+        cout << endl;
+        cout << "    return (pkt);" << endl;
+        cout << "}" << endl << endl;
+
+        delete pkt;
+    }
+    cout << "---8X-----------------------------------------" << endl;
+
+    // never happens. Infinite loop is infinite
+    delete pkt;
+    delete ifacemgr;
+}
+#endif
+
+TEST_F(IfaceMgrTest, basic) {
+    // checks that IfaceManager can be instantiated
+
+    IfaceMgr & ifacemgr = IfaceMgr::instance();
+    ASSERT_TRUE(&ifacemgr != 0);
+}
+
+TEST_F(IfaceMgrTest, ifaceClass) {
+    // basic tests for Iface inner class
+
+    IfaceMgr::Iface * iface = new IfaceMgr::Iface("eth5", 7);
+
+    EXPECT_STREQ("eth5/7", iface->getFullName().c_str());
+
+    delete iface;
+
+}
+
+// TODO: Implement getPlainMac() test as soon as interface detection
+// is implemented.
+TEST_F(IfaceMgrTest, getIface) {
+
+    cout << "Interface checks. Please ignore socket binding errors." << endl;
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    // interface name, ifindex
+    IfaceMgr::Iface iface1("lo1", 1);
+    IfaceMgr::Iface iface2("eth5", 2);
+    IfaceMgr::Iface iface3("en3", 5);
+    IfaceMgr::Iface iface4("e1000g0", 3);
+
+    // note: real interfaces may be detected as well
+    ifacemgr->getIfacesLst().push_back(iface1);
+    ifacemgr->getIfacesLst().push_back(iface2);
+    ifacemgr->getIfacesLst().push_back(iface3);
+    ifacemgr->getIfacesLst().push_back(iface4);
+
+    cout << "There are " << ifacemgr->getIfacesLst().size()
+         << " interfaces." << endl;
+    for (IfaceMgr::IfaceCollection::iterator iface=ifacemgr->getIfacesLst().begin();
+         iface != ifacemgr->getIfacesLst().end();
+         ++iface) {
+        cout << "  " << iface->getFullName() << endl;
+    }
+
+
+    // check that interface can be retrieved by ifindex
+    IfaceMgr::Iface * tmp = ifacemgr->getIface(5);
+    // ASSERT_NE(NULL, tmp); is not supported. hmmmm.
+    ASSERT_TRUE( tmp != NULL );
+
+    EXPECT_EQ( "en3", tmp->getName() );
+    EXPECT_EQ(5, tmp->getIndex());
+
+    // check that interface can be retrieved by name
+    tmp = ifacemgr->getIface("lo1");
+    ASSERT_TRUE( tmp != NULL );
+
+    EXPECT_EQ( "lo1", tmp->getName() );
+    EXPECT_EQ(1, tmp->getIndex());
+
+    // check that non-existing interfaces are not returned
+    EXPECT_EQ(static_cast<void*>(NULL), ifacemgr->getIface("wifi0") );
+
+    delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, detectIfaces) {
+
+    // test detects that interfaces can be detected
+    // there is no code for that now, but interfaces are
+    // read from file
+    fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
+    fakeifaces << "eth0 fe80::1234";
+    fakeifaces.close();
+
+    // this is not usable on systems that don't have eth0
+    // interfaces. Nevertheless, this fake interface should
+    // be on list, but if_nametoindex() will fail.
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    ASSERT_TRUE( ifacemgr->getIface("eth0") != NULL );
+
+    IfaceMgr::Iface * eth0 = ifacemgr->getIface("eth0");
+
+    // there should be one address
+    IfaceMgr::AddressCollection addrs = eth0->getAddresses();
+    ASSERT_EQ(1, addrs.size());
+
+    IOAddress addr = *addrs.begin();
+
+    EXPECT_STREQ( "fe80::1234", addr.toText().c_str() );
+
+    delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, sockets6) {
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+
+    createLoInterfacesTxt();
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    IOAddress loAddr("::1");
+
+    Pkt6 pkt6(128);
+    pkt6.iface_ = LOOPBACK;
+
+    // bind multicast socket to port 10547
+    int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+    EXPECT_GT(socket1, 0); // socket > 0
+
+    EXPECT_EQ(socket1, ifacemgr->getSocket(pkt6));
+
+    // bind unicast socket to port 10548
+    int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10548);
+    EXPECT_GT(socket2, 0);
+
+    // removed code for binding socket twice to the same address/port
+    // as it caused problems on some platforms (e.g. Mac OS X)
+
+    close(socket1);
+    close(socket2);
+
+    delete ifacemgr;
+}
+
+// TODO: disabled due to other naming on various systems
+// (lo in Linux, lo0 in BSD systems)
+TEST_F(IfaceMgrTest, DISABLED_sockets6Mcast) {
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    IOAddress loAddr("::1");
+    IOAddress mcastAddr("ff02::1:2");
+
+    // bind multicast socket to port 10547
+    int socket1 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
+    EXPECT_GT(socket1, 0); // socket > 0
+
+    // expect success. This address/port is already bound, but
+    // we are using SO_REUSEADDR, so we can bind it twice
+    int socket2 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
+    EXPECT_GT(socket2, 0);
+
+    // there's no good way to test negative case here.
+    // we would need non-multicast interface. We will be able
+    // to iterate thru available interfaces and check if there
+    // are interfaces without multicast-capable flag.
+
+    close(socket1);
+    close(socket2);
+
+    delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, sendReceive6) {
+
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+    createLoInterfacesTxt();
+
+    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+
+    // let's assume that every supported OS have lo interface
+    IOAddress loAddr("::1");
+    int socket1 = 0, socket2 = 0;
+    EXPECT_NO_THROW(
+        socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+        socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
+    );
+
+    EXPECT_GT(socket1, 0);
+    EXPECT_GT(socket2, 0);
+
+    boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
+
+    // prepare dummy payload
+    for (int i=0;i<128; i++) {
+        sendPkt->data_[i] = i;
+    }
+
+    sendPkt->remote_port_ = 10547;
+    sendPkt->remote_addr_ = IOAddress("::1");
+    sendPkt->ifindex_ = 1;
+    sendPkt->iface_ = LOOPBACK;
+
+    boost::shared_ptr<Pkt6> rcvPkt;
+
+    EXPECT_EQ(true, ifacemgr->send(sendPkt));
+
+    rcvPkt = ifacemgr->receive6();
+
+    ASSERT_TRUE( rcvPkt ); // received our own packet
+
+    // let's check that we received what was sent
+    EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
+    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
+                        rcvPkt->data_len_) );
+
+    EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
+
+    // since we opened 2 sockets on the same interface and none of them is multicast,
+    // none is preferred over the other for sending data, so we really should not
+    // assume the one or the other will always be choosen for sending data. Therefore
+    // we should accept both values as source ports.
+    EXPECT_TRUE( (rcvPkt->remote_port_ == 10546) || (rcvPkt->remote_port_ == 10547) );
+
+    delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, socket4) {
+
+    createLoInterfacesTxt();
+    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+
+    // Let's assume that every supported OS have lo interface.
+    IOAddress loAddr("127.0.0.1");
+    // Use unprivileged port (it's convenient for running tests as non-root).
+    int socket1 = 0;
+
+    EXPECT_NO_THROW(
+        socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000);
+    );
+
+    EXPECT_GT(socket1, 0);
+
+    Pkt4 pkt(DHCPDISCOVER, 1234);
+    pkt.setIface(LOOPBACK);
+
+    // Expect that we get the socket that we just opened.
+    EXPECT_EQ(socket1, ifacemgr->getSocket(pkt));
+
+    close(socket1);
+
+    delete ifacemgr;
+}
+
+// Test the Iface structure itself
+TEST_F(IfaceMgrTest, iface) {
+    IfaceMgr::Iface* iface = 0;
+    EXPECT_NO_THROW(
+        iface = new IfaceMgr::Iface("eth0",1);
+    );
+
+    EXPECT_EQ("eth0", iface->getName());
+    EXPECT_EQ(1, iface->getIndex());
+    EXPECT_EQ("eth0/1", iface->getFullName());
+
+    // Let's make a copy of this address collection.
+    IfaceMgr::AddressCollection addrs = iface->getAddresses();
+
+    EXPECT_EQ(0, addrs.size());
+
+    IOAddress addr1("192.0.2.6");
+    iface->addAddress(addr1);
+
+    addrs = iface->getAddresses();
+    ASSERT_EQ(1, addrs.size());
+    EXPECT_EQ("192.0.2.6", addrs.at(0).toText());
+
+    // No such address, should return false.
+    EXPECT_FALSE(iface->delAddress(IOAddress("192.0.8.9")));
+
+    // This address is present, delete it!
+    EXPECT_TRUE(iface->delAddress(IOAddress("192.0.2.6")));
+
+    // Not really necessary, previous reference still points to the same
+    // collection. Let's do it anyway, as test code may serve as example
+    // usage code as well.
+    addrs = iface->getAddresses();
+
+    EXPECT_EQ(0, addrs.size());
+
+    EXPECT_NO_THROW(
+        delete iface;
+    );
+}
+
+TEST_F(IfaceMgrTest, socketInfo) {
+
+    // check that socketinfo for IPv4 socket is functional
+    IfaceMgr::SocketInfo sock1(7, IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7);
+    EXPECT_EQ(7, sock1.sockfd_);
+    EXPECT_EQ("192.0.2.56", sock1.addr_.toText());
+    EXPECT_EQ(AF_INET, sock1.family_);
+    EXPECT_EQ(DHCP4_SERVER_PORT + 7, sock1.port_);
+
+    // check that socketinfo for IPv6 socket is functional
+    IfaceMgr::SocketInfo sock2(9, IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9);
+    EXPECT_EQ(9, sock2.sockfd_);
+    EXPECT_EQ("2001:db8:1::56", sock2.addr_.toText());
+    EXPECT_EQ(AF_INET6, sock2.family_);
+    EXPECT_EQ(DHCP4_SERVER_PORT + 9, sock2.port_);
+
+    // now let's test if IfaceMgr handles socket info properly
+    createLoInterfacesTxt();
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+    IfaceMgr::Iface* loopback = ifacemgr->getIface(LOOPBACK);
+    ASSERT_TRUE(loopback);
+    loopback->addSocket(sock1);
+    loopback->addSocket(sock2);
+
+    Pkt6 pkt6(100);
+
+    // pkt6 dos not have interface set yet
+    EXPECT_THROW(
+        ifacemgr->getSocket(pkt6),
+        BadValue
+    );
+
+    // try to send over non-existing interface
+    pkt6.iface_ = "nosuchinterface45";
+    EXPECT_THROW(
+        ifacemgr->getSocket(pkt6),
+        BadValue
+    );
+
+    // this will work
+    pkt6.iface_ = LOOPBACK;
+    EXPECT_EQ(9, ifacemgr->getSocket(pkt6));
+
+    bool deleted = false;
+    EXPECT_NO_THROW(
+        deleted = ifacemgr->getIface(LOOPBACK)->delSocket(9);
+    );
+    EXPECT_EQ(true, deleted);
+
+    // it should throw again, there's no usable socket anymore
+    EXPECT_THROW(
+        ifacemgr->getSocket(pkt6),
+        Unexpected
+    );
+
+    // repeat for pkt4
+    Pkt4 pkt4(DHCPDISCOVER, 1);
+
+    // pkt4 does not have interface set yet.
+    EXPECT_THROW(
+        ifacemgr->getSocket(pkt4),
+        BadValue
+    );
+
+    // Try to send over non-existing interface.
+    pkt4.setIface("nosuchinterface45");
+    EXPECT_THROW(
+        ifacemgr->getSocket(pkt4),
+        BadValue
+    );
+
+    // Socket info is set, packet has well defined interface. It should work.
+    pkt4.setIface(LOOPBACK);
+    EXPECT_EQ(7, ifacemgr->getSocket(pkt4));
+
+    EXPECT_NO_THROW(
+        ifacemgr->getIface(LOOPBACK)->delSocket(7);
+    );
+
+    // It should throw again, there's no usable socket anymore.
+    EXPECT_THROW(
+        ifacemgr->getSocket(pkt4),
+        Unexpected
+    );
+
+    delete ifacemgr;
+}
+
+}
diff --git a/src/lib/dhcp/tests/pkt4_unittest.cc b/src/lib/dhcp/tests/pkt4_unittest.cc
index 091bfac..fd28c5d 100644
--- a/src/lib/dhcp/tests/pkt4_unittest.cc
+++ b/src/lib/dhcp/tests/pkt4_unittest.cc
@@ -506,7 +506,7 @@ TEST(Pkt4Test, unpackOptions) {
 
     vector<uint8_t> expectedFormat = generateTestPacket2();
 
-    for (int i=0; i < sizeof(v4Opts); i++) {
+    for (int i = 0; i < sizeof(v4Opts); i++) {
         expectedFormat.push_back(v4Opts[i]);
     }
 
@@ -563,15 +563,19 @@ TEST(Pkt4Test, unpackOptions) {
 
 // This test verifies methods that are used for manipulating meta fields
 // i.e. fields that are not part of DHCPv4 (e.g. interface name).
-TEST(Pkt4Ttest, metaFields) {
-    Pkt4 pkt(DHCPDISCOVER, 1234);
+TEST(Pkt4Test, metaFields) {
 
-    pkt.setIface("lo0");
+    Pkt4* pkt = new Pkt4(DHCPOFFER, 1234);
+    pkt->setIface("loooopback");
+    pkt->setIndex(42);
+    pkt->setRemoteAddr(IOAddress("1.2.3.4"));
+    pkt->setLocalAddr(IOAddress("4.3.2.1"));
 
-    EXPECT_EQ("lo0", pkt.getIface());
+    EXPECT_EQ("loooopback", pkt->getIface());
+    EXPECT_EQ(42, pkt->getIndex());
+    EXPECT_EQ("1.2.3.4", pkt->getRemoteAddr().toText());
+    EXPECT_EQ("4.3.2.1", pkt->getLocalAddr().toText());
 
-    /// TODO: Expand this test once additonal getters/setters are
-    /// implemented.
 }
 
 } // end of anonymous namespace




More information about the bind10-changes mailing list