Commit 522d27a6 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[1186] Option6_AddrLst implemented (useful for storing v6 addresses)

parent c4291199
......@@ -546,9 +546,11 @@ IfaceMgr::receive() {
// 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));
......
......@@ -13,6 +13,7 @@ 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
......
// 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);
}
// 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_ */
......@@ -19,6 +19,7 @@ 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
......
// 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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment