Commit 0c53ade7 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

Merge branch 'trac1350'

Conflicts:
	ChangeLog
parents f9cbe6fb cc20ff99
337. [func] tomek
libdhcp++: Support for DHCPv4 option that can store a single
address or a list of IPv4 addresses added. Support for END option
added.
(Trac #1350, git cc20ff993da1ddb1c6e8a98370438b45a2be9e0a)
336. [func] jelte
libdns++ (and its python wrapper) now includes a class Serial, for
SOA SERIAL comparison and addition. Operations on instances of this
......
......@@ -14,6 +14,7 @@ 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 += option4_addrlst.cc option4_addrlst.h
libdhcp_la_SOURCES += dhcp6.h dhcp4.h
libdhcp_la_SOURCES += pkt6.cc pkt6.h
libdhcp_la_SOURCES += pkt4.cc pkt4.h
......
......@@ -17,6 +17,7 @@
#include <util/buffer.h>
#include <dhcp/libdhcp.h>
#include "config.h"
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
#include <dhcp/option6_ia.h>
......@@ -90,8 +91,17 @@ LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
size_t offset = 0;
// 2 - header of DHCPv4 option
while (offset + 2 <= buf.size()) {
while (offset + 1 <= buf.size()) {
uint8_t opt_type = buf[offset++];
if (offset + 1 == buf.size()) {
if (opt_type == DHO_END)
return; // just return. Don't need to add DHO_END option
else {
isc_throw(OutOfRange, "Attempt to parse truncated option "
<< opt_type);
}
}
uint8_t opt_len = buf[offset++];
if (offset + opt_len > buf.size() ) {
isc_throw(OutOfRange, "Option parse failed. Tried to parse "
......
......@@ -127,23 +127,6 @@ Option::pack4(isc::util::OutputBuffer& buf) {
}
}
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=" << len() << ": too small buffer.");
}
uint8_t *ptr = &buf[offset];
ptr[0] = type_;
ptr[1] = len() - getHeaderLen();
ptr += 2;
memcpy(ptr, &data_[0], data_.size());
return offset + len();
}
unsigned int
Option::pack6(boost::shared_array<uint8_t>& buf,
unsigned int buf_len,
......@@ -220,7 +203,7 @@ Option::unpack6(const boost::shared_array<uint8_t>& buf,
/// Returns length of the complete option (data length + DHCPv4/DHCPv6
/// option header)
unsigned short
uint16_t
Option::len() {
// length of the whole option is header and data stored in this option...
......@@ -295,17 +278,7 @@ std::string Option::toText(int indent /* =0 */ ) {
return tmp.str();
}
unsigned short
Option::getType() {
return type_;
}
const std::vector<uint8_t>&
Option::getData() {
return (data_);
}
unsigned short
uint16_t
Option::getHeaderLen() {
switch (universe_) {
case V4:
......
......@@ -178,20 +178,19 @@ public:
/// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
///
/// @return option type
unsigned short
getType();
unsigned short getType() { return (type_); }
/// Returns length of the complete option (data length + DHCPv4/DHCPv6
/// option header)
///
/// @return length of the option
virtual unsigned short
virtual uint16_t
len();
/// @brief Returns length of header (2 for v4, 4 for v6)
///
/// @return length of option header
virtual unsigned short
virtual uint16_t
getHeaderLen();
/// returns if option is valid (e.g. option may be truncated)
......@@ -202,9 +201,9 @@ public:
/// Returns pointer to actual data.
///
/// @return pointer to actual data (or NULL if there is no data)
virtual const std::vector<uint8_t>&
getData();
/// @return pointer to actual data (or reference to an empty vector
/// if there is no data)
virtual const std::vector<uint8_t>& getData() { return (data_); }
/// Adds a sub-option.
///
......@@ -242,20 +241,6 @@ public:
~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.
///
......
// 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 <exceptions/exceptions.h>
#include <asiolink/io_address.h>
#include <util/io_utilities.h>
#include <dhcp/option4_addrlst.h>
using namespace std;
using namespace isc::dhcp;
using namespace isc::util;
using namespace isc::asiolink;
Option4AddrLst::Option4AddrLst(uint8_t type)
:Option(V4, type) {
}
Option4AddrLst::Option4AddrLst(uint8_t type, const AddressContainer& addrs)
:Option(V4, type) {
setAddresses(addrs);
// don't set addrs_ directly. setAddresses() will do additional checks.
}
Option4AddrLst::Option4AddrLst(uint8_t type,
vector<uint8_t>::const_iterator first,
vector<uint8_t>::const_iterator last)
:Option(V4, type) {
if ( (distance(first, last) % V4ADDRESS_LEN) ) {
isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_
<< " has invalid length=" << distance(first, last)
<< ", must be divisible by 4.");
}
while (first != last) {
const uint8_t* ptr = &(*first);
addAddress(IOAddress(readUint32(ptr)));
first += V4ADDRESS_LEN;
}
}
Option4AddrLst::Option4AddrLst(uint8_t type, const IOAddress& addr)
:Option(V4, type) {
setAddress(addr);
}
void
Option4AddrLst::pack4(isc::util::OutputBuffer& buf) {
if (addrs_.size() * V4ADDRESS_LEN > 255) {
isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_ << " is too big."
<< "At most 255 bytes are supported.");
/// TODO Larger options can be stored as separate instances
/// of DHCPv4 options. Clients MUST concatenate them.
/// Fortunately, there are no such large options used today.
}
buf.writeUint8(type_);
buf.writeUint8(len() - getHeaderLen());
AddressContainer::const_iterator addr = addrs_.begin();
while (addr != addrs_.end()) {
buf.writeUint32(*addr);
++addr;
}
}
void Option4AddrLst::setAddress(const isc::asiolink::IOAddress& addr) {
if (addr.getFamily() != AF_INET) {
isc_throw(BadValue, "Can't store non-IPv4 address in "
<< "Option4AddrLst option");
}
addrs_.clear();
addAddress(addr);
}
void Option4AddrLst::setAddresses(const AddressContainer& addrs) {
// Do not copy it as a whole. addAddress() does sanity checks.
// i.e. throw if someone tries to set IPv6 address.
addrs_.clear();
for (AddressContainer::const_iterator addr = addrs.begin();
addr != addrs.end(); ++addr) {
addAddress(*addr);
}
}
void Option4AddrLst::addAddress(const isc::asiolink::IOAddress& addr) {
if (addr.getFamily() != AF_INET) {
isc_throw(BadValue, "Can't store non-IPv4 address in "
<< "Option4AddrLst option");
}
addrs_.push_back(addr);
}
uint16_t Option4AddrLst::len() {
// Returns length of the complete option (option header + data length)
return (getHeaderLen() + addrs_.size() * V4ADDRESS_LEN);
}
std::string Option4AddrLst::toText(int indent /* =0 */ ) {
std::stringstream tmp;
for (int i = 0; i < indent; i++) {
tmp << " ";
}
tmp << "type=" << type_ << ", len=" << len()-getHeaderLen() << ":";
for (AddressContainer::const_iterator addr = addrs_.begin();
addr != addrs_.end(); ++addr) {
tmp << " " << (*addr);
}
return tmp.str();
}
// 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 OPTION4_ADDRLST_H_
#define OPTION4_ADDRLST_H_
#include <string>
#include <map>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <util/buffer.h>
#include <dhcp/option.h>
namespace isc {
namespace dhcp {
/// @brief DHCPv4 Option class for handling list of IPv4 addresses.
///
/// This class handles a list of IPv4 addresses. An example of such option
/// is dns-servers option. It can also be used to handle a single address.
class Option4AddrLst : public isc::dhcp::Option {
public:
/// Defines a collection of IPv4 addresses.
typedef std::vector<isc::asiolink::IOAddress> AddressContainer;
/// @brief Constructor, creates an option with empty list of addresses.
///
/// Creates empty option that can hold addresses. Addresses can be added
/// with addAddress(), setAddress() or setAddresses().
///
/// @param type option type
Option4AddrLst(uint8_t type);
/// @brief Constructor, creates an option with a list of addresses.
///
/// Creates an option that contains specified list of IPv4 addresses.
///
/// @param type option type
/// @param addrs container with a list of addresses
Option4AddrLst(uint8_t type, const AddressContainer& addrs);
/// @brief Constructor, creates an option with a single address.
///
/// Creates an option that contains a single address.
///
/// @param type option type
/// @param addr a single address that will be stored as 1-elem. address list
Option4AddrLst(uint8_t type, const isc::asiolink::IOAddress& addr);
/// @brief Constructor, used for received options.
///
/// TODO: This can be templated to use different containers, not just
/// vector. Prototype should look like this:
/// template<typename InputIterator> Option(Universe u, uint16_t type,
/// InputIterator first, InputIterator last);
///
/// vector<int8_t> myData;
/// Example usage: new Option(V4, 123, myData.begin()+1, myData.end()-1)
/// This will create DHCPv4 option of type 123 that contains data from
/// trimmed (first and last byte removed) myData vector.
///
/// @param type option type (0-255 for V4 and 0-65535 for V6)
/// @param first iterator to the first element that should be copied
/// @param last iterator to the next element after the last one
/// to be copied.
Option4AddrLst(uint8_t type, std::vector<uint8_t>::const_iterator first,
std::vector<uint8_t>::const_iterator last);
/// @brief Writes option in a wire-format to a buffer.
///
/// Method will throw if option storing fails for some reason.
///
/// TODO Once old (DHCPv6) implementation is rewritten,
/// unify pack4() and pack6() and rename them to just pack().
///
/// @param buf output buffer (option will be stored there)
virtual void
pack4(isc::util::OutputBuffer& buf);
/// 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 length of the complete option (data length + DHCPv4/DHCPv6
/// option header)
///
/// @return length of the option
virtual uint16_t len();
/// @brief Returns vector with addresses.
///
/// We return a copy of our list. Although this includes overhead,
/// it also makes this list safe to use after this option object
/// is no longer available. As options are expected to hold only
/// a couple (1-3) addresses, the overhead is not that big.
///
/// @return address container with addresses
AddressContainer
getAddresses() { return addrs_; };
/// @brief Sets addresses list.
///
/// Clears existing list of addresses and adds a single address to that
/// list. This is very convenient method for options that are supposed to
/// only a single option. See addAddress() if you want to add
/// address to existing list or setAddresses() if you want to
/// set the whole list at once.
///
/// Passed address must be IPv4 address. Otherwire BadValue exception
/// will be thrown.
///
/// @param addrs address collection to be set
void setAddresses(const AddressContainer& addrs);
/// @brief Clears address list and sets a single address.
///
/// Clears existing list of addresses and adds a single address to that
/// list. This is very convenient method for options that are supposed to
/// only a single option. See addAddress() if you want to add
/// address to existing list or setAddresses() if you want to
/// set the whole list at once.
///
/// Passed address must be IPv4 address. Otherwire BadValue exception
/// will be thrown.
///
/// @param addr an address that is going to be set as 1-element address list
void setAddress(const isc::asiolink::IOAddress& addr);
/// @brief Adds address to existing list of addresses.
///
/// Adds a single address to that list. See setAddress() if you want to
/// define only a single address or setAddresses() if you want to
/// set the whole list at once.
///
/// Passed address must be IPv4 address. Otherwire BadValue exception
/// will be thrown.
///
/// @param addr an address thait is going to be added to existing list
void addAddress(const isc::asiolink::IOAddress& addr);
protected:
/// contains list of addresses
AddressContainer addrs_;
};
} // namespace isc::dhcp
} // namespace isc
#endif
......@@ -50,6 +50,10 @@ Option6AddrLst::Option6AddrLst(unsigned short type,
void
Option6AddrLst::setAddress(const isc::asiolink::IOAddress& addr) {
if (addr.getFamily() != AF_INET6) {
isc_throw(BadValue, "Can't store non-IPv6 address in Option6AddrLst option");
}
addrs_.clear();
addrs_.push_back(addr);
}
......@@ -128,7 +132,7 @@ std::string Option6AddrLst::toText(int indent /* =0 */) {
return tmp.str();
}
unsigned short Option6AddrLst::len() {
uint16_t Option6AddrLst::len() {
return (OPTION6_HDR_LEN + addrs_.size()*16);
}
......@@ -16,17 +16,16 @@
#define OPTION6_ADDRLST_H_
#include <vector>
#include "asiolink/io_address.h"
#include "dhcp/option.h"
#include <asiolink/io_address.h>
#include <dhcp/option.h>
namespace isc {
namespace dhcp {
/// @brief Option class for handling list of IPv6 addresses.
/// @brief DHCPv6 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:
......@@ -105,17 +104,17 @@ public:
/// @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
/// We return a copy of our list. Although this includes overhead,
/// it also makes this list safe to use after this option object
/// is no longer available. As options are expected to hold only
/// a couple (1-3) addresses, the overhead is not that big.
///
/// @return address container with addresses
AddressContainer
getAddresses() { return addrs_; };
// returns data length (data length + DHCPv4/DHCPv6 option header)
virtual unsigned short len();
virtual uint16_t len();
protected:
AddressContainer addrs_;
......
......@@ -77,7 +77,7 @@ Option6IA::unpack(const boost::shared_array<uint8_t>& buf,
if ( parse_len < OPTION6_IA_LEN || offset + OPTION6_IA_LEN > buf_len) {
isc_throw(OutOfRange, "Option " << type_ << " truncated");
}
iaid_ = readUint32(&buf[offset]);
offset += sizeof(uint32_t);
......@@ -121,9 +121,9 @@ std::string Option6IA::toText(int indent /* = 0*/) {
return tmp.str();
}
unsigned short Option6IA::len() {
uint16_t Option6IA::len() {
unsigned short length = OPTION6_HDR_LEN /*header (4)*/ +
uint16_t length = OPTION6_HDR_LEN /*header (4)*/ +
OPTION6_IA_LEN /* option content (12) */;
// length of all suboptions
......
......@@ -116,7 +116,7 @@ public:
/// Returns length of this option, including option header and suboptions
///
/// @return length of this option
virtual unsigned short
virtual uint16_t
len();
protected:
......
......@@ -116,9 +116,9 @@ std::string Option6IAAddr::toText(int indent /* =0 */) {
return tmp.str();
}
unsigned short Option6IAAddr::len() {
uint16_t Option6IAAddr::len() {
unsigned short length = OPTION6_HDR_LEN + OPTION6_IAADDR_LEN;
uint16_t length = OPTION6_HDR_LEN + OPTION6_IAADDR_LEN;
// length of all suboptions
// TODO implement:
......
......@@ -126,8 +126,7 @@ public:
getValid() const { return valid_; }
/// returns data length (data length + DHCPv4/DHCPv6 option header)
virtual unsigned short
len();
virtual uint16_t len();
protected:
/// contains an IPv6 address
......
......@@ -51,7 +51,6 @@ Pkt4::Pkt4(uint8_t msg_type, uint32_t transid)
bufferOut_(DHCPV4_PKT_HDR_LEN),
msg_type_(msg_type)
{
/// TODO: fixed fields, uncomment in ticket #1224
memset(chaddr_, 0, MAX_CHADDR_LEN);
memset(sname_, 0, MAX_SNAME_LEN);
memset(file_, 0, MAX_FILE_LEN);
......@@ -64,7 +63,6 @@ Pkt4::Pkt4(const uint8_t* data, size_t len)
ifindex_(-1),
local_port_(DHCP4_SERVER_PORT),
remote_port_(DHCP4_CLIENT_PORT),
/// TODO Fixed fields, uncomment in ticket #1224
op_(BOOTREQUEST),
transid_(0),
secs_(0),
......@@ -117,6 +115,10 @@ Pkt4::pack() {
LibDHCP::packOptions(bufferOut_, options_);
// add END option that indicates end of options
// (End option is very simple, just a 255 octet)
bufferOut_.writeUint8(DHO_END);
return (true);
}
bool
......
......@@ -18,6 +18,7 @@ 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 += ../option4_addrlst.cc ../option4_addrlst.h option4_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_SOURCES += ../pkt4.h ../pkt4.cc pkt4_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