--- /dev/null
+// 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 "libdhcp.h"
+#include "option6_addrlst.h"
+#include "dhcp6.h"
+#include "io_address.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+
+Option6AddrLst::Option6AddrLst(unsigned short type,
+ std::vector<isc::asiolink::IOAddress>& addrs)
+ :Option(V6, type) {
+ addrs_ = addrs;
+}
+
+Option6AddrLst::Option6AddrLst(unsigned short type,
+ isc::asiolink::IOAddress addr)
+ :Option(V6, type) {
+ addrs_.push_back(addr);
+}
+
+Option6AddrLst::Option6AddrLst(unsigned short type,
+ boost::shared_array<char> 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(isc::asiolink::IOAddress addr) {
+ addrs_.clear();
+ addrs_.push_back(addr);
+}
+
+void
+Option6AddrLst::setAddresses(std::vector<isc::asiolink::IOAddress>& addrs) {
+ addrs_ = addrs;
+}
+
+unsigned int
+Option6AddrLst::pack(boost::shared_array<char> 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 += 2;
+ *(uint16_t*)&buf[offset] = htons(len()-4); // len() returns complete option
+ // length. len field contains length without 4-byte option header
+ offset += 2;
+
+ for (std::vector<IOAddress>::const_iterator addr=addrs_.begin();
+ addr!=addrs_.end();
+ ++addr) {
+ memcpy(&buf[offset],
+ addr->getAddress().to_v6().to_bytes().data(),
+ 16);
+ offset += 16;
+ }
+
+ return offset;
+}
+
+unsigned int
+Option6AddrLst::unpack(boost::shared_array<char> 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 (AddrsContainer::const_iterator addr=addrs_.begin();
+ addr!=addrs_.end();
+ ++addr) {
+ tmp << addr->toText() << " ";
+ }
+ return tmp.str();
+}
+
+unsigned short Option6AddrLst::len() {
+
+ return (4 /* DHCPv6 option header len */ + addrs_.size()*16);
+}
--- /dev/null
+// 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 "io_address.h"
+#include "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:
+ typedef std::vector<isc::asiolink::IOAddress> AddrsContainer;
+
+ /// @brief Constructor used during option generation.
+ ///
+ /// @param type option type
+ /// @param addrs vector of addresses to be stored
+ ///
+ Option6AddrLst(unsigned short type,
+ AddrsContainer& addrs);
+
+ /// @brief Simplified constructor for a single address
+ ///
+ /// @param type option type
+ /// @param addr a single address to be stored
+ ///
+ Option6AddrLst(unsigned short type,
+ 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<char> 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<char> 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(boost::shared_array<char> 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(isc::asiolink::IOAddress addr);
+
+ /// @brief Sets list of addresses.
+ ///
+ /// @param addrs a vector of addresses to be added
+ ///
+ void setAddresses(std::vector<isc::asiolink::IOAddress>& 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
+ ///
+ AddrsContainer
+ getAddresses() { return addrs_; };
+
+ // returns data length (data length + DHCPv4/DHCPv6 option header)
+ virtual unsigned short len();
+
+protected:
+ AddrsContainer addrs_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION_ADDRLST_H_ */
--- /dev/null
+// 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) {
+
+ char 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
+ };
+
+ char 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,
+
+ };
+
+ char 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
+ };
+
+ char 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<char> buf(new char[300]);
+ for (int i=0; i<300; i++)
+ buf[i] = 0;
+
+ memcpy(&buf[0], sampledata, 48);
+
+ // just a single address
+ Option6AddrLst* opt1 = new Option6AddrLst(D6O_NAME_SERVERS,
+ buf,
+ 128,
+ 0,
+ 16);
+
+
+ EXPECT_EQ(D6O_NAME_SERVERS, opt1->getType());
+ EXPECT_EQ(20, opt1->len());
+ Option6AddrLst::AddrsContainer 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 = 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 = 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) );
+
+ delete opt1;
+ delete opt2;
+ delete opt3;
+}
+
+TEST_F(Option6AddrLstTest, constructors) {
+ Option6AddrLst * opt1 = new Option6AddrLst(1234,
+ IOAddress("::1"));
+ EXPECT_EQ(1234, opt1->getType());
+
+ Option6AddrLst::AddrsContainer 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 = new Option6AddrLst(5678,
+ addrs);
+
+ Option6AddrLst::AddrsContainer check = opt2->getAddresses();
+ ASSERT_EQ(2, check.size() );
+ EXPECT_EQ("fe80::1234", check[0].toText());
+ EXPECT_EQ("2001:db8:1::baca", check[1].toText());
+
+ delete opt1;
+ delete opt2;
+}
+
+TEST_F(Option6AddrLstTest, setAddress) {
+ Option6AddrLst * opt1 = new Option6AddrLst(1234,
+ IOAddress("::1"));
+ opt1->setAddress(IOAddress("::2"));
+
+ Option6AddrLst::AddrsContainer addrs = opt1->getAddresses();
+ ASSERT_EQ(1, addrs.size() );
+ EXPECT_EQ("::2", addrs[0].toText());
+
+ delete opt1;
+}
+
+} // namespace