BIND 10 master, updated. 67ea6de047d4dbd63c25fe7f03f5d5cc2452ad7d Merge branch 'master' of ssh://git.bind10.isc.org/var/bind10/git/bind10
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Oct 17 10:11:40 UTC 2011
The branch, master has been updated
via 67ea6de047d4dbd63c25fe7f03f5d5cc2452ad7d (commit)
via e9c6c3cf86e3b1b02c64bf567f0c20f6c1e2f589 (commit)
via 004e1238d580d601f7fd8847ff1c4933de465942 (commit)
via 5da6a0f0e8829140999c69bfb551a305c6bf0257 (commit)
via 25ce3ceaf98ed34ad3a4ebe3cac901c0b6e15a97 (commit)
via 5756a9c761748b960b974f422963fbf8e5498378 (commit)
via 566e635f4f2647a82457acb9c047d890f4cb459b (commit)
via 76f58b2ff1ebc572cef465f5be1445e08e4bf0fb (commit)
via f89dbf486bbbd41c3f4e85c15d2cda91706a37ba (commit)
via a91fbbe9905680873c4f0acf5cff1d712aa68831 (commit)
via 86cab473cc0113b0f83755c14db4035bae675065 (commit)
via ca22c5ab2322ab7620e4b84589da6761fdaa3b62 (commit)
via 838acbebc584fee662143c303b7a110563f4e0de (commit)
via c5d29c73bcd554111ada4dec49f61cfde497cb6c (commit)
via 4ec7a8d9ab678f28abf3b37d40acdf159344cf0f (commit)
via 92b2aa9c962e9ca1cec80f44bee713afa1ac53f3 (commit)
via 6b9d28f7602143bb85fcfcefbaa35cde95fdbde3 (commit)
via 223b19a30e4897c7281bb40c9f366a01c8f449ca (commit)
via bfea61834be28bc3c2413afb586971fc04056a41 (commit)
via 620072324ac5f111f8fd40a4ba6d10879c44e211 (commit)
via 522d27a63d1ff318173e7e4aeb6c1265aba93ca5 (commit)
via c4291199d0ebab1cdb49b80101239b9582c13148 (commit)
via 9d9680719eb0ce32ea039386bfe767dfa41d1968 (commit)
via 2f39435c981e3cb14d2c4e9551af93fbbfc28109 (commit)
via 2276752655f67044fb6ae8f7e14e9ba5f6ee6638 (commit)
via 54ba29f03a62c84ee9cbf1c92db74b57327a1868 (commit)
via 6433a51cb6e72309eb027411ea4fa98adb97a7f8 (commit)
via 4865dbd45b6f94b20b562b11224754313e74bf25 (commit)
via c7b8783766258a4321622b7d7e2bb02a647d0864 (commit)
via b8d8ea4cfb87fd12abe113cf63edbae4a342e6c1 (commit)
via 6ce36056a14fad339ffc6528343aadf12065ca44 (commit)
via 8dbb407ba4adc1bbaf061b5680bafd35c778cd90 (commit)
via f9ff938c75816df97f318a839f01be3f01c93f2a (commit)
via a69020025379d5430fff394465348aa430533458 (commit)
via af27ec87f09d82918b96c9dd6d236b4e39989f7f (commit)
via b47533e918cb5b0c2befe7b0da315819b009c47f (commit)
via f4c7155d41cb008a1a180e567e142ce096a21b88 (commit)
via d647a4589362d2b6efee86e58c9fb38e7084deb4 (commit)
from 01bc2a7ff47131144717e923108f71eda283475b (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 67ea6de047d4dbd63c25fe7f03f5d5cc2452ad7d
Merge: e9c6c3cf86e3b1b02c64bf567f0c20f6c1e2f589 01bc2a7ff47131144717e923108f71eda283475b
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Oct 17 11:33:04 2011 +0200
Merge branch 'master' of ssh://git.bind10.isc.org/var/bind10/git/bind10
Conflicts:
ChangeLog
commit e9c6c3cf86e3b1b02c64bf567f0c20f6c1e2f589
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 16:52:20 2011 +0200
[1186] Removed libdhcp_unittests on libutil_unitests.la
commit 004e1238d580d601f7fd8847ff1c4933de465942
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 16:40:21 2011 +0200
[1186] Reverting changes to src/lib/Makefile.am in commit d647a458
commit 5da6a0f0e8829140999c69bfb551a305c6bf0257
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 16:18:59 2011 +0200
[1186] Removed compilation warnings in option6_addrlst_unittest
commit 25ce3ceaf98ed34ad3a4ebe3cac901c0b6e15a97
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 14:13:32 2011 +0200
[1186] Yet another set of changes after review.
- implementation for setProto() added
- EXPECT_NO_THROW around many object creations added
commit 5756a9c761748b960b974f422963fbf8e5498378
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 13:52:03 2011 +0200
[1186] Changes after second review
- added passing by reference in many places
- started using writeUint16/readUint16 functions
commit 566e635f4f2647a82457acb9c047d890f4cb459b
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 12:07:23 2011 +0200
[1186] doxygen comments cleanup.
commit 76f58b2ff1ebc572cef465f5be1445e08e4bf0fb
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 12:00:02 2011 +0200
[1186] control_buf_ is now scoped_array<char> in dhcp/iface_mgr
commit f89dbf486bbbd41c3f4e85c15d2cda91706a37ba
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Oct 14 11:53:59 2011 +0200
[1186] Changes in reply to review comment 13.
commit a91fbbe9905680873c4f0acf5cff1d712aa68831
Author: Stephen Morris <stephen at isc.org>
Date: Thu Oct 13 16:08:39 2011 +0100
[1186] Fix problems when compiling with gcc 4.4.5
commit 86cab473cc0113b0f83755c14db4035bae675065
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Oct 12 18:46:35 2011 +0200
[1186] Added missing includes.
commit ca22c5ab2322ab7620e4b84589da6761fdaa3b62
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Oct 12 17:03:23 2011 +0200
[1186] Part 7 of review changes.
- test clean-up and improvements
commit 838acbebc584fee662143c303b7a110563f4e0de
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Oct 12 14:49:10 2011 +0200
Compilation fixes in dhcpv6_srv following recent changes in DHCPv6 Options.
commit c5d29c73bcd554111ada4dec49f61cfde497cb6c
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Oct 12 14:43:37 2011 +0200
[1186] Part 6 of review changes.
- Added V6ADDRESS_LEN and V4ADDRESS_LEN
- Removed unnecessary parameters to Option constructors
- Many missing Doxygen comments added
- using sizeof(uintXX_t) instead of 2 and 4 in pack()/unpack()
- Many other smaller changes.
commit 4ec7a8d9ab678f28abf3b37d40acdf159344cf0f
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Oct 12 11:35:28 2011 +0200
[1186] Part 5 of the review changes
- Option6Lst is now Option6Collection
- Corrected data_len_ mistake in Option::pack4
- Added comments about length calculation
- Added doxygen comments
- Some const and references added
- Many other minor changes.
commit 92b2aa9c962e9ca1cec80f44bee713afa1ac53f3
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Tue Oct 11 19:48:55 2011 +0200
[1186] Part 4 of review changes
- added consts in packOption6, unpackOptions6
- removed version() method
- alignments fixed in dhcp6.h
commit 6b9d28f7602143bb85fcfcefbaa35cde95fdbde3
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Tue Oct 11 18:57:19 2011 +0200
[1186] Part 3 of review changes
- buffer type changed: char => uint8_t
- removed unnecessary statements in Makefile.am
commit 223b19a30e4897c7281bb40c9f366a01c8f449ca
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Tue Oct 11 16:43:30 2011 +0200
[1186] Part 2 of review changes
- Dhcpv6Srv::process*() methods does not use references anymore
- Dhcpv6Srv::shutdown variable added for ordered shutdown procedure
- Dhcpv6Srv is now in isc::dhcp namespace
- Dhcpv6Srv is now derived from boot/noncopyable
- IfaceMgr methods and fields are now commented appropriately
- IfaceMgr
- Dhcpv6Srv friend declaration removed
- Dhcpv6SrvTest now uses derived class to access protected methods
- Dhcpv6SrvTest Solicit_Basic test now includes client-id, checks for
received client-id, server-id and content of ia
- IfaceMgrTest minor improvements
See comments in #1186 ticket for extensive list of smaller changes
and reasons behind them.
commit bfea61834be28bc3c2413afb586971fc04056a41
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Oct 10 13:48:27 2011 +0200
Part 1 of 1186 review changes
- include paths fixed
- dangling spaces removed
- many parameters are now passed by reference
- added doxygen comments for all methods in dhcp6_srv.h
- src/bin/dhcp6/Makefile.am no longer references Pkt6.{cc|h}
commit 620072324ac5f111f8fd40a4ba6d10879c44e211
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Thu Sep 8 17:30:09 2011 +0200
[1186] Make distcheck fixed.
commit 522d27a63d1ff318173e7e4aeb6c1265aba93ca5
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Thu Sep 8 16:57:10 2011 +0200
[1186] Option6_AddrLst implemented (useful for storing v6 addresses)
commit c4291199d0ebab1cdb49b80101239b9582c13148
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Thu Sep 8 16:53:17 2011 +0200
[1186] from_bytes() method implement in IOAddress
- similar to from_string() used in underlying boost::asio::address
commit 9d9680719eb0ce32ea039386bfe767dfa41d1968
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Sep 7 16:13:39 2011 +0200
[1186] Remaining tests for DHCPv6 Options fixed/implemented.
commit 2f39435c981e3cb14d2c4e9551af93fbbfc28109
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Tue Sep 6 19:15:58 2011 +0200
[1186] Added suboptions support in Option class, tests implemented.
commit 2276752655f67044fb6ae8f7e14e9ba5f6ee6638
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Sep 5 20:55:04 2011 +0200
[1186] Tests are now working on OS X.
commit 54ba29f03a62c84ee9cbf1c92db74b57327a1868
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Sep 5 20:46:02 2011 +0200
[1186] unittests implemented for LibDHCP.
commit 6433a51cb6e72309eb027411ea4fa98adb97a7f8
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Sep 5 20:45:39 2011 +0200
[1186] IfaceMgr tests should now work on both Linux and BSD.
commit 4865dbd45b6f94b20b562b11224754313e74bf25
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Sep 5 17:27:31 2011 +0200
[1186] Tests for libdhcp::packOptions6 implemented.
commit c7b8783766258a4321622b7d7e2bb02a647d0864
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Aug 31 19:12:55 2011 +0200
[1186] Added test for solicit;
Loopback interface name is now constant;
Function comments added;
commit b8d8ea4cfb87fd12abe113cf63edbae4a342e6c1
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Sat Aug 27 13:32:10 2011 +0200
[1186] trans-id unpacking fix.
commit 6ce36056a14fad339ffc6528343aadf12065ca44
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Sat Aug 27 09:46:52 2011 +0200
[1186] Advertise is now sent properly.
commit 8dbb407ba4adc1bbaf061b5680bafd35c778cd90
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Aug 26 01:05:24 2011 +0200
[1186] Duplicate length field removed in Option class.
commit f9ff938c75816df97f318a839f01be3f01c93f2a
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Aug 26 00:45:51 2011 +0200
[1186] Server now parses SOLICITs and replies with ADVERTISE.
Advertise is not perfect yet:
- server-id is missing
- client-id conveys invalid content
commit a69020025379d5430fff394465348aa430533458
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Aug 24 20:36:35 2011 +0200
[1186] IfaceMgr now uses boost::shared_ptr, skeleton functions added.
- IfaceMgr now uses shared_ptr.
- skeleton functions for specific message processing added.
- tests fixed.
commit af27ec87f09d82918b96c9dd6d236b4e39989f7f
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Wed Aug 24 20:20:34 2011 +0200
[878] Support for IA and IAADDR options and suboptions added.
- IA support (Option6IA class) added.
- Support for suboptions in IA option.
- IAADDR support (Option6IAAddr class) added.
- Initial tests added for new classes added.
commit b47533e918cb5b0c2befe7b0da315819b009c47f
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Tue Aug 23 21:21:11 2011 +0200
[1186] libdhcp now is able to parse and build packets and options.
commit f4c7155d41cb008a1a180e567e142ce096a21b88
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Aug 19 18:51:50 2011 +0200
[1186] Added missing libdhcp.cc|h files.
commit d647a4589362d2b6efee86e58c9fb38e7084deb4
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Aug 19 17:12:12 2011 +0200
[1186] Initial libdhcp skeleton implementation.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 11 +
configure.ac | 2 +
doc/Doxyfile | 2 +-
src/bin/dhcp6/Makefile.am | 20 +--
src/bin/dhcp6/dhcp6.h | 184 ---------------
src/bin/dhcp6/dhcp6_srv.cc | 202 ++++++++++++++++-
src/bin/dhcp6/dhcp6_srv.h | 150 +++++++++++--
src/bin/dhcp6/iface_mgr.cc | 127 ++++-------
src/bin/dhcp6/iface_mgr.h | 282 +++++++++++++++++-------
src/bin/dhcp6/main.cc | 10 +-
src/bin/dhcp6/pkt6.cc | 46 ----
src/bin/dhcp6/pkt6.h | 62 -----
src/bin/dhcp6/tests/Makefile.am | 7 +-
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 107 +++++++++-
src/bin/dhcp6/tests/iface_mgr_unittest.cc | 179 +++++++++++++---
src/bin/dhcp6/tests/pkt6_unittest.cc | 44 ----
src/lib/Makefile.am | 2 +-
src/lib/asiolink/io_address.cc | 20 ++-
src/lib/asiolink/io_address.h | 16 ++
src/lib/asiolink/tests/io_address_unittest.cc | 20 ++
src/lib/dhcp/Makefile.am | 25 ++
src/lib/dhcp/README | 11 +
src/lib/dhcp/dhcp6.h | 184 +++++++++++++++
src/lib/dhcp/libdhcp.cc | 130 +++++++++++
src/lib/dhcp/libdhcp.h | 83 +++++++
src/lib/dhcp/option.cc | 262 ++++++++++++++++++++++
src/lib/dhcp/option.h | 272 +++++++++++++++++++++++
src/lib/dhcp/option6_addrlst.cc | 134 +++++++++++
src/lib/dhcp/option6_addrlst.h | 127 +++++++++++
src/lib/dhcp/option6_ia.cc | 139 ++++++++++++
src/lib/dhcp/option6_ia.h | 137 ++++++++++++
src/lib/dhcp/option6_iaaddr.cc | 129 +++++++++++
src/lib/dhcp/option6_iaaddr.h | 146 ++++++++++++
src/lib/dhcp/pkt6.cc | 224 +++++++++++++++++++
src/lib/dhcp/pkt6.h | 234 ++++++++++++++++++++
src/lib/dhcp/tests/Makefile.am | 42 ++++
src/lib/dhcp/tests/libdhcp_unittest.cc | 137 ++++++++++++
src/lib/dhcp/tests/option6_addrlst_unittest.cc | 223 +++++++++++++++++++
src/lib/dhcp/tests/option6_ia_unittest.cc | 261 ++++++++++++++++++++++
src/lib/dhcp/tests/option6_iaaddr_unittest.cc | 101 +++++++++
src/lib/dhcp/tests/option_unittest.cc | 267 ++++++++++++++++++++++
src/lib/dhcp/tests/pkt6_unittest.cc | 206 +++++++++++++++++
src/lib/dhcp/tests/run_unittests.cc | 27 +++
43 files changed, 4404 insertions(+), 590 deletions(-)
delete mode 100644 src/bin/dhcp6/dhcp6.h
delete mode 100644 src/bin/dhcp6/pkt6.cc
delete mode 100644 src/bin/dhcp6/pkt6.h
delete mode 100644 src/bin/dhcp6/tests/pkt6_unittest.cc
create mode 100644 src/lib/dhcp/Makefile.am
create mode 100644 src/lib/dhcp/README
create mode 100644 src/lib/dhcp/dhcp6.h
create mode 100644 src/lib/dhcp/libdhcp.cc
create mode 100644 src/lib/dhcp/libdhcp.h
create mode 100644 src/lib/dhcp/option.cc
create mode 100644 src/lib/dhcp/option.h
create mode 100644 src/lib/dhcp/option6_addrlst.cc
create mode 100644 src/lib/dhcp/option6_addrlst.h
create mode 100644 src/lib/dhcp/option6_ia.cc
create mode 100644 src/lib/dhcp/option6_ia.h
create mode 100644 src/lib/dhcp/option6_iaaddr.cc
create mode 100644 src/lib/dhcp/option6_iaaddr.h
create mode 100644 src/lib/dhcp/pkt6.cc
create mode 100644 src/lib/dhcp/pkt6.h
create mode 100644 src/lib/dhcp/tests/Makefile.am
create mode 100644 src/lib/dhcp/tests/libdhcp_unittest.cc
create mode 100644 src/lib/dhcp/tests/option6_addrlst_unittest.cc
create mode 100644 src/lib/dhcp/tests/option6_ia_unittest.cc
create mode 100644 src/lib/dhcp/tests/option6_iaaddr_unittest.cc
create mode 100644 src/lib/dhcp/tests/option_unittest.cc
create mode 100644 src/lib/dhcp/tests/pkt6_unittest.cc
create mode 100644 src/lib/dhcp/tests/run_unittests.cc
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index f1f8a9c..15293df 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+300. [func]* tomek
+ libdhcp: DHCP packet library was implemented. Currently it handles
+ packet reception, option parsing, option generation and output
+ packet building. Generic and specialized classes for several
+ DHCPv6 options (IA_NA, IAADDR, address-list) are available. A
+ simple code was added that leverages libdhcp. It is a skeleton
+ DHCPv6 server. It receives incoming SOLICIT and REQUEST messages
+ and responds with proper ADVERTISE and REPLY. Note that since
+ LeaseManager is not implemented, server assigns a the same
+ hardcoded lease for every client.
+
299. [build] jreed
Do not install the libfake_session, libtestutils, or libbench
libraries. They are used by tests within the source tree.
diff --git a/configure.ac b/configure.ac
index b0f5f45..438883d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -870,6 +870,8 @@ AC_CONFIG_FILES([Makefile
src/lib/dns/python/Makefile
src/lib/dns/python/tests/Makefile
src/lib/dns/benchmarks/Makefile
+ src/lib/dhcp/Makefile
+ src/lib/dhcp/tests/Makefile
src/lib/exceptions/Makefile
src/lib/exceptions/tests/Makefile
src/lib/datasrc/Makefile
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 8be9098..ee5aaf8 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -574,7 +574,7 @@ INPUT = ../src/lib/exceptions ../src/lib/cc \
../src/lib/log/compiler ../src/lib/asiolink/ ../src/lib/nsas \
../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
../src/bin/sockcreator/ ../src/lib/util/ \
- ../src/lib/resolve ../src/lib/acl ../src/bin/dhcp6
+ ../src/lib/resolve ../src/lib/acl ../src/bin/dhcp6 ../src/lib/dhcp
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index 805d6bb..690ba5f 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -4,9 +4,7 @@ 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_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -31,20 +29,14 @@ spec_config.h: spec_config.h.pre
BUILT_SOURCES = spec_config.h
pkglibexec_PROGRAMS = b10-dhcp6
-b10_dhcp6_SOURCES = main.cc iface_mgr.cc pkt6.cc dhcp6_srv.cc
-b10_dhcp6_SOURCES += iface_mgr.h pkt6.h dhcp6_srv.h dhcp6.h
-b10_dhcp6_LDADD = $(top_builddir)/src/lib/datasrc/libdatasrc.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/libutil.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+
+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/exceptions/libexceptions.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-b10_dhcp6_LDADD += $(SQLITE_LIBS)
# TODO: config.h.in is wrong because doesn't honor pkgdatadir
# and can't use @datadir@ because doesn't expand default ${prefix}
diff --git a/src/bin/dhcp6/dhcp6.h b/src/bin/dhcp6/dhcp6.h
deleted file mode 100644
index b5512f3..0000000
--- a/src/bin/dhcp6/dhcp6.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (C) 2006-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 DHCP6_H
-#define DHCP6_H
-
-/* DHCPv6 Option codes: */
-
-#define D6O_CLIENTID 1 /* RFC3315 */
-#define D6O_SERVERID 2
-#define D6O_IA_NA 3
-#define D6O_IA_TA 4
-#define D6O_IAADDR 5
-#define D6O_ORO 6
-#define D6O_PREFERENCE 7
-#define D6O_ELAPSED_TIME 8
-#define D6O_RELAY_MSG 9
-/* Option code 10 unassigned. */
-#define D6O_AUTH 11
-#define D6O_UNICAST 12
-#define D6O_STATUS_CODE 13
-#define D6O_RAPID_COMMIT 14
-#define D6O_USER_CLASS 15
-#define D6O_VENDOR_CLASS 16
-#define D6O_VENDOR_OPTS 17
-#define D6O_INTERFACE_ID 18
-#define D6O_RECONF_MSG 19
-#define D6O_RECONF_ACCEPT 20
-#define D6O_SIP_SERVERS_DNS 21 /* RFC3319 */
-#define D6O_SIP_SERVERS_ADDR 22 /* RFC3319 */
-#define D6O_NAME_SERVERS 23 /* RFC3646 */
-#define D6O_DOMAIN_SEARCH 24 /* RFC3646 */
-#define D6O_IA_PD 25 /* RFC3633 */
-#define D6O_IAPREFIX 26 /* RFC3633 */
-#define D6O_NIS_SERVERS 27 /* RFC3898 */
-#define D6O_NISP_SERVERS 28 /* RFC3898 */
-#define D6O_NIS_DOMAIN_NAME 29 /* RFC3898 */
-#define D6O_NISP_DOMAIN_NAME 30 /* RFC3898 */
-#define D6O_SNTP_SERVERS 31 /* RFC4075 */
-#define D6O_INFORMATION_REFRESH_TIME 32 /* RFC4242 */
-#define D6O_BCMCS_SERVER_D 33 /* RFC4280 */
-#define D6O_BCMCS_SERVER_A 34 /* RFC4280 */
-/* 35 is unassigned */
-#define D6O_GEOCONF_CIVIC 36 /* RFC4776 */
-#define D6O_REMOTE_ID 37 /* RFC4649 */
-#define D6O_SUBSCRIBER_ID 38 /* RFC4580 */
-#define D6O_CLIENT_FQDN 39 /* RFC4704 */
-#define D6O_PANA_AGENT 40 /* paa-option */
-#define D6O_NEW_POSIX_TIMEZONE 41 /* RFC4833 */
-#define D6O_NEW_TZDB_TIMEZONE 42 /* RFC4833 */
-#define D6O_ERO 43 /* RFC4994 */
-#define D6O_LQ_QUERY 44 /* RFC5007 */
-#define D6O_CLIENT_DATA 45 /* RFC5007 */
-#define D6O_CLT_TIME 46 /* RFC5007 */
-#define D6O_LQ_RELAY_DATA 47 /* RFC5007 */
-#define D6O_LQ_CLIENT_LINK 48 /* RFC5007 */
-
-/*
- * Status Codes, from RFC 3315 section 24.4, and RFC 3633, 5007.
- */
-#define STATUS_Success 0
-#define STATUS_UnspecFail 1
-#define STATUS_NoAddrsAvail 2
-#define STATUS_NoBinding 3
-#define STATUS_NotOnLink 4
-#define STATUS_UseMulticast 5
-#define STATUS_NoPrefixAvail 6
-#define STATUS_UnknownQueryType 7
-#define STATUS_MalformedQuery 8
-#define STATUS_NotConfigured 9
-#define STATUS_NotAllowed 10
-
-/*
- * DHCPv6 message types, defined in section 5.3 of RFC 3315
- */
-#define DHCPV6_SOLICIT 1
-#define DHCPV6_ADVERTISE 2
-#define DHCPV6_REQUEST 3
-#define DHCPV6_CONFIRM 4
-#define DHCPV6_RENEW 5
-#define DHCPV6_REBIND 6
-#define DHCPV6_REPLY 7
-#define DHCPV6_RELEASE 8
-#define DHCPV6_DECLINE 9
-#define DHCPV6_RECONFIGURE 10
-#define DHCPV6_INFORMATION_REQUEST 11
-#define DHCPV6_RELAY_FORW 12
-#define DHCPV6_RELAY_REPL 13
-#define DHCPV6_LEASEQUERY 14
-#define DHCPV6_LEASEQUERY_REPLY 15
-
-extern const char *dhcpv6_type_names[];
-extern const int dhcpv6_type_name_max;
-
-/* DUID type definitions (RFC3315 section 9).
- */
-#define DUID_LLT 1
-#define DUID_EN 2
-#define DUID_LL 3
-
-/* Offsets into IA_*'s where Option spaces commence. */
-#define IA_NA_OFFSET 12 /* IAID, T1, T2, all 4 octets each */
-#define IA_TA_OFFSET 4 /* IAID only, 4 octets */
-#define IA_PD_OFFSET 12 /* IAID, T1, T2, all 4 octets each */
-
-/* Offset into IAADDR's where Option spaces commence. */
-#define IAADDR_OFFSET 24
-
-/* Offset into IAPREFIX's where Option spaces commence. */
-#define IAPREFIX_OFFSET 25
-
-/* Offset into LQ_QUERY's where Option spaces commence. */
-#define LQ_QUERY_OFFSET 17
-
-/*
- * DHCPv6 well-known multicast addressess, from section 5.1 of RFC 3315
- */
-#define ALL_DHCP_RELAY_AGENTS_AND_SERVERS "ff02::1:2"
-#define ALL_DHCP_SERVERS "ff05::1:3"
-
-#define DHCP6_CLIENT_PORT 546
-#define DHCP6_SERVER_PORT 547
-
-/*
- * DHCPv6 Retransmission Constants (RFC3315 section 5.5, RFC 5007)
- */
-
-#define SOL_MAX_DELAY 1
-#define SOL_TIMEOUT 1
-#define SOL_MAX_RT 120
-#define REQ_TIMEOUT 1
-#define REQ_MAX_RT 30
-#define REQ_MAX_RC 10
-#define CNF_MAX_DELAY 1
-#define CNF_TIMEOUT 1
-#define CNF_MAX_RT 4
-#define CNF_MAX_RD 10
-#define REN_TIMEOUT 10
-#define REN_MAX_RT 600
-#define REB_TIMEOUT 10
-#define REB_MAX_RT 600
-#define INF_MAX_DELAY 1
-#define INF_TIMEOUT 1
-#define INF_MAX_RT 120
-#define REL_TIMEOUT 1
-#define REL_MAX_RC 5
-#define DEC_TIMEOUT 1
-#define DEC_MAX_RC 5
-#define REC_TIMEOUT 2
-#define REC_MAX_RC 8
-#define HOP_COUNT_LIMIT 32
-#define LQ6_TIMEOUT 1
-#define LQ6_MAX_RT 10
-#define LQ6_MAX_RC 5
-
-/* Leasequery query-types (RFC 5007) */
-
-#define LQ6QT_BY_ADDRESS 1
-#define LQ6QT_BY_CLIENTID 2
-
-/*
- * DUID time starts 2000-01-01.
- * This constant is the number of seconds since 1970-01-01,
- * when the Unix epoch began.
- */
-#define DUID_TIME_EPOCH 946684800
-
-/* Information-Request Time option (RFC 4242) */
-
-#define IRT_DEFAULT 86400
-#define IRT_MINIMUM 600
-
-#endif
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 4d9244f..ba5afec 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -12,12 +12,18 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include "dhcp6/pkt6.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;
@@ -25,6 +31,12 @@ Dhcpv6Srv::Dhcpv6Srv() {
// first call to instance() will create IfaceMgr (it's a singleton)
// it may throw something if things go wrong
IfaceMgr::instance();
+
+ /// @todo: instantiate LeaseMgr here once it is imlpemented.
+
+ setServerID();
+
+ shutdown = false;
}
Dhcpv6Srv::~Dhcpv6Srv() {
@@ -33,23 +45,187 @@ Dhcpv6Srv::~Dhcpv6Srv() {
bool
Dhcpv6Srv::run() {
- while (true) {
- Pkt6* pkt;
+ while (!shutdown) {
+ boost::shared_ptr<Pkt6> query; // client's message
+ boost::shared_ptr<Pkt6> rsp; // server's response
- pkt = IfaceMgr::instance().receive();
+ query = IfaceMgr::instance().receive();
- if (pkt) {
- cout << "Received " << pkt->data_len_ << " bytes, echoing back."
- << endl;
- IfaceMgr::instance().send(*pkt);
- delete pkt;
- }
+ 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;
+ case DHCPV6_INFORMATION_REQUEST:
+ rsp = processInfRequest(query);
+ break;
+ default:
+ cout << "Unknown pkt type received:"
+ << query->getType() << endl;
+ }
- // TODO add support for config session (see src/bin/auth/main.cc)
- // so this daemon can be controlled from bob
- sleep(1);
+ cout << "Received " << query->data_len_ << " bytes packet type="
+ << query->getType() << endl;
+ cout << query->toText();
+ if (rsp) {
+ 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);
}
+
+void
+Dhcpv6Srv::setServerID() {
+ /// TODO implement this for real once interface detection is done.
+ /// Use hardcoded server-id for now
+
+ boost::shared_array<uint8_t> srvid(new uint8_t[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));
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
+
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_ADVERTISE,
+ solicit->getTransid(),
+ Pkt6::UDP));
+
+ /// TODO Rewrite this once LeaseManager is implemented.
+
+ // 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(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;
+}
+
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processInfRequest(boost::shared_ptr<Pkt6> infRequest) {
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+ infRequest->getTransid(),
+ Pkt6::UDP));
+ return reply;
+}
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index a02f5f6..4daef3a 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -15,26 +15,142 @@
#ifndef DHCPV6_SRV_H
#define DHCPV6_SRV_H
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include "dhcp/pkt6.h"
+#include "dhcp/option.h"
#include <iostream>
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);
-
- public:
- // default constructor
- Dhcpv6Srv();
- ~Dhcpv6Srv();
-
- bool run();
-
- protected:
- bool shutdown;
- };
+
+namespace dhcp {
+/// @brief DHCPv6 server service.
+///
+/// This singleton class represents DHCPv6 server. It contains all
+/// top-level methods and routines necessary for server operation.
+/// In particular, it instantiates IfaceMgr, loads or generates DUID
+/// that is going to be used as server-identifier, receives incoming
+/// packets, processes them, manages leases assignment and generates
+/// appropriate responses.
+class Dhcpv6Srv : public boost::noncopyable {
+
+public:
+ /// @brief Default constructor.
+ ///
+ /// Instantiates necessary services, required to run DHCPv6 server.
+ /// In particular, creates IfaceMgr that will be responsible for
+ /// network interaction. Will instantiate lease manager, and load
+ /// old or create new DUID.
+ Dhcpv6Srv();
+
+ /// @brief Destructor. Used during DHCPv6 service shutdown.
+ ~Dhcpv6Srv();
+
+ /// @brief Returns server-intentifier option
+ ///
+ /// @return server-id option
+ boost::shared_ptr<isc::dhcp::Option>
+ getServerID() { return serverid_; }
+
+ /// @brief Main server processing loop.
+ ///
+ /// Main server processing loop. Receives incoming packets, verifies
+ /// their correctness, generates appropriate answer (if needed) and
+ /// transmits respones.
+ ///
+ /// @return true, if being shut down gracefully, fail if experienced
+ /// critical error.
+ bool run();
+
+protected:
+ /// @brief Processes incoming SOLICIT and returns response.
+ ///
+ /// Processes received SOLICIT message and verifies that its sender
+ /// should be served. In particular IA, TA and PD options are populated
+ /// with to-be assinged addresses, temporary addresses and delegated
+ /// prefixes, respectively. In the usual 4 message exchange, server is
+ /// expected to respond with ADVERTISE message. However, if client
+ /// requests rapid-commit and server supports it, REPLY will be sent
+ /// instead of ADVERTISE and requested leases will be assigned
+ /// immediately.
+ ///
+ /// @param solicit SOLICIT message received from client
+ ///
+ /// @return ADVERTISE, REPLY message or NULL
+ boost::shared_ptr<Pkt6>
+ processSolicit(boost::shared_ptr<Pkt6> solicit);
+
+ /// @brief Processes incoming REQUEST and returns REPLY response.
+ ///
+ /// Processes incoming REQUEST message and verifies that its sender
+ /// should be served. In particular IA, TA and PD options are populated
+ /// with assinged addresses, temporary addresses and delegated
+ /// prefixes, respectively. Uses LeaseMgr to allocate or update existing
+ /// leases.
+ ///
+ /// @param request a message received from client
+ ///
+ /// @return REPLY message or NULL
+ boost::shared_ptr<Pkt6>
+ processRequest(boost::shared_ptr<Pkt6> request);
+
+ /// @brief Stub function that will handle incoming RENEW messages.
+ ///
+ /// @param renew message received from client
+ boost::shared_ptr<Pkt6>
+ processRenew(boost::shared_ptr<Pkt6> renew);
+
+ /// @brief Stub function that will handle incoming REBIND messages.
+ ///
+ /// @param rebind message received from client
+ boost::shared_ptr<Pkt6>
+ processRebind(boost::shared_ptr<Pkt6> rebind);
+
+ /// @brief Stub function that will handle incoming CONFIRM messages.
+ ///
+ /// @param confirm message received from client
+ boost::shared_ptr<Pkt6>
+ processConfirm(boost::shared_ptr<Pkt6> confirm);
+
+ /// @brief Stub function that will handle incoming RELEASE messages.
+ ///
+ /// @param release message received from client
+ boost::shared_ptr<Pkt6>
+ processRelease(boost::shared_ptr<Pkt6> release);
+
+ /// @brief Stub function that will handle incoming DECLINE messages.
+ ///
+ /// @param decline message received from client
+ boost::shared_ptr<Pkt6>
+ processDecline(boost::shared_ptr<Pkt6> decline);
+
+ /// @brief Stub function that will handle incoming INF-REQUEST messages.
+ ///
+ /// @param infRequest message received from client
+ boost::shared_ptr<Pkt6>
+ processInfRequest(boost::shared_ptr<Pkt6> infRequest);
+
+ /// @brief Sets server-identifier.
+ ///
+ /// This method attempts to set server-identifier DUID. It loads it
+ /// from a file. If file load fails, it generates new DUID using
+ /// interface link-layer addresses (EUI-64) + timestamp (DUID type
+ /// duid-llt, see RFC3315, section 9.2). If there are no suitable
+ /// interfaces present, exception it thrown
+ ///
+ /// @throws isc::Unexpected Failed to read DUID file and no suitable
+ /// interfaces for new DUID generation are detected.
+ void setServerID();
+
+ /// server DUID (to be sent in server-identifier option)
+ boost::shared_ptr<isc::dhcp::Option> serverid_;
+
+ /// indicates if shutdown is in progress. Setting it to true will
+ /// initiate server shutdown procedure.
+ volatile bool shutdown;
};
+}; // namespace isc::dhcp
+}; // namespace isc
+
#endif // DHCP6_SRV_H
diff --git a/src/bin/dhcp6/iface_mgr.cc b/src/bin/dhcp6/iface_mgr.cc
index 1e2551a..a96db07 100644
--- a/src/bin/dhcp6/iface_mgr.cc
+++ b/src/bin/dhcp6/iface_mgr.cc
@@ -18,17 +18,18 @@
#include <netinet/in.h>
#include <arpa/inet.h>
+#include "dhcp/dhcp6.h"
#include "dhcp6/iface_mgr.h"
-#include "dhcp6/dhcp6.h"
#include "exceptions/exceptions.h"
using namespace std;
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::dhcp;
namespace isc {
-// IfaceMgr is a singleton implementation
+/// IfaceMgr is a singleton implementation
IfaceMgr* IfaceMgr::instance_ = 0;
void
@@ -44,14 +45,16 @@ IfaceMgr::instanceCreate() {
IfaceMgr&
IfaceMgr::instance() {
- if (instance_ == 0)
+ 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);
+
+ memset(mac_, 0, sizeof(mac_));
}
std::string
@@ -64,18 +67,22 @@ IfaceMgr::Iface::getFullName() const {
std::string
IfaceMgr::Iface::getPlainMac() const {
ostringstream tmp;
- for (int i=0; i<mac_len_; i++) {
- tmp.fill('0');
+ tmp.fill('0');
+ tmp << hex;
+ for (int i = 0; i < mac_len_; i++) {
tmp.width(2);
- tmp << (hex) << (int) mac_[i];
- if (i<mac_len_-1) {
+ tmp << mac_[i];
+ if (i < mac_len_-1) {
tmp << ":";
}
}
return (tmp.str());
}
-IfaceMgr::IfaceMgr() {
+IfaceMgr::IfaceMgr()
+ :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
+ control_buf_(new char[control_buf_len_])
+{
cout << "IfaceMgr initialization." << endl;
@@ -83,8 +90,8 @@ IfaceMgr::IfaceMgr() {
// 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_];
+
+ // control_buf_ = boost::scoped_array<char>();
detectIfaces();
@@ -103,11 +110,8 @@ IfaceMgr::IfaceMgr() {
}
IfaceMgr::~IfaceMgr() {
- if (control_buf_) {
- delete [] control_buf_;
- control_buf_ = 0;
- control_buf_len_ = 0;
- }
+ // control_buf_ is deleted automatically (scoped_ptr)
+ control_buf_len_ = 0;
}
void
@@ -225,18 +229,6 @@ IfaceMgr::getIface(const std::string& ifname) {
return (NULL); // not found
}
-
-/**
- * Opens UDP/IPv6 socket and binds it to specific address, interface and 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,
@@ -321,15 +313,6 @@ IfaceMgr::openSocket(const std::string& ifname,
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) {
@@ -355,25 +338,14 @@ const std::string & mcast) {
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(Pkt6 &pkt) {
+IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
struct msghdr m;
struct iovec v;
int result;
struct in6_pktinfo *pktinfo;
struct cmsghdr *cmsg;
- memset(control_buf_, 0, control_buf_len_);
+ memset(&control_buf_[0], 0, control_buf_len_);
/*
* Initialize our message header structure.
@@ -386,11 +358,11 @@ IfaceMgr::send(Pkt6 &pkt) {
sockaddr_in6 to;
memset(&to, 0, sizeof(to));
to.sin6_family = AF_INET6;
- to.sin6_port = htons(pkt.remote_port_);
+ to.sin6_port = htons(pkt->remote_port_);
memcpy(&to.sin6_addr,
- pkt.remote_addr_.getAddress().to_v6().to_bytes().data(),
+ pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
16);
- to.sin6_scope_id = pkt.ifindex_;
+ to.sin6_scope_id = pkt->ifindex_;
m.msg_name = &to;
m.msg_namelen = sizeof(to);
@@ -400,8 +372,8 @@ IfaceMgr::send(Pkt6 &pkt) {
* "scatter-gather" stuff... we only have a single chunk
* of data to send, so we declare a single vector entry.)
*/
- v.iov_base = (char *) &pkt.data_[0];
- v.iov_len = pkt.data_len_;
+ v.iov_base = (char *) &pkt->data_[0];
+ v.iov_len = pkt->data_len_;
m.msg_iov = &v;
m.msg_iovlen = 1;
@@ -413,7 +385,7 @@ IfaceMgr::send(Pkt6 &pkt) {
* source address if we wanted, but we can safely let the
* kernel decide what that should be.
*/
- m.msg_control = control_buf_;
+ m.msg_control = &control_buf_[0];
m.msg_controllen = control_buf_len_;
cmsg = CMSG_FIRSTHDR(&m);
cmsg->cmsg_level = IPPROTO_IPV6;
@@ -421,7 +393,7 @@ IfaceMgr::send(Pkt6 &pkt) {
cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
memset(pktinfo, 0, sizeof(*pktinfo));
- pktinfo->ipi6_ifindex = pkt.ifindex_;
+ pktinfo->ipi6_ifindex = pkt->ifindex_;
m.msg_controllen = cmsg->cmsg_len;
result = sendmsg(sendsock_, &m, 0);
@@ -430,26 +402,16 @@ IfaceMgr::send(Pkt6 &pkt) {
}
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()
+ 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);
}
-
-/**
- * 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.
- */
-Pkt6*
+boost::shared_ptr<Pkt6>
IfaceMgr::receive() {
struct msghdr m;
struct iovec v;
@@ -458,7 +420,7 @@ IfaceMgr::receive() {
struct in6_pktinfo* pktinfo;
struct sockaddr_in6 from;
struct in6_addr to_addr;
- Pkt6* pkt;
+ boost::shared_ptr<Pkt6> pkt;
char addr_str[INET6_ADDRSTRLEN];
try {
@@ -469,13 +431,13 @@ IfaceMgr::receive() {
// we use larger buffer. This buffer limit is checked
// during reception (see iov_len below), so we are
// safe
- pkt = new Pkt6(65536);
+ pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
} catch (const std::exception& ex) {
cout << "Failed to create new packet." << endl;
- return (0);
+ return (boost::shared_ptr<Pkt6>()); // NULL
}
- memset(control_buf_, 0, control_buf_len_);
+ memset(&control_buf_[0], 0, control_buf_len_);
memset(&from, 0, sizeof(from));
memset(&to_addr, 0, sizeof(to_addr));
@@ -509,7 +471,7 @@ IfaceMgr::receive() {
* information (when we initialized the interface), so we
* should get the destination address from that.
*/
- m.msg_control = control_buf_;
+ m.msg_control = &control_buf_[0];
m.msg_controllen = control_buf_len_;
result = recvmsg(recvsock_, &m, 0);
@@ -537,20 +499,20 @@ IfaceMgr::receive() {
}
if (!found_pktinfo) {
cout << "Unable to find pktinfo" << endl;
- delete pkt;
- return (0);
+ return (boost::shared_ptr<Pkt6>()); // NULL
}
} else {
cout << "Failed to receive data." << endl;
- delete pkt;
- return (0);
+ return (boost::shared_ptr<Pkt6>()); // NULL
}
// That's ugly.
// TODO add IOAddress constructor that will take struct in6_addr*
+ // TODO: there's from_bytes() method added in IOAddress. Use it!
inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
pkt->local_addr_ = IOAddress(string(addr_str));
+ // TODO: there's from_bytes() method added in IOAddress. Use it!
inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
pkt->remote_addr_ = IOAddress(string(addr_str));
@@ -562,8 +524,7 @@ IfaceMgr::receive() {
} else {
cout << "Received packet over unknown interface (ifindex="
<< pkt->ifindex_ << ")." << endl;
- delete pkt;
- return (0);
+ return (boost::shared_ptr<Pkt6>()); // NULL
}
pkt->data_len_ = result;
diff --git a/src/bin/dhcp6/iface_mgr.h b/src/bin/dhcp6/iface_mgr.h
index 39061da..249c7ef 100644
--- a/src/bin/dhcp6/iface_mgr.h
+++ b/src/bin/dhcp6/iface_mgr.h
@@ -16,88 +16,214 @@
#define IFACE_MGR_H
#include <list>
-#include "io_address.h"
-#include "dhcp6/pkt6.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/noncopyable.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(Pkt6& pkt);
- 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);
+namespace dhcp {
+/// @brief handles network interfaces, transmission and reception
+///
+/// IfaceMgr is an interface manager class that detects available network
+/// interfaces, configured addresses, link-local addresses, and provides
+/// API for using sockets.
+///
+class IfaceMgr : public boost::noncopyable {
+public:
+ /// type that defines list of addresses
+ typedef std::list<isc::asiolink::IOAddress> Addr6Lst;
+
+ /// maximum MAC address length (Infiniband uses 20 bytes)
+ static const unsigned int MAX_MAC_LEN = 20;
+
+ /// @brief represents a single network interface
+ ///
+ /// Iface structure represents network interface with all useful
+ /// information, like name, interface index, MAC address and
+ /// list of assigned addresses
+ struct Iface {
+ /// constructor
+ Iface(const std::string& name, int ifindex);
+
+ /// returns full interface name in format ifname/ifindex
+ std::string getFullName() const;
+
+ /// returns link-layer address a plain text
+ std::string getPlainMac() const;
+
+ /// network interface name
+ std::string name_;
+
+ /// interface index (a value that uniquely indentifies an interface)
+ int ifindex_;
+
+ /// list of assigned addresses
+ Addr6Lst addrs_;
+
+ /// link-layer address
+ uint8_t mac_[MAX_MAC_LEN];
+
+ /// length of link-layer address (usually 6)
+ int mac_len_;
+
+ /// socket used to sending data
+ int sendsock_;
+
+ /// socket used for receiving data
+ int recvsock_;
};
+
+ // TODO performance improvement: we may change this into
+ // 2 maps (ifindex-indexed and name-indexed) and
+ // also hide it (make it public make tests easier for now)
+
+ /// type that holds a list of interfaces
+ typedef std::list<Iface> IfaceLst;
+
+ /// IfaceMgr is a singleton class. This method returns reference
+ /// to its sole instance.
+ ///
+ /// @return the only existing instance of interface manager
+ static IfaceMgr& instance();
+
+ /// @brief Returns interface with specified interface index
+ ///
+ /// @param ifindex index of searched interface
+ ///
+ /// @return interface with requested index (or NULL if no such
+ /// interface is present)
+ ///
+ Iface*
+ getIface(int ifindex);
+
+ /// @brief Returns interface with specified interface name
+ ///
+ /// @param ifname name of searched interface
+ ///
+ /// @return interface with requested name (or NULL if no such
+ /// interface is present)
+ ///
+ Iface*
+ getIface(const std::string& ifname);
+
+ /// debugging method that prints out all available interfaces
+ ///
+ /// @param out specifies stream to print list of interfaces to
+ void
+ printIfaces(std::ostream& out = std::cout);
+
+ /// @brief Sends a packet.
+ ///
+ /// Sends a packet. All parameters for actual transmission are specified in
+ /// Pkt6 structure itself. That includes destination address, src/dst port
+ /// and interface over which data will be sent.
+ ///
+ /// @param pkt packet to be sent
+ ///
+ /// @return true if sending was successful
+ bool
+ send(boost::shared_ptr<Pkt6>& pkt);
+
+ /// @brief Tries to receive packet over open sockets.
+ ///
+ /// Attempts to receive a single packet of any of the open sockets.
+ /// If reception is successful and all information about its sender
+ /// are obtained, Pkt6 object is created and returned.
+ ///
+ /// TODO Start using select() and add timeout to be able
+ /// to not wait infinitely, but rather do something useful
+ /// (e.g. remove expired leases)
+ ///
+ /// @return Pkt6 object representing received packet (or NULL)
+ boost::shared_ptr<Pkt6> receive();
+
+ // don't use private, we need derived classes in tests
+protected:
+
+ /// @brief Protected constructor.
+ ///
+ /// Protected constructor. This is a singleton class. We don't want
+ /// anyone to create instances of IfaceMgr. Use instance() method
+ IfaceMgr();
+
+ ~IfaceMgr();
+
+ /// @brief Detects network interfaces.
+ ///
+ /// This method will eventually detect available interfaces. For now
+ /// it offers stub implementation. First interface name and link-local
+ /// IPv6 address is read from intefaces.txt file.
+ void
+ detectIfaces();
+
+ ///
+ /// Opens UDP/IPv6 socket and binds it to address, interface and port.
+ ///
+ /// @param ifname name of the interface
+ /// @param addr address to be bound.
+ /// @param port UDP port.
+ ///
+ /// @return socket descriptor, if socket creation, binding and multicast
+ /// group join were all successful. -1 otherwise.
+ 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
+
+ /// List of available interfaces
+ IfaceLst ifaces_;
+
+ /// a pointer to a sole instance of this class (a singleton)
+ static IfaceMgr * instance_;
+
+ // TODO: Also keep this interface on Iface once interface detection
+ // is implemented. We may need it e.g. to close all sockets on
+ // specific interface
+ int recvsock_; // TODO: should be fd_set eventually, but we have only
+ int sendsock_; // 2 sockets for now. Will do for until next release
+ // we can't use the same socket, as receiving socket
+ // is bound to multicast address. And we all know what happens
+ // to people who try to use multicast as source address.
+
+ /// length of the control_buf_ array
+ int control_buf_len_;
+
+ /// control-buffer, used in transmission and reception
+ boost::scoped_array<char> control_buf_;
+
+private:
+ /// Opens sockets on detected interfaces.
+ bool
+ openSockets();
+
+ /// creates a single instance of this class (a singleton implementation)
+ static void
+ instanceCreate();
+
+ /// @brief Joins IPv6 multicast group on a socket.
+ ///
+ /// Socket must be created and bound to an address. Note that this
+ /// address is different than the multicast address. For example DHCPv6
+ /// server should bind its socket to link-local address (fe80::1234...)
+ /// and later join ff02::1:2 multicast group.
+ ///
+ /// @param sock socket fd (socket must be bound)
+ /// @param ifname interface name (for link-scoped multicast groups)
+ /// @param mcast multicast address to join (e.g. "ff02::1:2")
+ ///
+ /// @return true if multicast join was successful
+ ///
+ bool
+ joinMcast(int sock, const std::string& ifname,
+ const std::string& mcast);
};
+}; // namespace isc::dhcp
+}; // namespace isc
+
#endif
diff --git a/src/bin/dhcp6/main.cc b/src/bin/dhcp6/main.cc
index 95d2261..5323811 100644
--- a/src/bin/dhcp6/main.cc
+++ b/src/bin/dhcp6/main.cc
@@ -26,8 +26,11 @@
#include <iostream>
#include <exceptions/exceptions.h>
+#if 0
+// TODO cc is not used yet. It should be eventually
#include <cc/session.h>
#include <config/ccsession.h>
+#endif
#include <util/buffer.h>
#include <log/dummylog.h>
@@ -37,12 +40,9 @@
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;
+using namespace isc::dhcp;
namespace {
@@ -97,8 +97,6 @@ main(int argc, char* argv[]) {
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();
diff --git a/src/bin/dhcp6/pkt6.cc b/src/bin/dhcp6/pkt6.cc
deleted file mode 100644
index 5dcab86..0000000
--- a/src/bin/dhcp6/pkt6.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-
-#include "dhcp6/dhcp6.h"
-#include "dhcp6/pkt6.h"
-#include <iostream>
-
-namespace isc {
-
-///
-/// constructor
-///
-/// \param dataLen - length of the data to be allocated
-///
-Pkt6::Pkt6(int dataLen)
- :local_addr_("::"),
- remote_addr_("::") {
- try {
- data_ = boost::shared_array<char>(new char[dataLen]);
- data_len_ = dataLen;
- } catch (const std::exception& ex) {
- // TODO move to LOG_FATAL()
- // let's continue with empty pkt for now
- std::cout << "Failed to allocate " << dataLen << " bytes."
- << std::endl;
- data_len_ = 0;
- }
-}
-
-Pkt6::~Pkt6() {
- // no need to delete anything shared_ptr will take care of data_
-}
-
-};
diff --git a/src/bin/dhcp6/pkt6.h b/src/bin/dhcp6/pkt6.h
deleted file mode 100644
index 9a14d92..0000000
--- a/src/bin/dhcp6/pkt6.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef PKT6_H
-#define PKT6_H
-
-#include <iostream>
-#include <boost/shared_array.hpp>
-#include "io_address.h"
-
-namespace isc {
-
- class Pkt6 {
- public:
- Pkt6(int len);
- ~Pkt6();
-
- // XXX: probably need getter/setter wrappers
- // and hide fields as protected
- // buffer that holds memory. It is shared_array as options may
- // share pointer to this buffer
- boost::shared_array<char> data_;
-
- // length of the data
- int data_len_;
-
- // local address (destination if receiving packet, source if sending packet)
- isc::asiolink::IOAddress local_addr_;
-
- // remote address (source if receiving packet, destination if sending packet)
- isc::asiolink::IOAddress remote_addr_;
-
- // name of the network interface the packet was received/to be sent over
- std::string iface_;
-
- // interface index (each network interface has assigned unique ifindex
- // it is functional equvalent of name, but sometimes more useful, e.g.
- // when using crazy systems that allow spaces in interface names (Windows)
- int ifindex_;
-
- // local TDP or UDP port
- int local_port_;
-
- // remote TCP or UDP port
- int remote_port_;
-
- // XXX: add *a lot* here
- };
-}
-
-#endif
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index ae9d8e3..985368e 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -45,11 +45,9 @@ if HAVE_GTEST
TESTS += dhcp6_unittests
-dhcp6_unittests_SOURCES = ../pkt6.h ../pkt6.cc
-dhcp6_unittests_SOURCES += ../iface_mgr.h ../iface_mgr.cc
+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 += pkt6_unittest.cc
dhcp6_unittests_SOURCES += iface_mgr_unittest.cc
dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
@@ -58,8 +56,7 @@ 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/config/libcfgclient.la
-dhcp6_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
endif
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index 96c767e..f9a1d9d 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -19,13 +19,33 @@
#include <arpa/inet.h>
#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 NakedDhcpv6Srv: public Dhcpv6Srv {
+ // "naked" Interface Manager, exposes internal fields
+public:
+ NakedDhcpv6Srv() { }
+
+ boost::shared_ptr<Pkt6>
+ processSolicit(boost::shared_ptr<Pkt6>& request) {
+ return Dhcpv6Srv::processSolicit(request);
+ }
+ boost::shared_ptr<Pkt6>
+ processRequest(boost::shared_ptr<Pkt6>& request) {
+ return Dhcpv6Srv::processRequest(request);
+ }
+};
-namespace {
class Dhcpv6SrvTest : public ::testing::Test {
public:
Dhcpv6SrvTest() {
@@ -33,21 +53,94 @@ public:
};
TEST_F(Dhcpv6SrvTest, basic) {
- // there's almost no code now. What's there provides echo capability
+ // 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;
- });
-
+ delete srv;
+ });
+
+}
+
+TEST_F(Dhcpv6SrvTest, Solicit_basic) {
+ NakedDhcpv6Srv * srv = 0;
+ EXPECT_NO_THROW( srv = new NakedDhcpv6Srv(); );
+
+ // a dummy content for client-id
+ boost::shared_array<uint8_t> clntDuid(new uint8_t[32]);
+ for (int i=0; i<32; i++)
+ clntDuid[i] = 100+i;
+
+ boost::shared_ptr<Pkt6> sol =
+ boost::shared_ptr<Pkt6>(new Pkt6(DHCPV6_SOLICIT,
+ 1234, Pkt6::UDP));
+
+ boost::shared_ptr<Option6IA> ia =
+ boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
+ 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);
+
+ // constructed very simple SOLICIT message with:
+ // - client-id option (mandatory)
+ // - IA option (a request for address, without any addresses)
+
+ // expected returned ADVERTISE message:
+ // - copy of client-id
+ // - server-id
+ // - IA that includes IAADDR
+
+ boost::shared_ptr<Option> clientid =
+ boost::shared_ptr<Option>(new Option(Option::V6, D6O_CLIENTID,
+ clntDuid, 0, 16));
+ sol->addOption(clientid);
+
+ 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 );
+
+ Option6IA * reply_ia = dynamic_cast<Option6IA*> ( tmp.get() );
+ EXPECT_EQ( 234, reply_ia->getIAID() );
+
+ // check that there's an address included
+ EXPECT_TRUE( reply_ia->getOption(D6O_IAADDR));
+
+ // check that server included our own client-id
+ tmp = reply->getOption(D6O_CLIENTID);
+ ASSERT_TRUE( tmp );
+ EXPECT_EQ(clientid->getType(), tmp->getType() );
+ ASSERT_EQ(clientid->len(), tmp->len() );
+ EXPECT_FALSE(memcmp(clientid->getData(), tmp->getData(), tmp->len() ) );
+ // check that server included its server-id
+ tmp = reply->getOption(D6O_SERVERID);
+ EXPECT_EQ(tmp->getType(), srv->getServerID()->getType() );
+ ASSERT_EQ(tmp->len(), srv->getServerID()->len() );
+ EXPECT_FALSE( memcmp(tmp->getData(), srv->getServerID()->getData(),
+ tmp->len()) );
+
+ // more checks to be implemented
+ delete srv;
+
}
}
diff --git a/src/bin/dhcp6/tests/iface_mgr_unittest.cc b/src/bin/dhcp6/tests/iface_mgr_unittest.cc
index c9a9d72..5ce73f8 100644
--- a/src/bin/dhcp6/tests/iface_mgr_unittest.cc
+++ b/src/bin/dhcp6/tests/iface_mgr_unittest.cc
@@ -21,12 +21,16 @@
#include <gtest/gtest.h>
#include "io_address.h"
-#include "dhcp6/pkt6.h"
+#include "dhcp/pkt6.h"
#include "dhcp6/iface_mgr.h"
using namespace std;
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+// name of loopback interface detection
+char LOOPBACK[32] = "lo";
namespace {
const char* const INTERFACE_FILE = TEST_DATA_BUILDDIR "/interfaces.txt";
@@ -54,6 +58,113 @@ public:
}
};
+// We need some known interface to work reliably. Loopback interface
+// is named lo on Linux and lo0 on BSD boxes. We need to find out
+// which is available. This is not a real test, but rather a workaround
+// that will go away when interface detection is implemented.
+
+// NOTE: At this stage of development, write access to current directory
+// during running tests is required.
+TEST_F(IfaceMgrTest, loDetect) {
+
+ 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
+ if (socket1>0) {
+ cout << "This is Linux, using lo as loopback." << endl;
+ close(socket1);
+ } else {
+ // this fails on Linux and succeeds on BSD
+ socket1 = ifacemgr->openSocket("lo0", mcastAddr, 10547);
+ if (socket1>0) {
+ sprintf(LOOPBACK, "lo0");
+ cout << "This is BSD, using lo0 as loopback." << endl;
+ close(socket1);
+ } 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;
+
+ // TODO it is better to declare an array and then memcpy it to
+ // packet.
+ for (int i=0; i< pkt->data_len_; i++) {
+ cout << " pkt->data_[" << i << "]="
+ << (int)(unsigned char)pkt->data_[i] << "; ";
+ if (!(i%4))
+ cout << endl;
+ }
+ cout << endl;
+ cout << " return (pkt);" << endl;
+ cout << "}" << endl << endl;
+
+ delete pkt;
+ }
+ cout << "---8X-----------------------------------------" << endl;
+
+ // never happens. Infinite loop is infinite
+ delete pkt;
+ delete ifacemgr;
+}
+#endif
+
TEST_F(IfaceMgrTest, basic) {
// checks that IfaceManager can be instantiated
@@ -72,23 +183,34 @@ TEST_F(IfaceMgrTest, ifaceClass) {
}
-// TODO: Implement getPlainMac() test as soon as interface detection is implemented.
+// 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("lo", 1);
+ 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.
@@ -98,10 +220,10 @@ TEST_F(IfaceMgrTest, getIface) {
EXPECT_EQ(5, tmp->ifindex_);
// check that interface can be retrieved by name
- tmp = ifacemgr->getIface("lo");
+ tmp = ifacemgr->getIface("lo1");
ASSERT_TRUE( tmp != NULL );
- EXPECT_STREQ( "lo", tmp->name_.c_str() );
+ EXPECT_STREQ( "lo1", tmp->name_.c_str() );
EXPECT_EQ(1, tmp->ifindex_);
// check that non-existing interfaces are not returned
@@ -153,17 +275,22 @@ TEST_F(IfaceMgrTest, DISABLED_sockets) {
IOAddress loAddr("::1");
// bind multicast socket to port 10547
- int socket1 = ifacemgr->openSocket("lo", loAddr, 10547);
+ int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
EXPECT_GT(socket1, 0); // socket > 0
// bind unicast socket to port 10548
- int socket2 = ifacemgr->openSocket("lo", loAddr, 10548);
+ int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10548);
EXPECT_GT(socket2, 0);
// expect success. This address/port is already bound, but
// we are using SO_REUSEADDR, so we can bind it twice
- int socket3 = ifacemgr->openSocket("lo", loAddr, 10547);
- EXPECT_GT(socket3, 0); // socket > 0
+ 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.
@@ -186,12 +313,12 @@ TEST_F(IfaceMgrTest, DISABLED_socketsMcast) {
IOAddress mcastAddr("ff02::1:2");
// bind multicast socket to port 10547
- int socket1 = ifacemgr->openSocket("lo", mcastAddr, 10547);
+ int socket1 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
EXPECT_GT(socket1, 0); // socket > 0
// expect success. This address/port is already bound, but
// we are using SO_REUSEADDR, so we can bind it twice
- int socket2 = ifacemgr->openSocket("lo", mcastAddr, 10547);
+ int socket2 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
EXPECT_GT(socket2, 0);
// there's no good way to test negative case here.
@@ -214,49 +341,47 @@ TEST_F(IfaceMgrTest, DISABLED_sendReceive) {
// without interface detection implemented
fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
- fakeifaces << "lo ::1";
+ 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("lo", loAddr, 10547);
- int socket2 = ifacemgr->openSocket("lo", loAddr, 10546);
+ int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+ int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
ifacemgr->setSendSock(socket2);
ifacemgr->setRecvSock(socket1);
- Pkt6 sendPkt(128);
+ boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
// prepare dummy payload
for (int i=0;i<128; i++) {
- sendPkt.data_[i] = i;
+ sendPkt->data_[i] = i;
}
- sendPkt.remote_port_ = 10547;
- sendPkt.remote_addr_ = IOAddress("::1");
- sendPkt.ifindex_ = 1;
- sendPkt.iface_ = "lo";
+ sendPkt->remote_port_ = 10547;
+ sendPkt->remote_addr_ = IOAddress("::1");
+ sendPkt->ifindex_ = 1;
+ sendPkt->iface_ = LOOPBACK;
- Pkt6 * rcvPkt;
+ boost::shared_ptr<Pkt6> rcvPkt;
EXPECT_EQ(true, ifacemgr->send(sendPkt));
rcvPkt = ifacemgr->receive();
- ASSERT_TRUE( rcvPkt != NULL ); // received our own packet
+ ASSERT_TRUE( rcvPkt ); // received our own packet
// let's check that we received what was sent
- EXPECT_EQ(sendPkt.data_len_, rcvPkt->data_len_);
- EXPECT_EQ(0, memcmp(&sendPkt.data_[0], &rcvPkt->data_[0],
+ EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
+ EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
rcvPkt->data_len_) );
- EXPECT_EQ(sendPkt.remote_addr_.toText(), rcvPkt->remote_addr_.toText());
+ EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
EXPECT_EQ(rcvPkt->remote_port_, 10546);
- delete rcvPkt;
-
delete ifacemgr;
}
diff --git a/src/bin/dhcp6/tests/pkt6_unittest.cc b/src/bin/dhcp6/tests/pkt6_unittest.cc
deleted file mode 100644
index 5054c45..0000000
--- a/src/bin/dhcp6/tests/pkt6_unittest.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <sstream>
-
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-
-
-#include "dhcp6/pkt6.h"
-
-using namespace std;
-using namespace isc;
-
-namespace {
-// empty class for now, but may be extended once Addr6 becomes bigger
-class Pkt6Test : public ::testing::Test {
-public:
- Pkt6Test() {
- }
-};
-
-TEST_F(Pkt6Test, constructor) {
- Pkt6 * pkt1 = new Pkt6(17);
-
- ASSERT_EQ(pkt1->data_len_, 17);
-
- delete pkt1;
-}
-
-}
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 04eee45..a569ea7 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,3 +1,3 @@
SUBDIRS = exceptions util log cryptolink dns cc config acl xfr bench \
asiolink asiodns nsas cache resolve testutils datasrc \
- server_common python
+ server_common python dhcp
diff --git a/src/lib/asiolink/io_address.cc b/src/lib/asiolink/io_address.cc
index 7e2f5d4..51c0332 100644
--- a/src/lib/asiolink/io_address.cc
+++ b/src/lib/asiolink/io_address.cc
@@ -23,7 +23,7 @@
#include <exceptions/exceptions.h>
#include <asiolink/io_address.h>
#include <asiolink/io_error.h>
-
+#include <boost/static_assert.hpp>
using namespace asio;
using asio::ip::udp;
@@ -54,6 +54,22 @@ IOAddress::toText() const {
return (asio_address_.to_string());
}
+IOAddress
+IOAddress::from_bytes(short family, const uint8_t* data) {
+ if (data == NULL) {
+ isc_throw(BadValue, "NULL pointer received.");
+ } else
+ if ( (family != AF_INET) && (family != AF_INET6) ) {
+ isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6"
+ << "are supported");
+ }
+
+ BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN);
+ return IOAddress(string(addr_str));
+}
+
short
IOAddress::getFamily() const {
if (asio_address_.is_v4()) {
@@ -63,7 +79,7 @@ IOAddress::getFamily() const {
}
}
-const asio::ip::address&
+const asio::ip::address&
IOAddress::getAddress() const {
return asio_address_;
}
diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h
index 1b488fa..9fac580 100644
--- a/src/lib/asiolink/io_address.h
+++ b/src/lib/asiolink/io_address.h
@@ -29,6 +29,12 @@
namespace isc {
namespace asiolink {
+ /// Defines length of IPv6 address.
+ const static size_t V6ADDRESS_LEN = 16;
+
+ /// Defines length of IPv4 address.
+ const static size_t V4ADDRESS_LEN = 4;
+
/// \brief The \c IOAddress class represents an IP addresses (version
/// agnostic)
///
@@ -87,6 +93,16 @@ public:
/// \return AF_INET for IPv4 or AF_INET6 for IPv6.
short getFamily() const;
+
+ /// \brief Creates an address from over wire data.
+ ///
+ /// \param family AF_NET for IPv4 or AF_NET6 for IPv6.
+ /// \param data pointer to first char of data
+ ///
+ /// \return Created IOAddress object
+ static IOAddress
+ from_bytes(short family, const uint8_t* data);
+
/// \brief Compare addresses for equality
///
/// \param other Address to compare against.
diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc
index 56368a1..7943a9a 100644
--- a/src/lib/asiolink/tests/io_address_unittest.cc
+++ b/src/lib/asiolink/tests/io_address_unittest.cc
@@ -63,3 +63,23 @@ TEST(IOAddressTest, Family) {
EXPECT_EQ(AF_INET, IOAddress("192.0.2.1").getFamily());
EXPECT_EQ(AF_INET6, IOAddress("2001:0DB8:0:0::0012").getFamily());
}
+
+TEST(IOAddressTest, from_bytes) {
+ // 2001:db8:1::dead:beef
+ uint8_t v6[] = {
+ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0,
+ 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef };
+
+ uint8_t v4[] = { 192, 0 , 2, 3 };
+
+ IOAddress addr("::");
+ EXPECT_NO_THROW({
+ addr = IOAddress::from_bytes(AF_INET6, v6);
+ });
+ EXPECT_EQ("2001:db8:1::dead:beef", addr.toText());
+
+ EXPECT_NO_THROW({
+ addr = IOAddress::from_bytes(AF_INET, v4);
+ });
+ EXPECT_EQ(addr, IOAddress("192.0.2.3"));
+}
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
new file mode 100644
index 0000000..e146adb
--- /dev/null
+++ b/src/lib/dhcp/Makefile.am
@@ -0,0 +1,25 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+lib_LTLIBRARIES = libdhcp.la
+libdhcp_la_SOURCES =
+libdhcp_la_SOURCES += libdhcp.cc libdhcp.h
+libdhcp_la_SOURCES += option.cc option.h
+libdhcp_la_SOURCES += option6_ia.cc option6_ia.h
+libdhcp_la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
+libdhcp_la_SOURCES += option6_addrlst.cc option6_addrlst.h
+libdhcp_la_SOURCES += dhcp6.h
+libdhcp_la_SOURCES += pkt6.cc pkt6.h
+
+EXTRA_DIST = README
+#EXTRA_DIST += log_messages.mes
+
+libdhcp_la_CXXFLAGS = $(AM_CXXFLAGS)
+libdhcp_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libdhcp_la_LIBADD = $(top_builddir)/src/lib/util/libutil.la
diff --git a/src/lib/dhcp/README b/src/lib/dhcp/README
new file mode 100644
index 0000000..6c5353d
--- /dev/null
+++ b/src/lib/dhcp/README
@@ -0,0 +1,11 @@
+This directory holds implementation for libdhcp.
+
+
+Basic Ideas
+===========
+
+
+Notes
+=====
+This work just begun. Don't expect to see much useful code here.
+We are working on it.
\ No newline at end of file
diff --git a/src/lib/dhcp/dhcp6.h b/src/lib/dhcp/dhcp6.h
new file mode 100644
index 0000000..6012003
--- /dev/null
+++ b/src/lib/dhcp/dhcp6.h
@@ -0,0 +1,184 @@
+// Copyright (C) 2006-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 DHCP6_H
+#define DHCP6_H
+
+/* DHCPv6 Option codes: */
+
+#define D6O_CLIENTID 1 /* RFC3315 */
+#define D6O_SERVERID 2
+#define D6O_IA_NA 3
+#define D6O_IA_TA 4
+#define D6O_IAADDR 5
+#define D6O_ORO 6
+#define D6O_PREFERENCE 7
+#define D6O_ELAPSED_TIME 8
+#define D6O_RELAY_MSG 9
+/* Option code 10 unassigned. */
+#define D6O_AUTH 11
+#define D6O_UNICAST 12
+#define D6O_STATUS_CODE 13
+#define D6O_RAPID_COMMIT 14
+#define D6O_USER_CLASS 15
+#define D6O_VENDOR_CLASS 16
+#define D6O_VENDOR_OPTS 17
+#define D6O_INTERFACE_ID 18
+#define D6O_RECONF_MSG 19
+#define D6O_RECONF_ACCEPT 20
+#define D6O_SIP_SERVERS_DNS 21 /* RFC3319 */
+#define D6O_SIP_SERVERS_ADDR 22 /* RFC3319 */
+#define D6O_NAME_SERVERS 23 /* RFC3646 */
+#define D6O_DOMAIN_SEARCH 24 /* RFC3646 */
+#define D6O_IA_PD 25 /* RFC3633 */
+#define D6O_IAPREFIX 26 /* RFC3633 */
+#define D6O_NIS_SERVERS 27 /* RFC3898 */
+#define D6O_NISP_SERVERS 28 /* RFC3898 */
+#define D6O_NIS_DOMAIN_NAME 29 /* RFC3898 */
+#define D6O_NISP_DOMAIN_NAME 30 /* RFC3898 */
+#define D6O_SNTP_SERVERS 31 /* RFC4075 */
+#define D6O_INFORMATION_REFRESH_TIME 32 /* RFC4242 */
+#define D6O_BCMCS_SERVER_D 33 /* RFC4280 */
+#define D6O_BCMCS_SERVER_A 34 /* RFC4280 */
+/* 35 is unassigned */
+#define D6O_GEOCONF_CIVIC 36 /* RFC4776 */
+#define D6O_REMOTE_ID 37 /* RFC4649 */
+#define D6O_SUBSCRIBER_ID 38 /* RFC4580 */
+#define D6O_CLIENT_FQDN 39 /* RFC4704 */
+#define D6O_PANA_AGENT 40 /* paa-option */
+#define D6O_NEW_POSIX_TIMEZONE 41 /* RFC4833 */
+#define D6O_NEW_TZDB_TIMEZONE 42 /* RFC4833 */
+#define D6O_ERO 43 /* RFC4994 */
+#define D6O_LQ_QUERY 44 /* RFC5007 */
+#define D6O_CLIENT_DATA 45 /* RFC5007 */
+#define D6O_CLT_TIME 46 /* RFC5007 */
+#define D6O_LQ_RELAY_DATA 47 /* RFC5007 */
+#define D6O_LQ_CLIENT_LINK 48 /* RFC5007 */
+
+/*
+ * Status Codes, from RFC 3315 section 24.4, and RFC 3633, 5007.
+ */
+#define STATUS_Success 0
+#define STATUS_UnspecFail 1
+#define STATUS_NoAddrsAvail 2
+#define STATUS_NoBinding 3
+#define STATUS_NotOnLink 4
+#define STATUS_UseMulticast 5
+#define STATUS_NoPrefixAvail 6
+#define STATUS_UnknownQueryType 7
+#define STATUS_MalformedQuery 8
+#define STATUS_NotConfigured 9
+#define STATUS_NotAllowed 10
+
+/*
+ * DHCPv6 message types, defined in section 5.3 of RFC 3315
+ */
+#define DHCPV6_SOLICIT 1
+#define DHCPV6_ADVERTISE 2
+#define DHCPV6_REQUEST 3
+#define DHCPV6_CONFIRM 4
+#define DHCPV6_RENEW 5
+#define DHCPV6_REBIND 6
+#define DHCPV6_REPLY 7
+#define DHCPV6_RELEASE 8
+#define DHCPV6_DECLINE 9
+#define DHCPV6_RECONFIGURE 10
+#define DHCPV6_INFORMATION_REQUEST 11
+#define DHCPV6_RELAY_FORW 12
+#define DHCPV6_RELAY_REPL 13
+#define DHCPV6_LEASEQUERY 14
+#define DHCPV6_LEASEQUERY_REPLY 15
+
+extern const char *dhcpv6_type_names[];
+extern const int dhcpv6_type_name_max;
+
+/* DUID type definitions (RFC3315 section 9).
+ */
+#define DUID_LLT 1
+#define DUID_EN 2
+#define DUID_LL 3
+
+/* Offsets into IA_*'s where Option spaces commence. */
+#define IA_NA_OFFSET 12 /* IAID, T1, T2, all 4 octets each */
+#define IA_TA_OFFSET 4 /* IAID only, 4 octets */
+#define IA_PD_OFFSET 12 /* IAID, T1, T2, all 4 octets each */
+
+/* Offset into IAADDR's where Option spaces commence. */
+#define IAADDR_OFFSET 24
+
+/* Offset into IAPREFIX's where Option spaces commence. */
+#define IAPREFIX_OFFSET 25
+
+/* Offset into LQ_QUERY's where Option spaces commence. */
+#define LQ_QUERY_OFFSET 17
+
+/*
+ * DHCPv6 well-known multicast addressess, from section 5.1 of RFC 3315
+ */
+#define ALL_DHCP_RELAY_AGENTS_AND_SERVERS "ff02::1:2"
+#define ALL_DHCP_SERVERS "ff05::1:3"
+
+#define DHCP6_CLIENT_PORT 546
+#define DHCP6_SERVER_PORT 547
+
+/*
+ * DHCPv6 Retransmission Constants (RFC3315 section 5.5, RFC 5007)
+ */
+
+#define SOL_MAX_DELAY 1
+#define SOL_TIMEOUT 1
+#define SOL_MAX_RT 120
+#define REQ_TIMEOUT 1
+#define REQ_MAX_RT 30
+#define REQ_MAX_RC 10
+#define CNF_MAX_DELAY 1
+#define CNF_TIMEOUT 1
+#define CNF_MAX_RT 4
+#define CNF_MAX_RD 10
+#define REN_TIMEOUT 10
+#define REN_MAX_RT 600
+#define REB_TIMEOUT 10
+#define REB_MAX_RT 600
+#define INF_MAX_DELAY 1
+#define INF_TIMEOUT 1
+#define INF_MAX_RT 120
+#define REL_TIMEOUT 1
+#define REL_MAX_RC 5
+#define DEC_TIMEOUT 1
+#define DEC_MAX_RC 5
+#define REC_TIMEOUT 2
+#define REC_MAX_RC 8
+#define HOP_COUNT_LIMIT 32
+#define LQ6_TIMEOUT 1
+#define LQ6_MAX_RT 10
+#define LQ6_MAX_RC 5
+
+/* Leasequery query-types (RFC 5007) */
+
+#define LQ6QT_BY_ADDRESS 1
+#define LQ6QT_BY_CLIENTID 2
+
+/*
+ * DUID time starts 2000-01-01.
+ * This constant is the number of seconds since 1970-01-01,
+ * when the Unix epoch began.
+ */
+#define DUID_TIME_EPOCH 946684800
+
+/* Information-Request Time option (RFC 4242) */
+
+#define IRT_DEFAULT 86400
+#define IRT_MINIMUM 600
+
+#endif
diff --git a/src/lib/dhcp/libdhcp.cc b/src/lib/dhcp/libdhcp.cc
new file mode 100644
index 0000000..55c4ee7
--- /dev/null
+++ b/src/lib/dhcp/libdhcp.cc
@@ -0,0 +1,130 @@
+// 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 <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include "dhcp/libdhcp.h"
+#include "config.h"
+#include "dhcp6.h"
+
+#include "option.h"
+#include "option6_ia.h"
+#include "option6_iaaddr.h"
+
+using namespace std;
+using namespace isc::dhcp;
+
+// static array with factories for options
+std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
+
+unsigned int
+LibDHCP::unpackOptions6(const boost::shared_array<uint8_t> buf,
+ unsigned int buf_len,
+ unsigned int offset, unsigned int parse_len,
+ isc::dhcp::Option::Option6Collection& options) {
+ if (offset + parse_len > buf_len) {
+ isc_throw(OutOfRange, "Option parse failed. Tried to parse "
+ << parse_len << " bytes at offset " << offset
+ << ": out of buffer");
+ }
+ unsigned int end = offset + parse_len;
+
+ while (offset +4 <= end) {
+ uint16_t opt_type = buf[offset]*256 + buf[offset+1];
+ offset += 2;
+ uint16_t opt_len = buf[offset]*256 + buf[offset+1];
+ offset += 2;
+
+ if (offset + opt_len > end ) {
+ cout << "Option " << opt_type << " truncated." << endl;
+ return (offset);
+ }
+ boost::shared_ptr<Option> opt;
+ switch (opt_type) {
+ case D6O_IA_NA:
+ case D6O_IA_PD:
+ // cout << "Creating Option6IA" << endl;
+ opt = boost::shared_ptr<Option>(new Option6IA(opt_type,
+ buf, buf_len,
+ offset,
+ opt_len));
+ break;
+ case D6O_IAADDR:
+ // cout << "Creating Option6IAAddr" << endl;
+ opt = boost::shared_ptr<Option>(new Option6IAAddr(opt_type,
+ buf, buf_len,
+ offset, opt_len));
+ break;
+ default:
+ // cout << "Creating Option" << endl;
+ opt = boost::shared_ptr<Option>(new Option(Option::V6,
+ opt_type,
+ buf,
+ offset,
+ opt_len));
+ break;
+ }
+ // add option to options
+ options.insert(pair<int, boost::shared_ptr<Option> >(opt_type, opt));
+ offset += opt_len;
+ }
+
+ return (offset);
+}
+
+unsigned int
+LibDHCP::packOptions6(boost::shared_array<uint8_t> data,
+ unsigned int data_len,
+ unsigned int offset,
+ const isc::dhcp::Option::Option6Collection& options) {
+ try {
+ for (isc::dhcp::Option::Option6Collection::const_iterator it = options.begin();
+ it != options.end();
+ ++it) {
+ unsigned short opt_len = (*it).second->len();
+ if (offset + opt_len > data_len) {
+ isc_throw(OutOfRange, "Failed to build option " <<
+ (*it).first << ": out of buffer");
+ }
+ offset = (*it).second->pack(data, data_len, offset);
+ }
+ }
+ catch (Exception e) {
+ cout << "Packet build failed." << endl;
+ return (-1);
+ }
+ return (offset);
+}
+
+bool
+LibDHCP::OptionFactoryRegister(Option::Universe u,
+ unsigned short opt_type,
+ Option::Factory * factory) {
+ switch (u) {
+ case Option::V6: {
+ if (v6factories_.find(opt_type)!=v6factories_.end()) {
+ isc_throw(BadValue, "There is already DHCPv6 factory registered "
+ << "for option type " << opt_type);
+ }
+ v6factories_[opt_type]=factory;
+ return true;
+ }
+ case Option::V4:
+ default:{
+ isc_throw(BadValue, "This universe type is not supported yet.");
+ return false; // never happens
+ }
+ }
+
+}
diff --git a/src/lib/dhcp/libdhcp.h b/src/lib/dhcp/libdhcp.h
new file mode 100644
index 0000000..c2ac949
--- /dev/null
+++ b/src/lib/dhcp/libdhcp.h
@@ -0,0 +1,83 @@
+// 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 LIBDHCP_H_
+#define LIBDHCP_H_
+
+#include <iostream>
+#include "dhcp/pkt6.h"
+
+namespace isc {
+namespace dhcp {
+
+class LibDHCP {
+
+public:
+ /// Builds collection of options.
+ ///
+ /// Builds raw (on-wire) data for provided collection of options.
+ ///
+ /// @param buf shared pointer to buffer. Data will be stored there.
+ /// @param buf_len buffer length. Used for buffer overflow protection.
+ /// @param offset Offset from beginning of the buffer, where store options
+ /// @param options collection of options to store to
+ ///
+ /// @return offset to the first unused byte in buffer (next one after last
+ /// used byte)
+ ///
+ static unsigned int
+ packOptions6(boost::shared_array<uint8_t> buf, unsigned int buf_len,
+ unsigned int offset,
+ const isc::dhcp::Option::Option6Collection& options);
+
+ ///
+ /// Parses provided buffer and creates Option objects.
+ ///
+ /// Parses provided buf array and stores created Option objects
+ /// in options container.
+ ///
+ /// @param buf Buffer to be parsed.
+ /// @param offset Specifies offset for the first option.
+ /// @param options Reference to option container. Options will be
+ /// put here.
+ ///
+ /// @return offset to first byte after last parsed option
+ ///
+ static unsigned int
+ unpackOptions6(const boost::shared_array<uint8_t> buf, unsigned int buf_len,
+ unsigned int offset, unsigned int parse_len,
+ isc::dhcp::Option::Option6Collection& options_);
+
+ ///
+ /// Registers factory method that produces options of specific option types.
+ ///
+ /// @param u universe of the option (V4 or V6)
+ /// @param opt_type option-type
+ /// @param factory function pointer
+ ///
+ /// @return true, if registration was successful, false otherwise
+ ///
+ static bool
+ OptionFactoryRegister(Option::Universe u,
+ unsigned short type,
+ Option::Factory * factory);
+protected:
+ // pointers to factories that produce DHCPv6 options
+ static std::map<unsigned short, Option::Factory*> v6factories_;
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc
new file mode 100644
index 0000000..20eaf34
--- /dev/null
+++ b/src/lib/dhcp/option.cc
@@ -0,0 +1,262 @@
+// 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 <string.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <sstream>
+#include <iomanip>
+#include <boost/shared_array.hpp>
+#include "exceptions/exceptions.h"
+#include "util/io_utilities.h"
+
+#include "dhcp/option.h"
+#include "dhcp/libdhcp.h"
+
+using namespace std;
+using namespace isc::dhcp;
+using namespace isc::util;
+
+Option::Option(Universe u, unsigned short type)
+ :universe_(u), type_(type), data_len_(0) {
+
+
+}
+
+Option::Option(Universe u, unsigned short type,
+ const boost::shared_array<uint8_t>& buf,
+ unsigned int offset, unsigned int len)
+ :universe_(u), type_(type), data_(buf),
+ data_len_(len), offset_(offset)
+ {
+
+ // sanity checks
+ // TODO: universe must be in V4 and V6
+}
+
+unsigned int
+Option::pack(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset) {
+ switch (universe_) {
+ case V4:
+ return pack4(buf, buf_len, offset);
+ case V6:
+ return pack6(buf, buf_len, offset);
+ default:
+ isc_throw(BadValue, "Unknown universe defined for Option " << type_);
+ }
+}
+
+
+unsigned int
+Option::pack4(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset) {
+ if ( offset+len() > buf_len ) {
+ isc_throw(OutOfRange, "Failed to pack v4 option=" <<
+ type_ << ",len=" << data_len_ << ": too small buffer.");
+ }
+ uint8_t *ptr = &buf[offset];
+ ptr[0] = type_;
+ ptr[1] = data_len_;
+ ptr += 2;
+ memcpy(ptr, &data_[0], data_len_);
+
+ return offset + len();
+}
+
+unsigned int
+Option::pack6(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset) {
+ if ( offset+len() > buf_len ) {
+ isc_throw(OutOfRange, "Failed to pack v6 option=" <<
+ type_ << ",len=" << len() << ": too small buffer.");
+ }
+
+ int length = len() - getHeaderLen();
+
+ uint8_t * ptr = &buf[offset];
+ writeUint16(type_, ptr);
+ ptr += sizeof(uint16_t);
+
+ writeUint16(length, ptr);
+ ptr += sizeof(uint16_t);
+
+ if (data_len_)
+ memcpy(ptr, &data_[offset_], data_len_);
+
+ offset += OPTION6_HDR_LEN + data_len_; // end of this option
+
+ return LibDHCP::packOptions6(buf, buf_len, offset, options_);
+}
+
+unsigned int
+Option::unpack(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len) {
+ switch (universe_) {
+ case V4:
+ return unpack4(buf, buf_len, offset, parse_len);
+ case V6:
+ return unpack6(buf, buf_len, offset, parse_len);
+ default:
+ isc_throw(BadValue, "Unknown universe defined for Option " << type_);
+ }
+
+ return 0; // should not happen
+}
+
+unsigned int
+Option::unpack4(const boost::shared_array<uint8_t>&,
+ unsigned int ,
+ unsigned int ,
+ unsigned int ) {
+ isc_throw(Unexpected, "IPv4 support not implemented yet.");
+ return 0;
+}
+
+unsigned int
+Option::unpack6(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len) {
+
+ if (buf_len < offset+parse_len) {
+ isc_throw(OutOfRange, "Failed to unpack DHCPv6 option len="
+ << parse_len << " offset=" << offset
+ << " from buffer (length=" << buf_len
+ << "): too small buffer.");
+ }
+
+ data_ = buf;
+ offset_ = offset;
+ data_len_ = buf_len;
+
+ return LibDHCP::unpackOptions6(buf, buf_len, offset, parse_len,
+ options_);
+}
+
+unsigned short
+Option::len() {
+
+ // length of the whole option is header and data stored in this option...
+ int length = getHeaderLen() + data_len_;
+
+ // ... and sum of lengths of all suboptions
+ for (Option::Option6Collection::iterator it = options_.begin();
+ it != options_.end();
+ ++it) {
+ length += (*it).second->len();
+ }
+
+ // note that this is not equal to lenght field. This value denotes
+ // number of bytes required to store this option. length option should
+ // contain (len()-getHeaderLen()) value.
+ return (length);
+}
+
+bool
+Option::valid() {
+ if (universe_ != V4 &&
+ universe_ != V6) {
+ return (false);
+ }
+
+ return (true);
+}
+
+void
+isc::dhcp::Option::addOption(boost::shared_ptr<isc::dhcp::Option> opt) {
+ options_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(),
+ opt));
+
+}
+
+boost::shared_ptr<isc::dhcp::Option>
+Option::getOption(unsigned short opt_type) {
+ isc::dhcp::Option::Option6Collection::const_iterator x =
+ options_.find(opt_type);
+ if ( x != options_.end() ) {
+ return (*x).second;
+ }
+ return boost::shared_ptr<isc::dhcp::Option>(); // NULL
+}
+
+bool
+Option::delOption(unsigned short opt_type) {
+ isc::dhcp::Option::Option6Collection::iterator x = options_.find(opt_type);
+ if ( x != options_.end() ) {
+ options_.erase(x);
+ return true; // delete successful
+ }
+ return (false); // option not found, can't delete
+}
+
+
+std::string Option::toText(int indent /* =0 */ ) {
+ std::stringstream tmp;
+
+ for (int i=0; i<indent; i++)
+ tmp << " ";
+
+ tmp << "type=" << type_ << ", len=" << data_len_ << ":";
+
+ for (unsigned int i=0; i<data_len_; i++) {
+ if (i) {
+ tmp << ":";
+ }
+ tmp << setfill('0') << setw(2) << hex
+ << (unsigned short)(unsigned uint8_t)data_[offset_+i];
+ }
+
+ // print suboptions
+ for (Option6Collection::const_iterator opt=options_.begin();
+ opt!=options_.end();
+ ++opt) {
+ tmp << (*opt).second->toText(indent+2);
+ }
+ return tmp.str();
+}
+
+unsigned short
+Option::getType() {
+ return type_;
+}
+
+uint8_t*
+Option::getData() {
+ if (data_len_) {
+ return (&data_[offset_]);
+ } else {
+ return (NULL);
+ }
+}
+
+unsigned short
+Option::getHeaderLen() {
+ switch (universe_) {
+ case V4:
+ return OPTION4_HDR_LEN; // header length for v4
+ case V6:
+ return OPTION6_HDR_LEN; // header length for v6
+ }
+ return 0; // should not happen
+}
+
+Option::~Option() {
+
+}
diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h
new file mode 100644
index 0000000..f81a065
--- /dev/null
+++ b/src/lib/dhcp/option.h
@@ -0,0 +1,272 @@
+// 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 OPTION_H_
+#define OPTION_H_
+
+#include <string>
+#include <map>
+#include <boost/shared_array.hpp>
+
+namespace isc {
+namespace dhcp {
+
+class Option {
+public:
+ /// length of the usual DHCPv4 option header (there are exceptions)
+ const static size_t OPTION4_HDR_LEN = 2;
+
+ /// length of any DHCPv6 option header
+ const static size_t OPTION6_HDR_LEN = 4;
+
+ /// defines option universe DHCPv4 or DHCPv6
+ enum Universe { V4, V6 };
+
+ /// a collection of DHCPv4 options
+ typedef std::map<unsigned int, boost::shared_ptr<Option> >
+ Option4Collection;
+
+ /// a collection of DHCPv6 options
+ typedef std::multimap<unsigned int, boost::shared_ptr<Option> >
+ Option6Collection;
+
+ /// @brief a factory function prototype
+ ///
+ /// @param u option universe (DHCPv4 or DHCPv6)
+ /// @param type option type
+ /// @param buf pointer to a buffer
+ /// @param offset offset to first data byte in that buffer
+ /// @param len data length of this option
+ ///
+ /// @return a pointer to a created option object
+ typedef boost::shared_ptr<Option> Factory(Option::Universe u,
+ unsigned short type,
+ boost::shared_array<uint8_t>& buf,
+ unsigned int offset,
+ unsigned int len);
+
+ /// @brief ctor, used for options constructed, usually during transmission
+ ///
+ /// @param u option universe (DHCPv4 or DHCPv6)
+ /// @param type option type
+ Option(Universe u, unsigned short type);
+
+ /// @brief ctor, used for received options
+ ///
+ /// boost::shared_array allows sharing a buffer, but it requires that
+ /// different instances share pointer to the whole array, not point
+ /// to different elements in shared array. Therefore we need to share
+ /// pointer to the whole array and remember offset where data for
+ /// this option begins
+ ///
+ /// @param u specifies universe (V4 or V6)
+ /// @param type option type
+ /// @param buf pointer to a buffer
+ /// @param offset offset in a buffer pointing to first byte of data
+ /// @param len length of the option data
+ Option(Universe u, unsigned short type,
+ const boost::shared_array<uint8_t>& buf, unsigned int offset,
+ unsigned int len);
+
+ /// @brief writes option in wire-format to buf
+ ///
+ /// Writes option in wire-format to buffer, returns pointer to first unused
+ /// byte after stored option (that is useful for writing options one after
+ /// another)
+ ///
+ /// @param buf pointer to a buffer
+ /// @param buf_len length of the buffer
+ /// @param offset offset to place, where option shout be stored
+ ///
+ /// @return offset to first unused byte after stored option
+ ///
+ virtual unsigned int
+ pack(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset);
+
+ /// @brief Parses buffer.
+ ///
+ /// Parses received buffer, returns offset to the first unused byte after
+ /// parsed option.
+ ///
+ /// @param buf pointer to buffer
+ /// @param buf_len length of buf
+ /// @param offset offset, where start parsing option
+ /// @param parse_len how many bytes should be parsed
+ ///
+ /// @return offset after last parsed octet
+ virtual unsigned int
+ unpack(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len);
+
+ /// Returns string representation of the option.
+ ///
+ /// @param indent number of spaces before printing text
+ ///
+ /// @return string with text representation.
+ virtual std::string
+ toText(int indent = 0);
+
+ /// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
+ ///
+ /// @return option type
+ unsigned short
+ getType();
+
+ /// Returns length of the complete option (data length + DHCPv4/DHCPv6
+ /// option header)
+ ///
+ /// @return length of the option
+ virtual unsigned short
+ len();
+
+ /// @brief Returns length of header (2 for v4, 4 for v6)
+ ///
+ /// @return length of option header
+ virtual unsigned short
+ getHeaderLen();
+
+ /// returns if option is valid (e.g. option may be truncated)
+ ///
+ /// @return true, if option is valid
+ virtual bool
+ valid();
+
+ /// Returns pointer to actual data.
+ ///
+ /// @return pointer to actual data (or NULL if there is no data)
+ virtual uint8_t*
+ getData();
+
+ /// Adds a sub-option.
+ ///
+ /// Some DHCPv6 options can have suboptions. This method allows adding
+ /// options within options.
+ ///
+ /// Note: option is passed by value. That is very convenient as it allows
+ /// downcasting from any derived classes, e.g. shared_ptr<Option6_IA> type
+ /// can be passed directly, without any casts. That would not be possible
+ /// with passing by reference. addOption() is expected to be used in
+ /// many places. Requiring casting is not feasible.
+ ///
+ /// @param opt shared pointer to a suboption that is going to be added.
+ void
+ addOption(boost::shared_ptr<Option> opt);
+
+ /// Returns shared_ptr to suboption of specific type
+ ///
+ /// @param type type of requested suboption
+ ///
+ /// @return shared_ptr to requested suoption
+ boost::shared_ptr<isc::dhcp::Option>
+ getOption(unsigned short type);
+
+ /// Attempts to delete first suboption of requested type
+ ///
+ /// @param type Type of option to be deleted.
+ ///
+ /// @return true if option was deleted, false if no such option existed
+ bool
+ delOption(unsigned short type);
+
+ /// just to force that every option has virtual dtor
+ virtual
+ ~Option();
+
+protected:
+
+ /// Builds raw (over-wire) buffer of this option, including all
+ /// defined suboptions. Version for building DHCPv4 options.
+ ///
+ /// @param buf output buffer (built options will be stored here)
+ /// @param buf_len buffer length (used for buffer overflow checks)
+ /// @param offset offset from start of the buf buffer
+ ///
+ /// @return offset to the next byte after last used byte
+ virtual unsigned int
+ pack4(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset);
+
+ /// Builds raw (over-wire) buffer of this option, including all
+ /// defined suboptions. Version for building DHCPv4 options.
+ ///
+ /// @param buf output buffer (built options will be stored here)
+ /// @param buf_len buffer length (used for buffer overflow checks)
+ /// @param offset offset from start of the buf buffer
+ ///
+ /// @return offset to the next byte after last used byte
+ virtual unsigned int
+ pack6(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset);
+
+ /// Parses provided buffer and creates DHCPv4 options.
+ ///
+ /// @param buf buffer that contains raw buffer to parse (on-wire format)
+ /// @param buf_len buffer length (used for buffer overflow checks)
+ /// @param offset offset from start of the buf buffer
+ ///
+ /// @return offset to the next byte after last parsed byte
+ virtual unsigned int
+ unpack4(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len);
+
+ /// Parses provided buffer and creates DHCPv6 options.
+ ///
+ /// @param buf buffer that contains raw buffer to parse (on-wire format)
+ /// @param buf_len buffer length (used for buffer overflow checks)
+ /// @param offset offset from start of the buf buffer
+ ///
+ /// @return offset to the next byte after last parsed byte
+ virtual unsigned int
+ unpack6(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len);
+
+ /// option universe (V4 or V6)
+ Universe universe_;
+
+ /// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
+ unsigned short type_;
+
+ /// shared pointer to a buffer (usually a part of packet)
+ boost::shared_array<uint8_t> data_;
+
+ /// length of data only. Use len() if you want to
+ /// know proper length with option header overhead
+ unsigned int data_len_;
+
+ /// data is a shared_pointer that points out to the
+ /// whole packet. offset_ specifies where data for
+ /// this option begins.
+ unsigned int offset_;
+
+ /// collection for storing suboptions
+ Option6Collection options_;
+
+ /// TODO: probably 2 different containers have to be used for v4 (unique
+ /// options) and v6 (options with the same type can repeat)
+};
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif
diff --git a/src/lib/dhcp/option6_addrlst.cc b/src/lib/dhcp/option6_addrlst.cc
new file mode 100644
index 0000000..fc981fa
--- /dev/null
+++ b/src/lib/dhcp/option6_addrlst.cc
@@ -0,0 +1,134 @@
+// 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 <stdint.h>
+#include <arpa/inet.h>
+#include <sstream>
+#include "exceptions/exceptions.h"
+
+#include "asiolink/io_address.h"
+#include "util/io_utilities.h"
+#include "dhcp/libdhcp.h"
+#include "dhcp/option6_addrlst.h"
+#include "dhcp/dhcp6.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+Option6AddrLst::Option6AddrLst(unsigned short type,
+ const AddressContainer& addrs)
+ :Option(V6, type), addrs_(addrs) {
+}
+
+Option6AddrLst::Option6AddrLst(unsigned short type,
+ const isc::asiolink::IOAddress& addr)
+ :Option(V6, type), addrs_(1,addr) {
+}
+
+Option6AddrLst::Option6AddrLst(unsigned short type,
+ boost::shared_array<uint8_t> buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int option_len)
+ :Option(V6, type) {
+ unpack(buf, buf_len, offset, option_len);
+}
+
+void
+Option6AddrLst::setAddress(const isc::asiolink::IOAddress& addr) {
+ addrs_.clear();
+ addrs_.push_back(addr);
+}
+
+void
+Option6AddrLst::setAddresses(const AddressContainer& addrs) {
+ addrs_ = addrs;
+}
+
+unsigned int
+Option6AddrLst::pack(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset) {
+ if (len() > buf_len) {
+ isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
+ << ", buffer=" << buf_len << ": too small buffer.");
+ }
+
+ writeUint16(type_, &buf[offset]);
+ offset += sizeof(uint16_t);
+
+ // len() returns complete option length.
+ // len field contains length without 4-byte option header
+ writeUint16(len() - OPTION6_HDR_LEN, &buf[offset]);
+ offset += sizeof(uint16_t);
+
+ // this wrapping is *ugly*. I wish there was a a
+ for (AddressContainer::const_iterator addr=addrs_.begin();
+ addr!=addrs_.end();
+ ++addr) {
+ memcpy(&buf[offset],
+ addr->getAddress().to_v6().to_bytes().data(),
+ V6ADDRESS_LEN);
+ offset += V6ADDRESS_LEN;
+ }
+
+ return offset;
+}
+
+unsigned int
+Option6AddrLst::unpack(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int option_len) {
+ if (offset+option_len > buf_len) {
+ isc_throw(OutOfRange, "Option " << type_
+ << " truncated.");
+ }
+
+ if (option_len%16) {
+ isc_throw(OutOfRange, "Option " << type_
+ << " malformed: len=" << option_len
+ << " is not divisible by 16.");
+ }
+ while (option_len > 0) {
+ addrs_.push_back(IOAddress::from_bytes(AF_INET6, &buf[offset]));
+ offset += 16;
+ option_len -= 16;
+ }
+
+ return offset;
+}
+
+std::string Option6AddrLst::toText(int indent /* =0 */) {
+ stringstream tmp;
+ for (int i=0; i<indent; i++)
+ tmp << " ";
+
+ tmp << "type=" << type_ << " " << addrs_.size() << "addr(s): ";
+
+ for (AddressContainer::const_iterator addr=addrs_.begin();
+ addr!=addrs_.end();
+ ++addr) {
+ tmp << addr->toText() << " ";
+ }
+ return tmp.str();
+}
+
+unsigned short Option6AddrLst::len() {
+
+ return (OPTION6_HDR_LEN + addrs_.size()*16);
+}
diff --git a/src/lib/dhcp/option6_addrlst.h b/src/lib/dhcp/option6_addrlst.h
new file mode 100644
index 0000000..c5b32af
--- /dev/null
+++ b/src/lib/dhcp/option6_addrlst.h
@@ -0,0 +1,127 @@
+// 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 OPTION6_ADDRLST_H_
+#define OPTION6_ADDRLST_H_
+
+#include <vector>
+#include "asiolink/io_address.h"
+#include "dhcp/option.h"
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Option class for handling list of IPv6 addresses.
+///
+/// This class handles a list of IPv6 addresses. An example of such option
+/// is dns-servers option. It can also be used to handle single address.
+///
+class Option6AddrLst: public Option {
+
+public:
+ /// a container for (IPv6) addresses
+ typedef std::vector<isc::asiolink::IOAddress> AddressContainer;
+
+ /// @brief Constructor used during option generation.
+ ///
+ /// @param type option type
+ /// @param addrs vector of addresses to be stored
+ ///
+ Option6AddrLst(unsigned short type,
+ const AddressContainer& addrs);
+
+ /// @brief Simplified constructor for a single address
+ ///
+ /// @param type option type
+ /// @param addr a single address to be stored
+ ///
+ Option6AddrLst(unsigned short type,
+ const isc::asiolink::IOAddress& addr);
+
+ /// @brief Constructor used for parsing received option
+ ///
+ /// @param type option type
+ /// @param buf pointer to packet buffer
+ /// @param buf_len length of packet buffer
+ /// @param offset offset to beginning of option data
+ /// @param len length of option data
+ ///
+ Option6AddrLst(unsigned short type, boost::shared_array<uint8_t> buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int len);
+
+ /// @brief Assembles on-wire form of this option
+ ///
+ /// @param buf pointer to packet buffer
+ /// @param buf_len length of packet buffer
+ /// @param offset offset to place, where option is to be stored
+ ///
+ /// @return offset to the next unused char (just after stored option)
+ ///
+ unsigned int
+ pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
+ unsigned int offset);
+
+ /// @brief Parses received data
+ ///
+ /// @param buf pointer to packet buffer
+ /// @param buf_len length of packet buffer
+ /// @param offset offset to option data
+ /// @param parse_len specified option data length
+ ///
+ /// @return offset to the next unparsed char (just after parsed option)
+ ///
+ virtual unsigned int
+ unpack(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len);
+
+ virtual std::string toText(int indent = 0);
+
+ /// @brief Sets a single address.
+ ///
+ /// @param addr a single address to be added
+ ///
+ void setAddress(const isc::asiolink::IOAddress& addr);
+
+ /// @brief Sets list of addresses.
+ ///
+ /// @param addrs a vector of addresses to be added
+ ///
+ void setAddresses(const AddressContainer& addrs);
+
+ /// @brief Returns vector with addresses.
+ ///
+ /// As user may want to use/modify this list, it is better to return
+ /// a copy rather than const reference to the original. This is
+ /// usually one or two addresses long, so it is not a big deal.
+ ///
+ /// @return vector with addresses
+ ///
+ AddressContainer
+ getAddresses() { return addrs_; };
+
+ // returns data length (data length + DHCPv4/DHCPv6 option header)
+ virtual unsigned short len();
+
+protected:
+ AddressContainer addrs_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION_ADDRLST_H_ */
diff --git a/src/lib/dhcp/option6_ia.cc b/src/lib/dhcp/option6_ia.cc
new file mode 100644
index 0000000..350b32e
--- /dev/null
+++ b/src/lib/dhcp/option6_ia.cc
@@ -0,0 +1,139 @@
+// 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 <stdint.h>
+#include <arpa/inet.h>
+#include <sstream>
+#include "exceptions/exceptions.h"
+
+#include "dhcp/libdhcp.h"
+#include "dhcp/option6_ia.h"
+#include "dhcp/dhcp6.h"
+#include "util/io_utilities.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::util;
+
+Option6IA::Option6IA(unsigned short type, unsigned int iaid)
+ :Option(Option::V6, type), iaid_(iaid) {
+}
+
+Option6IA::Option6IA(unsigned short type,
+ const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int option_len)
+ :Option(Option::V6, type) {
+ unpack(buf, buf_len, offset, option_len);
+}
+
+unsigned int
+Option6IA::pack(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset) {
+ if (offset + len() > buf_len) {
+ isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
+ << ", buffer=" << buf_len << ": too small buffer.");
+ }
+
+ if (len() < 16 ) {
+ isc_throw(OutOfRange, "Attempt to build malformed IA option: len="
+ << len() << " is too small (at least 16 is required).");
+ }
+
+ writeUint16(type_, &buf[offset]);
+ offset += sizeof(uint16_t);
+
+ writeUint16(len() - OPTION6_HDR_LEN, &buf[offset]);
+ offset += sizeof(uint16_t);
+
+ /// TODO start using writeUint32 once such function is implemented
+ uint8_t* ptr = &buf[offset];
+
+ *(uint32_t*)ptr = htonl(iaid_);
+ ptr += sizeof(uint32_t);
+
+ *(uint32_t*)ptr = htonl(t1_);
+ ptr += sizeof(uint32_t);
+
+ *(uint32_t*)ptr = htonl(t2_);
+ ptr += sizeof(uint32_t);
+
+ offset = LibDHCP::packOptions6(buf, buf_len, offset+12, options_);
+ return offset;
+}
+
+unsigned int
+Option6IA::unpack(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len) {
+ if ( parse_len < OPTION6_IA_LEN || offset + OPTION6_IA_LEN > buf_len) {
+ isc_throw(OutOfRange, "Option " << type_ << " truncated");
+ }
+ iaid_ = ntohl(*(uint32_t*)&buf[offset]);
+ offset += sizeof(uint32_t);
+ t1_ = ntohl(*(uint32_t*)&buf[offset]);
+ offset += sizeof(uint32_t);
+ t2_ = ntohl(*(uint32_t*)&buf[offset]);
+ offset += sizeof(uint32_t);
+ offset = LibDHCP::unpackOptions6(buf, buf_len, offset,
+ parse_len - OPTION6_IA_LEN, options_);
+
+ return (offset);
+}
+
+std::string Option6IA::toText(int indent /* = 0*/) {
+ stringstream tmp;
+
+ for (int i=0; i<indent; i++)
+ tmp << " ";
+ tmp << "type=" << type_;
+
+ switch (type_) {
+ case D6O_IA_NA:
+ tmp << "(IA_NA)";
+ break;
+ case D6O_IA_PD:
+ tmp << "(IA_PD)";
+ break;
+ default:
+ tmp << "(unknown)";
+ }
+ tmp << " iaid=" << iaid_ << ", t1=" << t1_ << ", t2=" << t2_
+ << " " << options_.size() << " sub-options:" << endl;
+
+ for (Option6Collection::const_iterator opt=options_.begin();
+ opt!=options_.end();
+ ++opt) {
+ tmp << (*opt).second->toText(indent+2);
+ }
+ return tmp.str();
+}
+
+unsigned short Option6IA::len() {
+
+ unsigned short length = OPTION6_HDR_LEN /*header (4)*/ +
+ OPTION6_IA_LEN /* option content (12) */;
+
+ // length of all suboptions
+ for (Option::Option6Collection::iterator it = options_.begin();
+ it != options_.end();
+ ++it) {
+ length += (*it).second->len();
+ }
+ return (length);
+}
diff --git a/src/lib/dhcp/option6_ia.h b/src/lib/dhcp/option6_ia.h
new file mode 100644
index 0000000..7da2945
--- /dev/null
+++ b/src/lib/dhcp/option6_ia.h
@@ -0,0 +1,137 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef OPTION_IA_H_
+#define OPTION_IA_H_
+
+#include <stdint.h>
+#include "option.h"
+
+namespace isc {
+namespace dhcp {
+
+class Option6IA: public Option {
+
+public:
+ /// Length of IA_NA and IA_PD content
+ const static size_t OPTION6_IA_LEN = 12;
+
+ /// @brief ctor, used for options constructed, usually during transmission
+ ///
+ /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
+ /// @param iaid identity association identifier (id of IA)
+ Option6IA(uint16_t type, unsigned int iaid);
+
+ /// @brief ctor, used for received options
+ ///
+ /// boost::shared_array allows sharing a buffer, but it requires that
+ /// different instances share pointer to the whole array, not point
+ /// to different elements in shared array. Therefore we need to share
+ /// pointer to the whole array and remember offset where data for
+ /// this option begins
+ ///
+ /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
+ /// @param buf buffer to be parsed
+ /// @param buf_len buffer length
+ /// @param offset offset in buffer
+ /// @param len number of bytes to parse
+ Option6IA(uint16_t type, const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len, unsigned int offset, unsigned int len);
+
+ /// Writes option in wire-format to buf, returns pointer to first unused
+ /// byte after stored option.
+ ///
+ /// @param buf buffer (option will be stored here)
+ /// @param buf_len (buffer length)
+ /// @param offset offset place where option should be stored
+ ///
+ /// @return offset to the first unused byte after stored option
+ unsigned int
+ pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
+ unsigned int offset);
+
+ /// @brief Parses received buffer
+ ///
+ /// Parses received buffer and returns offset to the first unused byte after
+ /// parsed option.
+ ///
+ /// @param buf pointer to buffer
+ /// @param buf_len length of buf
+ /// @param offset offset, where start parsing option
+ /// @param parse_len how many bytes should be parsed
+ ///
+ /// @return offset after last parsed octet
+ virtual unsigned int
+ unpack(const boost::shared_array<uint8_t>& buf, unsigned int buf_len,
+ unsigned int offset, unsigned int parse_len);
+
+ /// Provides human readable text representation
+ ///
+ /// @param indent number of leading space characters
+ ///
+ /// @return string with text represenation
+ virtual std::string
+ toText(int indent = 0);
+
+ /// Sets T1 timer.
+ ///
+ /// @param t1 t1 value to be set
+ void setT1(unsigned int t1) { t1_=t1; }
+
+
+ /// Sets T2 timer.
+ ///
+ /// @param t2 t2 value to be set
+ void setT2(unsigned int t2) { t2_=t2; }
+
+ /// Returns IA identifier.
+ ///
+ /// @return IAID value.
+ ///
+ unsigned int getIAID() { return iaid_; }
+
+ /// Returns T1 timer.
+ ///
+ /// @return T1 value.
+ unsigned int getT1() { return t1_; }
+
+ /// Returns T2 timer.
+ ///
+ /// @return T2 value.
+ unsigned int getT2() { return t2_; }
+
+ /// @brief returns complete length of option
+ ///
+ /// Returns length of this option, including option header and suboptions
+ ///
+ /// @return length of this option
+ virtual unsigned short
+ len();
+
+protected:
+
+ /// keeps IA identifier
+ unsigned int iaid_;
+
+ /// keeps T1 timer value
+ unsigned int t1_;
+
+ /// keeps T2 timer value
+ unsigned int t2_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION_IA_H_ */
diff --git a/src/lib/dhcp/option6_iaaddr.cc b/src/lib/dhcp/option6_iaaddr.cc
new file mode 100644
index 0000000..56b7ba0
--- /dev/null
+++ b/src/lib/dhcp/option6_iaaddr.cc
@@ -0,0 +1,129 @@
+// 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 <stdint.h>
+#include <arpa/inet.h>
+#include <sstream>
+#include "exceptions/exceptions.h"
+
+#include "dhcp/libdhcp.h"
+#include "dhcp/option6_iaaddr.h"
+#include "dhcp/dhcp6.h"
+#include "asiolink/io_address.h"
+#include "util/io_utilities.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+Option6IAAddr::Option6IAAddr(unsigned short type,
+ const isc::asiolink::IOAddress& addr,
+ unsigned int pref, unsigned int valid)
+ :Option(V6, type), addr_(addr), preferred_(pref),
+ valid_(valid) {
+}
+
+Option6IAAddr::Option6IAAddr(unsigned short type,
+ boost::shared_array<uint8_t> buf,
+ unsigned int buf_len, unsigned int offset,
+ unsigned int option_len)
+ :Option(V6, type), addr_("::") {
+ unpack(buf, buf_len, offset, option_len);
+}
+
+unsigned int
+Option6IAAddr::pack(boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset) {
+ if (len() > buf_len) {
+ isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
+ << ", buffer=" << buf_len << ": too small buffer.");
+ }
+
+ *(uint16_t*)&buf[offset] = htons(type_);
+ offset += sizeof(uint16_t);
+ *(uint16_t*)&buf[offset] = htons(len() - OPTION6_HDR_LEN); // len() returns complete option
+ // length. len field contains length without 4-byte option header
+ offset += sizeof(uint16_t);
+
+ memcpy(&buf[offset], addr_.getAddress().to_v6().to_bytes().data(), 16);
+ offset += V6ADDRESS_LEN;
+
+ *(uint32_t*)&buf[offset] = htonl(preferred_);
+ offset += sizeof(uint32_t);
+ *(uint32_t*)&buf[offset] = htonl(valid_);
+ offset += sizeof(uint32_t);
+
+ // parse suboption (there shouldn't be any)
+ offset = LibDHCP::packOptions6(buf, buf_len, offset, options_);
+ return offset;
+}
+
+unsigned int
+Option6IAAddr::unpack(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len) {
+ if ( parse_len < OPTION6_IAADDR_LEN || offset + OPTION6_IAADDR_LEN > buf_len) {
+ isc_throw(OutOfRange, "Option " << type_ << " truncated");
+ }
+
+ // 16 bytes: IPv6 address
+ addr_ = IOAddress::from_bytes(AF_INET6, &buf[offset]);
+ offset += V6ADDRESS_LEN;
+
+ preferred_ = ntohl(*(uint32_t*)&buf[offset]);
+ offset += sizeof(uint32_t);
+
+ valid_ = ntohl(*(uint32_t*)&buf[offset]);
+ offset += sizeof(uint32_t);
+ offset = LibDHCP::unpackOptions6(buf, buf_len, offset,
+ parse_len - 24, options_);
+
+ return offset;
+}
+
+std::string Option6IAAddr::toText(int indent /* =0 */) {
+ stringstream tmp;
+ for (int i=0; i<indent; i++)
+ tmp << " ";
+
+ tmp << "type=" << type_ << "(IAADDR) addr=" << addr_.toText()
+ << ", preferred-lft=" << preferred_ << ", valid-lft="
+ << valid_ << endl;
+
+ for (Option6Collection::const_iterator opt=options_.begin();
+ opt!=options_.end();
+ ++opt) {
+ tmp << (*opt).second->toText(indent+2);
+ }
+ return tmp.str();
+}
+
+unsigned short Option6IAAddr::len() {
+
+ unsigned short length = OPTION6_HDR_LEN + OPTION6_IAADDR_LEN;
+
+ // length of all suboptions
+ // TODO implement:
+ // protected: unsigned short Option::lenHelper(int header_size);
+ for (Option::Option6Collection::iterator it = options_.begin();
+ it != options_.end();
+ ++it) {
+ length += (*it).second->len();
+ }
+ return (length);
+}
diff --git a/src/lib/dhcp/option6_iaaddr.h b/src/lib/dhcp/option6_iaaddr.h
new file mode 100644
index 0000000..26391bc
--- /dev/null
+++ b/src/lib/dhcp/option6_iaaddr.h
@@ -0,0 +1,146 @@
+// 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 OPTION6_IAADDR_H_
+#define OPTION6_IAADDR_H_
+
+#include "asiolink/io_address.h"
+#include "dhcp/option.h"
+
+namespace isc {
+namespace dhcp {
+
+class Option6IAAddr: public Option {
+
+public:
+ /// length of the fixed part of the IAADDR option
+ static const size_t OPTION6_IAADDR_LEN = 24;
+
+ /// @brief ctor, used for options constructed (during transmission)
+ ///
+ /// @param type option type
+ /// @param addr reference to an address
+ /// @param preferred address preferred lifetime (in seconds)
+ /// @param valid address valid lifetime (in seconds)
+ Option6IAAddr(unsigned short type, const isc::asiolink::IOAddress& addr,
+ unsigned int preferred, unsigned int valid);
+
+ /// ctor, used for received options
+ /// boost::shared_array allows sharing a buffer, but it requires that
+ /// different instances share pointer to the whole array, not point
+ /// to different elements in shared array. Therefore we need to share
+ /// pointer to the whole array and remember offset where data for
+ /// this option begins
+ ///
+ /// @param type option type
+ /// @param buf pointer to a buffer
+ /// @param offset offset to first data byte in that buffer
+ /// @param len data length of this option
+ Option6IAAddr(unsigned short type, boost::shared_array<uint8_t> buf,
+ unsigned int buf_len, unsigned int offset, unsigned int len);
+
+ /// @brief Writes option in wire-format.
+ ///
+ /// Writes option in wire-format to buf, returns pointer to first unused
+ /// byte after stored option.
+ ///
+ /// @param buf pointer to a buffer
+ /// @param buf_len length of the buffer
+ /// @param offset offset to place, where option shout be stored
+ ///
+ /// @return offset to first unused byte after stored option
+ unsigned int
+ pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
+ unsigned int offset);
+
+ /// @brief Parses buffer.
+ ///
+ /// Parses received buffer, returns offset to the first unused byte after
+ /// parsed option.
+ ///
+ /// @param buf pointer to buffer
+ /// @param buf_len length of buf
+ /// @param offset offset, where start parsing option
+ /// @param parse_len how many bytes should be parsed
+ ///
+ /// @return offset after last parsed octet
+ virtual unsigned int
+ unpack(const boost::shared_array<uint8_t>& buf,
+ unsigned int buf_len,
+ unsigned int offset,
+ unsigned int parse_len);
+
+ /// Returns string representation of the option.
+ ///
+ /// @param indent number of spaces before printing text
+ ///
+ /// @return string with text representation.
+ virtual std::string
+ toText(int indent = 0);
+
+
+ /// sets address in this option.
+ ///
+ /// @param addr address to be sent in this option
+ void setAddress(const isc::asiolink::IOAddress& addr) { addr_ = addr; }
+
+ /// Sets preferred lifetime (in seconds)
+ ///
+ /// @param pref address preferred lifetime (in seconds)
+ ///
+ void setPreferred(unsigned int pref) { preferred_=pref; }
+
+ /// Sets valid lifetime (in seconds).
+ ///
+ /// @param valid address valid lifetime (in seconds)
+ ///
+ void setValid(unsigned int valid) { valid_=valid; }
+
+ /// Returns address contained within this option.
+ ///
+ /// @return address
+ isc::asiolink::IOAddress
+ getAddress() { return addr_; }
+
+ /// Returns preferred lifetime of an address.
+ ///
+ /// @return preferred lifetime (in seconds)
+ unsigned int
+ getPreferred() { return preferred_; }
+
+ /// Returns valid lifetime of an address.
+ ///
+ /// @return valid lifetime (in seconds)
+ unsigned int
+ getValid() { return valid_; }
+
+ /// returns data length (data length + DHCPv4/DHCPv6 option header)
+ virtual unsigned short
+ len();
+
+protected:
+ /// contains an IPv6 address
+ isc::asiolink::IOAddress addr_;
+
+ /// contains preferred-lifetime timer (in seconds)
+ unsigned int preferred_;
+
+ /// contains valid-lifetime timer (in seconds)
+ unsigned int valid_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION_IA_H_ */
diff --git a/src/lib/dhcp/pkt6.cc b/src/lib/dhcp/pkt6.cc
new file mode 100644
index 0000000..65bd95e
--- /dev/null
+++ b/src/lib/dhcp/pkt6.cc
@@ -0,0 +1,224 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+
+#include "dhcp/dhcp6.h"
+#include "dhcp/pkt6.h"
+#include "dhcp/libdhcp.h"
+#include "exceptions/exceptions.h"
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+using namespace isc::dhcp;
+
+namespace isc {
+
+Pkt6::Pkt6(unsigned int dataLen, DHCPv6Proto proto /* = UDP */)
+ :data_len_(dataLen),
+ local_addr_("::"),
+ remote_addr_("::"),
+ iface_(""),
+ ifindex_(-1),
+ local_port_(-1),
+ remote_port_(-1),
+ proto_(proto),
+ msg_type_(-1),
+ transid_(rand()%0xffffff)
+{
+
+ data_ = boost::shared_array<uint8_t>(new uint8_t[dataLen]);
+ data_len_ = dataLen;
+}
+
+Pkt6::Pkt6(uint8_t msg_type,
+ unsigned int transid,
+ DHCPv6Proto proto /*= UDP*/)
+ :local_addr_("::"),
+ remote_addr_("::"),
+ iface_(""),
+ ifindex_(-1),
+ local_port_(-1),
+ remote_port_(-1),
+ proto_(proto),
+ msg_type_(msg_type),
+ transid_(transid) {
+
+ data_ = boost::shared_array<uint8_t>(new uint8_t[4]);
+ data_len_ = 4;
+}
+
+unsigned short
+Pkt6::len() {
+ unsigned int length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
+
+ for (Option::Option6Collection::iterator it = options_.begin();
+ it != options_.end();
+ ++it) {
+ length += (*it).second->len();
+ }
+
+ return (length);
+}
+
+
+bool
+Pkt6::pack() {
+ switch (proto_) {
+ case UDP:
+ return packUDP();
+ case TCP:
+ return packTCP();
+ default:
+ isc_throw(BadValue, "Invalid protocol specified (non-TCP, non-UDP)");
+ }
+ return (false); // never happens
+}
+
+bool
+Pkt6::packUDP() {
+ unsigned short length = len();
+ if (data_len_ < length) {
+ cout << "Previous len=" << data_len_ << ", allocating new buffer: len="
+ << length << endl;
+
+ // May throw exception if out of memory. That is rather fatal,
+ // so we don't catch this
+ data_ = boost::shared_array<uint8_t>(new uint8_t[length]);
+ data_len_ = length;
+ }
+
+ data_len_ = length;
+ try {
+ // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
+ data_[0] = msg_type_;
+
+ // store 3-octet transaction-id
+ data_[1] = (transid_ >> 16) & 0xff;
+ data_[2] = (transid_ >> 8) & 0xff;
+ data_[3] = (transid_) & 0xff;
+
+ // the rest are options
+ unsigned short offset = LibDHCP::packOptions6(data_, length,
+ 4/*offset*/,
+ options_);
+
+ // sanity check
+ if (offset != length) {
+ isc_throw(OutOfRange, "Packet build failed: expected size="
+ << length << ", actual len=" << offset);
+ }
+ }
+ catch (Exception e) {
+ cout << "Packet build failed:" << e.what() << endl;
+ return (false);
+ }
+ cout << "Packet built, len=" << len() << endl;
+ return (true);
+}
+
+bool
+Pkt6::packTCP() {
+ /// TODO Implement this function.
+ isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover)"
+ "not implemented yet.");
+}
+
+bool
+Pkt6::unpack() {
+ switch (proto_) {
+ case UDP:
+ return unpackUDP();
+ case TCP:
+ return unpackTCP();
+ default:
+ isc_throw(BadValue, "Invalid protocol specified (non-TCP, non-UDP)");
+ }
+ return (false); // never happens
+}
+
+bool
+Pkt6::unpackUDP() {
+ if (data_len_ < 4) {
+ std::cout << "DHCPv6 packet truncated. Only " << data_len_
+ << " bytes. Need at least 4." << std::endl;
+ return (false);
+ }
+ msg_type_ = data_[0];
+ transid_ = ( (data_[1]) << 16 ) +
+ ((data_[2]) << 8) + (data_[3]);
+ transid_ = transid_ & 0xffffff;
+
+ unsigned int offset = LibDHCP::unpackOptions6(data_,
+ data_len_,
+ 4, //offset
+ data_len_ - 4,
+ options_);
+ if (offset != data_len_) {
+ cout << "DHCPv6 packet contains trailing garbage. Parsed "
+ << offset << " bytes, packet is " << data_len_ << " bytes."
+ << endl;
+ // just a warning. Ignore trailing garbage and continue
+ }
+ return (true);
+}
+
+bool
+Pkt6::unpackTCP() {
+ isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover) "
+ "not implemented yet.");
+}
+
+
+std::string
+Pkt6::toText() {
+ stringstream tmp;
+ tmp << "localAddr=[" << local_addr_.toText() << "]:" << local_port_
+ << " remoteAddr=[" << remote_addr_.toText()
+ << "]:" << remote_port_ << endl;
+ tmp << "msgtype=" << msg_type_ << ", transid=0x" << hex << transid_
+ << dec << endl;
+ for (isc::dhcp::Option::Option6Collection::iterator opt=options_.begin();
+ opt != options_.end();
+ ++opt) {
+ tmp << opt->second->toText() << std::endl;
+ }
+ return tmp.str();
+}
+
+boost::shared_ptr<isc::dhcp::Option>
+Pkt6::getOption(unsigned short opt_type) {
+ isc::dhcp::Option::Option6Collection::const_iterator x = options_.find(opt_type);
+ if (x!=options_.end()) {
+ return (*x).second;
+ }
+ return boost::shared_ptr<isc::dhcp::Option>(); // NULL
+}
+
+void
+Pkt6::addOption(boost::shared_ptr<Option> opt) {
+ options_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
+}
+
+bool
+Pkt6::delOption(unsigned short type) {
+ isc::dhcp::Option::Option6Collection::iterator x = options_.find(type);
+ if (x!=options_.end()) {
+ options_.erase(x);
+ return (true); // delete successful
+ }
+ return (false); // can't find option to be deleted
+}
+
+};
diff --git a/src/lib/dhcp/pkt6.h b/src/lib/dhcp/pkt6.h
new file mode 100644
index 0000000..35bccbc
--- /dev/null
+++ b/src/lib/dhcp/pkt6.h
@@ -0,0 +1,234 @@
+// 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 PKT6_H
+#define PKT6_H
+
+#include <iostream>
+#include <boost/shared_ptr.hpp>
+#include <boost/shared_array.hpp>
+#include "asiolink/io_address.h"
+#include "option.h"
+
+namespace isc {
+
+namespace dhcp {
+
+class Pkt6 {
+public:
+ /// specifes DHCPv6 packet header length
+ const static size_t DHCPV6_PKT_HDR_LEN = 4;
+
+ /// DHCPv6 transport protocol
+ enum DHCPv6Proto {
+ UDP = 0, // most packets are UDP
+ TCP = 1 // there are TCP DHCPv6 packets (bulk leasequery, failover)
+ };
+
+ /// Constructor, used in replying to a message
+ ///
+ /// @param msg_type type of message (SOLICIT=1, ADVERTISE=2, ...)
+ /// @param transid transaction-id
+ /// @param proto protocol (TCP or UDP)
+ Pkt6(unsigned char msg_type,
+ unsigned int transid,
+ DHCPv6Proto proto = UDP);
+
+ /// Constructor, used in message transmission
+ ///
+ /// Creates new message. Transaction-id will randomized.
+ ///
+ /// @param len size of buffer to be allocated for this packet.
+ /// @param proto protocol (usually UDP, but TCP will be supported eventually)
+ Pkt6(unsigned int len, DHCPv6Proto proto = UDP);
+
+ /// @brief Prepares on-wire format.
+ ///
+ /// Prepares on-wire format of message and all its options.
+ /// Options must be stored in options_ field.
+ /// Output buffer will be stored in data_. Length
+ /// will be set in data_len_.
+ ///
+ /// @return true if packing procedure was successful
+ bool
+ pack();
+
+ /// @brief Dispatch method that handles binary packet parsing.
+ ///
+ /// This method calls appropriate dispatch function (unpackUDP or
+ /// unpackTCP).
+ ///
+ /// @return true if parsing was successful
+ bool
+ unpack();
+
+ /// Returns protocol of this packet (UDP or TCP)
+ ///
+ /// @return protocol type
+ DHCPv6Proto
+ getProto();
+
+ /// Sets protocol of this packet.
+ ///
+ /// @param proto protocol (UDP or TCP)
+ ///
+ void
+ setProto(DHCPv6Proto proto = UDP) { proto_ = proto; }
+
+ /// @brief Returns text representation of the packet.
+ ///
+ /// This function is useful mainly for debugging.
+ ///
+ /// @return string with text representation
+ std::string
+ toText();
+
+ /// @brief Returns calculated length of the packet.
+ ///
+ /// This function returns size of required buffer to buld this packet.
+ /// To use that function, options_ field must be set.
+ ///
+ /// @return number of bytes required to build this packet
+ unsigned short
+ len();
+
+ /// Returns message type (e.g. 1 = SOLICIT)
+ ///
+ /// @return message type
+ unsigned char
+ getType() { return (msg_type_); }
+
+ /// Sets message type (e.g. 1 = SOLICIT)
+ ///
+ /// @param type message type to be set
+ void setType(unsigned char type) { msg_type_=type; };
+
+ /// Returns value of transaction-id field
+ ///
+ /// @return transaction-id
+ unsigned int getTransid() { return (transid_); };
+
+ /// Adds an option to this packet.
+ ///
+ /// @param opt option to be added.
+ void addOption(boost::shared_ptr<isc::dhcp::Option> opt);
+
+ /// @brief Returns the first option of specified type.
+ ///
+ /// Returns the first option of specified type. Note that in DHCPv6 several
+ /// instances of the same option are allowed (and frequently used).
+ /// See getOptions().
+ ///
+ /// @param opt_type option type we are looking for
+ ///
+ /// @return pointer to found option (or NULL)
+ boost::shared_ptr<isc::dhcp::Option>
+ getOption(unsigned short type);
+
+ /// Attempts to delete first suboption of requested type
+ ///
+ /// @param type Type of option to be deleted.
+ ///
+ /// @return true if option was deleted, false if no such option existed
+ bool
+ delOption(unsigned short type);
+
+ /// TODO need getter/setter wrappers
+ /// and hide following fields as protected
+
+ /// buffer that holds memory. It is shared_array as options may
+ /// share pointer to this buffer
+ boost::shared_array<uint8_t> data_;
+
+ /// length of the data
+ unsigned int data_len_;
+
+ /// local address (dst if receiving packet, src if sending packet)
+ isc::asiolink::IOAddress local_addr_;
+
+ /// remote address (src if receiving packet, dst if sending packet)
+ isc::asiolink::IOAddress remote_addr_;
+
+ /// name of the network interface the packet was received/to be sent over
+ std::string iface_;
+
+ /// @brief interface index
+ ///
+ /// interface index (each network interface has assigned unique ifindex
+ /// it is functional equvalent of name, but sometimes more useful, e.g.
+ /// when using crazy systems that allow spaces in interface names
+ /// e.g. windows
+ int ifindex_;
+
+ /// local TDP or UDP port
+ int local_port_;
+
+ /// remote TCP or UDP port
+ int remote_port_;
+
+ /// TODO Need to implement getOptions() as well
+
+ /// collection of options present in this message
+ isc::dhcp::Option::Option6Collection options_;
+
+protected:
+ /// Builds on wire packet for TCP transmission.
+ ///
+ /// TODO This function is not implemented yet.
+ ///
+ /// @return true, if build was successful
+ bool packTCP();
+
+ /// Builds on wire packet for UDP transmission.
+ ///
+ /// @return true, if build was successful
+ bool packUDP();
+
+ /// @brief Parses on-wire form of TCP DHCPv6 packet.
+ ///
+ /// Parses received packet, stored in on-wire format in data_.
+ /// data_len_ must be set to indicate data length.
+ /// Will create a collection of option objects that will
+ /// be stored in options_ container.
+ ///
+ /// TODO This function is not implemented yet.
+ ///
+ /// @return true, if build was successful
+ bool unpackTCP();
+
+ /// @brief Parses on-wire form of UDP DHCPv6 packet.
+ ///
+ /// Parses received packet, stored in on-wire format in data_.
+ /// data_len_ must be set to indicate data length.
+ /// Will create a collection of option objects that will
+ /// be stored in options_ container.
+ ///
+ /// @return true, if build was successful
+ bool unpackUDP();
+
+ /// UDP (usually) or TCP (bulk leasequery or failover)
+ DHCPv6Proto proto_;
+
+ /// DHCPv6 message type
+ int msg_type_;
+
+ /// DHCPv6 transaction-id
+ unsigned int transid_;
+}; // Pkt6 class
+
+} // isc::dhcp namespace
+
+} // isc namespace
+
+#endif
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
new file mode 100644
index 0000000..3fce27e
--- /dev/null
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -0,0 +1,42 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+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
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += libdhcp_unittests
+libdhcp_unittests_SOURCES = run_unittests.cc
+libdhcp_unittests_SOURCES += ../libdhcp.h ../libdhcp.cc libdhcp_unittest.cc
+libdhcp_unittests_SOURCES += ../option6_iaaddr.h ../option6_iaaddr.cc option6_iaaddr_unittest.cc
+libdhcp_unittests_SOURCES += ../option6_ia.h ../option6_ia.cc option6_ia_unittest.cc
+libdhcp_unittests_SOURCES += ../option6_addrlst.h ../option6_addrlst.cc option6_addrlst_unittest.cc
+libdhcp_unittests_SOURCES += ../option.h ../option.cc option_unittest.cc
+libdhcp_unittests_SOURCES += ../pkt6.h ../pkt6.cc pkt6_unittest.cc
+
+libdhcp_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
+libdhcp_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+libdhcp_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_CLANGPP
+# This is to workaround unused variables tcout and tcerr in
+# log4cplus's streams.h.
+libdhcp_unittests_CXXFLAGS += -Wno-unused-variable
+endif
+libdhcp_unittests_LDADD = $(GTEST_LDADD)
+libdhcp_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+libdhcp_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+libdhcp_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+libdhcp_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/dhcp/tests/libdhcp_unittest.cc b/src/lib/dhcp/tests/libdhcp_unittest.cc
new file mode 100644
index 0000000..d9d7c47
--- /dev/null
+++ b/src/lib/dhcp/tests/libdhcp_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include "dhcp/libdhcp.h"
+#include "config.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+class LibDhcpTest : public ::testing::Test {
+public:
+ LibDhcpTest() {
+ }
+};
+
+static const uint8_t packed[] = {
+ 0, 12, 0, 5, 100, 101, 102, 103, 104, // opt1 (9 bytes)
+ 0, 13, 0, 3, 105, 106, 107, // opt2 (7 bytes)
+ 0, 14, 0, 2, 108, 109, // opt3 (6 bytes)
+ 1, 0, 0, 4, 110, 111, 112, 113, // opt4 (8 bytes)
+ 1, 1, 0, 1, 114 // opt5 (5 bytes)
+};
+
+TEST_F(LibDhcpTest, packOptions6) {
+ boost::shared_array<uint8_t> buf(new uint8_t[512]);
+ isc::dhcp::Option::Option6Collection opts; // list of options
+
+ // generate content for options
+ for (int i = 0; i < 64; i++) {
+ buf[i]=i+100;
+ }
+
+ boost::shared_ptr<Option> opt1(new Option(Option::V6, 12, buf, 0, 5));
+ boost::shared_ptr<Option> opt2(new Option(Option::V6, 13, buf, 5, 3));
+ boost::shared_ptr<Option> opt3(new Option(Option::V6, 14, buf, 8, 2));
+ boost::shared_ptr<Option> opt4(new Option(Option::V6,256, buf,10, 4));
+ boost::shared_ptr<Option> opt5(new Option(Option::V6,257, buf,14, 1));
+
+ opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt1));
+ opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt2));
+ opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt3));
+ opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt4));
+ opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt5));
+
+ unsigned int offset;
+ EXPECT_NO_THROW ({
+ offset = LibDHCP::packOptions6(buf, 512, 100, opts);
+ });
+ EXPECT_EQ(135, offset); // options should take 35 bytes
+ EXPECT_EQ(0, memcmp(&buf[100], packed, 35) );
+}
+
+TEST_F(LibDhcpTest, unpackOptions6) {
+
+ // just couple of random options
+ // Option is used as a simple option implementation
+ // More advanced uses are validated in tests dedicated for
+ // specific derived classes.
+ isc::dhcp::Option::Option6Collection options; // list of options
+
+ // we can't use packed directly, as shared_array would try to
+ // free it eventually
+ boost::shared_array<uint8_t> buf(new uint8_t[512]);
+ memcpy(&buf[0], packed, 35);
+
+ unsigned int offset;
+ EXPECT_NO_THROW ({
+ offset = LibDHCP::unpackOptions6(buf, 512, 0, 35, options);
+ });
+
+ EXPECT_EQ(35, offset); // parsed first 35 bytes (offset 0..34)
+ EXPECT_EQ(options.size(), 5); // there should be 5 options
+
+ isc::dhcp::Option::Option6Collection::const_iterator x = options.find(12);
+ ASSERT_FALSE(x == options.end()); // option 1 should exist
+ EXPECT_EQ(12, x->second->getType()); // this should be option 12
+ ASSERT_EQ(9, x->second->len()); // it should be of length 9
+ EXPECT_EQ(0, memcmp(x->second->getData(), packed+4, 5)); // data len=5
+
+ x = options.find(13);
+ ASSERT_FALSE(x == options.end()); // option 13 should exist
+ EXPECT_EQ(13, x->second->getType()); // this should be option 13
+ ASSERT_EQ(7, x->second->len()); // it should be of length 7
+ EXPECT_EQ(0, memcmp(x->second->getData(), packed+13, 3)); // data len=3
+
+ x = options.find(14);
+ ASSERT_FALSE(x == options.end()); // option 3 should exist
+ EXPECT_EQ(14, x->second->getType()); // this should be option 14
+ ASSERT_EQ(6, x->second->len()); // it should be of length 6
+ EXPECT_EQ(0, memcmp(x->second->getData(), packed+20, 2)); // data len=2
+
+ x = options.find(256);
+ ASSERT_FALSE(x == options.end()); // option 256 should exist
+ EXPECT_EQ(256, x->second->getType()); // this should be option 256
+ ASSERT_EQ(8, x->second->len()); // it should be of length 7
+ EXPECT_EQ(0, memcmp(x->second->getData(), packed+26, 4)); // data len=4
+
+ x = options.find(257);
+ ASSERT_FALSE(x == options.end()); // option 257 should exist
+ EXPECT_EQ(257, x->second->getType()); // this should be option 257
+ ASSERT_EQ(5, x->second->len()); // it should be of length 5
+ EXPECT_EQ(0, memcmp(x->second->getData(), packed+34, 1)); // data len=1
+
+ x = options.find(0);
+ EXPECT_TRUE(x == options.end()); // option 0 not found
+
+ x = options.find(1); // 1 is htons(256) on little endians. Worth checking
+ EXPECT_TRUE(x == options.end()); // option 1 not found
+
+ x = options.find(2);
+ EXPECT_TRUE(x == options.end()); // option 2 not found
+
+ x = options.find(32000);
+ EXPECT_TRUE(x == options.end()); // option 32000 not found
+}
+
+}
diff --git a/src/lib/dhcp/tests/option6_addrlst_unittest.cc b/src/lib/dhcp/tests/option6_addrlst_unittest.cc
new file mode 100644
index 0000000..3a1975d
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_addrlst_unittest.cc
@@ -0,0 +1,223 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include "io_address.h"
+#include "dhcp/dhcp6.h"
+#include "dhcp/option.h"
+#include "dhcp/option6_addrlst.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+namespace {
+class Option6AddrLstTest : public ::testing::Test {
+public:
+ Option6AddrLstTest() {
+ }
+};
+
+TEST_F(Option6AddrLstTest, basic) {
+
+ // limiting tests to just a 2001:db8::/32 as is *wrong*.
+ // Good tests check corner cases as well.
+ // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff checks
+ // for integer overflow
+ // ff02::face:b00c checks if multicast addresses
+ // can be represented properly.
+
+ uint8_t sampledata[] = {
+ // 2001:db8:1::dead:beef
+ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0,
+ 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef,
+
+ // ff02::face:b00c
+ 0xff, 02, 0, 0, 0, 0, 0 , 0,
+ 0, 0, 0, 0, 0xfa, 0xce, 0xb0, 0x0c,
+
+ // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ uint8_t expected1[] = {
+ D6O_NAME_SERVERS/256, D6O_NAME_SERVERS%256,//type
+ 0, 16, // len = 16 (1 address)
+ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0,
+ 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef,
+
+ };
+
+ uint8_t expected2[] = {
+ D6O_SIP_SERVERS_ADDR/256, D6O_SIP_SERVERS_ADDR%256,
+ 0, 32, // len = 32 (2 addresses)
+ // 2001:db8:1::dead:beef
+ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0,
+ 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef,
+
+ // ff02::face:b00c
+ 0xff, 02, 0, 0, 0, 0, 0 , 0,
+ 0, 0, 0, 0, 0xfa, 0xce, 0xb0, 0x0c,
+
+ // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ uint8_t expected3[] = {
+ D6O_NIS_SERVERS/256, D6O_NIS_SERVERS%256,
+ 0, 48,
+ // 2001:db8:1::dead:beef
+ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0,
+ 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef,
+
+ // ff02::face:b00c
+ 0xff, 02, 0, 0, 0, 0, 0 , 0,
+ 0, 0, 0, 0, 0xfa, 0xce, 0xb0, 0x0c,
+
+ // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ boost::shared_array<uint8_t> buf(new uint8_t[300]);
+ for (int i = 0; i < 300; i++)
+ buf[i] = 0;
+
+ memcpy(&buf[0], sampledata, 48);
+
+ // just a single address
+ Option6AddrLst* opt1 = 0;
+ EXPECT_NO_THROW(
+ opt1 = new Option6AddrLst(D6O_NAME_SERVERS, buf, 128, 0, 16);
+ );
+
+ EXPECT_EQ(D6O_NAME_SERVERS, opt1->getType());
+ EXPECT_EQ(20, opt1->len());
+ Option6AddrLst::AddressContainer addrs = opt1->getAddresses();
+ ASSERT_EQ(1, addrs.size());
+ IOAddress addr = addrs[0];
+ EXPECT_EQ("2001:db8:1::dead:beef", addr.toText());
+
+ // pack this option again in the same buffer, but in
+ // different place
+ int offset = opt1->pack(buf,300, 100);
+
+ EXPECT_EQ(120, offset);
+ EXPECT_EQ( 0, memcmp(expected1, &buf[100], 20) );
+
+ // two addresses
+ Option6AddrLst* opt2 = 0;
+ EXPECT_NO_THROW(
+ opt2 = new Option6AddrLst(D6O_SIP_SERVERS_ADDR, buf, 128, 0, 32);
+ );
+ EXPECT_EQ(D6O_SIP_SERVERS_ADDR, opt2->getType());
+ EXPECT_EQ(36, opt2->len());
+ addrs = opt2->getAddresses();
+ ASSERT_EQ(2, addrs.size());
+ EXPECT_EQ("2001:db8:1::dead:beef", addrs[0].toText());
+ EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
+
+ // pack this option again in the same buffer, but in
+ // different place
+ offset = opt2->pack(buf,300, 150);
+
+ EXPECT_EQ(150+36, offset);
+ EXPECT_EQ( 0, memcmp(expected2, &buf[150], 36));
+
+ // three addresses
+ Option6AddrLst* opt3 = 0;
+ EXPECT_NO_THROW(
+ opt3 = new Option6AddrLst(D6O_NIS_SERVERS, buf, 128, 0, 48);
+ );
+
+ EXPECT_EQ(D6O_NIS_SERVERS, opt3->getType());
+ EXPECT_EQ(52, opt3->len());
+ addrs = opt3->getAddresses();
+ ASSERT_EQ(3, addrs.size());
+ EXPECT_EQ("2001:db8:1::dead:beef", addrs[0].toText());
+ EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
+ EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", addrs[2].toText());
+
+ // pack this option again in the same buffer, but in
+ // different place
+ offset = opt3->pack(buf,300, 200);
+
+ EXPECT_EQ(252, offset);
+ EXPECT_EQ( 0, memcmp(expected3, &buf[200], 52) );
+
+ EXPECT_NO_THROW(
+ delete opt1;
+ delete opt2;
+ delete opt3;
+ );
+}
+
+TEST_F(Option6AddrLstTest, constructors) {
+
+ Option6AddrLst* opt1 = 0;
+ EXPECT_NO_THROW(
+ opt1 = new Option6AddrLst(1234, IOAddress("::1"));
+ );
+ EXPECT_EQ(1234, opt1->getType());
+
+ Option6AddrLst::AddressContainer addrs = opt1->getAddresses();
+ ASSERT_EQ(1, addrs.size() );
+ EXPECT_EQ("::1", addrs[0].toText());
+
+ addrs.clear();
+ addrs.push_back(IOAddress(string("fe80::1234")));
+ addrs.push_back(IOAddress(string("2001:db8:1::baca")));
+
+ Option6AddrLst* opt2 = 0;
+ EXPECT_NO_THROW(
+ opt2 = new Option6AddrLst(5678, addrs);
+ );
+
+ Option6AddrLst::AddressContainer check = opt2->getAddresses();
+ ASSERT_EQ(2, check.size() );
+ EXPECT_EQ("fe80::1234", check[0].toText());
+ EXPECT_EQ("2001:db8:1::baca", check[1].toText());
+
+ EXPECT_NO_THROW(
+ delete opt1;
+ delete opt2;
+ );
+}
+
+TEST_F(Option6AddrLstTest, setAddress) {
+ Option6AddrLst* opt1 = 0;
+ EXPECT_NO_THROW(
+ opt1 = new Option6AddrLst(1234, IOAddress("::1"));
+ );
+ opt1->setAddress(IOAddress("::2"));
+
+ Option6AddrLst::AddressContainer addrs = opt1->getAddresses();
+ ASSERT_EQ(1, addrs.size() );
+ EXPECT_EQ("::2", addrs[0].toText());
+
+ EXPECT_NO_THROW(
+ delete opt1;
+ );
+}
+
+} // namespace
diff --git a/src/lib/dhcp/tests/option6_ia_unittest.cc b/src/lib/dhcp/tests/option6_ia_unittest.cc
new file mode 100644
index 0000000..ab949de
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_ia_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "dhcp/dhcp6.h"
+#include "dhcp/option.h"
+#include "dhcp/option6_ia.h"
+#include "dhcp/option6_iaaddr.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+namespace {
+class Option6IATest : public ::testing::Test {
+public:
+ Option6IATest() {
+ }
+};
+
+TEST_F(Option6IATest, basic) {
+
+ boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
+ for (int i = 0; i < 128; i++)
+ simple_buf[i] = 0;
+ simple_buf[0] = 0xa1; // iaid
+ simple_buf[1] = 0xa2;
+ simple_buf[2] = 0xa3;
+ simple_buf[3] = 0xa4;
+
+ simple_buf[4] = 0x81; // T1
+ simple_buf[5] = 0x02;
+ simple_buf[6] = 0x03;
+ simple_buf[7] = 0x04;
+
+ simple_buf[8] = 0x84; // T2
+ simple_buf[9] = 0x03;
+ simple_buf[10] = 0x02;
+ simple_buf[11] = 0x01;
+
+ // create an option
+ // unpack() is called from constructor
+ Option6IA* opt = new Option6IA(D6O_IA_NA,
+ simple_buf,
+ 128,
+ 0,
+ 12);
+
+ EXPECT_EQ(D6O_IA_NA, opt->getType());
+ EXPECT_EQ(0xa1a2a3a4, opt->getIAID());
+ EXPECT_EQ(0x81020304, opt->getT1());
+ EXPECT_EQ(0x84030201, opt->getT2());
+
+ // pack this option again in the same buffer, but in
+ // different place
+
+ // test for pack()
+ int offset = opt->pack(simple_buf, 128, 60);
+
+ // 4 bytes header + 4 bytes content
+ EXPECT_EQ(12, opt->len() - 4);
+ EXPECT_EQ(D6O_IA_NA, opt->getType());
+
+ EXPECT_EQ(offset, 76); // 60 + lenght(IA_NA) = 76
+
+ // check if pack worked properly:
+ // if option type is correct
+ EXPECT_EQ(D6O_IA_NA, simple_buf[60]*256 + simple_buf[61]);
+
+ // if option length is correct
+ EXPECT_EQ(12, simple_buf[62]*256 + simple_buf[63]);
+
+ // if iaid is correct
+ unsigned int iaid = htonl(*(unsigned int*)&simple_buf[64]);
+ EXPECT_EQ(0xa1a2a3a4, iaid );
+
+ // if T1 is correct
+ EXPECT_EQ(0x81020304, (simple_buf[68] << 24) +
+ (simple_buf[69] << 16) +
+ (simple_buf[70] << 8) +
+ (simple_buf[71]) );
+
+ // if T1 is correct
+ EXPECT_EQ(0x84030201, (simple_buf[72] << 24) +
+ (simple_buf[73] << 16) +
+ (simple_buf[74] << 8) +
+ (simple_buf[75]) );
+
+ EXPECT_NO_THROW(
+ delete opt;
+ );
+}
+
+TEST_F(Option6IATest, simple) {
+ boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
+ for (int i = 0; i < 128; i++)
+ simple_buf[i] = 0;
+
+ Option6IA * ia = new Option6IA(D6O_IA_NA, 1234);
+ ia->setT1(2345);
+ ia->setT2(3456);
+
+ EXPECT_EQ(D6O_IA_NA, ia->getType());
+ EXPECT_EQ(1234, ia->getIAID());
+ EXPECT_EQ(2345, ia->getT1());
+ EXPECT_EQ(3456, ia->getT2());
+
+ EXPECT_NO_THROW(
+ delete ia;
+ );
+}
+
+// test if option can build suboptions
+TEST_F(Option6IATest, suboptions_pack) {
+ boost::shared_array<uint8_t> buf(new uint8_t[128]);
+ for (int i=0; i<128; i++)
+ buf[i] = 0;
+ buf[0] = 0xff;
+ buf[1] = 0xfe;
+ buf[2] = 0xfc;
+
+ Option6IA * ia = new Option6IA(D6O_IA_NA, 0x13579ace);
+ ia->setT1(0x2345);
+ ia->setT2(0x3456);
+
+ boost::shared_ptr<Option> sub1(new Option(Option::V6,
+ 0xcafe));
+
+ boost::shared_ptr<Option6IAAddr> addr1(
+ new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"),
+ 0x5000, 0x7000));
+
+ ia->addOption(sub1);
+ ia->addOption(addr1);
+
+ ASSERT_EQ(28, addr1->len());
+ ASSERT_EQ(4, sub1->len());
+ ASSERT_EQ(48, ia->len());
+
+ uint8_t expected[] = {
+ D6O_IA_NA/256, D6O_IA_NA%256, // type
+ 0, 44, // length
+ 0x13, 0x57, 0x9a, 0xce, // iaid
+ 0, 0, 0x23, 0x45, // T1
+ 0, 0, 0x34, 0x56, // T2
+
+ // iaaddr suboption
+ D6O_IAADDR/256, D6O_IAADDR%256, // type
+ 0, 24, // len
+ 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+ 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+ 0, 0, 0x50, 0, // preferred-lifetime
+ 0, 0, 0x70, 0, // valid-lifetime
+
+ // suboption
+ 0xca, 0xfe, // type
+ 0, 0 // len
+ };
+
+ int offset = ia->pack(buf, 128, 10);
+ ASSERT_EQ(offset, 10 + 48);
+
+ EXPECT_EQ(0, memcmp(&buf[10], expected, 48));
+
+ EXPECT_NO_THROW(
+ delete ia;
+ );
+}
+
+// test if option can parse suboptions
+TEST_F(Option6IATest, suboptions_unpack) {
+
+
+ uint8_t expected[] = {
+ D6O_IA_NA/256, D6O_IA_NA%256, // type
+ 0, 28, // length
+ 0x13, 0x57, 0x9a, 0xce, // iaid
+ 0, 0, 0x23, 0x45, // T1
+ 0, 0, 0x34, 0x56, // T2
+
+ // iaaddr suboption
+ D6O_IAADDR/256, D6O_IAADDR%256, // type
+ 0, 24, // len
+ 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+ 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+ 0, 0, 0x50, 0, // preferred-lifetime
+ 0, 0, 0x70, 0, // valid-lifetime
+
+ // suboption
+ 0xca, 0xfe, // type
+ 0, 0 // len
+ };
+
+ boost::shared_array<uint8_t> buf(new uint8_t[128]);
+ for (int i = 0; i < 128; i++)
+ buf[i] = 0;
+ memcpy(&buf[0], expected, 48);
+
+ Option6IA* ia = 0;
+ EXPECT_NO_THROW({
+ ia = new Option6IA(D6O_IA_NA, buf, 128, 4, 44);
+ cout << "Parsed option:" << endl << ia->toText() << endl;
+ });
+ ASSERT_TRUE(ia);
+
+ EXPECT_EQ(D6O_IA_NA, ia->getType());
+ EXPECT_EQ(0x13579ace, ia->getIAID());
+ EXPECT_EQ(0x2345, ia->getT1());
+ EXPECT_EQ(0x3456, ia->getT2());
+
+ boost::shared_ptr<Option> subopt = ia->getOption(D6O_IAADDR);
+ ASSERT_NE(boost::shared_ptr<Option>(), subopt); // non-NULL
+
+ // checks for address option
+ Option6IAAddr * addr = dynamic_cast<Option6IAAddr*>(subopt.get());
+ ASSERT_TRUE(NULL != addr);
+
+ EXPECT_EQ(D6O_IAADDR, addr->getType());
+ EXPECT_EQ(28, addr->len());
+ EXPECT_EQ(0x5000, addr->getPreferred());
+ EXPECT_EQ(0x7000, addr->getValid());
+ EXPECT_EQ("2001:db8:1234:5678::abcd", addr->getAddress().toText());
+
+ // checks for dummy option
+ subopt = ia->getOption(0xcafe);
+ ASSERT_TRUE(subopt); // should be non-NULL
+
+ EXPECT_EQ(0xcafe, subopt->getType());
+ EXPECT_EQ(4, subopt->len());
+ EXPECT_EQ(NULL, subopt->getData());
+
+ subopt = ia->getOption(1); // get option 1
+ ASSERT_FALSE(subopt); // should be NULL
+
+ EXPECT_NO_THROW(
+ delete ia;
+ );
+}
+
+}
diff --git a/src/lib/dhcp/tests/option6_iaaddr_unittest.cc b/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
new file mode 100644
index 0000000..f92304e
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include "dhcp/dhcp6.h"
+#include "dhcp/option.h"
+#include "dhcp/option6_iaaddr.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+class Option6IAAddrTest : public ::testing::Test {
+public:
+ Option6IAAddrTest() {
+ }
+};
+
+TEST_F(Option6IAAddrTest, basic) {
+
+ boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
+ for (int i = 0; i < 128; i++)
+ simple_buf[i] = 0;
+ simple_buf[0] = 0x20;
+ simple_buf[1] = 0x01;
+ simple_buf[2] = 0x0d;
+ simple_buf[3] = 0xb8;
+ simple_buf[4] = 0x00;
+ simple_buf[5] = 0x01;
+ simple_buf[12] = 0xde;
+ simple_buf[13] = 0xad;
+ simple_buf[14] = 0xbe;
+ simple_buf[15] = 0xef; // 2001:db8:1::dead:beef
+
+ simple_buf[16] = 0x00;
+ simple_buf[17] = 0x00;
+ simple_buf[18] = 0x03;
+ simple_buf[19] = 0xe8; // 1000
+
+ simple_buf[20] = 0xb2;
+ simple_buf[21] = 0xd0;
+ simple_buf[22] = 0x5e;
+ simple_buf[23] = 0x00; // 3,000,000,000
+
+ // create an option (unpack content)
+ Option6IAAddr* opt = new Option6IAAddr(D6O_IAADDR,
+ simple_buf,
+ 128,
+ 0,
+ 24);
+
+ // pack this option again in the same buffer, but in
+ // different place
+ int offset = opt->pack(simple_buf, 128, 50);
+
+ EXPECT_EQ(78, offset);
+
+ // 4 bytes header + 4 bytes content
+ EXPECT_EQ("2001:db8:1::dead:beef", opt->getAddress().toText());
+ EXPECT_EQ(1000, opt->getPreferred());
+ EXPECT_EQ(3000000000U, opt->getValid());
+
+ EXPECT_EQ(D6O_IAADDR, opt->getType());
+
+ EXPECT_EQ(Option::OPTION6_HDR_LEN + Option6IAAddr::OPTION6_IAADDR_LEN,
+ opt->len());
+
+ // check if pack worked properly:
+ // if option type is correct
+ EXPECT_EQ(D6O_IAADDR, simple_buf[50]*256 + simple_buf[51]);
+
+ // if option length is correct
+ EXPECT_EQ(24, simple_buf[52]*256 + simple_buf[53]);
+
+ // if option content is correct
+ EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[54],24));
+
+ EXPECT_NO_THROW(
+ delete opt;
+ );
+}
+
+}
diff --git a/src/lib/dhcp/tests/option_unittest.cc b/src/lib/dhcp/tests/option_unittest.cc
new file mode 100644
index 0000000..2bfe781
--- /dev/null
+++ b/src/lib/dhcp/tests/option_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+#include <boost/shared_ptr.hpp>
+
+#include "dhcp/dhcp6.h"
+#include "dhcp/option.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+class OptionTest : public ::testing::Test {
+public:
+ OptionTest() {
+ }
+};
+
+// v4 is not really implemented yet. A simple test will do for now
+TEST_F(OptionTest, basic4) {
+
+ Option* opt = new Option(Option::V4, 17);
+
+ EXPECT_EQ(17, opt->getType());
+ EXPECT_EQ(NULL, opt->getData());
+ EXPECT_EQ(2, opt->len()); // just v4 header
+
+ EXPECT_NO_THROW(
+ delete opt;
+ );
+}
+
+// tests simple constructor
+TEST_F(OptionTest, basic6) {
+
+ Option* opt = new Option(Option::V6, 1);
+
+ EXPECT_EQ(1, opt->getType());
+ EXPECT_EQ(NULL, opt->getData());
+ EXPECT_EQ(4, opt->len()); // just v6 header
+
+ EXPECT_NO_THROW(
+ delete opt;
+ );
+}
+
+// tests contructor used in pkt reception
+// option contains actual data
+TEST_F(OptionTest, data1) {
+ boost::shared_array<uint8_t> buf(new uint8_t[32]);
+ for (int i = 0; i < 32; i++)
+ buf[i] = 100+i;
+ Option* opt = new Option(Option::V6, 333, //type
+ buf,
+ 3, // offset
+ 7); // 7 bytes of data
+ EXPECT_EQ(333, opt->getType());
+ ASSERT_EQ(&buf[3], opt->getData());
+ ASSERT_EQ(11, opt->len());
+ EXPECT_EQ(0, memcmp(&buf[3], opt->getData(), 7) );
+
+ int offset = opt->pack(buf, 32, 20);
+ EXPECT_EQ(31, offset);
+
+ EXPECT_EQ(buf[20], 333/256); // type
+ EXPECT_EQ(buf[21], 333%256);
+
+ EXPECT_EQ(buf[22], 0); // len
+ EXPECT_EQ(buf[23], 7);
+
+ // payload
+ EXPECT_EQ(0, memcmp(&buf[3], &buf[24], 7) );
+
+ EXPECT_NO_THROW(
+ delete opt;
+ );
+}
+
+// another text that tests the same thing, just
+// with different input parameters
+TEST_F(OptionTest, data2) {
+
+ boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
+ for (int i = 0; i < 128; i++)
+ simple_buf[i] = 0;
+ simple_buf[0] = 0xa1;
+ simple_buf[1] = 0xa2;
+ simple_buf[2] = 0xa3;
+ simple_buf[3] = 0xa4;
+
+ // create an option (unpack content)
+ Option* opt = new Option(Option::V6,
+ D6O_CLIENTID,
+ simple_buf,
+ 0,
+ 4);
+
+ // pack this option again in the same buffer, but in
+ // different place
+ int offset18 = opt->pack(simple_buf, 128, 10);
+
+ // 4 bytes header + 4 bytes content
+ EXPECT_EQ(8, opt->len());
+ EXPECT_EQ(D6O_CLIENTID, opt->getType());
+
+ EXPECT_EQ(offset18, 18);
+
+ // check if pack worked properly:
+ // if option type is correct
+ EXPECT_EQ(D6O_CLIENTID, simple_buf[10]*256 + simple_buf[11]);
+
+ // if option length is correct
+ EXPECT_EQ(4, simple_buf[12]*256 + simple_buf[13]);
+
+ // if option content is correct
+ EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[14],4));
+
+ EXPECT_NO_THROW(
+ delete opt;
+ );
+}
+
+// check that an option can contain 2 suboptions:
+// opt1
+// +----opt2
+// |
+// +----opt3
+//
+TEST_F(OptionTest, suboptions1) {
+ boost::shared_array<uint8_t> buf(new uint8_t[128]);
+ for (int i=0; i<128; i++)
+ buf[i] = 100+i;
+ Option* opt1 = new Option(Option::V6, 65535, //type
+ buf,
+ 0, // offset
+ 3); // 3 bytes of data
+ boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
+ boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
+ buf,
+ 3, // offset
+ 5)); // 5 bytes of data
+ opt1->addOption(opt2);
+ opt1->addOption(opt3);
+ // opt2 len = 4 (just header)
+ // opt3 len = 9 4(header)+5(data)
+ // opt1 len = 7 + suboptions() = 7 + 4 + 9 = 20
+
+ EXPECT_EQ(4, opt2->len());
+ EXPECT_EQ(9, opt3->len());
+ EXPECT_EQ(20, opt1->len());
+
+ uint8_t expected[] = {
+ 0xff, 0xff, 0, 16, 100, 101, 102,
+ 0, 7, 0, 5, 103, 104, 105, 106, 107,
+ 0, 13, 0, 0 // no data at all
+ };
+
+ int offset = opt1->pack(buf, 128, 20);
+ EXPECT_EQ(40, offset);
+
+ // payload
+ EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+
+ EXPECT_NO_THROW(
+ delete opt1;
+ );
+}
+
+// check that an option can contain 2 suboptions:
+// opt1
+// +----opt2
+// |
+// +----opt3
+//
+TEST_F(OptionTest, suboptions2) {
+ boost::shared_array<uint8_t> buf(new uint8_t[128]);
+ for (int i=0; i<128; i++)
+ buf[i] = 100+i;
+ Option* opt1 = new Option(Option::V6, 65535, //type
+ buf,
+ 0, // offset
+ 3); // 3 bytes of data
+ boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
+ boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
+ buf,
+ 3, // offset
+ 5)); // 5 bytes of data
+ opt1->addOption(opt2);
+ opt2->addOption(opt3);
+ // opt3 len = 9 4(header)+5(data)
+ // opt2 len = 4 (just header) + len(opt3)
+ // opt1 len = 7 + len(opt2)
+
+ uint8_t expected[] = {
+ 0xff, 0xff, 0, 16, 100, 101, 102,
+ 0, 13, 0, 9,
+ 0, 7, 0, 5, 103, 104, 105, 106, 107,
+ };
+
+ int offset = opt1->pack(buf, 128, 20);
+ EXPECT_EQ(40, offset);
+
+ // payload
+ EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+
+ EXPECT_NO_THROW(
+ delete opt1;
+ );
+}
+
+TEST_F(OptionTest, addgetdel) {
+ boost::shared_array<uint8_t> buf(new uint8_t[128]);
+ for (int i=0; i<128; i++)
+ buf[i] = 100+i;
+ Option* parent = new Option(Option::V6, 65535); //type
+ boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
+ boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
+ boost::shared_ptr<Option> opt3(new Option(Option::V6, 2));
+
+ parent->addOption(opt1);
+ parent->addOption(opt2);
+
+ // getOption() test
+ EXPECT_EQ(opt1, parent->getOption(1));
+ EXPECT_EQ(opt2, parent->getOption(2));
+
+ // expect NULL
+ EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(4));
+
+ // now there are 2 options of type 2
+ parent->addOption(opt3);
+
+ // let's delete one of them
+ EXPECT_EQ(true, parent->delOption(2));
+
+ // there still should be the other option 2
+ EXPECT_NE(boost::shared_ptr<Option>(), parent->getOption(2));
+
+ // let's delete the other option 2
+ EXPECT_EQ(true, parent->delOption(2));
+
+ // no more options with type=2
+ EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(2));
+
+ // let's try to delete - should fail
+ EXPECT_TRUE(false == parent->delOption(2));
+}
+
+}
diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc
new file mode 100644
index 0000000..2819f7d
--- /dev/null
+++ b/src/lib/dhcp/tests/pkt6_unittest.cc
@@ -0,0 +1,206 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include "io_address.h"
+#include "dhcp/option.h"
+#include "dhcp/pkt6.h"
+#include "dhcp/dhcp6.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+namespace {
+// empty class for now, but may be extended once Addr6 becomes bigger
+class Pkt6Test : public ::testing::Test {
+public:
+ Pkt6Test() {
+ }
+};
+
+TEST_F(Pkt6Test, constructor) {
+ Pkt6 * pkt1 = new Pkt6(17);
+
+ EXPECT_EQ(pkt1->data_len_, 17);
+
+ delete pkt1;
+}
+
+// captured actual SOLICIT packet: transid=0x3d79fb
+// options: client-id, in_na, dns-server, elapsed-time, option-request
+// this code is autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c)
+Pkt6 *capture1() {
+ Pkt6* pkt;
+ pkt = new Pkt6(98);
+ pkt->remote_port_ = 546;
+ pkt->remote_addr_ = IOAddress("fe80::21e:8cff:fe9b:7349");
+ pkt->local_port_ = 0;
+ pkt->local_addr_ = IOAddress("ff02::1:2");
+ pkt->ifindex_ = 2;
+ pkt->iface_ = "eth0";
+ pkt->data_[0]=1;
+ pkt->data_[1]=01; pkt->data_[2]=02; pkt->data_[3]=03; pkt->data_[4]=0;
+ pkt->data_[5]=1; pkt->data_[6]=0; pkt->data_[7]=14; pkt->data_[8]=0;
+ pkt->data_[9]=1; pkt->data_[10]=0; pkt->data_[11]=1; pkt->data_[12]=21;
+ pkt->data_[13]=158; pkt->data_[14]=60; pkt->data_[15]=22; pkt->data_[16]=0;
+ pkt->data_[17]=30; pkt->data_[18]=140; pkt->data_[19]=155; pkt->data_[20]=115;
+ pkt->data_[21]=73; pkt->data_[22]=0; pkt->data_[23]=3; pkt->data_[24]=0;
+ pkt->data_[25]=40; pkt->data_[26]=0; pkt->data_[27]=0; pkt->data_[28]=0;
+ pkt->data_[29]=1; pkt->data_[30]=255; pkt->data_[31]=255; pkt->data_[32]=255;
+ pkt->data_[33]=255; pkt->data_[34]=255; pkt->data_[35]=255; pkt->data_[36]=255;
+ pkt->data_[37]=255; pkt->data_[38]=0; pkt->data_[39]=5; pkt->data_[40]=0;
+ pkt->data_[41]=24; pkt->data_[42]=32; pkt->data_[43]=1; pkt->data_[44]=13;
+ pkt->data_[45]=184; pkt->data_[46]=0; pkt->data_[47]=1; pkt->data_[48]=0;
+ pkt->data_[49]=0; pkt->data_[50]=0; pkt->data_[51]=0; pkt->data_[52]=0;
+ pkt->data_[53]=0; pkt->data_[54]=0; pkt->data_[55]=0; pkt->data_[56]=18;
+ pkt->data_[57]=52; pkt->data_[58]=255; pkt->data_[59]=255; pkt->data_[60]=255;
+ pkt->data_[61]=255; pkt->data_[62]=255; pkt->data_[63]=255; pkt->data_[64]=255;
+ pkt->data_[65]=255; pkt->data_[66]=0; pkt->data_[67]=23; pkt->data_[68]=0;
+ pkt->data_[69]=16; pkt->data_[70]=32; pkt->data_[71]=1; pkt->data_[72]=13;
+ pkt->data_[73]=184; pkt->data_[74]=0; pkt->data_[75]=1; pkt->data_[76]=0;
+ pkt->data_[77]=0; pkt->data_[78]=0; pkt->data_[79]=0; pkt->data_[80]=0;
+ pkt->data_[81]=0; pkt->data_[82]=0; pkt->data_[83]=0; pkt->data_[84]=221;
+ pkt->data_[85]=221; pkt->data_[86]=0; pkt->data_[87]=8; pkt->data_[88]=0;
+ pkt->data_[89]=2; pkt->data_[90]=0; pkt->data_[91]=100; pkt->data_[92]=0;
+ pkt->data_[93]=6; pkt->data_[94]=0; pkt->data_[95]=2; pkt->data_[96]=0;
+ pkt->data_[97]=23;
+ return (pkt);
+}
+
+TEST_F(Pkt6Test, unpack_solicit1) {
+ Pkt6 * sol = capture1();
+
+ ASSERT_EQ(true, sol->unpack());
+
+ // check for length
+ EXPECT_EQ(98, sol->len() );
+
+ // check for type
+ EXPECT_EQ(DHCPV6_SOLICIT, sol->getType() );
+
+ // check that all present options are returned
+ EXPECT_TRUE(sol->getOption(D6O_CLIENTID)); // client-id is present
+ EXPECT_TRUE(sol->getOption(D6O_IA_NA)); // IA_NA is present
+ EXPECT_TRUE(sol->getOption(D6O_ELAPSED_TIME)); // elapsed is present
+ EXPECT_TRUE(sol->getOption(D6O_NAME_SERVERS));
+ EXPECT_TRUE(sol->getOption(D6O_ORO));
+
+ // let's check that non-present options are not returned
+ EXPECT_FALSE(sol->getOption(D6O_SERVERID)); // server-id is missing
+ EXPECT_FALSE(sol->getOption(D6O_IA_TA));
+ EXPECT_FALSE(sol->getOption(D6O_IAADDR));
+
+ std::cout << sol->toText();
+
+ delete sol;
+}
+
+TEST_F(Pkt6Test, packUnpack) {
+
+ Pkt6 * parent = new Pkt6(100);
+
+ parent->setType(DHCPV6_SOLICIT);
+
+ boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
+ boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
+ boost::shared_ptr<Option> opt3(new Option(Option::V6, 100));
+ // let's not use zero-length option type 3 as it is IA_NA
+
+ parent->addOption(opt1);
+ parent->addOption(opt2);
+ parent->addOption(opt3);
+
+ EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
+ int transid = parent->getTransid();
+ // transaction-id was randomized, let's remember it
+
+ // calculated length should be 16
+ EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN,
+ parent->len() );
+
+ EXPECT_TRUE( parent->pack() );
+
+ //
+ EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN,
+ parent->len() );
+
+ // let's delete options from options_ collection
+ // they still be defined in packed
+ parent->options_.clear();
+
+ // that that removed options are indeed are gone
+ EXPECT_EQ( 4, parent->len() );
+
+ // now recreate options list
+ EXPECT_TRUE( parent->unpack() );
+
+ // transid, message-type should be the same as before
+ EXPECT_EQ(transid, parent->getTransid());
+ EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
+
+ EXPECT_TRUE( parent->getOption(1));
+ EXPECT_TRUE( parent->getOption(2));
+ EXPECT_TRUE( parent->getOption(100));
+ EXPECT_FALSE( parent->getOption(4));
+
+ delete parent;
+}
+
+TEST_F(Pkt6Test, addGetDelOptions) {
+ Pkt6 * parent = new Pkt6(100);
+
+ boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
+ boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
+ boost::shared_ptr<Option> opt3(new Option(Option::V6, 2));
+
+ parent->addOption(opt1);
+ parent->addOption(opt2);
+
+ // getOption() test
+ EXPECT_EQ(opt1, parent->getOption(1));
+ EXPECT_EQ(opt2, parent->getOption(2));
+
+ // expect NULL
+ EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(4));
+
+ // now there are 2 options of type 2
+ parent->addOption(opt3);
+
+ // let's delete one of them
+ EXPECT_EQ(true, parent->delOption(2));
+
+ // there still should be the other option 2
+ EXPECT_NE(boost::shared_ptr<Option>(), parent->getOption(2));
+
+ // let's delete the other option 2
+ EXPECT_EQ(true, parent->delOption(2));
+
+ // no more options with type=2
+ EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(2));
+
+ // let's try to delete - should fail
+ EXPECT_TRUE(false == parent->delOption(2));
+
+ delete parent;
+}
+
+
+}
diff --git a/src/lib/dhcp/tests/run_unittests.cc b/src/lib/dhcp/tests/run_unittests.cc
new file mode 100644
index 0000000..db27f76
--- /dev/null
+++ b/src/lib/dhcp/tests/run_unittests.cc
@@ -0,0 +1,27 @@
+// 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 <gtest/gtest.h>
+
+#include <log/logger_support.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+
+ int result = RUN_ALL_TESTS();
+
+ return (result);
+}
More information about the bind10-changes
mailing list