BIND 10 trac826, updated. 18f7b4e77b33207a54aaa19616cad1468a41c5f0 [trac826] dhcp6 bin updates
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Sep 28 23:00:38 UTC 2011
The branch, trac826 has been updated
via 18f7b4e77b33207a54aaa19616cad1468a41c5f0 (commit)
from a345a7b3ab571567f79decba3a8488c8ace56258 (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 18f7b4e77b33207a54aaa19616cad1468a41c5f0
Author: Francis Dupont <fdupont at isc.org>
Date: Thu Sep 29 00:59:40 2011 +0200
[trac826] dhcp6 bin updates
bin/dhcp6 (including updates)
compiles but doesn't yet fully work
-----------------------------------------------------------------------
Summary of changes:
src/bin/dhcp6/.gitignore | 9 +
src/bin/dhcp6/Makefile.am | 47 ++
src/bin/dhcp6/b10-dhcp6.8 | 50 ++
src/bin/dhcp6/dhcp6.spec | 14 +
src/bin/dhcp6/dhcp6_srv.cc | 220 ++++++
src/bin/dhcp6/dhcp6_srv.h | 78 ++
src/bin/dhcp6/iface_mgr.cc | 743 ++++++++++++++++++++
src/bin/dhcp6/iface_mgr.h | 104 +++
src/bin/dhcp6/interfaces.txt | 10 +
src/bin/dhcp6/main.cc | 130 ++++
.../spec_config.h.pre.in} | 9 +-
.../dhcp6/spec_config.h.win32} | 4 +-
src/bin/dhcp6/tests/Makefile.am | 64 ++
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 100 +++
src/bin/dhcp6/tests/dhcp6_test.py | 65 ++
.../dhcp6/tests/dhcp6_unittests.cc} | 13 +-
src/bin/dhcp6/tests/iface_mgr_unittest.cc | 418 +++++++++++
.../b10-dhcp6.vcxproj} | 47 +-
.../b10-dhcp6.vcxproj.filters} | 15 +-
.../b10-dhcp6.vcxproj.user} | 0
.../b10-dhcp6_tests.vcxproj} | 40 +-
.../b10-dhcp6_tests.vcxproj.filters} | 23 +-
.../b10-dhcp6_tests.vcxproj.user} | 0
win32build/VS2010/bind10.sln | 53 ++-
24 files changed, 2179 insertions(+), 77 deletions(-)
create mode 100644 src/bin/dhcp6/.gitignore
create mode 100644 src/bin/dhcp6/Makefile.am
create mode 100644 src/bin/dhcp6/b10-dhcp6.8
create mode 100644 src/bin/dhcp6/dhcp6.spec
create mode 100644 src/bin/dhcp6/dhcp6_srv.cc
create mode 100644 src/bin/dhcp6/dhcp6_srv.h
create mode 100644 src/bin/dhcp6/iface_mgr.cc
create mode 100644 src/bin/dhcp6/iface_mgr.h
create mode 100644 src/bin/dhcp6/interfaces.txt
create mode 100644 src/bin/dhcp6/main.cc
copy src/bin/{sockcreator/tests/run_unittests.cc => dhcp6/spec_config.h.pre.in} (85%)
copy src/{lib/config/tests/data_def_unittests_config.h.in => bin/dhcp6/spec_config.h.win32} (85%)
create mode 100644 src/bin/dhcp6/tests/Makefile.am
create mode 100644 src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
create mode 100644 src/bin/dhcp6/tests/dhcp6_test.py
copy src/{lib/resolve/tests/run_unittests.cc => bin/dhcp6/tests/dhcp6_unittests.cc} (86%)
create mode 100644 src/bin/dhcp6/tests/iface_mgr_unittest.cc
copy win32build/VS2010/{libcc_tests/libcc_tests.vcxproj => b10-dhcp6/b10-dhcp6.vcxproj} (66%)
copy win32build/VS2010/{libcfgclient/libcfgclient.vcxproj.filters => b10-dhcp6/b10-dhcp6.vcxproj.filters} (70%)
copy win32build/VS2010/{BINDInstall/BINDInstall.vcxproj.user => b10-dhcp6/b10-dhcp6.vcxproj.user} (100%)
copy win32build/VS2010/{libdhcp_tests/libdhcp_tests.vcxproj => b10-dhcp6_tests/b10-dhcp6_tests.vcxproj} (67%)
copy win32build/VS2010/{libasiodns_tests/libasiodns_tests.vcxproj.filters => b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.filters} (67%)
copy win32build/VS2010/{BINDInstall/BINDInstall.vcxproj.user => b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.user} (100%)
-----------------------------------------------------------------------
diff --git a/src/bin/dhcp6/.gitignore b/src/bin/dhcp6/.gitignore
new file mode 100644
index 0000000..6a6060b
--- /dev/null
+++ b/src/bin/dhcp6/.gitignore
@@ -0,0 +1,9 @@
+*~
+Makefile
+Makefile.in
+*.o
+.deps
+.libs
+b10-dhcp6
+spec_config.h
+spec_config.h.pre
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
new file mode 100644
index 0000000..6665573
--- /dev/null
+++ b/src/bin/dhcp6/Makefile.am
@@ -0,0 +1,47 @@
+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 += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiolink
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+
+CLEANFILES = *.gcno *.gcda spec_config.h
+
+man_MANS = b10-dhcp6.8
+EXTRA_DIST = $(man_MANS) dhcp6.spec interfaces.txt
+
+#if ENABLE_MAN
+#b10-dhcp6.8: b10-dhcp6.xml
+# xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-dhcp6.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-dhcp6
+b10_dhcp6_SOURCES = main.cc iface_mgr.cc dhcp6_srv.cc
+b10_dhcp6_SOURCES += iface_mgr.h dhcp6_srv.h
+
+b10_dhcp6_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+b10_dhcp6_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_dhcp6dir = $(pkgdatadir)
+b10_dhcp6_DATA = dhcp6.spec interfaces.txt
diff --git a/src/bin/dhcp6/b10-dhcp6.8 b/src/bin/dhcp6/b10-dhcp6.8
new file mode 100644
index 0000000..a05bf71
--- /dev/null
+++ b/src/bin/dhcp6/b10-dhcp6.8
@@ -0,0 +1,50 @@
+'\" t
+.\" Title: b10-dhpc6
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\" Date: March 8, 2011
+.\" Manual: BIND10
+.\" Source: BIND10
+.\" Language: English
+.\"
+.TH "B10\-DHCP6" "8" "March 8, 2011" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-dhcp6 \- DHCPv6 daemon in BIND10 architecture
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-dhcp6
+\fBb10\-dhcp6\fR [\fB\-v\fR]
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-dhcp6\fR
+daemon will provide DHCPv6 server implementation when it becomes functional.
+.PP
+.SH "SEE ALSO"
+.PP
+
+\fBb10-cfgmgr\fR(8),
+\fBb10-loadzone\fR(8),
+\fBb10-msgq\fR(8),
+\fBb10-stats\fR(8),
+\fBb10-zonemgr\fR(8),
+\fBbind10\fR(8),
+BIND 10 Guide\&.
+.SH "HISTORY"
+.PP
+The
+\fBb10\-dhcp6\fR
+daemon was first coded in June 2011\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
new file mode 100644
index 0000000..0e7e852
--- /dev/null
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -0,0 +1,14 @@
+{
+ "module_spec": {
+ "module_name": "dhcp6",
+ "module_description": "DHCPv6 daemon",
+ "config_data": [
+ { "item_name": "interface",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "eth0"
+ }
+ ],
+ "commands": []
+ }
+}
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
new file mode 100644
index 0000000..c15fecb
--- /dev/null
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -0,0 +1,220 @@
+// 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 <dhcp/dhcp6.h>
+#include <dhcp/pkt6.h>
+#include <dhcp6/iface_mgr.h>
+#include <dhcp6/dhcp6_srv.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <asiolink/io_address.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+Dhcpv6Srv::Dhcpv6Srv() {
+ cout << "Initialization" << endl;
+
+ // first call to instance() will create IfaceMgr (it's a singleton)
+ // it may throw something if things go wrong
+ IfaceMgr::instance();
+
+ if (!setServerID()) {
+ isc_throw(Unexpected, "Failed to set up server-id.");
+ }
+}
+
+Dhcpv6Srv::~Dhcpv6Srv() {
+ cout << "DHCPv6 Srv shutdown." << endl;
+}
+
+bool
+Dhcpv6Srv::run() {
+ while (true) {
+ boost::shared_ptr<Pkt6> query; // client's message
+ boost::shared_ptr<Pkt6> rsp; // server's response
+
+ query = IfaceMgr::instance().receive();
+
+ if (query) {
+ if (!query->unpack()) {
+ cout << "Failed to parse incoming packet" << endl;
+ continue;
+ }
+ switch (query->getType()) {
+ case DHCPV6_SOLICIT:
+ rsp = processSolicit(query);
+ break;
+ case DHCPV6_REQUEST:
+ rsp = processRequest(query);
+ break;
+ case DHCPV6_RENEW:
+ rsp = processRenew(query);
+ break;
+ case DHCPV6_REBIND:
+ rsp = processRebind(query);
+ break;
+ case DHCPV6_CONFIRM:
+ rsp = processConfirm(query);
+ break;
+ case DHCPV6_RELEASE:
+ rsp = processRelease(query);
+ break;
+ case DHCPV6_DECLINE:
+ rsp = processDecline(query);
+ break;
+ default:
+ cout << "Unknown pkt type received:"
+ << query->getType() << endl;
+ }
+
+ cout << "Received " << query->data_len_ << " bytes packet type="
+ << query->getType() << endl;
+ cout << query->toText();
+ if (rsp != boost::shared_ptr<Pkt6>()) {
+ rsp->remote_addr_ = query->remote_addr_;
+ rsp->local_addr_ = query->local_addr_;
+ rsp->remote_port_ = DHCP6_CLIENT_PORT;
+ rsp->local_port_ = DHCP6_SERVER_PORT;
+ rsp->ifindex_ = query->ifindex_;
+ rsp->iface_ = query->iface_;
+ cout << "Replying with:" << rsp->getType() << endl;
+ cout << rsp->toText();
+ cout << "----" << endl;
+ if (rsp->pack()) {
+ cout << "#### pack successful." << endl;
+ }
+ IfaceMgr::instance().send(rsp);
+ }
+ }
+
+ // TODO add support for config session (see src/bin/auth/main.cc)
+ // so this daemon can be controlled from bob
+ }
+
+ return (true);
+}
+
+boost::shared_ptr<Option>
+Dhcpv6Srv::getServerID() {
+ return serverid_;
+}
+
+bool
+Dhcpv6Srv::setServerID() {
+ /// TODO implement this for real once interface detection is done.
+ /// Use hardcoded server-id for now
+
+ boost::shared_array<char> srvid(new char[14]);
+ srvid[0] = 0;
+ srvid[1] = 1; // DUID type 1 = DUID-LLT (see section 9.2 of RFC3315)
+ srvid[2] = 0;
+ srvid[3] = 6; // HW type = ethernet (I think. I'm typing this from my head
+ // in hotel, without Internet connection)
+ for (int i=4; i<14; i++) {
+ srvid[i]=i-4;
+ }
+ serverid_ = boost::shared_ptr<Option>(new Option(Option::V6,
+ D6O_SERVERID,
+ srvid,
+ 0, 14));
+ return (true);
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
+
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_ADVERTISE,
+ solicit->getTransid(),
+ Pkt6::UDP));
+
+ // answer client's IA (this is mostly a dummy,
+ // so let's answer only first IA and hope there is only one)
+ boost::shared_ptr<Option> ia_opt = solicit->getOption(D6O_IA_NA);
+ if (ia_opt) {
+ // found IA
+ Option * tmp = ia_opt.get();
+ Option6IA * ia_req = dynamic_cast<Option6IA*> (tmp);
+ if (ia_req) {
+ boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(Option::V6, D6O_IA_NA, ia_req->getIAID()));
+ ia_rsp->setT1(1500);
+ ia_rsp->setT2(2600);
+ boost::shared_ptr<Option6IAAddr> addr(new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 5000, 7000));
+ ia_rsp->addOption(addr);
+ reply->addOption(ia_rsp);
+ }
+ }
+
+ // add client-id
+ boost::shared_ptr<Option> clientid = solicit->getOption(D6O_CLIENTID);
+ if (clientid) {
+ reply->addOption(clientid);
+ }
+
+ // add server-id
+ reply->addOption(getServerID());
+ return reply;
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processRequest(boost::shared_ptr<Pkt6> request) {
+ /// TODO: Implement processRequest() for real
+ boost::shared_ptr<Pkt6> reply = processSolicit(request);
+ reply->setType(DHCPV6_REPLY);
+ return reply;
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processRenew(boost::shared_ptr<Pkt6> renew) {
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+ renew->getTransid(),
+ Pkt6::UDP));
+ return reply;
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processRebind(boost::shared_ptr<Pkt6> rebind) {
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+ rebind->getTransid(),
+ Pkt6::UDP));
+ return reply;
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processConfirm(boost::shared_ptr<Pkt6> confirm) {
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+ confirm->getTransid(),
+ Pkt6::UDP));
+ return reply;
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processRelease(boost::shared_ptr<Pkt6> release) {
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+ release->getTransid(),
+ Pkt6::UDP));
+ return reply;
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processDecline(boost::shared_ptr<Pkt6> decline) {
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+ decline->getTransid(),
+ Pkt6::UDP));
+ return reply;
+}
+
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
new file mode 100644
index 0000000..830132b
--- /dev/null
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -0,0 +1,78 @@
+// 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 DHCPV6_SRV_H
+#define DHCPV6_SRV_H
+
+#include <boost/shared_ptr.hpp>
+#include <dhcp/pkt6.h>
+#include <dhcp/option.h>
+#include <iostream>
+
+namespace test {
+class Dhcpv6SrvTest_Solicit_basic_Test;
+}
+
+namespace isc {
+ class Dhcpv6Srv {
+ private:
+ // defined private on purpose. We don't want to have more than
+ // one copy
+ Dhcpv6Srv(const Dhcpv6Srv& src);
+ Dhcpv6Srv& operator=(const Dhcpv6Srv& src);
+
+ boost::shared_ptr<isc::dhcp::Option> getServerID();
+
+ // this method sets server-identifier. it loads it from a file or
+ // generates using interface link-layer addresses (EUI-64)
+ bool setServerID();
+
+ boost::shared_ptr<isc::dhcp::Option> serverid_;
+
+ public:
+ // default constructor
+ Dhcpv6Srv();
+ ~Dhcpv6Srv();
+
+ bool run();
+
+ protected:
+ boost::shared_ptr<Pkt6>
+ processSolicit(boost::shared_ptr<Pkt6> solicit);
+
+ boost::shared_ptr<Pkt6>
+ processRequest(boost::shared_ptr<Pkt6> solicit);
+
+ boost::shared_ptr<Pkt6>
+ processRenew(boost::shared_ptr<Pkt6> solicit);
+
+ boost::shared_ptr<Pkt6>
+ processRebind(boost::shared_ptr<Pkt6> solicit);
+
+ boost::shared_ptr<Pkt6>
+ processConfirm(boost::shared_ptr<Pkt6> solicit);
+
+ boost::shared_ptr<Pkt6>
+ processRelease(boost::shared_ptr<Pkt6> solicit);
+
+ boost::shared_ptr<Pkt6>
+ processDecline(boost::shared_ptr<Pkt6> solicit);
+
+ bool shutdown;
+
+ friend class test::Dhcpv6SrvTest_Solicit_basic_Test;
+ };
+};
+
+#endif // DHCP6_SRV_H
diff --git a/src/bin/dhcp6/iface_mgr.cc b/src/bin/dhcp6/iface_mgr.cc
new file mode 100644
index 0000000..f7b273b
--- /dev/null
+++ b/src/bin/dhcp6/iface_mgr.cc
@@ -0,0 +1,743 @@
+// 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>
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#include <netioapi.h>
+#else
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#endif
+
+#include <dhcp/dhcp6.h>
+#include <dhcp6/iface_mgr.h>
+#include <exceptions/exceptions.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+
+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, 20);
+}
+
+std::string
+IfaceMgr::Iface::getFullName() const {
+ ostringstream tmp;
+ tmp << name_ << "/" << ifindex_;
+ return (tmp.str());
+}
+
+std::string
+IfaceMgr::Iface::getPlainMac() const {
+ ostringstream tmp;
+ for (int i=0; i<mac_len_; i++) {
+ tmp.fill('0');
+ tmp.width(2);
+ tmp << (hex) << (int) mac_[i];
+ if (i<mac_len_-1) {
+ tmp << ":";
+ }
+ }
+ return (tmp.str());
+}
+
+IfaceMgr::IfaceMgr() {
+
+ 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_len_ = CMSG_SPACE(sizeof(struct in6_pktinfo));
+ control_buf_ = new char[control_buf_len_];
+
+ detectIfaces();
+
+ if (!openSockets()) {
+ isc_throw(Unexpected, "Failed to open/bind sockets.");
+ }
+ } catch (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;
+ }
+}
+
+IfaceMgr::~IfaceMgr() {
+ if (control_buf_) {
+ delete [] control_buf_;
+ control_buf_ = 0;
+ 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.addrs_.push_back(addr);
+ ifaces_.push_back(iface);
+ interfaces.close();
+ } catch (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;
+ }
+}
+
+bool
+IfaceMgr::openSockets() {
+ int sock;
+
+ for (IfaceLst::iterator iface=ifaces_.begin();
+ iface!=ifaces_.end();
+ ++iface) {
+
+ for (Addr6Lst::iterator addr=iface->addrs_.begin();
+ addr!=iface->addrs_.end();
+ ++addr) {
+
+ sock = openSocket(iface->name_, *addr,
+ DHCP6_SERVER_PORT);
+#ifdef _WIN32
+ if (sock == INVALID_SOCKET) {
+ cout << "Failed to open unicast socket." << endl;
+ return (false);
+ }
+#else
+ if (sock<0) {
+ cout << "Failed to open unicast socket." << endl;
+ return (false);
+ }
+#endif
+
+ sendsock_ = sock;
+
+ sock = openSocket(iface->name_,
+ IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
+ DHCP6_SERVER_PORT);
+#ifdef _WIN32
+ if (sock == INVALID_SOCKET) {
+ cout << "Failed to open multicast socket." << endl;
+ closesocket(sendsock_);
+ return (false);
+ }
+#else
+ if (sock<0) {
+ cout << "Failed to open multicast socket." << endl;
+ close(sendsock_);
+ return (false);
+ }
+#endif
+ recvsock_ = sock;
+ }
+ }
+
+ return (true);
+}
+
+void
+IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
+ for (IfaceLst::const_iterator iface=ifaces_.begin();
+ iface!=ifaces_.end();
+ ++iface) {
+ out << "Detected interface " << iface->getFullName() << endl;
+ out << " " << iface->addrs_.size() << " addr(s):" << endl;
+ for (Addr6Lst::const_iterator addr=iface->addrs_.begin();
+ addr != iface->addrs_.end();
+ ++addr) {
+ out << " " << addr->toText() << endl;
+ }
+ out << " mac: " << iface->getPlainMac() << endl;
+ }
+}
+
+IfaceMgr::Iface*
+IfaceMgr::getIface(int ifindex) {
+ for (IfaceLst::iterator iface=ifaces_.begin();
+ iface!=ifaces_.end();
+ ++iface) {
+ if (iface->ifindex_ == ifindex)
+ return (&(*iface));
+ }
+
+ return (NULL); // not found
+}
+
+IfaceMgr::Iface*
+IfaceMgr::getIface(const std::string& ifname) {
+ for (IfaceLst::iterator iface=ifaces_.begin();
+ iface!=ifaces_.end();
+ ++iface) {
+ if (iface->name_ == ifname)
+ return (&(*iface));
+ }
+
+ return (NULL); // not found
+}
+
+
+/**
+ * Opens UDP/IPv6 socket and binds it to specific address, interface nad port.
+ *
+ * @param ifname name of the interface
+ * @param addr address to be bound.
+ * @param port UDP port.
+ * @param mcast Should multicast address also be bound?
+ *
+ * @return socket descriptor, if socket creation, binding and multicast
+ * group join were all successful. -1 otherwise.
+ */
+int
+IfaceMgr::openSocket(const std::string& ifname,
+ const IOAddress& addr,
+ int port) {
+ struct sockaddr_storage name;
+ int name_len;
+ struct sockaddr_in6 *addr6;
+
+ cout << "Creating socket on " << ifname << "/" << addr.toText()
+ << "/port=" << port << endl;
+
+ memset(&name, 0, sizeof(name));
+ addr6 = (struct sockaddr_in6 *)&name;
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_port = htons(port);
+ addr6->sin6_scope_id = if_nametoindex(ifname.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
+ name_len = sizeof(*addr6);
+
+ // TODO: use sockcreator once it becomes available
+
+ // make a socket
+ int sock = socket(AF_INET6, SOCK_DGRAM, 0);
+#ifdef _WIN32
+ if (sock == INVALID_SOCKET) {
+ cout << "Failed to create UDP6 socket." << endl;
+ return (INVALID_SOCKET);
+ }
+#else
+ if (sock < 0) {
+ cout << "Failed to create UDP6 socket." << endl;
+ return (-1);
+ }
+#endif
+ /* 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) {
+ cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
+#ifdef _WIN32
+ closesocket(sock);
+ return (INVALID_SOCKET);
+#else
+ close(sock);
+ return (-1);
+#endif
+ }
+
+#ifdef _WIN32
+ if (::bind(sock, (struct sockaddr *)&name, name_len) < 0) {
+ cout << "Failed to bind socket " << sock << " to " << addr.toText()
+ << "/port=" << port << endl;
+ closesocket(sock);
+ return (INVALID_SOCKET);
+ }
+#else
+ if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
+ cout << "Failed to bind socket " << sock << " to " << addr.toText()
+ << "/port=" << port << endl;
+ close(sock);
+ return (-1);
+ }
+#endif
+
+
+#ifdef IPV6_RECVPKTINFO
+ /* RFC3542 - a new way */
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (char *)&flag, sizeof(flag)) != 0) {
+ cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
+#ifdef _WIN32
+ closesocket(sock);
+ return (INVALID_SOCKET);
+#else
+ close(sock);
+ return (-1);
+#endif
+ }
+#else
+ /* RFC2292 - an old way */
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
+ (char *)&flag, sizeof(flag)) != 0) {
+ cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
+#ifdef _WIN32
+ closesocket(sock);
+ return (INVALID_SOCKET);
+#else
+ close(sock);
+ return (-1);
+#endif
+ }
+#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, ifname,
+ string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
+#ifdef _WIN32
+ closesocket(sock);
+ return (INVALID_SOCKET);
+#else
+ close(sock);
+ return (-1);
+#endif
+ }
+ }
+
+ cout << "Created socket " << sock << " on " << ifname << "/" <<
+ addr.toText() << "/port=" << port << endl;
+
+ return (sock);
+}
+
+/**
+ * joins multicast group
+ *
+ * @param sock socket file descriptor
+ * @param ifname name of the interface (DHCPv6 uses link-scoped mc groups)
+ * @param mcast multicast address to join (string)
+ *
+ * @return true if joined successfully, false otherwise
+ */
+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,
+ (char *)&mreq, sizeof(mreq)) < 0) {
+ cout << "Failed to join " << mcast << " multicast group." << endl;
+ return (false);
+ }
+
+ cout << "Joined multicast " << mcast << " group." << endl;
+
+ return (true);
+}
+
+/**
+ * Sends UDP packet over IPv6.
+ *
+ * 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 A packet object that is going to be sent.
+ *
+ * @return True, if transmission was successful. False otherwise.
+ */
+bool
+IfaceMgr::send(boost::shared_ptr<Pkt6> pkt) {
+#ifdef _WIN32
+ WSAMSG m;
+ WSABUF v;
+#else
+ struct msghdr m;
+ struct iovec v;
+#endif
+ int result;
+ struct in6_pktinfo *pktinfo;
+#ifdef _WIN32
+ WSACMSGHDR *cmsg;
+#else
+ struct cmsghdr *cmsg;
+#endif
+ memset(control_buf_, 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_;
+
+#ifdef _WIN32
+ m.name = (struct sockaddr *)&to;
+ m.namelen = sizeof(to);
+#else
+ m.msg_name = (struct sockaddr *)&to;
+ m.msg_namelen = sizeof(to);
+#endif
+
+ /*
+ * 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.)
+ */
+#ifdef _WIN32
+ v.buf = (char *) &pkt->data_[0];
+ v.len = pkt->data_len_;
+ m.lpBuffers = &v;
+ m.dwBufferCount = 1;
+#else
+ v.iov_base = (char *) &pkt->data_[0];
+ v.iov_len = pkt->data_len_;
+ m.msg_iov = &v;
+ m.msg_iovlen = 1;
+#endif
+
+ /*
+ * 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.
+ */
+#ifdef _WIN32
+ m.Control.buf = control_buf_;
+ m.Control.len = control_buf_len_;
+ cmsg = CMSG_FIRSTHDR(&m);
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(*pktinfo));
+ pktinfo = (struct in6_pktinfo *)WSA_CMSG_DATA(cmsg);
+ memset(pktinfo, 0, sizeof(*pktinfo));
+ pktinfo->ipi6_ifindex = pkt->ifindex_;
+ m.Control.len = cmsg->cmsg_len;
+#else
+ m.msg_control = control_buf_;
+ 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;
+#endif
+
+#ifdef _WIN32
+ DWORD bsent;
+ if (WSASendMsg(sendsock_, &m, 0, &bsent, NULL, NULL) == SOCKET_ERROR)
+ result = -1;
+ else
+ result = (int) bsent;
+#else
+ result = sendmsg(sendsock_, &m, 0);
+#endif
+ if (result < 0) {
+ cout << "Send packet failed." << endl;
+ }
+ cout << "Sent " << result << " bytes." << endl;
+
+ cout << "Sent " << pkt->data_len_ << " bytes over "
+ << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
+ << " dst=" << pkt->remote_addr_.toText()
+ << ", src=" << pkt->local_addr_.toText()
+ << endl;
+
+ return (result >= 0);
+}
+
+
+/**
+ * Attempts to receive UDP/IPv6 packet over open sockets.
+ *
+ * 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 Object prepresenting received packet.
+ */
+boost::shared_ptr<Pkt6>
+IfaceMgr::receive() {
+#ifdef _WIN32
+ GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
+ LPFN_WSARECVMSG WSARecvMsg;
+ WSAMSG m;
+ WSABUF v;
+#else
+ struct msghdr m;
+ struct iovec v;
+#endif
+ int result;
+#ifdef _WIN32
+ WSACMSGHDR *cmsg;
+#else
+ struct cmsghdr *cmsg;
+#endif
+ 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 (std::exception&) {
+ cout << "Failed to create new packet." << endl;
+ return (boost::shared_ptr<Pkt6>()); // NULL
+ }
+
+ memset(control_buf_, 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.
+ */
+#ifdef _WIN32
+ m.name = (struct sockaddr *)&from;
+ m.namelen = sizeof(from);
+#else
+ m.msg_name = (struct sockaddr *)&from;
+ m.msg_namelen = sizeof(from);
+#endif
+
+ /*
+ * 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.)
+ */
+#ifdef _WIN32
+ v.buf = (char *)&pkt->data_[0];
+ v.len = pkt->data_len_;
+ m.lpBuffers = &v;
+ m.dwBufferCount = 1;
+#else
+ v.iov_base = (char *)&pkt->data_[0];
+ v.iov_len = pkt->data_len_;
+ m.msg_iov = &v;
+ m.msg_iovlen = 1;
+#endif
+
+ /*
+ * 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.
+ */
+#ifdef _WIN32
+ m.Control.buf = control_buf_;
+ m.Control.len = control_buf_len_;
+#else
+ m.msg_control = control_buf_;
+ m.msg_controllen = control_buf_len_;
+#endif
+
+#ifdef _WIN32
+ DWORD brecv;
+ if ((WSAIoctl(recvsock_, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
+ &WSARecvMsg, sizeof(WSARecvMsg),
+ &brecv, NULL, NULL) == SOCKET_ERROR) ||
+ (WSARecvMsg(recvsock_, &m, &brecv, NULL, NULL) == SOCKET_ERROR))
+ result = -1;
+ else
+ result = (int) brecv;
+#else
+ result = recvmsg(recvsock_, &m, 0);
+#endif
+
+ 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;
+#ifdef _WIN32
+ cmsg = WSA_CMSG_FIRSTHDR(&m);
+#else
+ cmsg = CMSG_FIRSTHDR(&m);
+#endif
+ while (cmsg != NULL) {
+ if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
+ (cmsg->cmsg_type == IPV6_PKTINFO)) {
+#ifdef _WIN32
+ pktinfo = (struct in6_pktinfo*)WSA_CMSG_DATA(cmsg);
+#else
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+#endif
+ to_addr = pktinfo->ipi6_addr;
+ pkt->ifindex_ = pktinfo->ipi6_ifindex;
+ found_pktinfo = 1;
+ }
+#ifdef _WIN32
+ cmsg = WSA_CMSG_NXTHDR(&m, cmsg);
+#else
+ cmsg = CMSG_NXTHDR(&m, cmsg);
+#endif
+ }
+ 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!
+#ifdef _WIN32
+#define DECONST (void *)
+#else
+#define DECONST
+#endif
+ inet_ntop(AF_INET6, DECONST &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, DECONST &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->name_;
+ } 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);
+}
+
+}
diff --git a/src/bin/dhcp6/iface_mgr.h b/src/bin/dhcp6/iface_mgr.h
new file mode 100644
index 0000000..67ebefc
--- /dev/null
+++ b/src/bin/dhcp6/iface_mgr.h
@@ -0,0 +1,104 @@
+// 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 <asiolink/io_address.h>
+#include <dhcp/pkt6.h>
+
+namespace isc {
+
+ /**
+ * 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:
+ typedef std::list<isc::asiolink::IOAddress> Addr6Lst;
+ struct Iface { // TODO: could be a class as well
+ std::string name_; // network interface name
+ int ifindex_; // interface index (a value that uniquely indentifies
+ // an interface
+ Addr6Lst addrs_;
+ char mac_[20]; // Infiniband used 20 bytes indentifiers
+ int mac_len_;
+
+ Iface(const std::string& name, int ifindex);
+ std::string getFullName() const;
+ std::string getPlainMac() const;
+
+ int sendsock_; // socket used to sending data
+ int recvsock_; // socket used for receiving data
+
+ // next field is not needed, let's keep it in cointainers
+ };
+
+ // 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)
+ typedef std::list<Iface> IfaceLst;
+
+ static IfaceMgr& instance();
+
+ Iface * getIface(int ifindex);
+ Iface * getIface(const std::string& ifname);
+
+ void printIfaces(std::ostream& out = std::cout);
+
+ bool send(boost::shared_ptr<Pkt6> pkt);
+ boost::shared_ptr<Pkt6> receive();
+
+ // don't use private, we need derived classes in tests
+ protected:
+ IfaceMgr(); // don't create IfaceMgr directly, use instance() method
+ ~IfaceMgr();
+
+ void detectIfaces();
+
+ int openSocket(const std::string& ifname,
+ const isc::asiolink::IOAddress& addr,
+ int port);
+
+ // TODO: having 2 maps (ifindex->iface and ifname->iface would)
+ // probably be better for performance reasons
+ IfaceLst ifaces_;
+
+ 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.
+
+ char * control_buf_;
+ int control_buf_len_;
+
+ private:
+ bool openSockets();
+ static void instanceCreate();
+ bool joinMcast(int sock, const std::string& ifname,
+ const std::string& mcast);
+ };
+};
+
+#endif
diff --git a/src/bin/dhcp6/interfaces.txt b/src/bin/dhcp6/interfaces.txt
new file mode 100644
index 0000000..6a64309
--- /dev/null
+++ b/src/bin/dhcp6/interfaces.txt
@@ -0,0 +1,10 @@
+eth0 fe80::21e:8cff:fe9b:7349
+
+#
+# only first line is read.
+# please use following format:
+# interface-name link-local-ipv6-address
+#
+# This file will become obsolete once proper interface detection
+# is implemented.
+#
diff --git a/src/bin/dhcp6/main.cc b/src/bin/dhcp6/main.cc
new file mode 100644
index 0000000..a73434f
--- /dev/null
+++ b/src/bin/dhcp6/main.cc
@@ -0,0 +1,130 @@
+// 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>
+
+#ifdef _WIN32
+#include <getopt.h>
+#include <ws2tcpip.h>
+#include <process.h>
+#define getpid _getpid
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+
+#include <cassert>
+#include <iostream>
+
+#include <exceptions/exceptions.h>
+#include <cc/session.h>
+#include <config/ccsession.h>
+
+#include <util/buffer.h>
+#include <log/dummylog.h>
+
+#include <dhcp6/spec_config.h>
+#include <dhcp6/dhcp6_srv.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::data;
+using namespace isc::cc;
+using namespace isc::config;
+using namespace isc::util;
+
+using namespace isc;
+
+namespace {
+
+bool verbose_mode = false;
+
+void
+usage() {
+ cerr << "Usage: b10-dhcp6 [-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();
+ }
+
+#ifdef _WIN32
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(2,2), &wsaData);
+#endif
+
+ int ret = 0;
+
+ // TODO remainder of auth to dhcp6 code copy. We need to enable this in
+ // dhcp6 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/dhcp6.spec";
+ } else {
+ specfile = string(DHCP6_SPECFILE_LOCATION);
+ }
+
+ // auth_server = new AuthSrv(cache, xfrout_client);
+ // auth_server->setVerbose(verbose_mode);
+ cout << "[b10-dhcp6] Initiating DHCPv6 operation." << endl;
+
+ Dhcpv6Srv* srv = new Dhcpv6Srv();
+
+ srv->run();
+
+ } catch (const std::exception& ex) {
+ cerr << "[b10-dhcp6] Server failed: " << ex.what() << endl;
+ ret = 1;
+ }
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ return (ret);
+}
diff --git a/src/bin/dhcp6/spec_config.h.pre.in b/src/bin/dhcp6/spec_config.h.pre.in
new file mode 100644
index 0000000..42775b2
--- /dev/null
+++ b/src/bin/dhcp6/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 DHCP6_SPECFILE_LOCATION "@prefix@/share/@PACKAGE@/dhcp6.spec"
diff --git a/src/bin/dhcp6/spec_config.h.win32 b/src/bin/dhcp6/spec_config.h.win32
new file mode 100644
index 0000000..1f4c8bd
--- /dev/null
+++ b/src/bin/dhcp6/spec_config.h.win32
@@ -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 DHCP6_SPECFILE_LOCATION "c:/Temp/dhcp6.spec"
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
new file mode 100644
index 0000000..dac3081
--- /dev/null
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -0,0 +1,64 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+#PYTESTS = args_test.py bind10_test.py
+# NOTE: this has a generated test found in the builddir
+PYTESTS = dhcp6_test.py
+EXTRA_DIST = $(PYTESTS)
+
+# 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/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:$$$(ENV_LIBRARY_PATH)
+endif
+
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+ for pytest in $(PYTESTS) ; do \
+ echo Running test: $$pytest ; \
+ env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
+ $(LIBRARY_PATH_PLACEHOLDER) \
+ BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
+ $(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
+ done
+
+
+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/lib/testutils/testdata\"
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+TESTS =
+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_unittests.cc
+dhcp6_unittests_SOURCES += iface_mgr_unittest.cc
+dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
+
+dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+dhcp6_unittests_LDADD = $(GTEST_LDADD)
+dhcp6_unittests_LDADD += $(SQLITE_LIBS)
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
new file mode 100644
index 0000000..1758bbc
--- /dev/null
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -0,0 +1,100 @@
+// 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>
+
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#else
+#include <arpa/inet.h>
+#endif
+#include <gtest/gtest.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp6/dhcp6_srv.h>
+#include <dhcp/option6_ia.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+
+// namespace has to be named, because friends are defined in Dhcpv6Srv class
+// Maybe it should be isc::test?
+namespace test {
+
+class Dhcpv6SrvTest : public ::testing::Test {
+public:
+ Dhcpv6SrvTest() {
+ }
+};
+
+TEST_F(Dhcpv6SrvTest, basic) {
+ // there's almost no code now. What's there provides echo capability
+ // that is just a proof of concept and will be removed soon
+ // No need to thoroughly test it
+
+ // srv has stubbed interface detection. It will read
+ // interfaces.txt instead. It will pretend to have detected
+ // fe80::1234 link-local address on eth0 interface. Obviously
+
+ // an attempt to bind this socket will fail.
+ EXPECT_NO_THROW( {
+ Dhcpv6Srv * srv = new Dhcpv6Srv();
+
+ delete srv;
+ });
+
+}
+
+TEST_F(Dhcpv6SrvTest,Solicit_basic) {
+ Dhcpv6Srv * srv = 0;
+ EXPECT_NO_THROW( srv = new Dhcpv6Srv(); );
+
+ boost::shared_ptr<Pkt6> sol =
+ boost::shared_ptr<Pkt6>(new Pkt6(DHCPV6_SOLICIT,
+ 1234, Pkt6::UDP));
+
+ boost::shared_ptr<Option6IA> ia(new Option6IA(Option::V6, D6O_IA_NA, 2345));
+ ia->setT1(1501);
+ ia->setT2(2601);
+ sol->addOption(ia);
+
+ // Let's not send address in solicit yet
+ // boost::shared_ptr<Option6IAAddr> addr(new Option6IAAddr(D6O_IAADDR,
+ // IOAddress("2001:db8:1234:ffff::ffff"), 5001, 7001));
+ // ia->addOption(addr);
+ // sol->addOption(ia);
+
+ boost::shared_ptr<Pkt6> reply = srv->processSolicit(sol);
+
+ // check if we get response at all
+ ASSERT_TRUE( reply != boost::shared_ptr<Pkt6>() );
+
+ EXPECT_EQ( DHCPV6_ADVERTISE, reply->getType() );
+ EXPECT_EQ( 1234, reply->getTransid() );
+
+ boost::shared_ptr<Option> tmp = reply->getOption(D6O_IA_NA);
+ ASSERT_TRUE( tmp != boost::shared_ptr<Option>() );
+
+ Option6IA * reply_ia = dynamic_cast<Option6IA*> ( tmp.get() );
+ EXPECT_EQ( 2345, reply_ia->getIAID() );
+
+ // more checks to be implemented
+ delete srv;
+
+}
+
+}
diff --git a/src/bin/dhcp6/tests/dhcp6_test.py b/src/bin/dhcp6/tests/dhcp6_test.py
new file mode 100644
index 0000000..61ec009
--- /dev/null
+++ b/src/bin/dhcp6/tests/dhcp6_test.py
@@ -0,0 +1,65 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+from bind10 import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
+
+import unittest
+import sys
+import os
+import signal
+import socket
+from isc.net.addr import IPAddr
+import time
+import isc
+
+class TestDhcpv6Daemon(unittest.TestCase):
+ def setUp(self):
+ # redirect stdout to a pipe so we can check that our
+ # process spawning is doing the right thing with stdout
+ self.old_stdout = os.dup(sys.stdout.fileno())
+ self.pipes = os.pipe()
+ os.dup2(self.pipes[1], sys.stdout.fileno())
+ os.close(self.pipes[1])
+ # note that we use dup2() to restore the original stdout
+ # to the main program ASAP in each test... this prevents
+ # hangs reading from the child process (as the pipe is only
+ # open in the child), and also insures nice pretty output
+
+ def tearDown(self):
+ # clean up our stdout munging
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ os.close(self.pipes[0])
+
+ def test_alive(self):
+ """
+ Simple test. Checks that b10-dhcp6 can be started and prints out info
+ about starting DHCPv6 operation.
+ """
+ pi = ProcessInfo('Test Process', [ '../b10-dhcp6' , '-v' ])
+ pi.spawn()
+ time.sleep(1)
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ self.assertNotEqual(pi.process, None)
+ self.assertTrue(type(pi.pid) is int)
+ output = os.read(self.pipes[0], 4096)
+ self.assertEqual( str(output).count("[b10-dhcp6] Initiating DHCPv6 operation."), 1)
+
+ # kill this process
+ # XXX: b10-dhcp6 is too dumb to understand 'shutdown' command for now,
+ # so let's just kill the bastard
+ os.kill(pi.pid, signal.SIGTERM)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/bin/dhcp6/tests/dhcp6_unittests.cc b/src/bin/dhcp6/tests/dhcp6_unittests.cc
new file mode 100644
index 0000000..c410bd4
--- /dev/null
+++ b/src/bin/dhcp6/tests/dhcp6_unittests.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2009 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>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#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();
+
+#ifdef _WIN32
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(2,2), &wsaData);
+ int result = RUN_ALL_TESTS();
+ WSACleanup();
+#else
+ int result = RUN_ALL_TESTS();
+#endif
+
+ return result;
+}
diff --git a/src/bin/dhcp6/tests/iface_mgr_unittest.cc b/src/bin/dhcp6/tests/iface_mgr_unittest.cc
new file mode 100644
index 0000000..8f3b7ca
--- /dev/null
+++ b/src/bin/dhcp6/tests/iface_mgr_unittest.cc
@@ -0,0 +1,418 @@
+// 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>
+
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#define unlink _unlink
+#else
+#include <arpa/inet.h>
+#endif
+#include <gtest/gtest.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/pkt6.h>
+#include <dhcp6/iface_mgr.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+
+// name of loopback interface detection
+char LOOPBACK[32] = "lo";
+
+namespace {
+class NakedIfaceMgr: public IfaceMgr {
+ // "naked" Interface Manager, exposes internal fields
+public:
+ NakedIfaceMgr() { }
+ IfaceLst & getIfacesLst() { return ifaces_; }
+ void setSendSock(int sock) { sendsock_ = sock; }
+ void setRecvSock(int sock) { recvsock_ = sock; }
+
+ int openSocket(const std::string& ifname,
+ const isc::asiolink::IOAddress& addr,
+ int port) {
+ return IfaceMgr::openSocket(ifname, addr, port);
+ }
+
+};
+
+// dummy class for now, but this will be expanded when needed
+class IfaceMgrTest : public ::testing::Test {
+public:
+ IfaceMgrTest() {
+ }
+};
+
+// 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.
+TEST_F(IfaceMgrTest, loDetect) {
+
+ unlink("interfaces.txt");
+
+ ofstream interfaces("interfaces.txt", ios::ate);
+ interfaces << "lo ::1";
+ interfaces.close();
+
+ NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+ IOAddress loAddr("::1");
+ IOAddress mcastAddr("ff02::1:2");
+
+ // bind multicast socket to port 10547
+ int socket1 = ifacemgr->openSocket("lo", mcastAddr, 10547);
+ // this fails on BSD (there's no lo interface there)
+
+ // poor man's interface dection
+ // it will go away as soon as proper interface detection
+ // is implemented
+#ifdef _WIN32
+ if (socket1 != INVALID_SOCKET) {
+ cout << "This is Linux, using lo as loopback." << endl;
+ closesocket(socket1);
+ }
+#else
+ if (socket1>0) {
+ cout << "This is Linux, using lo as loopback." << endl;
+ close(socket1);
+ }
+#endif
+ else {
+ // this fails on Linux and succeeds on BSD
+ socket1 = ifacemgr->openSocket("lo0", mcastAddr, 10547);
+#ifdef _WIN32
+ if (socket1 != INVALID_SOCKET) {
+ sprintf(LOOPBACK, "lo0");
+ cout << "This is BSD, using lo0 as loopback." << endl;
+ closesocket(socket1);
+ }
+#else
+ if (socket1>0) {
+ sprintf(LOOPBACK, "lo0");
+ cout << "This is BSD, using lo0 as loopback." << endl;
+ close(socket1);
+ }
+#endif
+ else {
+ cout << "Failed to detect loopback interface. Neither "
+ << "lo or lo0 worked. I give up." << endl;
+ ASSERT_TRUE(false);
+ }
+ }
+
+ delete ifacemgr;
+}
+
+// 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 << "// 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;
+ 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::IfaceLst::iterator iface=ifacemgr->getIfacesLst().begin();
+ iface != ifacemgr->getIfacesLst().end();
+ ++iface) {
+ cout << " " << iface->name_ << "/" << iface->ifindex_ << 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_STREQ( "en3", tmp->name_.c_str() );
+ EXPECT_EQ(5, tmp->ifindex_);
+
+ // check that interface can be retrieved by name
+ tmp = ifacemgr->getIface("lo1");
+ ASSERT_TRUE( tmp != NULL );
+
+ EXPECT_STREQ( "lo1", tmp->name_.c_str() );
+ EXPECT_EQ(1, tmp->ifindex_);
+
+ // check that non-existing interfaces are not returned
+ EXPECT_EQ(0, 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("interfaces.txt", 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
+ EXPECT_EQ(1, eth0->addrs_.size());
+
+ IOAddress * addr = &(*eth0->addrs_.begin());
+ ASSERT_TRUE( addr != NULL );
+
+ EXPECT_STREQ( "fe80::1234", addr->toText().c_str() );
+
+ delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, sockets) {
+ // testing socket operation in a portable way is tricky
+ // without interface detection implemented
+
+ NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+ IOAddress loAddr("::1");
+
+ // bind multicast socket to port 10547
+ int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+#ifdef _WIN32
+ EXPECT_NE(socket1, INVALID_SOCKET); // socket != INVALID_SOCKET
+#else
+ EXPECT_GT(socket1, 0); // socket > 0
+#endif
+
+ // bind unicast socket to port 10548
+ int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10548);
+#ifdef _WIN32
+ EXPECT_NE(socket2, INVALID_SOCKET);
+#else
+ EXPECT_GT(socket2, 0);
+#endif
+
+ // expect success. This address/port is already bound, but
+ // we are using SO_REUSEADDR, so we can bind it twice
+ int socket3 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+
+ // rebinding succeeds on Linux, fails on BSD
+ // TODO: add OS-specific defines here (or modify code to
+ // behave the same way on all OSes, but that may not be
+ // possible
+ // EXPECT_GT(socket3, 0); // socket > 0
+
+ // we now have 3 sockets open at the same time. Looks good.
+
+#ifdef _WIN32
+ closesocket(socket1);
+ closesocket(socket2);
+ closesocket(socket3);
+#else
+ close(socket1);
+ close(socket2);
+ close(socket3);
+#endif
+ delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, socketsMcast) {
+ // 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);
+#ifdef _WIN32
+ EXPECT_NE(socket1, INVALID_SOCKET); // socket != INVALID_SOCKET
+#else
+ EXPECT_GT(socket1, 0); // socket > 0
+#endif
+
+ // 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);
+#ifdef _WIN32
+ EXPECT_NE(socket2, INVALID_SOCKET);
+#else
+ EXPECT_GT(socket2, 0);
+#endif
+
+ // 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.
+
+#ifdef _WIN32
+ closesocket(socket1);
+ closesocket(socket2);
+#else
+ close(socket1);
+ close(socket2);
+#endif
+
+ delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, sendReceive) {
+ // testing socket operation in a portable way is tricky
+ // without interface detection implemented
+
+ fstream fakeifaces("interfaces.txt", ios::out|ios::trunc);
+ fakeifaces << LOOPBACK << " ::1";
+ fakeifaces.close();
+
+ NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+ // let's assume that every supported OS have lo interface
+ IOAddress loAddr("::1");
+ int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+ int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
+
+ ifacemgr->setSendSock(socket2);
+ ifacemgr->setRecvSock(socket1);
+
+ 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->receive();
+
+ ASSERT_TRUE( rcvPkt != NULL ); // 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_, rcvPkt->remote_addr_);
+ EXPECT_EQ(rcvPkt->remote_port_, 10546);
+
+ delete ifacemgr;
+}
+
+}
diff --git a/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj b/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj
new file mode 100755
index 0000000..d3e54d0
--- /dev/null
+++ b/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>b10dhcp6</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>b10-dhcp6</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>b10-dhcp6</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;..\..\..\src\lib;..\..\..\src\bin;..\..\..\ext\asio;%BOOST%;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OutputFile>$(OutDir)b10-dhcp6$(TargetExt)</OutputFile>
+ <AdditionalDependencies>libexceptions.lib;libutil.lib;liblog.lib;libcc.lib;libcfgclient.lib;libasiolink.lib;libdhcp.lib;log4cplusSD.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>..\libexceptions\Debug;..\libutil\Debug;..\liblog\Debug;..\libcc\Debug;..\libcfgclient\Debug;..\libasiolink\Debug;..\libdhcp\Debug;..\..\..\..\log4cplus\md10\Debug;%BOOST%\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PreBuildEvent>
+ <Command>cd ..\..\..\src\bin\dhcp6
+copy spec_config.h.win32 spec_config.h
+</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;..\..\..\src\lib;..\..\..\src\bin;..\..\..\ext\asio;%BOOST%;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <OutputFile>$(OutDir)b10-dhcp6$(TargetExt)</OutputFile>
+ <AdditionalDependencies>libexceptions.lib;libutil.lib;liblog.lib;libcc.lib;libcfgclient.lib;libasiolink.lib;libdhcp.lib;log4cplusS.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>..\libexceptions\Release;..\libutil\Release;..\liblog\Release;..\libcc\Release;..\libcfgclient\Release;..\libasiolink\Release;..\libdhcp\Release;..\..\..\..\log4cplus\md10\Release;%BOOST%\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PreBuildEvent>
+ <Command>cd ..\..\..\src\bin\dhcp6
+copy spec_config.h.win32 spec_config.h
+</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\src\bin\dhcp6\dhcp6_srv.h" />
+ <ClInclude Include="..\..\..\src\bin\dhcp6\iface_mgr.h" />
+ <ClInclude Include="..\..\getopt.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\dhcp6_srv.cc" />
+ <ClCompile Include="..\..\..\src\bin\dhcp6\iface_mgr.cc" />
+ <ClCompile Include="..\..\..\src\bin\dhcp6\main.cc" />
+ <ClCompile Include="..\..\getopt.cc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj.filters b/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj.filters
new file mode 100755
index 0000000..62adc75
--- /dev/null
+++ b/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj.filters
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\src\bin\dhcp6\dhcp6_srv.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\bin\dhcp6\iface_mgr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\getopt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\dhcp6_srv.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\iface_mgr.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\main.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\getopt.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj.user b/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj.user
new file mode 100755
index 0000000..695b5c7
--- /dev/null
+++ b/win32build/VS2010/b10-dhcp6/b10-dhcp6.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
\ No newline at end of file
diff --git a/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj b/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj
new file mode 100755
index 0000000..31f22c7
--- /dev/null
+++ b/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{E5640378-81D0-4769-B108-4DF4E2B0AD0C}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>b10dhcp6_tests</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>dhcp6_unittests</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(Configuration)\</OutDir>
+ <TargetName>dhcp6_unittests</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;..\..\..\src\lib;..\..\..\src\bin;..\..\..\ext\asio;..\..\..\..\gtest\include;%BOOST%;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <CompileAs>CompileAsCpp</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OutputFile>$(OutDir)dhcp6_unittests$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>..\libexceptions\Debug;..\libutil\Debug;..\libutil_unittests\Debug;..\liblog\Debug;..\libcc\Debug;..\libcfgclient\Debug;..\libasiolink\Debug;..\libdhcp\Debug;..\..\..\..\log4cplus\md10\Debug;..\..\..\..\gtest\md10\Debug;%BOOST%\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libexceptions.lib;libutil.lib;libutil_unittests.lib;liblog.lib;libcc.lib;libcfgclient.lib;libasiolink.lib;libdhcp.lib;log4cplusSD.lib;gtestd.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;..\..\..\src\lib;..\..\..\src\bin;..\..\..\ext\asio;..\..\..\..\gtest\include;%BOOST%;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <CompileAs>CompileAsCpp</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <OutputFile>$(OutDir)dhcp6_unittests$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>..\libexceptions\Release;..\libutil\Release;..\libutil_unittests\Release;..\liblog\Release;..\libcc\Release;..\libcfgclient\Release;..\libasiolink\Release;..\libdhcp\Release;..\..\..\..\log4cplus\md10\Release;..\..\..\..\gtest\md10\Release;%BOOST%\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libexceptions.lib;libutil.lib;libutil_unittests.lib;liblog.lib;libcc.lib;libcfgclient.lib;libasiolink.lib;libdhcp.lib;log4cplusS.lib;gtest.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\src\bin\dhcp6\dhcp6_srv.h" />
+ <ClInclude Include="..\..\..\src\bin\dhcp6\iface_mgr.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\dhcp6_srv.cc" />
+ <ClCompile Include="..\..\..\src\bin\dhcp6\iface_mgr.cc" />
+ <ClCompile Include="..\..\..\src\bin\dhcp6\tests\dhcp6_srv_unittest.cc" />
+ <ClCompile Include="..\..\..\src\bin\dhcp6\tests\dhcp6_unittests.cc" />
+ <ClCompile Include="..\..\..\src\bin\dhcp6\tests\iface_mgr_unittest.cc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.filters b/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.filters
new file mode 100755
index 0000000..e08588f
--- /dev/null
+++ b/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.filters
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\src\bin\dhcp6\dhcp6_srv.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\bin\dhcp6\iface_mgr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\dhcp6_srv.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\iface_mgr.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\tests\dhcp6_srv_unittest.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\tests\dhcp6_unittests.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\bin\dhcp6\tests\iface_mgr_unittest.cc">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.user b/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.user
new file mode 100755
index 0000000..695b5c7
--- /dev/null
+++ b/win32build/VS2010/b10-dhcp6_tests/b10-dhcp6_tests.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
\ No newline at end of file
diff --git a/win32build/VS2010/bind10.sln b/win32build/VS2010/bind10.sln
index b84eac5..cd51477 100755
--- a/win32build/VS2010/bind10.sln
+++ b/win32build/VS2010/bind10.sln
@@ -9,6 +9,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BINDInstall", "BINDInstall\
{4D551D14-3C0F-4554-B20C-4B600249E42A} = {4D551D14-3C0F-4554-B20C-4B600249E42A}
{5D857B14-7763-466C-9D4E-D7C2E57C0E7F} = {5D857B14-7763-466C-9D4E-D7C2E57C0E7F}
{32624520-5341-471B-B88D-2599DBCDABF5} = {32624520-5341-471B-B88D-2599DBCDABF5}
+ {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6} = {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}
{D781E925-FE57-4C75-9E26-BBC102B6A24A} = {D781E925-FE57-4C75-9E26-BBC102B6A24A}
{7D04222B-643C-446C-A2B8-93AF74A86246} = {7D04222B-643C-446C-A2B8-93AF74A86246}
{DCF4ED2E-FFD1-4432-AFEF-8D6EC96B79A2} = {DCF4ED2E-FFD1-4432-AFEF-8D6EC96B79A2}
@@ -20,8 +21,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BINDInstall", "BINDInstall\
{8412D26C-6C2B-4FCC-ABB4-E9509E833951} = {8412D26C-6C2B-4FCC-ABB4-E9509E833951}
{DC86E86E-BB80-4C93-8A1F-E409C1FA38D2} = {DC86E86E-BB80-4C93-8A1F-E409C1FA38D2}
{2C518972-FF5F-4D33-9D3E-5BCC6357EDD7} = {2C518972-FF5F-4D33-9D3E-5BCC6357EDD7}
+ {E5640378-81D0-4769-B108-4DF4E2B0AD0C} = {E5640378-81D0-4769-B108-4DF4E2B0AD0C}
{F8616086-9CE9-4F32-BC97-8494EADAEC6F} = {F8616086-9CE9-4F32-BC97-8494EADAEC6F}
{761E7D88-6CCB-4E41-9F1E-6C1FBBD062F5} = {761E7D88-6CCB-4E41-9F1E-6C1FBBD062F5}
+ {D9178188-26B3-466B-A85A-C3C3344438BE} = {D9178188-26B3-466B-A85A-C3C3344438BE}
{6280D58A-5E05-45D1-8B79-DF677C114CD4} = {6280D58A-5E05-45D1-8B79-DF677C114CD4}
{D09B618B-D0E4-468D-A4BD-E204B4344C18} = {D09B618B-D0E4-468D-A4BD-E204B4344C18}
{6AC4F7A4-9BDC-415F-81DB-6332CACA38B3} = {6AC4F7A4-9BDC-415F-81DB-6332CACA38B3}
@@ -31,6 +34,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BINDInstall", "BINDInstall\
{813BA1C9-8CD8-4B06-B1C0-FDAB576AC4B6} = {813BA1C9-8CD8-4B06-B1C0-FDAB576AC4B6}
{FEFFE0CB-CD6B-4E61-854C-39506D6DCD5D} = {FEFFE0CB-CD6B-4E61-854C-39506D6DCD5D}
{2E64F6CC-3AD9-4DA7-8E05-ABBB83F9AFC4} = {2E64F6CC-3AD9-4DA7-8E05-ABBB83F9AFC4}
+ {F27BC0D0-A334-4DC0-9DC9-880D5DA74524} = {F27BC0D0-A334-4DC0-9DC9-880D5DA74524}
{AC4806D1-C2CC-444B-8F0D-209851A969D2} = {AC4806D1-C2CC-444B-8F0D-209851A969D2}
{65B0B6D2-94CE-4A21-85E7-A047C79044F9} = {65B0B6D2-94CE-4A21-85E7-A047C79044F9}
{F6E728D3-A0B2-40F6-9B91-7D4474D778F3} = {F6E728D3-A0B2-40F6-9B91-7D4474D778F3}
@@ -54,7 +58,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libutil", "libutil\libutil.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcryptolink", "libcryptolink\libcryptolink.vcxproj", "{13215E3E-E75D-463D-A0EF-93A1C9A20896}"
ProjectSection(ProjectDependencies) = postProject
- {AC4806D1-C2CC-444B-8F0D-209851A969D2} = {AC4806D1-C2CC-444B-8F0D-209851A969D2}
+ {AEF3DFFE-B566-4E6A-B299-B59B81022C06} = {AEF3DFFE-B566-4E6A-B299-B59B81022C06}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdns++", "libdns++\libdns++.vcxproj", "{F6E728D3-A0B2-40F6-9B91-7D4474D778F3}"
@@ -77,7 +81,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libutil_tests", "libutil_te
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libutil_unittests", "libutil_unittests\libutil_unittests.vcxproj", "{2844FDFB-A0A1-4FA4-A654-15D69CC717DD}"
ProjectSection(ProjectDependencies) = postProject
- {8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
+ {AC4806D1-C2CC-444B-8F0D-209851A969D2} = {AC4806D1-C2CC-444B-8F0D-209851A969D2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcryptolink_tests", "libcryptolink_tests\libcryptolink_tests.vcxproj", "{8412D26C-6C2B-4FCC-ABB4-E9509E833951}"
@@ -85,6 +89,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcryptolink_tests", "libc
{7D04222B-643C-446C-A2B8-93AF74A86246} = {7D04222B-643C-446C-A2B8-93AF74A86246}
{13215E3E-E75D-463D-A0EF-93A1C9A20896} = {13215E3E-E75D-463D-A0EF-93A1C9A20896}
{8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdns++_tests", "libdns++_tests\libdns++_tests.vcxproj", "{65B0B6D2-94CE-4A21-85E7-A047C79044F9}"
@@ -111,7 +116,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcc_tests", "libcc_tests\libcc_tests.vcxproj", "{D781E925-FE57-4C75-9E26-BBC102B6A24A}"
ProjectSection(ProjectDependencies) = postProject
{7D04222B-643C-446C-A2B8-93AF74A86246} = {7D04222B-643C-446C-A2B8-93AF74A86246}
+ {8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
{CC29C1F9-A77B-476C-803E-8830F8312571} = {CC29C1F9-A77B-476C-803E-8830F8312571}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcfgclient", "libcfgclient\libcfgclient.vcxproj", "{813BA1C9-8CD8-4B06-B1C0-FDAB576AC4B6}"
@@ -122,18 +129,21 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcfgclient_tests", "libcfgclient_tests\libcfgclient_tests.vcxproj", "{5D857B14-7763-466C-9D4E-D7C2E57C0E7F}"
ProjectSection(ProjectDependencies) = postProject
{7D04222B-643C-446C-A2B8-93AF74A86246} = {7D04222B-643C-446C-A2B8-93AF74A86246}
+ {8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
{813BA1C9-8CD8-4B06-B1C0-FDAB576AC4B6} = {813BA1C9-8CD8-4B06-B1C0-FDAB576AC4B6}
{CC29C1F9-A77B-476C-803E-8830F8312571} = {CC29C1F9-A77B-476C-803E-8830F8312571}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblog", "liblog\liblog.vcxproj", "{AEF3DFFE-B566-4E6A-B299-B59B81022C06}"
ProjectSection(ProjectDependencies) = postProject
- {DC86E86E-BB80-4C93-8A1F-E409C1FA38D2} = {DC86E86E-BB80-4C93-8A1F-E409C1FA38D2}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblog_tests", "liblog_tests\liblog_tests.vcxproj", "{9F69DE07-D285-4B5C-8528-DF975C59ED3B}"
ProjectSection(ProjectDependencies) = postProject
{8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
{AEF3DFFE-B566-4E6A-B299-B59B81022C06} = {AEF3DFFE-B566-4E6A-B299-B59B81022C06}
EndProjectSection
EndProject
@@ -145,14 +155,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblog_compiler", "liblog_c
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libasiolink", "libasiolink\libasiolink.vcxproj", "{69048307-9655-4AAA-B07E-B67345C1DEF9}"
ProjectSection(ProjectDependencies) = postProject
- {AEF3DFFE-B566-4E6A-B299-B59B81022C06} = {AEF3DFFE-B566-4E6A-B299-B59B81022C06}
+ {DC86E86E-BB80-4C93-8A1F-E409C1FA38D2} = {DC86E86E-BB80-4C93-8A1F-E409C1FA38D2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libasiolink_tests", "libasiolink_tests\libasiolink_tests.vcxproj", "{6AC4F7A4-9BDC-415F-81DB-6332CACA38B3}"
ProjectSection(ProjectDependencies) = postProject
{69048307-9655-4AAA-B07E-B67345C1DEF9} = {69048307-9655-4AAA-B07E-B67345C1DEF9}
{7D04222B-643C-446C-A2B8-93AF74A86246} = {7D04222B-643C-446C-A2B8-93AF74A86246}
+ {8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
{F6E728D3-A0B2-40F6-9B91-7D4474D778F3} = {F6E728D3-A0B2-40F6-9B91-7D4474D778F3}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
{AEF3DFFE-B566-4E6A-B299-B59B81022C06} = {AEF3DFFE-B566-4E6A-B299-B59B81022C06}
EndProjectSection
EndProject
@@ -184,6 +196,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnsas_tests", "libnsas_te
{67046450-CCEA-4CAC-A05B-17516F3FB540} = {67046450-CCEA-4CAC-A05B-17516F3FB540}
{8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
{F6E728D3-A0B2-40F6-9B91-7D4474D778F3} = {F6E728D3-A0B2-40F6-9B91-7D4474D778F3}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcache", "libcache\libcache.vcxproj", "{F8616086-9CE9-4F32-BC97-8494EADAEC6F}"
@@ -199,6 +212,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcache_tests", "libcache_
{8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
{F8616086-9CE9-4F32-BC97-8494EADAEC6F} = {F8616086-9CE9-4F32-BC97-8494EADAEC6F}
{F6E728D3-A0B2-40F6-9B91-7D4474D778F3} = {F6E728D3-A0B2-40F6-9B91-7D4474D778F3}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libresolve", "libresolve\libresolve.vcxproj", "{3FFD260A-C606-49D1-A34F-74B78D8DC76F}"
@@ -216,6 +230,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libresolve_tests", "libreso
{F8616086-9CE9-4F32-BC97-8494EADAEC6F} = {F8616086-9CE9-4F32-BC97-8494EADAEC6F}
{F6E728D3-A0B2-40F6-9B91-7D4474D778F3} = {F6E728D3-A0B2-40F6-9B91-7D4474D778F3}
{7EB244E7-D381-4CF4-A2D4-739B81F77588} = {7EB244E7-D381-4CF4-A2D4-739B81F77588}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
{AEF3DFFE-B566-4E6A-B299-B59B81022C06} = {AEF3DFFE-B566-4E6A-B299-B59B81022C06}
EndProjectSection
EndProject
@@ -237,6 +252,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdatasrc_tests", "libdata
{8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
{F6E728D3-A0B2-40F6-9B91-7D4474D778F3} = {F6E728D3-A0B2-40F6-9B91-7D4474D778F3}
{CC29C1F9-A77B-476C-803E-8830F8312571} = {CC29C1F9-A77B-476C-803E-8830F8312571}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libserver_common", "libserver_common\libserver_common.vcxproj", "{66C9A5EC-514B-4BDC-AC74-ED4CB465CAAF}"
@@ -267,6 +283,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbench_tests", "libbench_
{8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
{DC86E86E-BB80-4C93-8A1F-E409C1FA38D2} = {DC86E86E-BB80-4C93-8A1F-E409C1FA38D2}
{F6E728D3-A0B2-40F6-9B91-7D4474D778F3} = {F6E728D3-A0B2-40F6-9B91-7D4474D778F3}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbench_example", "libbench_example\libbench_example.vcxproj", "{6280D58A-5E05-45D1-8B79-DF677C114CD4}"
@@ -308,6 +325,26 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdhcp", "libdhcp\libdhcp.
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdhcp_tests", "libdhcp_tests\libdhcp_tests.vcxproj", "{D9178188-26B3-466B-A85A-C3C3344438BE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {69048307-9655-4AAA-B07E-B67345C1DEF9} = {69048307-9655-4AAA-B07E-B67345C1DEF9}
+ {7D04222B-643C-446C-A2B8-93AF74A86246} = {7D04222B-643C-446C-A2B8-93AF74A86246}
+ {8F120666-1A69-4506-8546-0F665E80FFB7} = {8F120666-1A69-4506-8546-0F665E80FFB7}
+ {813BA1C9-8CD8-4B06-B1C0-FDAB576AC4B6} = {813BA1C9-8CD8-4B06-B1C0-FDAB576AC4B6}
+ {F27BC0D0-A334-4DC0-9DC9-880D5DA74524} = {F27BC0D0-A334-4DC0-9DC9-880D5DA74524}
+ {CC29C1F9-A77B-476C-803E-8830F8312571} = {CC29C1F9-A77B-476C-803E-8830F8312571}
+ {2844FDFB-A0A1-4FA4-A654-15D69CC717DD} = {2844FDFB-A0A1-4FA4-A654-15D69CC717DD}
+ {AEF3DFFE-B566-4E6A-B299-B59B81022C06} = {AEF3DFFE-B566-4E6A-B299-B59B81022C06}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "b10-dhcp6", "b10-dhcp6\b10-dhcp6.vcxproj", "{831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F27BC0D0-A334-4DC0-9DC9-880D5DA74524} = {F27BC0D0-A334-4DC0-9DC9-880D5DA74524}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "b10-dhcp6_tests", "b10-dhcp6_tests\b10-dhcp6_tests.vcxproj", "{E5640378-81D0-4769-B108-4DF4E2B0AD0C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6} = {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -487,6 +524,14 @@ Global
{D9178188-26B3-466B-A85A-C3C3344438BE}.Debug|Win32.Build.0 = Debug|Win32
{D9178188-26B3-466B-A85A-C3C3344438BE}.Release|Win32.ActiveCfg = Release|Win32
{D9178188-26B3-466B-A85A-C3C3344438BE}.Release|Win32.Build.0 = Release|Win32
+ {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}.Debug|Win32.Build.0 = Debug|Win32
+ {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}.Release|Win32.ActiveCfg = Release|Win32
+ {831EDB24-3B0A-44AE-A192-6F3DEA1A9BA6}.Release|Win32.Build.0 = Release|Win32
+ {E5640378-81D0-4769-B108-4DF4E2B0AD0C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E5640378-81D0-4769-B108-4DF4E2B0AD0C}.Debug|Win32.Build.0 = Debug|Win32
+ {E5640378-81D0-4769-B108-4DF4E2B0AD0C}.Release|Win32.ActiveCfg = Release|Win32
+ {E5640378-81D0-4769-B108-4DF4E2B0AD0C}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
More information about the bind10-changes
mailing list