libkea_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
libkea_dhcp___la_SOURCES += option4_client_fqdn.cc option4_client_fqdn.h
libkea_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
+libkea_dhcp___la_SOURCES += option6_auth.cc option6_auth.h
libkea_dhcp___la_SOURCES += option6_client_fqdn.cc option6_client_fqdn.h
libkea_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
libkea_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
option4_addrlst.h \
option4_client_fqdn.h \
option6_addrlst.h \
+ option6_auth.h \
option6_client_fqdn.h \
option6_ia.h \
option6_iaaddr.h \
--- /dev/null
+// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_auth.h>
+#include <dhcp/option_space.h>
+#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+
+#include <sstream>
+#include <stdint.h>
+
+using namespace std;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+ Option6Auth::Option6Auth(const uint8_t proto, const uint8_t algo,
+ const uint8_t method, const uint64_t rdm,
+ const std::vector<uint8_t>& info)
+ : Option(Option::V6, D6O_AUTH),
+ protocol_(proto), algorithm_(algo),
+ rdm_method_(method), rdm_value_(rdm),
+ auth_info_(info) {
+}
+
+OptionPtr
+Option6Auth::clone() const {
+ return (cloneInternal<Option6Auth>());
+}
+
+void
+Option6Auth::pack(isc::util::OutputBuffer& buf) const {
+ if (buf.getCapacity() < (OPTION6_AUTH_MIN_LEN + OPTION6_HASH_MSG_LEN)) {
+ isc_throw(OutOfRange, "Option " << type_ << "No space for"
+ "computing packing data");
+ }
+
+ //header = option code + length
+ buf.writeUint16(type_);
+ // length = 11 bytes fixed field length+ length of auth information
+ buf.writeUint16(11 + uint16_t(auth_info_.size()));
+ // protocol 1 byte
+ buf.writeUint8(protocol_);
+ // algoritm 1 byte
+ buf.writeUint8(algorithm_);
+ // replay detection method
+ buf.writeUint8(rdm_method_);
+ // replay detection value
+ buf.writeUint64( rdm_value_);
+ // authentication information for reconfig msg
+ // should have zero
+
+ for (auto i : auth_info_) {
+ buf.writeUint8(i);
+ }
+}
+
+void
+Option6Auth::packHashInput(isc::util::OutputBuffer& buf) const {
+ if (buf.getCapacity() < (OPTION6_AUTH_MIN_LEN + OPTION6_HASH_MSG_LEN)) {
+ isc_throw(OutOfRange, "Option " << type_ << "No space for"
+ "computing hash input");
+ }
+
+ //header = option code + length
+ buf.writeUint16(type_);
+ // length = 11 bytes fixed field length+ length of auth information
+ buf.writeUint16(OPTION6_AUTH_MIN_LEN + OPTION6_HASH_MSG_LEN);
+ // protocol 1 byte
+ buf.writeUint8(protocol_);
+ // algoritm 1 byte
+ buf.writeUint8(algorithm_);
+ // replay detection method
+ buf.writeUint8(rdm_method_);
+ // replay detection value
+ buf.writeUint64(rdm_value_);
+ // authentication information for reconfig msg
+ // should have zero
+ for (uint8_t i = 0; i < OPTION6_HASH_MSG_LEN; i++) {
+ buf.writeUint8(0);
+ }
+}
+
+void
+Option6Auth::unpack(OptionBufferConstIter begin,
+ OptionBufferConstIter end) {
+ // throw if it contains length less than minimum size of the auth option
+ if (distance(begin, end) < Option6Auth::OPTION6_AUTH_MIN_LEN) {
+ isc_throw(OutOfRange, "Option " << type_ << " truncated");
+ }
+
+ protocol_ = *begin;
+ begin += sizeof(uint8_t);
+
+ algorithm_ = *begin;
+ begin += sizeof(uint8_t);
+
+ rdm_method_ = *begin;
+ begin += sizeof(uint8_t);
+
+ rdm_value_ = isc::util::readUint64(&(*begin), sizeof(uint64_t));
+ begin += sizeof(uint64_t);
+
+ auth_info_.erase(auth_info_.begin(), auth_info_.end());
+ std::for_each(begin, end, [this](uint8_t msgdata)
+ { auth_info_.push_back(msgdata); });
+}
+
+std::string
+Option6Auth::toText(int indent) const {
+ stringstream output;
+ std::string in(indent, ' '); //base indent
+
+ output << in << "protocol= " << protocol_ << "algorithm= " << algorithm_
+ << "rdm method= " << rdm_method_ << "rdm value= " << rdm_value_ ;
+ return std::string(output);
+}
+
+} // end namespace dhcp
+} // end namespace isc
--- /dev/null
+// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef OPTION6_AUTH_H
+#define OPTION6_AUTH_H
+#endif
+
+#include <dhcp/option.h>
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+class Option6Auth;
+
+/// A pointer to the @c isc::dhcp::Option6Auth object.
+typedef boost::shared_ptr<Option6Auth> Option6AuthPtr;
+
+class Option6Auth: public Option {
+
+public:
+
+ static const uint8_t OPTION6_AUTH_MIN_LEN = 11;
+ static const uint8_t OPTION6_HASH_MSG_LEN = 16;
+ /// @brief Constructor, used for auth options while transmitting
+ ///
+ /// @param proto protocol type
+ /// @param algo algorithm type
+ /// @param method remote detection method
+ /// @param rdm replay detection value
+ /// @param info authentication info.
+ Option6Auth(const uint8_t proto, const uint8_t algo, const uint8_t method,
+ const uint64_t rdm, const std::vector<uint8_t>& info);
+
+ /// @brief Copies this option and returns a pointer to the copy.
+ virtual OptionPtr clone() const;
+
+ /// Writes option in wire-format to buf, returns pointer to first unused
+ /// byte after stored option.
+ ///
+ /// @param buf buffer (option will be stored here)
+ void pack(isc::util::OutputBuffer& buf) const;
+
+ /// Writes option in wire-format to buf, for computing hash
+ /// auth info filled with 0 for a length of 128 bits
+ /// returns with pointer to first unused
+ /// byte after stored option.
+ ///
+ /// @param buf buffer (option will be stored here)
+ void packHashInput(isc::util::OutputBuffer& buf) const;
+
+ /// @brief Parses received buffer
+ /// @brief Parses received buffer
+ ///
+ /// Parses received buffer and returns offset to the first unused byte after
+ /// parsed option.
+ ///
+ /// @param begin iterator to first byte of option data
+ /// @param end iterator to end of option data (first byte after option end)
+ virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+ /// Provides human readable text representation
+ ///
+ /// @param indent number of leading space characters
+ ///
+ /// @return string with text representation
+ virtual std::string toText(int indent = 0) const;
+
+ /// Set protocol type
+ ///
+ /// @param proto protocol type to be set
+ void setProtocol(uint8_t proto) { protocol_ = proto; }
+
+ /// Set hash alogrithm type
+ ///
+ /// @param algo hash alogrithm type to be set
+ void setHashAlgo(uint8_t algo) { algorithm_ = algo; }
+
+ /// Set replay detection method type
+ ///
+ /// @param method replay detection method to be set
+ void setRplyDtctnMthd(uint8_t method) { rdm_method_ = method; }
+
+ /// Set replay detection method value
+ ///
+ /// @param rdm replay detection method value to be set
+ void setRplyDtctnValue(uint64_t value) { rdm_value_ = value; }
+ /// Set authentication information
+ ///
+ /// @param auth_info authentication information to be set
+ void setAuthInfo(const std::vector<uint8_t>& auth_info) { auth_info_ = auth_info; }
+
+ /// Returns protocol type
+ ///
+ /// @return protocol value
+ uint8_t getProtocol() const { return protocol_; }
+
+ /// Returns hash algorithm type
+ ///
+ /// @return hash algorithm value
+ uint8_t getHashAlgo() const { return algorithm_; }
+
+ /// Returns replay detection method type
+ ///
+ /// @return replay detection method type value
+ uint8_t getRplyDtctnMthd() const { return rdm_method_; }
+
+ /// Return replay detection mechanism
+ ///
+ /// @return replay detection method value
+ uint64_t getRplyDtctnValue() const { return rdm_value_; }
+
+ /// Return authentication information
+ ///
+ /// @return authentication information value
+ std::vector<uint8_t> getAuthInfo() const { return auth_info_; }
+
+protected:
+ /// keeps protocol type
+ uint8_t protocol_;
+
+ /// keeps hash algorithm value
+ uint8_t algorithm_;
+
+ /// keeps replay detection method type
+ uint8_t rdm_method_;
+
+ /// keeps replay detection method value
+ uint64_t rdm_value_;
+
+ /// keeps authentication information
+ std::vector<uint8_t> auth_info_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
libdhcp___unittests_SOURCES += option4_client_fqdn_unittest.cc
libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option6_client_fqdn_unittest.cc
+libdhcp___unittests_SOURCES += option6_auth_unittest.cc
libdhcp___unittests_SOURCES += option6_ia_unittest.cc
libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
libdhcp___unittests_SOURCES += option6_iaprefix_unittest.cc
--- /dev/null
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_auth.h>
+#include <util/buffer.h>
+
+#include <gtest/gtest.h>
+#include <boost/scoped_ptr.hpp>
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::util;
+using boost::scoped_ptr;
+
+namespace {
+class Option6AuthTest : public ::testing::Test {
+public:
+ Option6AuthTest(): buff_(28) {
+ }
+ OptionBuffer buff_;
+};
+
+// check constructor, setters and getters
+TEST_F(Option6AuthTest, basic) {
+
+ scoped_ptr<Option6Auth> auth;
+ ASSERT_NO_THROW(auth.reset(new Option6Auth(1,2,0,0x9000,{'a','b','c','d'})));
+
+ ASSERT_EQ(1, auth->getProtocol());
+ ASSERT_EQ(2, auth->getHashAlgo());
+ ASSERT_EQ(0, auth->getRplyDtctnMthd());
+ ASSERT_EQ(0x9000, auth->getRplyDtctnValue());
+
+ std::vector<uint8_t> test_buf = {'a','b','c','d'};
+ ASSERT_EQ(test_buf, auth->getAuthInfo());
+
+ auth->setProtocol(2);
+ auth->setHashAlgo(3);
+ auth->setRplyDtctnMthd(1);
+ auth->setRplyDtctnValue(109034830);
+ auth->setAuthInfo({1,2,3,4});
+
+ ASSERT_EQ(2, auth->getProtocol());
+ ASSERT_EQ(3, auth->getHashAlgo());
+ ASSERT_EQ(1, auth->getRplyDtctnMthd());
+ ASSERT_EQ(109034830, auth->getRplyDtctnValue());
+
+ test_buf = {1,2,3,4};
+ ASSERT_EQ(test_buf, auth->getAuthInfo());
+}
+
+//Check if all the fields are properly parsed and stored
+// todo define userdefined literal and add packing function to it
+TEST_F(Option6AuthTest, parseFields) {
+ buff_[0] = 0xa1; //protocol
+ buff_[1] = 0xa2; //algo
+ buff_[2] = 0xa3; //rdm method
+ buff_[3] = 0xa4; //rdm value
+ buff_[4] = 0xa5; //rdm value
+ buff_[5] = 0xa6; //rdm value
+ buff_[6] = 0xa7; //rdm value
+ buff_[7] = 0xa8; //rdm value
+ buff_[8] = 0xa9; //rdm value
+ buff_[9] = 0xaa; //rdm value
+ buff_[10] = 0xab; //rdm value
+ for ( uint8_t i = 11; i < 27; i++ ) {
+ buff_[i] = 0xa8; //auth info 16 bytes
+ }
+
+ scoped_ptr<Option6Auth> auth;
+ auth.reset(new Option6Auth(1,2,0,9000,{'a','b','c','d'}));
+
+ auth->unpack(buff_.begin(), buff_.begin()+27); //26 element is 16 byte offset from 10
+
+ std::vector<uint8_t> test_buf(16,0xa8);
+ ASSERT_EQ(0xa1, auth->getProtocol());
+ ASSERT_EQ(0xa2, auth->getHashAlgo());
+ ASSERT_EQ(0xa3, auth->getRplyDtctnMthd());
+ ASSERT_EQ(0xa4a5a6a7a8a9aaab, auth->getRplyDtctnValue());
+ ASSERT_EQ(test_buf, auth->getAuthInfo());
+}
+
+//Check of the options are correctly packed and set
+TEST_F(Option6AuthTest, setFields) {
+ scoped_ptr<Option6Auth> auth;
+ std::vector<uint8_t> test_buf(16,0xa8);
+ auth.reset(new Option6Auth(1,2,0,0x0090000000000000,test_buf));
+
+ isc::util::OutputBuffer buf(29);//2 header + fixed 11 and key 16
+ ASSERT_NO_THROW(auth->pack(buf));
+
+ const uint8_t ref_data[] = {
+ 0, 11, 0, 27, 1, 2, 0, //header , proto algo method
+ 0, 0x90, 0, 0, 0, 0, 0, 0, //64 bit rdm field
+ 0xa8, 0xa8, 0xa8, 0xa8, //128 bits/16 byte key
+ 0xa8, 0xa8, 0xa8, 0xa8,
+ 0xa8, 0xa8, 0xa8, 0xa8,
+ 0xa8, 0xa8, 0xa8, 0xa8
+ };
+ //first check if they are of equal size
+ ASSERT_EQ(buf.getLength(), sizeof(ref_data));
+
+ //evaluate the contents of the option byte by byte
+ ASSERT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
+}
+
+TEST_F(Option6AuthTest, checkHashInput) {
+ scoped_ptr<Option6Auth> auth;
+
+ std::vector<uint8_t> test_buf(16,0xa8);
+ std::vector<uint8_t> hash_op(16,0x00);
+ auth.reset(new Option6Auth(1,2,0,0x0090000000000000,test_buf));
+
+ isc::util::OutputBuffer buf(29);
+ auth->packHashInput(buf);
+ //auth info must be 0 for calculating the checksum
+ const uint8_t ref_data[] = {
+ 0, 11, 0, 27, 1, 2, 0, //header , proto algo method
+ 0, 0x90, 0, 0, 0, 0, 0, 0, //64 bit rdm field
+ 0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
+ 0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
+ 0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
+ 0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
+ };
+ //first check if they are of equal size
+ ASSERT_EQ(buf.getLength(), sizeof(ref_data));
+
+ //evaluate the contents of the option byte by byte
+ ASSERT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
+}
+
+} //end namespace
buffer_[size_ ++] = static_cast<uint8_t>(data & 0x000000ff);
}
+ /// \brief Write an unsigned 64-bit integer in host byte order
+ /// into the buffer in network byte order.
+ ///
+ /// \param data The 64-bit integer to be written into the buffer.
+ void writeUint64(uint64_t data) {
+ ensureAllocated(size_ + sizeof(data));
+ buffer_[size_ ++] = static_cast<uint8_t>((data & 0xff00000000000000) >> 56);
+ buffer_[size_ ++] = static_cast<uint8_t>((data & 0x00ff000000000000) >> 48);
+ buffer_[size_ ++] = static_cast<uint8_t>((data & 0x0000ff0000000000) >> 40);
+ buffer_[size_ ++] = static_cast<uint8_t>((data & 0x000000ff00000000) >> 32);
+ buffer_[size_ ++] = static_cast<uint8_t>((data & 0x00000000ff000000) >> 24);
+ buffer_[size_ ++] = static_cast<uint8_t>((data & 0x0000000000ff0000) >> 16);
+ buffer_[size_ ++] = static_cast<uint8_t>((data & 0x000000000000ff00) >> 8);
+ buffer_[size_ ++] = static_cast<uint8_t>(data & 0x00000000000000ff);
+ }
+
/// \brief Copy an arbitrary length of data into the buffer.
///
/// No conversion on the copied data is performed.
return (result);
}
+/// \brief Read Unsigned 64-Bit Integer from Buffer
+///
+/// \param buffer Data buffer at least four bytes long of which the first four
+/// bytes are assumed to represent a 64-bit integer in network-byte
+/// order.
+/// \param length Length of the data buffer.
+///
+/// \return Value of 64-bit unsigned integer
+inline uint64_t
+readUint64(const uint8_t* buffer, size_t length) {
+ if (length < sizeof(uint64_t)) {
+ isc_throw(isc::OutOfRange,
+ "Length (" << length << ") of buffer is insufficient " <<
+ "to read a uint64_t");
+ }
+
+ const uint8_t* byte_buffer = static_cast<const uint8_t*>(buffer);
+
+ uint64_t result = (static_cast<uint64_t>(byte_buffer[0])) << 56;
+ result |= (static_cast<uint64_t>(byte_buffer[1])) << 48;
+ result |= (static_cast<uint64_t>(byte_buffer[2])) << 40;
+ result |= (static_cast<uint64_t>(byte_buffer[3])) << 32;
+ result |= (static_cast<uint64_t>(byte_buffer[4])) << 24;
+ result |= (static_cast<uint64_t>(byte_buffer[5])) << 16;
+ result |= (static_cast<uint64_t>(byte_buffer[6])) << 8;
+ result |= (static_cast<uint64_t>(byte_buffer[7]));
+
+
+ return (result);
+}
+
/// \brief Write Unsigned 32-Bit Integer to Buffer
///
/// \param value 32-bit value to convert