},
]
},
+ { "item_name": "4o6-enable",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": false,
+ "item_description": "Enable DHCPv4 over DHCPv6 function"
+ },
],
"commands": [
53 is valid but the message will not be processed by the server. This includes
messages being normally sent by the server to the client, such as Offer, ACK,
NAK etc.
+
+% DHCP4_IPC_CONSTRUCT_ERROR failed to create DHCP4o6IPC in DHCPv4 server
+This error message indicates that the construction of a
+DHCP4o6 IPC within the DHCPv4 server has failed.
+As a result, DHCPv4 over DHCPv6 function is disabled.
+The server will continue running its regular DHCPv4 function.
+
+% DHCP4_IPC_SEND_ERROR failed to send message through DHCP4o6IPC
+This error message indicates that the DHCP4o6IPC failed to send
+a packet through unix socket.
Pkt4Ptr query;
Pkt4Ptr rsp;
- try {
- query = receivePacket(timeout);
+ // 4o6
+ bool dhcp4o6Request = false;
+ if (!query && ipc_ && !ipc_->empty()) {
+ query = ipc_->pop()->getPkt4();
+ dhcp4o6Request = true;
+
+ //set Pkt4's localAddr according to U flag in Pkt6's transid field
+ ipc_->currentPkt4o6()->setPkt4LocalAddr();
+ }
+ try {
+ if (!query) {
+ query = receivePacket(timeout);
+ }
} catch (const SignalInterruptOnSelect) {
// Packet reception interrupted because a signal has been received.
// This is not an error because we might have received a SIGTERM,
DHCP4_RESPONSE_DATA)
.arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
- sendPacket(rsp);
+ if (ipc_ && dhcp4o6Request) {//4o6
+ try {
+ Pkt4o6Ptr rsp4o6(new Pkt4o6(ipc_->currentPkt4o6(), rsp));
+ ipc_->sendPkt4o6(rsp4o6);
+ } catch (const Exception& ex) {
+ LOG_ERROR(dhcp4_logger, DHCP4_IPC_SEND_ERROR).arg(ex.what());
+ }
+ } else {
+ sendPacket(rsp);
+ }
} catch (const std::exception& e) {
LOG_ERROR(dhcp4_logger, DHCP4_PACKET_SEND_FAIL)
.arg(e.what());
CfgMgr::instance().getD2ClientMgr().suspendUpdates();
}
+void
+Dhcpv4Srv::enable4o6() {
+ /// init DHCP4o6 IPC
+ try {
+ ipc_ = DHCP4o6IPCPtr(new DHCP4o6IPC("DHCPv4_over_DHCPv6_v6tov4",
+ "DHCPv4_over_DHCPv6_v4tov6"));
+ } catch (const Exception &e) {
+ LOG_ERROR(dhcp4_logger, DHCP4_IPC_CONSTRUCT_ERROR).arg(e.what());
+ ipc_ = DHCP4o6IPCPtr();
+ }
+ if (!ipc_)
+ return;
+ IfaceMgr::instance().addExternalSocket(ipc_->getSocket(),
+ boost::bind(&DHCP4o6IPC::recvPkt4o6, ipc_));
+}
+
+void
+Dhcpv4Srv::disable4o6() {
+ if (!ipc_)
+ return;
+ IfaceMgr::instance().deleteExternalSocket(ipc_->getSocket());
+ ipc_ = boost::shared_ptr<DHCP4o6IPC>();
+}
+
std::string
Daemon::getVersion(bool extended) {
std::stringstream tmp;
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/alloc_engine.h>
#include <hooks/callout_handle.h>
+#include <dhcpsrv/dhcp4o6_ipc.h>
#include <dhcpsrv/daemon.h>
#include <boost/noncopyable.hpp>
virtual void d2ClientErrorHandler(const dhcp_ddns::
NameChangeSender::Result result,
dhcp_ddns::NameChangeRequestPtr& ncr);
+
+ /// @brief Enable DHCPv4 over DHCPv6 function
+ ///
+ /// Calling this method enables 4o6 function in dhcpv4 server
+ void enable4o6();
+
+ /// @brief Disable DHCPv4 over DHCPv6 function
+ ///
+ /// Calling this method disables 4o6 function in dhcpv4 server
+ void disable4o6();
+
protected:
/// @name Functions filtering and sanity-checking received messages.
int hook_index_pkt4_receive_;
int hook_index_subnet4_select_;
int hook_index_pkt4_send_;
+
+ /// IPC used for communation with dhcp4_srv (for RFC7341).
+ DHCP4o6IPCPtr ipc_;
};
}; // namespace isc::dhcp
#include <dhcpsrv/option_space_container.h>
#include <util/encode/hex.h>
#include <util/strutil.h>
+#include <dhcp4/dhcp4_srv.h>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
parser = new DbAccessParser(config_id, *globalContext());
} else if (config_id.compare("hooks-libraries") == 0) {
parser = new HooksLibrariesParser(config_id);
- } else if (config_id.compare("echo-client-id") == 0) {
+ } else if ((config_id.compare("echo-client-id") == 0) ||
+ (config_id.compare("4o6-enable") == 0)) {
parser = new BooleanParser(config_id, globalContext()->boolean_values_);
} else if (config_id.compare("dhcp-ddns") == 0) {
parser = new D2ClientConfigParser(config_id);
}
isc::data::ConstElementPtr
-configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
+configureDhcp4Server(Dhcpv4Srv& srv, isc::data::ConstElementPtr config_set) {
if (!config_set) {
ConstElementPtr answer = isc::config::createAnswer(1,
string("Can't parse NULL config"));
// but we need it so as the subnet6 parser can access the
// parsed data.
parser->commit();
+ if (config_pair.first == "4o6-enable") {
+ try {
+ if (config_pair.second->boolValue()) {
+ srv.enable4o6();
+ } else {
+ srv.disable4o6();
+ }
+ } catch (const isc::Exception& e) {
+ //TODO: do someting
+ }
+ }
}
}
},
]
},
+ { "item_name": "4o6-enable",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": false,
+ "item_description": "Enable DHCPv4 over DHCPv6 function"
+ },
+
],
"commands": [
{
lease, but no such lease is known by the server. See the explanation
of the status code DHCP6_UNKNOWN_RENEW_PD for possible reasons for
such behavior.
+
+% DHCP6_IPC_CONSTRUCT_ERROR failed to create DHCP4o6IPC in DHCPv6 server
+This error message indicates that the construction of a
+DHCP4o6 IPC within the DHCPv6 server has failed.
+As a result, DHCPv4 over DHCPv6 function is disabled.
+The server will continue running its regular DHCPv6 function.
+
+% DHCP6_IPC_SEND_ERROR failed to send message through DHCP4o6IPC
+This error message indicates that the DHCP4o6IPC failed to send
+a packet through unix socket.
#include <util/encode/hex.h>
#include <util/io_utilities.h>
#include <util/range_utilities.h>
+#include <dhcp/pkt4o6.h> //used by DHCP4o6
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
->cfg_iface_.setFamily(CfgIface::V6);
/// @todo call loadLibraries() when handling configuration changes
-
+
} catch (const std::exception &e) {
LOG_ERROR(dhcp6_logger, DHCP6_SRV_CONSTRUCT_ERROR).arg(e.what());
return;
// client's message and server's response
Pkt6Ptr query;
Pkt6Ptr rsp;
+
+ // 4o6
+ bool dhcp4o6Response = false;
+ if (!query && ipc_ && !ipc_->empty()) {
+ query = ipc_->pop()->getPkt6();
+ dhcp4o6Response = true;
+ }
try {
- query = receivePacket(timeout);
-
+ if (!query) {
+ query = receivePacket(timeout);
+ }
} catch (const SignalInterruptOnSelect) {
// Packet reception interrupted because a signal has been received.
// This is not an error because we might have received a SIGTERM,
case DHCPV6_INFORMATION_REQUEST:
rsp = processInfRequest(query);
break;
+
+ case DHCPV4_QUERY:
+ if (dhcp4o6Response)
+ rsp = processDHCPv4Response(query);
+ else
+ processDHCPv4Query(query);
+ break;
default:
// We received a packet type that we do not recognize.
return reply;
}
+void
+Dhcpv6Srv::processDHCPv4Query(const Pkt6Ptr& query) {
+ try {
+ Pkt4o6Ptr pkt4o6(new Pkt4o6(query));
+ ipc_->sendPkt4o6(pkt4o6);
+ } catch (const Exception& ex) {
+ LOG_ERROR(dhcp6_logger, DHCP6_IPC_SEND_ERROR).arg(ex.what());
+ }
+}
+
+Pkt6Ptr
+Dhcpv6Srv::processDHCPv4Response(const Pkt6Ptr& query) {
+ Pkt6Ptr reply = Pkt6Ptr(new Pkt6(DHCPV4_RESPONSE, query->getTransid()));
+
+ appendRequestedOptions(query, reply);//TODO: should we remove this?
+
+ OptionPtr option(new Option(Option::V6,
+ OPTION_DHCPV4_MSG,
+ ipc_->currentPkt4o6()->getDHCPv4MsgOption()));
+ reply->addOption(option);
+
+ //Add relay info
+ if (!query->relay_info_.empty()) {
+ reply->copyRelayInfo(query);
+ }
+ return reply;
+}
+
+
+void
+Dhcpv6Srv::enable4o6() {
+ /// init DHCP4o6 IPC
+ try {
+ ipc_ = DHCP4o6IPCPtr(new DHCP4o6IPC("DHCPv4_over_DHCPv6_v4tov6",
+ "DHCPv4_over_DHCPv6_v6tov4"));
+ } catch (const Exception &e) {
+ LOG_ERROR(dhcp6_logger, DHCP6_IPC_CONSTRUCT_ERROR).arg(e.what());
+ ipc_ = DHCP4o6IPCPtr();
+ }
+ if (!ipc_)
+ return;
+ IfaceMgr::instance().addExternalSocket(ipc_->getSocket(),
+ boost::bind(&DHCP4o6IPC::recvPkt4o6, ipc_));
+}
+
+void
+Dhcpv6Srv::disable4o6() {
+ if (!ipc_)
+ return;
+ IfaceMgr::instance().deleteExternalSocket(ipc_->getSocket());
+ ipc_ = boost::shared_ptr<DHCP4o6IPC>();
+}
+
size_t
Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
const std::string& option_space,
#include <dhcpsrv/d2_client_mgr.h>
#include <dhcpsrv/subnet.h>
#include <hooks/callout_handle.h>
+#include <dhcpsrv/dhcp4o6_ipc.h> //4o6
#include <dhcpsrv/daemon.h>
#include <iostream>
NameChangeSender::Result result,
dhcp_ddns::NameChangeRequestPtr& ncr);
+ /// @brief Enable DHCPv4 over DHCPv6 function
+ ///
+ /// Calling this method enables 4o6 function in dhcpv6 server
+ void enable4o6();
+
+ /// @brief Disable DHCPv4 over DHCPv6 function
+ ///
+ /// Calling this method disables 4o6 function in dhcpv6 server
+ void disable4o6();
+
protected:
/// @brief Compare received server id with our server id
///
/// @param infRequest message received from client
Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
+
+ /// @brief Processing incoming DHCPv4-QUERY messages.
+ ///
+ /// Processes incoming DHCPv4-QUERY messages (DHCPv4 over DHCPv6) from clients.
+ /// Payload DHCPv4 message from clients will be sent to dhcp4_srv through ipc.
+ ///
+ /// @param query DHCPv4-QUERY message received from client
+ void processDHCPv4Query(const Pkt6Ptr& query);
+ /// @brief Processing DHCPv4 response from dhcpv4 server.
+ ///
+ /// Processes DHCPv4 response from dhcp4_srv (used by DHCPv4 over DHCPv6).
+ /// DHCPv4 response from dhcp4_srv will result a DHCPv4-RESPONSE packet and
+ /// send back to the client.
+ ///
+ /// @param query Raw DHCPv4 message and original DHCPv6 information
+ /// received from dhcp4_srv.
+ Pkt6Ptr processDHCPv4Response(const Pkt6Ptr& query);
+
/// @brief Creates status-code option.
///
/// @param code status code value (see RFC3315)
/// UDP port number on which server listens.
uint16_t port_;
+
+ /// IPC used for communation with dhcp4_srv (for RFC7341).
+ DHCP4o6IPCPtr ipc_;
protected:
#include <log/logger_support.h>
#include <util/encode/hex.h>
#include <util/strutil.h>
+#include <dhcp6/dhcp6_srv.h>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("dhcp-ddns") == 0) {
parser = new D2ClientConfigParser(config_id);
+ } else if (config_id.compare("4o6-enable") == 0) {
+ parser = new BooleanParser(config_id, globalContext()->boolean_values_);
} else {
isc_throw(DhcpConfigError,
"unsupported global configuration parameter: "
}
isc::data::ConstElementPtr
-configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
+configureDhcp6Server(Dhcpv6Srv& srv, isc::data::ConstElementPtr config_set) {
if (!config_set) {
ConstElementPtr answer = isc::config::createAnswer(1,
string("Can't parse NULL config"));
// but we need it so as the subnet6 parser can access the
// parsed data.
parser->commit();
+ if (config_pair.first == "4o6-enable") {
+ try {
+ if (config_pair.second->boolValue()) {
+ srv.enable4o6();
+ } else {
+ srv.disable4o6();
+ }
+ } catch (const isc::Exception& e) {
+ //TODO: do someting
+ }
+ }
}
}
libkea_dhcp___la_SOURCES += pkt_filter_inet.cc pkt_filter_inet.h
libkea_dhcp___la_SOURCES += pkt_filter_inet6.cc pkt_filter_inet6.h
+#DHCP4o6
+libkea_dhcp___la_SOURCES += pkt4o6.cc pkt4o6.h
+
# Utilize Linux Packet Filtering on Linux.
if OS_LINUX
libkea_dhcp___la_SOURCES += pkt_filter_lpf.cc pkt_filter_lpf.h
-// Copyright (C) 2006-2011 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2006-2014 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
#define STATUS_NotConfigured 9
#define STATUS_NotAllowed 10
+/* DHCPv4 Message Option, defined in RFC 7341 */
+#define OPTION_DHCPV4_MSG 87
+
/*
* DHCPv6 message types, defined in section 5.3 of RFC 3315
*/
#define DHCPV6_LEASEQUERY 14
#define DHCPV6_LEASEQUERY_REPLY 15
+/*
+ * DHCPv4-query and DHCPv4-response message types,
+ * defined in RFC 7341
+ */
+#define DHCPV4_QUERY 20
+#define DHCPV4_RESPONSE 21
+
extern const char *dhcpv6_type_names[];
extern const int dhcpv6_type_name_max;
--- /dev/null
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")\r
+//\r
+// Permission to use, copy, modify, and/or distribute this software for any\r
+// purpose with or without fee is hereby granted, provided that the above\r
+// copyright notice and this permission notice appear in all copies.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH\r
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\r
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\r
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r
+// PERFORMANCE OF THIS SOFTWARE.\r
+\r
+#include <dhcp/pkt4o6.h>\r
+#include <dhcp/dhcp4.h>\r
+#include <asiolink/io_address.h>\r
+\r
+#include <boost/property_tree/ptree.hpp>\r
+#include <boost/property_tree/json_parser.hpp>\r
+#include <sstream>\r
+\r
+using namespace std;\r
+\r
+namespace isc {\r
+namespace dhcp {\r
+ \r
+Pkt4o6::Pkt4o6(const uint8_t* data4, size_t len4,\r
+ const uint8_t* data6, size_t len6)\r
+ :pkt4_(new Pkt4(data4, len4)),\r
+ pkt6_(new Pkt6(data6, len6))\r
+{\r
+ pkt6_->repack();//call repack() to generate outputBuffer\r
+ pkt4_->repack();//call repack() to generate outputBuffer\r
+}\r
+\r
+Pkt4o6::Pkt4o6(const Pkt6Ptr& pkt6) {\r
+ if (pkt6->getType() != DHCPV4_QUERY && \r
+ pkt6->getType() != DHCPV4_RESPONSE) {\r
+ isc_throw(Pkt4o6ConstructError,\r
+ "The DHCPv6 packet is not DHCPV4_QUERY or DHCPV4_RESPONSE");\r
+ }\r
+ OptionPtr opt = pkt6->getOption(OPTION_DHCPV4_MSG);\r
+ if (opt) {\r
+ const OptionBuffer& data = opt->getData();\r
+ pkt4_ = Pkt4Ptr(new Pkt4(data.data(), data.size()));\r
+ } else {\r
+ isc_throw(Pkt4o6ConstructError,\r
+ "The DHCPv6 message doesn't contain a DHCPv4 Message Option");\r
+ }\r
+ \r
+ pkt6_ = pkt6;\r
+ pkt6_->repack();//call repack() to generate outputBuffer\r
+ pkt4_->repack();//call repack() to generate outputBuffer\r
+}\r
+\r
+Pkt4o6::Pkt4o6(const Pkt4o6Ptr& pkt4o6, const Pkt4Ptr& pkt4) {\r
+ pkt4_ = pkt4;\r
+ pkt6_ = pkt4o6->getPkt6();\r
+}\r
+\r
+void\r
+Pkt4o6::setPkt4LocalAddr() {\r
+ if (pkt4_ && pkt6_) {\r
+ pkt6_->unpack();\r
+ if (pkt6_->getTransid() & 0x800000) {//U flag is 1, pkt4 sent unicast\r
+ pkt4_->setLocalAddr(isc::asiolink::IOAddress("8.8.8.8"));\r
+ } else {//u flag is 0, pkt4 sent to broadcast\r
+ pkt4_->setLocalAddr(isc::asiolink::IOAddress("255.255.255.255"));\r
+ }\r
+ }\r
+}\r
+\r
+std::string\r
+Pkt4o6::getJsonAttribute() {\r
+ using boost::property_tree::ptree;\r
+ ptree pt;\r
+ pt.put("RemoteAddr", pkt6_->getRemoteAddr().toText());\r
+ pt.put("LocalAddr", pkt6_->getLocalAddr().toText());\r
+ pt.put("RemotePort", pkt6_->getRemotePort());\r
+ pt.put("LocalPort", pkt6_->getLocalPort());\r
+ pt.put("Index", pkt6_->getIndex());\r
+ pt.put("Iface", pkt6_->getIface());\r
+ std::stringstream sout;\r
+ write_json(sout, pt);\r
+ return (sout.str());\r
+}\r
+\r
+void\r
+Pkt4o6::setJsonAttribute(std::string json) {\r
+ using boost::property_tree::ptree;\r
+ std::istringstream sin(json);\r
+ ptree pt;\r
+ read_json(sin, pt);\r
+ try {\r
+ pkt6_->setRemoteAddr(isc::asiolink::IOAddress(pt.get<std::string>("RemoteAddr")));\r
+ pkt6_->setLocalAddr(isc::asiolink::IOAddress(pt.get<std::string>("LocalAddr")));\r
+ pkt6_->setRemotePort(pt.get<uint16_t>("RemotePort"));\r
+ pkt6_->setLocalPort(pt.get<uint16_t>("LocalPort"));\r
+ pkt6_->setIndex(pt.get<uint32_t>("Index"));\r
+ pkt6_->setIface(pt.get<std::string>("Iface"));\r
+ \r
+ pkt4_->setIface(pkt6_->getIface());\r
+ } catch (const std::exception& ex) {\r
+ //TODO: logging\r
+ }\r
+}\r
+\r
+OptionBuffer\r
+Pkt4o6::getDHCPv4MsgOption() {\r
+ const isc::util::OutputBuffer &buf(pkt4_->getBuffer());\r
+ uint8_t* head = (uint8_t*)buf.getData();\r
+ OptionBuffer ret(head, head + buf.getLength());\r
+ return ret;\r
+}\r
+\r
+}\r
+}\r
--- /dev/null
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")\r
+//\r
+// Permission to use, copy, modify, and/or distribute this software for any\r
+// purpose with or without fee is hereby granted, provided that the above\r
+// copyright notice and this permission notice appear in all copies.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH\r
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\r
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\r
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r
+// PERFORMANCE OF THIS SOFTWARE.\r
+\r
+#ifndef PKT4o6_H\r
+#define PKT4o6_H\r
+\r
+#include <dhcp/pkt6.h>\r
+#include <dhcp/pkt4.h>\r
+#include <dhcp/option.h>\r
+#include <dhcp/dhcp6.h>\r
+\r
+namespace isc {\r
+\r
+namespace dhcp {\r
+\r
+/// @brief Pkt4o6 exception thrown when construction fails.\r
+class Pkt4o6ConstructError : public Exception {\r
+public:\r
+ Pkt4o6ConstructError(const char* file, size_t line, const char* what) :\r
+ isc::Exception(file, line, what) { };\r
+};\r
+\r
+/// Forward declaration for Pkt4o6\r
+class Pkt4o6;\r
+\r
+/// Pointer of Pkt4o6\r
+typedef boost::shared_ptr<Pkt4o6> Pkt4o6Ptr;\r
+\r
+/// @brief DHCPv4 over DHCPv6 packet (RFC 7341)\r
+///\r
+/// It represents DHCPv4o6 packet by including a Pkt4ptr and a Pkt6ptr \r
+/// member variables. Generally the Pkt4ptr points to its DHCPv4 message\r
+/// content, and Pkt6ptr gives DHCPv6 information.\r
+class Pkt4o6{\r
+public:\r
+ /// @brief Constructor, used in DHCP4o6IPC to construct Pkt4o6 from\r
+ /// raw data.\r
+ ///\r
+ /// It is used when a DHCP4o6IPC receives raw data from the other server.\r
+ /// It constructs internal Pkt4 and Pkt6 seperately using the given raw data.\r
+ ///\r
+ /// @param data4 raw data of Pkt4\r
+ /// @param len4 raw data length of Pkt4\r
+ /// @param data6 raw data of Pkt6\r
+ /// @param len6 raw data length of Pkt6\r
+ Pkt4o6(const uint8_t* data4, size_t len4,\r
+ const uint8_t* data6, size_t len6);\r
+ \r
+ /// @brief Constructor, used in DHCPv6 server to construct Pkt4o6 from Pkt6.\r
+ ///\r
+ /// It is used when a DHCPv6 server receives a DHCPv4-query message, and \r
+ /// converts it into a DHCP4o6 message.\r
+ /// It constructs internal Pkt4 using the pkt6's DHCPv4 Message Option\r
+ /// \r
+ /// @throw Pkt4o6ConstructError if given mssage is not DHCPV4_QUERY or \r
+ /// DHCPV4_RESPONSE, or if OPTION_DHCPV4_MSG not found\r
+ ///\r
+ /// @param pkt6 A DHCPv6 DHCPV4_QUERY message.\r
+ Pkt4o6(const Pkt6Ptr& pkt6); \r
+\r
+ /// @brief Constructor, used in DHCPv4 server to construct Pkt4o6 from\r
+ /// Pkt4 response and Pkt4o6 query.\r
+ ///\r
+ /// It is used when a DHCPv4 server successfully produces a DHCPv4 reply\r
+ /// for a DHCP4o6 query. It converts the DHCPv4 reply into a DHCP4o6 message.\r
+ ///\r
+ /// @param pkt4o6 a DHCPv4 over DHCPv6 message\r
+ /// @param pkt4 a DHCPv4 response message\r
+ Pkt4o6(const Pkt4o6Ptr& pkt4o6, const Pkt4Ptr& pkt4);\r
+\r
+ /// @brief Get Pkt6 format of this DHCPv4 over DHCPv6 packet\r
+ ///\r
+ /// @return A pointer to the Pkt6 object.\r
+ Pkt6Ptr getPkt6() const { return (pkt6_); }\r
+ \r
+ /// @brief Get Pkt4 content of this DHCPv4 over DHCPv6 packet\r
+ /// @return A pointer to the Pkt4 object.\r
+ Pkt4Ptr getPkt4() const { return (pkt4_); }\r
+ \r
+ /// @brief Json format of nessary information\r
+ ///\r
+ /// There are some nessary information that needs to be passed between\r
+ /// DHCPv4 and DHCPv6 servers, such as IPv6 addresses, ports, iface, etc.\r
+ /// The raw data of the DHCPv6 packet does not contain these information,\r
+ /// so we transmit them using json format string\r
+ ///\r
+ /// @return A json format string containing all necessary information\r
+ std::string getJsonAttribute();\r
+ \r
+ /// @brief Set Packet attributes according to a json format string\r
+ void setJsonAttribute(std::string json);\r
+ \r
+ /// @brief Get a DHCPv4MsgOption that contains pkt4_\r
+ ///\r
+ /// @return A DHCPv4MsgOption\r
+ OptionBuffer getDHCPv4MsgOption();\r
+ \r
+ /// @brief Set local address in pkt4_ according to U flag in pkt6_\r
+ void setPkt4LocalAddr();\r
+ \r
+protected:\r
+ /// @brief A poiner to a DHCPv4 packet\r
+ Pkt4Ptr pkt4_;\r
+ \r
+ /// @brief A pointer to a DHCPv6 packet\r
+ Pkt6Ptr pkt6_; \r
+};// pkt4o6 class\r
+\r
+} // isc::dhcp namespace\r
+\r
+} // isc namespace \r
+ \r
+#endif\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
libdhcp___unittests_SOURCES += pkt_filter_test_utils.h pkt_filter_test_utils.cc
libdhcp___unittests_SOURCES += pkt_filter6_test_utils.h pkt_filter6_test_utils.cc
+#4o6
+libdhcp___unittests_SOURCES += pkt4o6_unittest.cc
+
# Utilize Linux Packet Filtering on Linux.
if OS_LINUX
libdhcp___unittests_SOURCES += pkt_filter_lpf_unittest.cc
--- /dev/null
+// Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")\r
+//\r
+// Permission to use, copy, modify, and/or distribute this software for any\r
+// purpose with or without fee is hereby granted, provided that the above\r
+// copyright notice and this permission notice appear in all copies.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH\r
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\r
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\r
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r
+// PERFORMANCE OF THIS SOFTWARE.\r
+\r
+#include <config.h>\r
+\r
+#include <asiolink/io_address.h>\r
+#include <dhcp/dhcp4.h>\r
+#include <dhcp/dhcp6.h>\r
+#include <dhcp/libdhcp++.h>\r
+#include <dhcp/docsis3_option_defs.h>\r
+#include <dhcp/option_string.h>\r
+#include <dhcp/pkt4.h>\r
+#include <dhcp/pkt6.h>\r
+#include <dhcp/option.h>\r
+#include <exceptions/exceptions.h>\r
+#include <util/buffer.h>\r
+#include <dhcp/pkt4o6.h>\r
+#include <boost/shared_array.hpp>\r
+#include <boost/shared_ptr.hpp>\r
+#include <boost/static_assert.hpp>\r
+#include <gtest/gtest.h>\r
+\r
+#include <iostream>\r
+#include <sstream>\r
+\r
+#include <arpa/inet.h>\r
+\r
+using namespace std;\r
+using namespace isc;\r
+using namespace isc::asiolink;\r
+using namespace isc::dhcp;\r
+using namespace isc::util;\r
+\r
+namespace {\r
+\r
+//Test buffer length\r
+const int LENGTH = 250;\r
+\r
+/// @brief A test fixture class for Pkt4o6.\r
+class Pkt4o6Test : public ::testing::Test {\r
+public:\r
+ \r
+ /// @brief Constructor.\r
+ Pkt4o6Test() {\r
+ for (int i = 0; i < LENGTH; i++) {\r
+ testData[i] = i;\r
+ }\r
+ }\r
+ \r
+ /// @brief Generate a 4o6 packet for testing.\r
+ ///\r
+ /// It first generates a Pkt6, and then generates a Pkt4o6 from the Pkt6.\r
+ ///\r
+ /// @return A pointer to allocated Pkt4o6 object\r
+ Pkt4o6Ptr generatePkt4o6(){\r
+ //First generate a Pkt6\r
+ Pkt6Ptr pkt6(new Pkt6(testData, LENGTH));\r
+ pkt6->setType(DHCPV4_QUERY);\r
+ pkt6->setRemotePort(546);\r
+ pkt6->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));\r
+ pkt6->setLocalPort(0);\r
+ pkt6->setLocalAddr(IOAddress("ff02::1:2"));\r
+ pkt6->setIndex(2);\r
+ pkt6->setIface("eth0");\r
+ \r
+ //Then generate a Pkt4, and put it into a OPTION_DHCPV4_MSG of the pkt6\r
+ Pkt4Ptr pkt4(new Pkt4(testData, LENGTH));\r
+ pkt4->repack();\r
+ isc::util::OutputBuffer tmp = pkt4->getBuffer();\r
+ OptionBuffer p((uint8_t*)tmp.getData(),\r
+ (uint8_t*)tmp.getData() + tmp.getLength());\r
+ OptionPtr opt = OptionPtr(new Option(Option::V6, OPTION_DHCPV4_MSG, p));\r
+ pkt6->addOption(opt);\r
+ \r
+ //Finally generate a Pkt4o6\r
+ Pkt4o6Ptr pkt4o6(new Pkt4o6(pkt6));\r
+ return pkt4o6;\r
+ }\r
+\r
+ /// @brief Generate a 4o6 packet for testing.\r
+ ///\r
+ /// It generates a Pkt4o6 directly from raw data.\r
+ ///\r
+ /// @return A pointer to allocated Pkt4o6 object\r
+ Pkt4o6Ptr generatePkt4o6_2(){\r
+ Pkt4o6Ptr pkt4o6(new Pkt4o6(testData, LENGTH, testData, LENGTH));\r
+ return pkt4o6;\r
+ }\r
+\r
+protected: \r
+ ///Buffer for test data\r
+ uint8_t testData[LENGTH];\r
+};\r
+\r
+\r
+//Test Pkt4o6 class constructor\r
+TEST_F(Pkt4o6Test, constructor) {\r
+ Pkt4o6Ptr pkt4o6;\r
+ uint8_t* data;\r
+ Pkt6Ptr pkt6;\r
+ Pkt4Ptr pkt4;\r
+\r
+ //Case 1:test Pkt4o6::Pkt4o6(const Pkt6Ptr& pkt6)\r
+ pkt6 = Pkt6Ptr(new Pkt6(testData, LENGTH));\r
+ pkt4 = Pkt4Ptr(new Pkt4(testData, LENGTH));\r
+ pkt4->repack();\r
+ isc::util::OutputBuffer tmp = pkt4->getBuffer();\r
+ OptionBuffer buf((uint8_t*)tmp.getData(),\r
+ (uint8_t*)tmp.getData() + tmp.getLength());\r
+ OptionPtr opt(new Option(Option::V6, OPTION_DHCPV4_MSG, buf));\r
+ \r
+ EXPECT_THROW(\r
+ pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt6)),\r
+ Pkt4o6ConstructError\r
+ );\r
+ pkt6->setType(DHCPV4_QUERY);\r
+ EXPECT_THROW(\r
+ pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt6)),\r
+ Pkt4o6ConstructError\r
+ );\r
+ pkt6->addOption(opt);\r
+ EXPECT_NO_THROW(\r
+ pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt6))\r
+ );\r
+ pkt4 = pkt4o6->getPkt4();\r
+ ASSERT_EQ(LENGTH, pkt4->getBuffer().getLength());\r
+ data = (uint8_t*)pkt4->getBuffer().getData();\r
+ for(int i = 0;i < LENGTH;i++)\r
+ EXPECT_EQ(i, data[i]);\r
+\r
+ //Case 2: test Pkt4o6::Pkt4o6(const uint8_t* data4, size_t len4, \r
+ // const uint8_t* data6, size_t len6)\r
+ \r
+ pkt4o6 = Pkt4o6Ptr(new Pkt4o6(testData, LENGTH, testData, LENGTH));\r
+ pkt4 = pkt4o6->getPkt4();\r
+ pkt6 = pkt4o6->getPkt6();\r
+ \r
+ ASSERT_EQ(LENGTH, pkt4->getBuffer().getLength());\r
+ ASSERT_EQ(LENGTH, pkt6->getBuffer().getLength());\r
+ data = (uint8_t*)pkt4->getBuffer().getData();\r
+ for(int i = 0;i < LENGTH;i++)\r
+ EXPECT_EQ(i, data[i]);\r
+ data = (uint8_t*)pkt6->getBuffer().getData();\r
+ for(int i = 0;i < LENGTH;i++){\r
+ EXPECT_EQ(i,data[i]);\r
+ }\r
+\r
+ //Case 3:test Pkt4o6::Pkt4o6(const Pkt4o6Ptr& pkt4o6, const Pkt4Ptr& pkt4)\r
+ const int LEN2 = 240;\r
+ uint8_t newData[LEN2];\r
+ for(int i = 0 ;i < LEN2;i++)\r
+ newData[i] = i + 2;\r
+\r
+ pkt4 = Pkt4Ptr(new Pkt4(newData, LEN2));\r
+ \r
+ //Create testing PKt4o6 now \r
+ pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt4o6, pkt4));\r
+ pkt4 = pkt4o6->getPkt4();\r
+ pkt6 = pkt4o6->getPkt6();\r
+ pkt4->repack();\r
+ //pkt6->repack();\r
+ ASSERT_EQ(LEN2, pkt4->getBuffer().getLength());\r
+ ASSERT_EQ(LENGTH, pkt6->getBuffer().getLength());\r
+ data = (uint8_t*)pkt4->getBuffer().getData();\r
+ for(int i = 0;i < LEN2;i++)\r
+ EXPECT_EQ(i + 2, data[i]);\r
+ data = (uint8_t*)pkt6->getBuffer().getData();\r
+ for(int i = 0;i < LENGTH;i++){\r
+ EXPECT_EQ(i,data[i]);\r
+ }\r
+\r
+}\r
+\r
+//Test setJsonAttribute and getJsonAttribute\r
+TEST_F(Pkt4o6Test, jsonAttribute) {\r
+\r
+ Pkt4o6Ptr pkt4o6 = generatePkt4o6();\r
+ \r
+ //store pkt4o6 josn info.\r
+ std::string json = pkt4o6->getJsonAttribute();\r
+ Pkt4o6Ptr pkt4o6_ = generatePkt4o6_2();\r
+ pkt4o6_->setJsonAttribute(json);\r
+ int RemotePort = 546; \r
+ std::string RemoteAddr("fe80::21e:8cff:fe9b:7349");\r
+ int LocalPort = 0;\r
+ std::string LocalAddr("ff02::1:2");\r
+ int Index = 2;\r
+ std::string Iface("eth0");\r
+ \r
+ // test current pkt4o6 json info.\r
+ Pkt6Ptr v6(pkt4o6_->getPkt6());\r
+ EXPECT_EQ(RemotePort,v6->getRemotePort());\r
+ EXPECT_EQ(RemoteAddr,v6->getRemoteAddr().toText());\r
+ EXPECT_EQ(LocalPort,v6->getLocalPort());\r
+ EXPECT_EQ(LocalAddr,v6->getLocalAddr().toText());\r
+ EXPECT_EQ(Index,v6->getIndex());\r
+ EXPECT_EQ(Iface,v6->getIface());\r
+}\r
+\r
+//Test DHCPv4MsgOption\r
+TEST_F(Pkt4o6Test, generateDHCPv4MsgOption) {\r
+ Pkt4o6Ptr pkt4o6 = generatePkt4o6();\r
+ \r
+ //get DHCPv4MsgOption from Pkt4o6\r
+ OptionBuffer buf(pkt4o6->getDHCPv4MsgOption());\r
+ for(int i = 0;i < LENGTH;i++)\r
+ EXPECT_EQ(i,buf[i]);\r
+\r
+}\r
+\r
+//Test unicast/broadcast flag\r
+TEST_F(Pkt4o6Test, unicastFlag) {\r
+ //create and test a broadcast packet\r
+ uint8_t buf0[] = {DHCPV4_QUERY, 0, 0, 0};//U=0\r
+ Pkt4o6Ptr pkt4o6;\r
+ pkt4o6 = Pkt4o6Ptr(new Pkt4o6(testData, LENGTH, buf0, sizeof(buf0)));\r
+ pkt4o6->setPkt4LocalAddr();\r
+ EXPECT_EQ("255.255.255.255", pkt4o6->getPkt4()->getLocalAddr().toText());\r
+ \r
+ //create and test a unicast packet\r
+ uint8_t buf1[] = {DHCPV4_QUERY, 0x80, 0, 0};//U=1\r
+ pkt4o6 = Pkt4o6Ptr(new Pkt4o6(testData, LENGTH, buf1, sizeof(buf0)));\r
+ pkt4o6->setPkt4LocalAddr();\r
+ EXPECT_NE("255.255.255.255", pkt4o6->getPkt4()->getLocalAddr().toText());\r
+}\r
+\r
+} // end of anonymous namespace\r
libkea_dhcpsrv_la_SOURCES += triplet.h
libkea_dhcpsrv_la_SOURCES += utils.h
+#DHCP4o6
+libkea_dhcpsrv_la_SOURCES += dhcp4o6_ipc.h dhcp4o6_ipc.cc
+
nodist_libkea_dhcpsrv_la_SOURCES = dhcpsrv_messages.h dhcpsrv_messages.cc
libkea_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
--- /dev/null
+// Copyright (C) 2014 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 <dhcpsrv/dhcp4o6_ipc.h>
+#include <dhcp/iface_mgr.h>
+
+namespace isc {
+namespace dhcp {
+
+DHCP4o6IPC::DHCP4o6IPC(const std::string& local_filename, const std::string& remote_filename) :
+ BaseIPC(local_filename, remote_filename) {
+ open();
+}
+
+void
+DHCP4o6IPC::sendPkt4o6(const Pkt4o6Ptr& pkt4o6) {
+ if (!pkt4o6) {
+ isc_throw(DHCP4o6IPCSendError, "NULL 4o6 Packet");
+ }
+ isc::util::OutputBuffer buf(0);
+ const isc::util::OutputBuffer &buf4(pkt4o6->getPkt4()->getBuffer());
+ size_t len = buf4.getLength();
+ buf.writeData(&len, sizeof(size_t));
+ buf.writeData(buf4.getData(), len);
+ const isc::util::OutputBuffer &buf6(pkt4o6->getPkt6()->getBuffer());
+ len = buf6.getLength();
+ buf.writeData(&len, sizeof(size_t));
+ buf.writeData(buf6.getData(), len);
+ std::string att = pkt4o6->getJsonAttribute();
+ len = att.size();
+ buf.writeData(&len, sizeof(size_t));
+ buf.writeData(att.c_str(), len);
+
+ BaseIPC::send(buf);
+}
+
+void
+DHCP4o6IPC::recvPkt4o6() {
+ isc::util::InputBuffer buf = recv();
+ size_t len4, len6, len_json;
+ uint8_t buf4[RCVBUFSIZE];
+ uint8_t buf6[RCVBUFSIZE];
+ char buf_json[RCVBUFSIZE] = {0};
+ buf.readData(&len4, sizeof(size_t));
+ buf.readData(buf4, len4);
+ buf.readData(&len6, sizeof(size_t));
+ buf.readData(buf6, len6);
+ buf.readData(&len_json, sizeof(size_t));
+ buf.readData(buf_json, len_json);
+
+ Pkt4o6Ptr p(new Pkt4o6(buf4, len4, buf6, len6));
+ p->setJsonAttribute(buf_json);
+ queue_.push(p);
+}
+
+Pkt4o6Ptr
+DHCP4o6IPC::pop() {
+ if (queue_.empty())
+ return Pkt4o6Ptr();
+ current_ = queue_.front();
+ queue_.pop();
+ return current_;
+}
+
+} // isc::dhcp namespace
+} // isc namespace
--- /dev/null
+// Copyright (C) 2014 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 DHCP4O6_IPC_H
+#define DHCP4O6_IPC_H
+
+#include <dhcp/pkt4o6.h>
+#include <util/ipc.h>
+
+#include <queue>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception thrown when DHCP4o6IPC::send() failed.
+class DHCP4o6IPCSendError : public isc::util::IPCSendError {
+public:
+ DHCP4o6IPCSendError(const char* file, size_t line, const char* what) :
+ isc::util::IPCSendError(file, line, what) { };
+};
+
+/// @brief IPC class to pass Pkt4o6 between DHCPv4 and DHCPv6 servers
+class DHCP4o6IPC : public isc::util::BaseIPC {
+public:
+ /// @brief Default constructor.
+ ///
+ /// This function calls BaseIPC::open() to initiate socket directly
+ /// Method will throw if BaseIPC::open() method failed
+ ///
+ /// @param local_filename Filename for receiving socket
+ /// @param remote_filename Filename for sending socket
+ DHCP4o6IPC(const std::string& local_filename, const std::string& remote_filename);
+
+ /// @brief Send a DHCPv4 ove DHCPv6 packet
+ ///
+ /// This function converts Pkt4o6 into binary data and sends it
+ /// through BaseIPC::send().
+ /// Method will throw if BaseIPC::send() failed
+ ///
+ /// @param pkt4o6 Pointer to the packet to be sent
+ void sendPkt4o6(const Pkt4o6Ptr& pkt4o6);
+
+ /// @brief Receive a DHCPv4 ove DHCPv6 packet
+ ///
+ /// This function calls BaseIPC::recv() to receive binary data
+ /// and converts it into Pkt4o6
+ /// It pushes received Pkt4o6 into a queue and does not return immediately.
+ /// Method will throw if BaseIPC::recv() failed or Pkt4o6
+ /// construction failed
+ void recvPkt4o6();
+
+ /// @brief Test if Pkt4o6 receiving queue is empty.
+ ///
+ /// @return true if the Pkt4o6 receiving queue is empty.
+ bool empty() const { return queue_.empty(); }
+
+ /// @brief Retrive a Pkt4o6 in the receiving queue and remove it.
+ ///
+ /// If the receiving queue is not empty, return the one
+ /// in front of the queue and remove it from the queue.
+ ///
+ /// @return A pointer to the retrived Pkt4o6, or a null pointer if the
+ /// queue is empty.
+ Pkt4o6Ptr pop();
+
+ /// @brief Get the instance of current processing Pkt4o6
+ Pkt4o6Ptr currentPkt4o6() { return current_; }
+
+protected:
+
+ /// @brief A queue of received DHCPv4 over DHCPv6 packets that has
+ /// not been processed
+ std::queue<Pkt4o6Ptr> queue_;
+
+ /// @brief The current processing DHCPv4 over DHCPv6 packet
+ Pkt4o6Ptr current_;
+};//DHCP4o6IPC class
+
+typedef boost::shared_ptr<DHCP4o6IPC> DHCP4o6IPCPtr;
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif //DHCP4O6_IPC_H
libdhcpsrv_unittests_SOURCES += triplet_unittest.cc
libdhcpsrv_unittests_SOURCES += test_utils.cc test_utils.h
+#4o6
+libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc
+
libdhcpsrv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
if HAVE_MYSQL
libdhcpsrv_unittests_CPPFLAGS += $(MYSQL_CPPFLAGS)
--- /dev/null
+// Copyright (C) 2014 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 <asiolink/io_address.h>
+#include <dhcpsrv/dhcp4o6_ipc.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/docsis3_option_defs.h>
+#include <dhcp/option_string.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/option.h>
+#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+#include <dhcp/pkt4o6.h>
+#include <dhcp/iface_mgr.h>
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/static_assert.hpp>
+
+#include <gtest/gtest.h>
+
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
+
+namespace {
+
+//Test buffer length
+const int LENGTH = 250;
+
+/// @brief A test fixture class for DHCP4o6IPC.
+class DHCP4o6IPCTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor.
+ DHCP4o6IPCTest() {
+ for (int i = 0; i < LENGTH; ++i)
+ testData[i] = i;
+ }
+
+ /// @brief Generate a 4o6 packet for testing.
+ ///
+ /// @return A pointer to allocated Pkt4o6 object
+ Pkt4o6Ptr generatePkt4o6(){
+ Pkt4Ptr pkt4(new Pkt4(testData,LENGTH));
+ Pkt6Ptr pkt6(new Pkt6(testData,LENGTH));
+ pkt6->setType(DHCPV4_QUERY);
+ pkt6->setRemotePort(546);
+ pkt6->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));
+ pkt6->setLocalPort(0);
+ pkt6->setLocalAddr(IOAddress("ff02::1:2"));
+ pkt6->setIndex(2);
+ pkt6->setIface("eth0");
+ pkt4->repack();
+ isc::util::OutputBuffer tmp = pkt4->getBuffer();
+ OptionBuffer p((uint8_t*)tmp.getData(),
+ (uint8_t*)tmp.getData()+tmp.getLength());
+ OptionPtr opt = OptionPtr(new Option(Option::V6, OPTION_DHCPV4_MSG, p));
+ pkt6->addOption(opt);
+ Pkt4o6Ptr pkt4o6(new Pkt4o6(pkt6));
+ return pkt4o6;
+ }
+
+protected:
+ ///Buffer for test data
+ uint8_t testData[LENGTH];
+};
+
+// This test verifies sending and receiving between v4/v6 IPCs
+TEST_F(DHCP4o6IPCTest, send_receive) {
+ //create Pkt4o6
+ Pkt4o6Ptr pkt4o6 = generatePkt4o6();
+
+ std::string json = pkt4o6->getJsonAttribute();
+
+ DHCP4o6IPC ipc4("DHCP4o6IPCTest_6to4", "DHCP4o6IPCTest_4to6");
+ DHCP4o6IPC ipc6("DHCP4o6IPCTest_4to6", "DHCP4o6IPCTest_6to4");
+
+ EXPECT_NO_THROW(
+ ipc4.sendPkt4o6(pkt4o6);
+ );
+ EXPECT_NO_THROW(
+ ipc6.sendPkt4o6(pkt4o6);
+ );
+ EXPECT_NO_THROW(
+ ipc6.recvPkt4o6();
+ );
+ EXPECT_NO_THROW(
+ ipc4.recvPkt4o6();
+ );
+ Pkt4o6Ptr recvmsg1 = ipc6.pop();
+ Pkt4o6Ptr recvmsg2 = ipc4.pop();
+
+ ASSERT_EQ(json, recvmsg1->getJsonAttribute());//json must be equal
+ const OutputBuffer &buf4_1(recvmsg1->getPkt4()->getBuffer());
+ size_t len = buf4_1.getLength();
+ ASSERT_EQ(LENGTH,len);//length of data in pkt4 must be equal
+ const OutputBuffer &buf6_1(recvmsg1->getPkt6()->getBuffer());
+ len = buf6_1.getLength();
+ ASSERT_EQ(LENGTH,len);//length of data in pkt6 must be equal
+
+ uint8_t *pkt4data1 = (uint8_t*)buf4_1.getData();
+ for(int i = 0;i < LENGTH ;i++){//test data in pkt4
+ EXPECT_EQ(pkt4data1[i],testData[i]);
+ }
+ uint8_t *pkt6data1 = (uint8_t*)buf6_1.getData();
+ for(int i = 0;i < LENGTH ;i++){//test data in pkt6
+ EXPECT_EQ(pkt6data1[i],testData[i]);
+ }
+
+ ASSERT_EQ(json, recvmsg2->getJsonAttribute());//json must be equal
+ const OutputBuffer &buf4_2(recvmsg2->getPkt4()->getBuffer());
+ len = buf4_2.getLength();
+ ASSERT_EQ(LENGTH,len);//length of data in pkt4 must be equal
+ const OutputBuffer &buf6_2(recvmsg2->getPkt6()->getBuffer());
+ len = buf6_2.getLength();
+ ASSERT_EQ(LENGTH,len);//length of data in pkt6 must be equal
+
+ uint8_t *pkt4data2 = (uint8_t*)buf4_2.getData();
+ for(int i = 0;i < LENGTH ;i++){//test data in pkt4
+ EXPECT_EQ(pkt4data2[i],testData[i]);
+ }
+ uint8_t *pkt6data2 = (uint8_t*)buf6_2.getData();
+ for(int i = 0;i < LENGTH ;i++){//test data in pkt6
+ EXPECT_EQ(pkt6data2[i],testData[i]);
+ }
+}
+
+// Test send exception
+TEST_F(DHCP4o6IPCTest, exception) {
+ DHCP4o6IPC ipc4("DHCP4o6IPCTest_6to4", "DHCP4o6IPCTest_4to6");
+
+ EXPECT_THROW(
+ ipc4.sendPkt4o6(Pkt4o6Ptr()),
+ DHCP4o6IPCSendError
+ );
+}
+
+
+}
+
+
+
libkea_util_la_SOURCES += random/qid_gen.h random/qid_gen.cc
libkea_util_la_SOURCES += random/random_number_generator.h
+#4o6
+libkea_util_la_SOURCES += ipc.h
+
libkea_util_la_LIBADD = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
CLEANFILES = *.gcno *.gcda
--- /dev/null
+// Copyright (C) 2014 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 IPC_H
+#define IPC_H
+
+#include <util/buffer.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <errno.h>
+
+namespace isc {
+namespace util {
+
+/// @brief Exception thrown when BaseIPC::open() failed.
+class IPCOpenError : public Exception {
+public:
+ IPCOpenError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when BaseIPC::recv() failed.
+class IPCRecvError : public Exception {
+public:
+ IPCRecvError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when BaseIPC::send() failed.
+class IPCSendError : public Exception {
+public:
+ IPCSendError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief An Inter Process Communication(IPC) tool based on UNIX domain socket.
+///
+/// It is used by 2 processes for data communication. It provides methods for
+/// bi-directional binary data transfer.
+///
+/// There should be 2 instances (a sender and a receiver) using this tool
+/// at the same time. The filename for the sockets must match (i.e.
+/// the remote filename of the sender = the local filename of the receiver).
+///
+/// It should be used as a base class and not directly used for future classes
+/// implementing inter process communication.
+class BaseIPC {
+public:
+
+ /// @brief Packet reception buffer size
+ ///
+ /// Receive buffer size of UNIX socket
+ static const uint32_t RCVBUFSIZE = 4096;
+
+ /// @brief BaseIPC constructor.
+ ///
+ /// Creates BaseIPC object for UNIX socket communication using the given
+ /// filenames. It doesn't create the socket immediately.
+ ///
+ /// @param local_filename Filename for receiving socket
+ /// @param remote_filename Filename for sending socket
+ BaseIPC(const std::string& local_filename, const std::string& remote_filename) :
+ socketfd_(-1),
+ remote_addr_len_(0),
+ local_filename_(local_filename),
+ remote_filename_(remote_filename)
+ {
+ }
+
+ /// @brief BaseIPC destructor.
+ ///
+ /// It closes the socket explicitly.
+ virtual ~BaseIPC() { closeIPC(); }
+
+
+ /// @brief Open UNIX socket
+ ///
+ /// Method will throw if socket creation fails.
+ ///
+ /// @return A int value of the socket descriptor.
+ int open() {
+ //create socket
+ int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ isc_throw(IPCOpenError, "Failed to create a socket");
+ }
+ socketfd_ = fd;
+
+ bindSocket();
+ setRemoteFilename();
+
+ return socketfd_;
+ }
+
+ /// @brief Close opened socket.
+ void closeIPC() {
+ if(socketfd_ >= 0)
+ close(socketfd_);
+ socketfd_ = -1;
+ }
+
+ /// @brief Send data.
+ ///
+ /// @param buf The data to be sent.
+ ///
+ /// Method will throw if open() has not been called or sendto() failed.
+ /// open() MUST be called before calling this function.
+ ///
+ /// @return The number of bytes sent.
+ int send(const isc::util::OutputBuffer &buf) {
+ if (remote_addr_len_ == 0) {
+ isc_throw(IPCSendError, "Remote address unset");
+ }
+ int count = sendto(socketfd_, buf.getData(), buf.getLength(), 0,
+ (struct sockaddr*)&remote_addr_, remote_addr_len_);
+ if (count < 0) {
+ isc_throw(IPCSendError, "BaseIPC failed on sendto: "
+ << strerror(errno));
+ }
+ return count;
+ }
+
+ /// @brief Receive data.
+ ///
+ /// Method will throw if socket recvfrom() failed.
+ /// open() MUST be called before calling this function.
+ ///
+ /// @return The number of bytes received.
+ isc::util::InputBuffer recv() {
+ uint8_t buf[RCVBUFSIZE];
+ int len = recvfrom(socketfd_, buf, RCVBUFSIZE, 0, NULL, NULL);
+ if (len < 0) {
+ isc_throw(IPCRecvError, "BaseIPC failed on recvfrom: "
+ << strerror(errno));
+ }
+ isc::util::InputBuffer ibuf(buf, len);
+ return ibuf;
+ }
+
+ /// @brief Get socket fd.
+ ///
+ /// @return The socket fd of the unix socket.
+ int getSocket() { return socketfd_; }
+
+protected:
+
+ /// @brief Set remote filename
+ ///
+ /// The remote filename is used for sending data. The filename is given
+ /// in the constructor.
+ void setRemoteFilename() {
+ memset(&remote_addr_, 0, sizeof(struct sockaddr_un));
+ remote_addr_.sun_family = AF_UNIX;
+ strcpy(&remote_addr_.sun_path[1], remote_filename_.c_str());
+ remote_addr_len_ = sizeof(sa_family_t) + remote_filename_.size() + 1;
+ }
+
+ /// @brief Bind the UNIX socket to the given filename
+ ///
+ /// The filename is given in the constructor.
+ ///
+ /// Method will throw if socket binding fails.
+ void bindSocket() {
+ struct sockaddr_un local_addr_;
+ int local_addr_len_;
+
+ //init address
+ memset(&local_addr_, 0, sizeof(struct sockaddr_un));
+ local_addr_.sun_family = AF_UNIX;
+ strcpy(&local_addr_.sun_path[1], local_filename_.c_str());
+ local_addr_len_ = sizeof(sa_family_t) + local_filename_.size() + 1;
+
+ //bind to local_address
+ if (bind(socketfd_, (struct sockaddr *)&local_addr_, local_addr_len_) < 0) {
+ isc_throw(IPCOpenError, "failed to bind to local address: " + local_filename_);
+ }
+ }
+
+ /// UNIX socket value.
+ int socketfd_;
+
+ /// Remote UNIX socket address
+ struct sockaddr_un remote_addr_;
+
+ /// Length of remote_addr_
+ int remote_addr_len_;
+
+ /// Filename for receiving and sending socket
+ std::string local_filename_, remote_filename_;
+
+}; // BaseIPC class
+
+} // namespace util
+} // namespace isc
+#endif // IPC_H
+
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+#4o6
+run_unittests_SOURCES += ipc_unittest.cc
run_unittests_LDADD = $(top_builddir)/src/lib/util/libkea-util.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libkea-util-io.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
--- /dev/null
+// Copyright (C) 2014 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 <util/ipc.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util;
+
+
+namespace {
+
+/// @brief A test fixture class for BaseIPC.
+class IPCTest : public ::testing::Test {
+public:
+ /// @brief Constructor.
+ ///
+ /// It initializes 2 BaseIPC objects.
+ IPCTest() :
+ ipc1("test_ipc_2to1", "test_ipc_1to2"),
+ ipc2("test_ipc_1to2", "test_ipc_2to1")
+ {
+ }
+protected:
+ /// BaseIPC objects for testing.
+ BaseIPC ipc1, ipc2;
+};
+
+// Test BaseIPC constructor
+TEST_F(IPCTest, constructor) {
+ EXPECT_EQ(-1, ipc1.getSocket());
+}
+
+
+// Test openSocket function
+TEST_F(IPCTest, openSocket) {
+ int fd;
+ EXPECT_NO_THROW(
+ fd = ipc1.open();
+ );
+
+ EXPECT_EQ(fd, ipc1.getSocket());
+}
+
+// Test BaseIPC bidirectional data sending and receiving
+TEST_F(IPCTest, bidirectionalTransmission) {
+ const int LEN1 = 100;
+ const int LEN2 = 200;
+ uint8_t data1[LEN2];
+ uint8_t data2[LEN2];
+ uint8_t data3[LEN2];
+ uint8_t data4[LEN2];
+ for (int i = 0; i < LEN2; ++i) {
+ data1[i] = i;
+ data2[i] = -i;
+ }
+ EXPECT_NO_THROW(
+ ipc1.open();
+ );
+ EXPECT_NO_THROW(
+ ipc2.open();
+ );
+
+ OutputBuffer sendbuf1(LEN1), sendbuf2(LEN2);
+ sendbuf1.writeData((void*)data1, LEN1);
+ sendbuf2.writeData((void*)data2, LEN2);
+ EXPECT_NO_THROW(
+ ipc1.send(sendbuf1);
+ );
+ EXPECT_NO_THROW(
+ ipc2.send(sendbuf2);
+ );
+
+ InputBuffer recvbuf1(0, 0), recvbuf2(0, 0);
+ EXPECT_NO_THROW(
+ recvbuf1 = ipc1.recv();
+ );
+ EXPECT_NO_THROW(
+ recvbuf2 = ipc2.recv();
+ );
+
+ size_t len1 = recvbuf1.getLength();
+ size_t len2 = recvbuf2.getLength();
+ recvbuf1.readData((void*)data3, len1);
+ recvbuf2.readData((void*)data4, len2);
+
+ //check out length.
+ ASSERT_EQ(LEN2, len1);
+ ASSERT_EQ(LEN1, len2);
+
+ for (int i = 0; i < len1; i++) {
+ EXPECT_EQ(data2[i], data3[i]);
+ }
+ for (int i = 0; i < len2; i++) {
+ EXPECT_EQ(data1[i], data4[i]);
+ }
+}
+
+// Test exceptions
+TEST_F(IPCTest, exceptions) {
+ EXPECT_THROW(
+ ipc1.recv(),
+ IPCRecvError
+ );
+ EXPECT_THROW(
+ ipc1.send(OutputBuffer(10)),
+ IPCSendError
+ );
+ EXPECT_NO_THROW(
+ ipc1.open();
+ ipc2.open();
+ );
+ EXPECT_NO_THROW(
+ ipc1.send(OutputBuffer(10))
+ );
+}
+
+}
+