BIND 10 master, updated. be309bf010ba993fb13e79bb4ce8802d8dacf0a4 Merge branch 'trac1230'
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Dec 29 22:34:20 UTC 2011
The branch, master has been updated
via be309bf010ba993fb13e79bb4ce8802d8dacf0a4 (commit)
via aac05f566c49daad4d3de35550cfaff31c124513 (commit)
via 33595d0d554cf7208472d31929cae013cebdc485 (commit)
via 4881a52f6541d200ad2755ce4b159525466498db (commit)
via 7e0fdfb412969cc6ba46aa53dd6d7af6200c7e24 (commit)
via de6f226ae7bc45d144b6e012884bfd28ca74e350 (commit)
via 3344e8b8d949fa9b4bcd9cf007f6a234f0fa5b1c (commit)
via a9f48f11eda70e641b4c4624eef4dbada03828ff (commit)
via 01a1b2f4d210c62fc1d7a9b53e7967057e93d331 (commit)
via c6fd1d3c3c57b9273c7598119e2654e35beebccc (commit)
via 7bf0432cb1f1b7777a25bfd8c0e3c1c8def9bf18 (commit)
via f60bf56ebed7189ad71d6c4ed4044d97b5e5c7a5 (commit)
via e945e57855e4252349635d4b1f90f11626da7508 (commit)
from 55aa7ec8abaae5ddf3e16d613ef7f63395a1849c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit be309bf010ba993fb13e79bb4ce8802d8dacf0a4
Merge: 55aa7ec8abaae5ddf3e16d613ef7f63395a1849c aac05f566c49daad4d3de35550cfaff31c124513
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Thu Dec 29 23:26:40 2011 +0100
Merge branch 'trac1230'
Conflicts:
ChangeLog
src/lib/dhcp/iface_mgr.h
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 6 ++
src/bin/dhcp4/dhcp4_srv.cc | 139 +++++++++++++++++++++++++----
src/bin/dhcp4/dhcp4_srv.h | 39 ++++++++
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 120 +++++++++++++++++++++++--
src/bin/dhcp6/dhcp6_srv.cc | 123 ++++++++++++++++++--------
src/bin/dhcp6/dhcp6_srv.h | 60 +++++++++++--
src/lib/dhcp/iface_mgr.cc | 53 +++++++-----
src/lib/dhcp/iface_mgr.h | 2 +-
src/lib/dhcp/option.cc | 15 +++
src/lib/dhcp/option.h | 21 +++++
src/lib/dhcp/pkt4.cc | 11 ++-
src/lib/dhcp/pkt4.h | 7 +-
src/lib/dhcp/tests/iface_mgr_unittest.cc | 8 ++-
src/lib/dhcp/tests/option_unittest.cc | 45 +++++++++-
src/lib/dhcp/tests/pkt4_unittest.cc | 22 ++++-
15 files changed, 566 insertions(+), 105 deletions(-)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index ff15bf7..0892d4c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+363. [func] tomek
+ dhcp4: Support for DISCOVER and OFFER implemented. b10-dhcp4 is
+ now able to offer hardcoded leases to DHCPv4 clients.
+ dhcp6: Code refactored to use the same approach as dhcp4.
+ (Trac #1230, git aac05f566c49daad4d3de35550cfaff31c124513)
+
362. [func] tomek
libdhcp++: Interface detection in Linux implemented. libdhcp++
if now able to detect available network interfaces, its link-layer
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index d4cae5c..89b48c6 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -17,13 +17,22 @@
#include <dhcp/iface_mgr.h>
#include <dhcp4/dhcp4_srv.h>
#include <asiolink/io_address.h>
+#include <dhcp/option4_addrlst.h>
using namespace std;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::asiolink;
-// #define ECHO_SERVER
+// These are hardcoded parameters. Currently this is a skeleton server that only
+// grants those options and a single, fixed, hardcoded lease.
+const std::string HARDCODED_LEASE = "192.0.2.222"; // assigned lease
+const std::string HARDCODED_NETMASK = "255.255.255.0";
+const uint32_t HARDCODED_LEASE_TIME = 60; // in seconds
+const std::string HARDCODED_GATEWAY = "192.0.2.1";
+const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
+const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
+const std::string HARDCODED_SERVER_ID = "192.0.2.1";
Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
cout << "Initialization: opening sockets on port " << port << endl;
@@ -55,12 +64,6 @@ Dhcpv4Srv::run() {
query = IfaceMgr::instance().receive4();
-#if defined(ECHO_SERVER)
- query->repack();
- IfaceMgr::instance().send(query);
- continue;
-#endif
-
if (query) {
try {
query->unpack();
@@ -98,9 +101,16 @@ Dhcpv4Srv::run() {
cout << query->toText();
if (rsp) {
- rsp->setRemoteAddr(query->getRemoteAddr());
+ if (rsp->getRemoteAddr().toText() == "0.0.0.0") {
+ rsp->setRemoteAddr(query->getRemoteAddr());
+ }
+ if (!rsp->getHops()) {
+ rsp->setRemotePort(DHCP4_CLIENT_PORT);
+ } else {
+ rsp->setRemotePort(DHCP4_SERVER_PORT);
+ }
+
rsp->setLocalAddr(query->getLocalAddr());
- rsp->setRemotePort(DHCP4_CLIENT_PORT);
rsp->setLocalPort(DHCP4_SERVER_PORT);
rsp->setIface(query->getIface());
rsp->setIndex(query->getIndex());
@@ -112,10 +122,7 @@ Dhcpv4Srv::run() {
if (rsp->pack()) {
cout << "Packet assembled correctly." << endl;
}
-#if 1
- // uncomment this once ticket 1240 is merged.
IfaceMgr::instance().send(rsp);
-#endif
}
}
@@ -139,16 +146,116 @@ Dhcpv4Srv::setServerID() {
#endif
}
+
+void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
+ boost::shared_ptr<Pkt4>& answer) {
+ answer->setIface(question->getIface());
+ answer->setIndex(question->getIndex());
+ answer->setCiaddr(question->getCiaddr());
+
+ answer->setSiaddr(IOAddress("0.0.0.0")); // explictly set this to 0
+ answer->setHops(question->getHops());
+
+ // copy MAC address
+ vector<uint8_t> mac(question->getChaddr(),
+ question->getChaddr() + Pkt4::MAX_CHADDR_LEN);
+ answer->setHWAddr(question->getHtype(), question->getHlen(), mac);
+
+ // relay address
+ answer->setGiaddr(question->getGiaddr());
+
+ if (question->getGiaddr().toText() != "0.0.0.0") {
+ // relayed traffic
+ answer->setRemoteAddr(question->getGiaddr());
+ } else {
+ // direct traffic
+ answer->setRemoteAddr(question->getRemoteAddr());
+ }
+
+}
+
+void Dhcpv4Srv::appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type) {
+ boost::shared_ptr<Option> opt;
+
+ // add Message Type Option (type 53)
+ std::vector<uint8_t> tmp;
+ tmp.push_back(static_cast<uint8_t>(msg_type));
+ opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE, tmp));
+ msg->addOption(opt);
+
+ // DHCP Server Identifier (type 54)
+ opt = boost::shared_ptr<Option>
+ (new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, IOAddress(HARDCODED_SERVER_ID)));
+ msg->addOption(opt);
+
+ // more options will be added here later
+}
+
+
+void Dhcpv4Srv::appendRequestedOptions(boost::shared_ptr<Pkt4>& msg) {
+ boost::shared_ptr<Option> opt;
+
+ // Domain name (type 15)
+ vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
+ opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
+ msg->addOption(opt);
+ // TODO: Add Option_String class
+
+ // DNS servers (type 6)
+ opt = boost::shared_ptr<Option>
+ (new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
+ msg->addOption(opt);
+}
+
+void Dhcpv4Srv::tryAssignLease(boost::shared_ptr<Pkt4>& msg) {
+ boost::shared_ptr<Option> opt;
+
+ // TODO: Implement actual lease assignment here
+ msg->setYiaddr(IOAddress(HARDCODED_LEASE));
+
+ // IP Address Lease time (type 51)
+ opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
+ opt->setUint32(HARDCODED_LEASE_TIME);
+ msg->addOption(opt);
+ // TODO: create Option_IntArray that holds list of integers, similar to Option4_AddrLst
+
+ // Subnet mask (type 1)
+ opt = boost::shared_ptr<Option>
+ (new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
+ msg->addOption(opt);
+
+ // Router (type 3)
+ opt = boost::shared_ptr<Option>
+ (new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
+ msg->addOption(opt);
+}
+
boost::shared_ptr<Pkt4>
Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
- /// TODO: Currently implemented echo mode. Implement this for real
- return (discover);
+ boost::shared_ptr<Pkt4> offer = boost::shared_ptr<Pkt4>
+ (new Pkt4(DHCPOFFER, discover->getTransid()));
+
+ copyDefaultFields(discover, offer);
+ appendDefaultOptions(offer, DHCPOFFER);
+ appendRequestedOptions(offer);
+
+ tryAssignLease(offer);
+
+ return (offer);
}
boost::shared_ptr<Pkt4>
Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
- /// TODO: Currently implemented echo mode. Implement this for real
- return (request);
+ boost::shared_ptr<Pkt4> ack = boost::shared_ptr<Pkt4>
+ (new Pkt4(DHCPACK, request->getTransid()));
+
+ copyDefaultFields(request, ack);
+ appendDefaultOptions(ack, DHCPACK);
+ appendRequestedOptions(ack);
+
+ tryAssignLease(ack);
+
+ return (ack);
}
void Dhcpv4Srv::processRelease(boost::shared_ptr<Pkt4>& release) {
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index 033ac5a..cd46977 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -106,6 +106,45 @@ protected:
/// @param infRequest message received from client
boost::shared_ptr<Pkt4> processInform(boost::shared_ptr<Pkt4>& inform);
+ /// @brief Copies default parameters from client's to server's message
+ ///
+ /// Some fields are copied from client's message into server's response,
+ /// e.g. client HW address, number of hops, transaction-id etc.
+ ///
+ /// @param question any message sent by client
+ /// @param answer any message server is going to send as response
+ void copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
+ boost::shared_ptr<Pkt4>& answer);
+
+
+ /// @brief Appends options requested by client.
+ ///
+ /// This method assigns options that were requested by client
+ /// (sent in PRL) or are enforced by server.
+ ///
+ /// @param msg outgoing message (options will be added here)
+ void appendRequestedOptions(boost::shared_ptr<Pkt4>& msg);
+
+
+ /// @brief Assigns a lease and appends corresponding options
+ ///
+ /// This method chooses the most appropriate lease for reqesting
+ /// client and assigning it. Options corresponding to the lease
+ /// are added to specific message.
+ ///
+ /// Note: Lease manager is not implemented yet, so this method
+ /// used fixed, hardcoded lease.
+ ///
+ /// @param msg OFFER or ACK message (lease options will be added here)
+ void tryAssignLease(boost::shared_ptr<Pkt4>& msg);
+
+
+ /// @brief Appends default options to a message
+ ///
+ /// @param msg message object (options will be added to it)
+ /// @param msg_type specifies message type
+ void appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type);
+
/// @brief Returns server-intentifier option
///
/// @return server-id option
diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
index bb6bede..cfc12fb 100644
--- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
@@ -23,10 +23,12 @@
#include <dhcp/dhcp4.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcp/option.h>
+#include <asiolink/io_address.h>
using namespace std;
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::asiolink;
namespace {
const char* const INTERFACE_FILE = "interfaces.txt";
@@ -66,6 +68,30 @@ public:
fakeifaces.close();
}
+ void MessageCheck(const boost::shared_ptr<Pkt4>& q,
+ const boost::shared_ptr<Pkt4>& a) {
+ ASSERT_TRUE(q);
+ ASSERT_TRUE(a);
+
+ EXPECT_EQ(q->getHops(), a->getHops());
+ EXPECT_EQ(q->getIface(), a->getIface());
+ EXPECT_EQ(q->getIndex(), a->getIndex());
+ EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
+
+ // check that bare minimum of required options are there
+ EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
+ EXPECT_TRUE(a->getOption(DHO_ROUTERS));
+ EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));
+ EXPECT_TRUE(a->getOption(DHO_DHCP_LEASE_TIME));
+ EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
+ EXPECT_TRUE(a->getOption(DHO_ROUTERS));
+ EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME));
+ EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME_SERVERS));
+
+ // check that something is offered
+ EXPECT_TRUE(a->getYiaddr().toText() != "0.0.0.0");
+ }
+
~Dhcpv4SrvTest() {
unlink(INTERFACE_FILE);
};
@@ -85,37 +111,113 @@ TEST_F(Dhcpv4SrvTest, basic) {
TEST_F(Dhcpv4SrvTest, processDiscover) {
NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
+ vector<uint8_t> mac(6);
+ for (int i = 0; i < 6; i++) {
+ mac[i] = 255 - i;
+ }
boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDISCOVER, 1234));
+ boost::shared_ptr<Pkt4> offer;
+
+ pkt->setIface("eth0");
+ pkt->setIndex(17);
+ pkt->setHWAddr(1, 6, mac);
+ pkt->setRemoteAddr(IOAddress("192.0.2.56"));
+ pkt->setGiaddr(IOAddress("192.0.2.67"));
+
+ // let's make it a relayed message
+ pkt->setHops(3);
+ pkt->setRemotePort(DHCP4_SERVER_PORT);
// should not throw
EXPECT_NO_THROW(
- srv->processDiscover(pkt);
+ offer = srv->processDiscover(pkt);
);
// should return something
- EXPECT_TRUE(srv->processDiscover(pkt));
+ ASSERT_TRUE(offer);
+
+ EXPECT_EQ(DHCPOFFER, offer->getType());
+
+ // this is relayed message. It should be sent back to relay address.
+ EXPECT_EQ(pkt->getGiaddr(), offer->getRemoteAddr());
+
+ MessageCheck(pkt, offer);
+
+ // now repeat the test for directly sent message
+ pkt->setHops(0);
+ pkt->setGiaddr(IOAddress("0.0.0.0"));
+ pkt->setRemotePort(DHCP4_CLIENT_PORT);
+
+ EXPECT_NO_THROW(
+ offer = srv->processDiscover(pkt);
+ );
+
+ // should return something
+ ASSERT_TRUE(offer);
+
+ EXPECT_EQ(DHCPOFFER, offer->getType());
+
+ // this is direct message. It should be sent back to origin, not
+ // to relay.
+ EXPECT_EQ(pkt->getRemoteAddr(), offer->getRemoteAddr());
+
+ MessageCheck(pkt, offer);
- // TODO: Implement more reasonable tests before starting
- // work on processSomething() method.
delete srv;
}
TEST_F(Dhcpv4SrvTest, processRequest) {
NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
+ vector<uint8_t> mac(6);
+ for (int i = 0; i < 6; i++) {
+ mac[i] = i*10;
+ }
- boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPREQUEST, 1234));
+ boost::shared_ptr<Pkt4> req(new Pkt4(DHCPREQUEST, 1234));
+ boost::shared_ptr<Pkt4> ack;
+
+ req->setIface("eth0");
+ req->setIndex(17);
+ req->setHWAddr(1, 6, mac);
+ req->setRemoteAddr(IOAddress("192.0.2.56"));
+ req->setGiaddr(IOAddress("192.0.2.67"));
// should not throw
+ ASSERT_NO_THROW(
+ ack = srv->processRequest(req);
+ );
+
+ // should return something
+ ASSERT_TRUE(ack);
+
+ EXPECT_EQ(DHCPACK, ack->getType());
+
+ // this is relayed message. It should be sent back to relay address.
+ EXPECT_EQ(req->getGiaddr(), ack->getRemoteAddr());
+
+ MessageCheck(req, ack);
+
+ // now repeat the test for directly sent message
+ req->setHops(0);
+ req->setGiaddr(IOAddress("0.0.0.0"));
+ req->setRemotePort(DHCP4_CLIENT_PORT);
+
EXPECT_NO_THROW(
- srv->processRequest(pkt);
+ ack = srv->processDiscover(req);
);
// should return something
- EXPECT_TRUE(srv->processRequest(pkt));
+ ASSERT_TRUE(ack);
+
+ EXPECT_EQ(DHCPOFFER, ack->getType());
+
+ // this is direct message. It should be sent back to origin, not
+ // to relay.
+ EXPECT_EQ(ack->getRemoteAddr(), req->getRemoteAddr());
+
+ MessageCheck(req, ack);
- // TODO: Implement more reasonable tests before starting
- // work on processSomething() method.
delete srv;
}
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 7d1b549..4e69f05 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -18,6 +18,7 @@
#include <dhcp6/dhcp6_srv.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_addrlst.h>
#include <asiolink/io_address.h>
#include <exceptions/exceptions.h>
@@ -26,21 +27,28 @@ using namespace isc;
using namespace isc::dhcp;
using namespace isc::asiolink;
+const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
+const uint32_t HARDCODED_T1 = 1500; // in seconds
+const uint32_t HARDCODED_T2 = 2600; // in seconds
+const uint32_t HARDCODED_PREFERRED_LIFETIME = 3600; // in seconds
+const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds
+const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";
+
Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
cout << "Initialization" << endl;
// first call to instance() will create IfaceMgr (it's a singleton)
// it may throw something if things go wrong
try {
- IfaceMgr::instance();
+ IfaceMgr::instance();
} catch (const std::exception &e) {
- cout << "Failed to instantiate InterfaceManager:" << e.what() << ". Aborting." << endl;
- shutdown = true;
+ cout << "Failed to instantiate InterfaceManager:" << e.what() << ". Aborting." << endl;
+ shutdown = true;
}
if (IfaceMgr::instance().countIfaces() == 0) {
- cout << "Failed to detect any network interfaces. Aborting." << endl;
- shutdown = true;
+ cout << "Failed to detect any network interfaces. Aborting." << endl;
+ shutdown = true;
}
// Now try to open IPv6 sockets on detected interfaces.
@@ -115,8 +123,9 @@ Dhcpv6Srv::run() {
cout << "Replying with:" << rsp->getType() << endl;
cout << rsp->toText();
cout << "----" << endl;
- if (rsp->pack()) {
- cout << "#### pack successful." << endl;
+ if (!rsp->pack()) {
+ cout << "Failed to assemble response packet." << endl;
+ continue;
}
IfaceMgr::instance().send(rsp);
}
@@ -149,18 +158,45 @@ Dhcpv6Srv::setServerID() {
0, 14));
}
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
+void Dhcpv6Srv::copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+ boost::shared_ptr<Pkt6>& answer) {
+ // add client-id
+ boost::shared_ptr<Option> clientid = question->getOption(D6O_CLIENTID);
+ if (clientid) {
+ answer->addOption(clientid);
+ }
- boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_ADVERTISE,
- solicit->getTransid(),
- Pkt6::UDP));
+ // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
+}
+
+void Dhcpv6Srv::appendDefaultOptions(const boost::shared_ptr<Pkt6>& /*question*/,
+ boost::shared_ptr<Pkt6>& answer) {
+ // TODO: question is currently unused, but we need it at least to know
+ // message type we are answering
+ // add server-id
+ answer->addOption(getServerID());
+}
+
+
+void Dhcpv6Srv::appendRequestedOptions(const boost::shared_ptr<Pkt6>& /*question*/,
+ boost::shared_ptr<Pkt6>& answer) {
+ // TODO: question is currently unused, but we need to extract ORO from it
+ // and act on its content. Now we just send DNS-SERVERS option.
+
+ // add dns-servers option
+ boost::shared_ptr<Option> dnsservers(new Option6AddrLst(D6O_NAME_SERVERS,
+ IOAddress(HARDCODED_DNS_SERVER)));
+ answer->addOption(dnsservers);
+}
+
+void Dhcpv6Srv::assignLeases(const boost::shared_ptr<Pkt6>& question,
+ boost::shared_ptr<Pkt6>& answer) {
/// TODO Rewrite this once LeaseManager is implemented.
// answer client's IA (this is mostly a dummy,
// so let's answer only first IA and hope there is only one)
- boost::shared_ptr<Option> ia_opt = solicit->getOption(D6O_IA_NA);
+ boost::shared_ptr<Option> ia_opt = question->getOption(D6O_IA_NA);
if (ia_opt) {
// found IA
Option* tmp = ia_opt.get();
@@ -168,38 +204,51 @@ Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
if (ia_req) {
boost::shared_ptr<Option6IA>
ia_rsp(new Option6IA(D6O_IA_NA, ia_req->getIAID()));
- ia_rsp->setT1(1500);
- ia_rsp->setT2(2600);
+ ia_rsp->setT1(HARDCODED_T1);
+ ia_rsp->setT2(HARDCODED_T2);
boost::shared_ptr<Option6IAAddr>
addr(new Option6IAAddr(D6O_IAADDR,
- IOAddress("2001:db8:1234:5678::abcd"),
- 5000, 7000));
+ IOAddress(HARDCODED_LEASE),
+ HARDCODED_PREFERRED_LIFETIME,
+ HARDCODED_VALID_LIFETIME));
ia_rsp->addOption(addr);
- reply->addOption(ia_rsp);
+ answer->addOption(ia_rsp);
}
}
+}
- // add client-id
- boost::shared_ptr<Option> clientid = solicit->getOption(D6O_CLIENTID);
- if (clientid) {
- reply->addOption(clientid);
- }
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
- // add server-id
- reply->addOption(getServerID());
- return reply;
+ boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE,
+ solicit->getTransid()));
+
+ copyDefaultOptions(solicit, advertise);
+ appendDefaultOptions(solicit, advertise);
+ appendRequestedOptions(solicit, advertise);
+
+ assignLeases(solicit, advertise);
+
+ return (advertise);
}
boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRequest(boost::shared_ptr<Pkt6> request) {
- /// TODO: Implement processRequest() for real
- boost::shared_ptr<Pkt6> reply = processSolicit(request);
- reply->setType(DHCPV6_REPLY);
- return reply;
+Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
+
+ boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+ request->getTransid()));
+
+ copyDefaultOptions(request, reply);
+ appendDefaultOptions(request, reply);
+ appendRequestedOptions(request, reply);
+
+ assignLeases(request, reply);
+
+ return (reply);
}
boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRenew(boost::shared_ptr<Pkt6> renew) {
+Dhcpv6Srv::processRenew(const boost::shared_ptr<Pkt6>& renew) {
boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
renew->getTransid(),
Pkt6::UDP));
@@ -207,7 +256,7 @@ Dhcpv6Srv::processRenew(boost::shared_ptr<Pkt6> renew) {
}
boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRebind(boost::shared_ptr<Pkt6> rebind) {
+Dhcpv6Srv::processRebind(const boost::shared_ptr<Pkt6>& rebind) {
boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
rebind->getTransid(),
Pkt6::UDP));
@@ -215,7 +264,7 @@ Dhcpv6Srv::processRebind(boost::shared_ptr<Pkt6> rebind) {
}
boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processConfirm(boost::shared_ptr<Pkt6> confirm) {
+Dhcpv6Srv::processConfirm(const boost::shared_ptr<Pkt6>& confirm) {
boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
confirm->getTransid(),
Pkt6::UDP));
@@ -223,7 +272,7 @@ Dhcpv6Srv::processConfirm(boost::shared_ptr<Pkt6> confirm) {
}
boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRelease(boost::shared_ptr<Pkt6> release) {
+Dhcpv6Srv::processRelease(const boost::shared_ptr<Pkt6>& release) {
boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
release->getTransid(),
Pkt6::UDP));
@@ -231,7 +280,7 @@ Dhcpv6Srv::processRelease(boost::shared_ptr<Pkt6> release) {
}
boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processDecline(boost::shared_ptr<Pkt6> decline) {
+Dhcpv6Srv::processDecline(const boost::shared_ptr<Pkt6>& decline) {
boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
decline->getTransid(),
Pkt6::UDP));
@@ -239,7 +288,7 @@ Dhcpv6Srv::processDecline(boost::shared_ptr<Pkt6> decline) {
}
boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processInfRequest(boost::shared_ptr<Pkt6> infRequest) {
+Dhcpv6Srv::processInfRequest(const boost::shared_ptr<Pkt6>& infRequest) {
boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
infRequest->getTransid(),
Pkt6::UDP));
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index bcc7818..44a9f8a 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -81,7 +81,7 @@ protected:
///
/// @return ADVERTISE, REPLY message or NULL
boost::shared_ptr<Pkt6>
- processSolicit(boost::shared_ptr<Pkt6> solicit);
+ processSolicit(const boost::shared_ptr<Pkt6>& solicit);
/// @brief Processes incoming REQUEST and returns REPLY response.
///
@@ -95,43 +95,87 @@ protected:
///
/// @return REPLY message or NULL
boost::shared_ptr<Pkt6>
- processRequest(boost::shared_ptr<Pkt6> request);
+ processRequest(const boost::shared_ptr<Pkt6>& request);
/// @brief Stub function that will handle incoming RENEW messages.
///
/// @param renew message received from client
boost::shared_ptr<Pkt6>
- processRenew(boost::shared_ptr<Pkt6> renew);
+ processRenew(const boost::shared_ptr<Pkt6>& renew);
/// @brief Stub function that will handle incoming REBIND messages.
///
/// @param rebind message received from client
boost::shared_ptr<Pkt6>
- processRebind(boost::shared_ptr<Pkt6> rebind);
+ processRebind(const boost::shared_ptr<Pkt6>& rebind);
/// @brief Stub function that will handle incoming CONFIRM messages.
///
/// @param confirm message received from client
boost::shared_ptr<Pkt6>
- processConfirm(boost::shared_ptr<Pkt6> confirm);
+ processConfirm(const boost::shared_ptr<Pkt6>& confirm);
/// @brief Stub function that will handle incoming RELEASE messages.
///
/// @param release message received from client
boost::shared_ptr<Pkt6>
- processRelease(boost::shared_ptr<Pkt6> release);
+ processRelease(const boost::shared_ptr<Pkt6>& release);
/// @brief Stub function that will handle incoming DECLINE messages.
///
/// @param decline message received from client
boost::shared_ptr<Pkt6>
- processDecline(boost::shared_ptr<Pkt6> decline);
+ processDecline(const boost::shared_ptr<Pkt6>& decline);
/// @brief Stub function that will handle incoming INF-REQUEST messages.
///
/// @param infRequest message received from client
boost::shared_ptr<Pkt6>
- processInfRequest(boost::shared_ptr<Pkt6> infRequest);
+ processInfRequest(const boost::shared_ptr<Pkt6>& infRequest);
+
+ /// @brief Copies required options from client message to server answer
+ ///
+ /// Copies options that must appear in any server response (ADVERTISE, REPLY)
+ /// to client's messages (SOLICIT, REQUEST, RENEW, REBIND, DECLINE, RELEASE).
+ /// One notable example is client-id. Other options may be copied as required.
+ ///
+ /// @param question client's message (options will be copied from here)
+ /// @param answer server's message (options will be copied here)
+ void copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+ boost::shared_ptr<Pkt6>& answer);
+
+ /// @brief Appends default options to server's answer.
+ ///
+ /// Adds required options to server's answer. In particular, server-id
+ /// is added. Possibly other mandatory options will be added, depending
+ /// on type (or content) of client message.
+ ///
+ /// @param question client's message
+ /// @param answer server's message (options will be added here)
+ void appendDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+ boost::shared_ptr<Pkt6>& answer);
+
+ /// @brief Appends requested options to server's answer.
+ ///
+ /// Appends options requested by client to the server's answer.
+ /// TODO: This method is currently a stub. It just appends DNS-SERVERS
+ /// option.
+ ///
+ /// @param question client's message
+ /// @param answer server's message (options will be added here)
+ void appendRequestedOptions(const boost::shared_ptr<Pkt6>& question,
+ boost::shared_ptr<Pkt6>& answer);
+
+ /// @brief Assigns leases.
+ ///
+ /// TODO: This method is currently a stub. It just appends one
+ /// hardcoded lease. It supports addresses (IA_NA) only. It does NOT
+ /// support temporary addresses (IA_TA) nor prefixes (IA_PD).
+ ///
+ /// @param question client's message (with requested IA_NA)
+ /// @param answer server's message (IA_NA options will be added here)
+ void assignLeases(const boost::shared_ptr<Pkt6>& question,
+ boost::shared_ptr<Pkt6>& answer);
/// @brief Sets server-identifier.
///
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index 153ffda..b704370 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -211,13 +211,11 @@ bool IfaceMgr::openSockets4(uint16_t port) {
cout << "Trying interface " << iface->getFullName() << endl;
-#if 0
if (iface->flag_loopback_ ||
!iface->flag_up_ ||
!iface->flag_running_) {
continue;
}
-#endif
AddressCollection addrs = iface->getAddresses();
@@ -225,7 +223,7 @@ bool IfaceMgr::openSockets4(uint16_t port) {
addr != addrs.end();
++addr) {
- // skip IPv4 addresses
+ // skip IPv6 addresses
if (addr->getFamily() != AF_INET) {
continue;
}
@@ -251,6 +249,12 @@ bool IfaceMgr::openSockets6(uint16_t port) {
iface!=ifaces_.end();
++iface) {
+ if (iface->flag_loopback_ ||
+ !iface->flag_up_ ||
+ !iface->flag_running_) {
+ continue;
+ }
+
AddressCollection addrs = iface->getAddresses();
for (AddressCollection::iterator addr= addrs.begin();
@@ -276,15 +280,15 @@ bool IfaceMgr::openSockets6(uint16_t port) {
}
count++;
-#if 0
+#if defined(OS_LINUX)
// this doesn't work too well on NetBSD
- sock2 = openSocket(iface->getName(),
- IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
- DHCP6_SERVER_PORT);
+ int sock2 = openSocket(iface->getName(),
+ IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
+ port);
if (sock2<0) {
isc_throw(Unexpected, "Failed to open multicast socket on "
<< " interface " << iface->getFullName());
- iface->delSocket(sock1); // delete previously opened socket
+ iface->delSocket(sock); // delete previously opened socket
}
#endif
}
@@ -876,25 +880,32 @@ IfaceMgr::receive6() {
/// all available sockets. For now, we just take the
/// first interface and use first socket from it.
IfaceCollection::const_iterator iface = ifaces_.begin();
- if (iface == ifaces_.end()) {
- isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
- }
- SocketCollection::const_iterator s = iface->sockets_.begin();
const SocketInfo* candidate = 0;
- while (s != iface->sockets_.end()) {
- if (s->addr_.getFamily() != AF_INET6) {
+ while (iface != ifaces_.end()) {
+ SocketCollection::const_iterator s = iface->sockets_.begin();
+ while (s != iface->sockets_.end()) {
+ if (s->addr_.getFamily() != AF_INET6) {
+ ++s;
+ continue;
+ }
+ if (s->addr_.getAddress().to_v6().is_multicast()) {
+ candidate = &(*s);
+ break;
+ }
+ if (!candidate) {
+ candidate = &(*s); // it's not multicast, but it's better than nothing
+ }
++s;
- continue;
}
- if (s->addr_.getAddress().to_v6().is_multicast()) {
- candidate = &(*s);
+ if (candidate) {
break;
}
- if (!candidate) {
- candidate = &(*s); // it's not multicast, but it's better than nothing
- }
- ++s;
+ ++iface;
}
+ if (iface == ifaces_.end()) {
+ isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
+ }
+
if (!candidate) {
isc_throw(Unexpected, "Interface " << iface->getFullName()
<< " does not have any sockets open.");
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index 2cfd1ee..5eba76b 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/src/lib/dhcp/iface_mgr.h
@@ -343,7 +343,7 @@ public:
/// Opens IPv4 sockets on detected interfaces.
/// Will throw exception if socket creation fails.
///
- /// @param port specifies port number (usually DHCP6_SERVER_PORT)
+ /// @param port specifies port number (usually DHCP4_SERVER_PORT)
///
/// @return true if any sockets were open
bool openSockets4(uint16_t port = DHCP4_SERVER_PORT);
diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc
index a2db551..23de315 100644
--- a/src/lib/dhcp/option.cc
+++ b/src/lib/dhcp/option.cc
@@ -326,6 +326,21 @@ uint32_t Option::getUint32() {
return ( readUint32(&data_[0]) );
}
+void Option::setUint8(uint8_t value) {
+ data_.resize(1);
+ data_[0] = value;
+}
+
+void Option::setUint16(uint16_t value) {
+ data_.resize(2);
+ writeUint16(value, &data_[0]);
+}
+
+void Option::setUint32(uint32_t value) {
+ data_.resize(4);
+ writeUint32(value, &data_[0]);
+}
+
Option::~Option() {
}
diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h
index 00920fb..d80fc05 100644
--- a/src/lib/dhcp/option.h
+++ b/src/lib/dhcp/option.h
@@ -257,6 +257,27 @@ public:
/// @return uint32_t value stored on first four bytes
uint32_t getUint32();
+ /// @brief Sets content of this option to singe uint8 value.
+ ///
+ /// Option it resized appropriately (to length of 1 octet).
+ ///
+ /// @param value value to be set
+ void setUint8(uint8_t value);
+
+ /// @brief Sets content of this option to singe uint16 value.
+ ///
+ /// Option it resized appropriately (to length of 2 octets).
+ ///
+ /// @param value value to be set
+ void setUint16(uint16_t value);
+
+ /// @brief Sets content of this option to singe uint32 value.
+ ///
+ /// Option it resized appropriately (to length of 4 octets).
+ ///
+ /// @param value value to be set
+ void setUint32(uint32_t value);
+
/// just to force that every option has virtual dtor
virtual ~Option();
diff --git a/src/lib/dhcp/pkt4.cc b/src/lib/dhcp/pkt4.cc
index dcba2ed..e456631 100644
--- a/src/lib/dhcp/pkt4.cc
+++ b/src/lib/dhcp/pkt4.cc
@@ -125,7 +125,8 @@ Pkt4::pack() {
return (true);
}
-bool
+
+void
Pkt4::unpack() {
// input buffer (used during message reception)
@@ -156,7 +157,7 @@ Pkt4::unpack() {
// this is *NOT* DHCP packet. It does not have any DHCPv4 options. In
// particular, it does not have magic cookie, a 4 byte sequence that
// differentiates between DHCP and BOOTP packets.
- return (true);
+ isc_throw(InvalidOperation, "Recevied BOOTP packet. BOOTP is not supported.");
}
if (bufferIn.getLength() - bufferIn.getPosition() < 4) {
@@ -172,11 +173,13 @@ Pkt4::unpack() {
size_t opts_len = bufferIn.getLength() - bufferIn.getPosition();
vector<uint8_t> optsBuffer;
- // fist use of readVector
+ // First use of readVector.
bufferIn.readVector(optsBuffer, opts_len);
LibDHCP::unpackOptions4(optsBuffer, options_);
- return (true);
+ // TODO: check will need to be called separately, so hooks can be called after
+ // packet is parsed, but before its content is verified
+ check();
}
void Pkt4::check() {
diff --git a/src/lib/dhcp/pkt4.h b/src/lib/dhcp/pkt4.h
index 8fb0a65..c520747 100644
--- a/src/lib/dhcp/pkt4.h
+++ b/src/lib/dhcp/pkt4.h
@@ -74,9 +74,8 @@ public:
/// Will create a collection of option objects that will
/// be stored in options_ container.
///
- /// @return true, if parsing was successful
- bool
- unpack();
+ /// Method with throw exception if packet parsing fails.
+ void unpack();
/// @brief performs sanity check on a packet.
///
@@ -86,6 +85,8 @@ public:
/// reasonable value. This method is expected to grow significantly.
/// It makes sense to separate unpack() and check() for testing purposes.
///
+ /// TODO: It is called from unpack() directly. It should be separated.
+ ///
/// Method will throw exception if anomaly is found.
void check();
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
index ee0769d..9991e54 100644
--- a/src/lib/dhcp/tests/iface_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -406,6 +406,12 @@ TEST_F(IfaceMgrTest, sendReceive4) {
sendPkt->setYiaddr(IOAddress("192.0.2.3"));
sendPkt->setGiaddr(IOAddress("192.0.2.4"));
+ // unpack() now checks if mandatory DHCP_MESSAGE_TYPE is present
+ boost::shared_ptr<Option> msgType(new Option(Option::V4,
+ static_cast<uint16_t>(DHO_DHCP_MESSAGE_TYPE)));
+ msgType->setUint8(static_cast<uint8_t>(DHCPDISCOVER));
+ sendPkt->addOption(msgType);
+
uint8_t sname[] = "That's just a string that will act as SNAME";
sendPkt->setSname(sname, strlen((const char*)sname));
uint8_t file[] = "/another/string/that/acts/as/a/file_name.txt";
@@ -761,7 +767,7 @@ void parse_ifconfig(const std::string& textFile, IfaceMgr::IfaceCollection& ifac
// (check that each interface is reported, i.e. no missing or extra interfaces) and
// address completeness is verified.
//
-// Things that are not tested:
+// Things that are not tested:
// - ifindex (ifconfig does not print it out)
// - address scopes and lifetimes (we don't need it, so it is not implemented in IfaceMgr)
TEST_F(IfaceMgrTest, detectIfaces_linux) {
diff --git a/src/lib/dhcp/tests/option_unittest.cc b/src/lib/dhcp/tests/option_unittest.cc
index 1338ef7..c83a839 100644
--- a/src/lib/dhcp/tests/option_unittest.cc
+++ b/src/lib/dhcp/tests/option_unittest.cc
@@ -33,8 +33,14 @@ using namespace isc::util;
namespace {
class OptionTest : public ::testing::Test {
public:
- OptionTest() {
+ OptionTest(): outBuffer_(255) {
+ buf_ = boost::shared_array<uint8_t>(new uint8_t[255]);
+ for (int i = 0; i < 255; i++) {
+ buf_[i] = 255 - i;
+ }
}
+ boost::shared_array<uint8_t> buf_;
+ OutputBuffer outBuffer_;
};
// v4 is not really implemented yet. A simple test will do for now
@@ -421,6 +427,8 @@ TEST_F(OptionTest, v6_toText) {
}
TEST_F(OptionTest, getUintX) {
+
+ // TODO: Update this test to use buf_ instead of buf
boost::shared_array<uint8_t> buf(new uint8_t[5]);
buf[0] = 0x5;
buf[1] = 0x4;
@@ -457,3 +465,38 @@ TEST_F(OptionTest, getUintX) {
EXPECT_EQ(0x05040302, opt5->getUint32());
}
+
+TEST_F(OptionTest, setUintX) {
+ boost::shared_ptr<Option> opt1(new Option(Option::V4, 125));
+ boost::shared_ptr<Option> opt2(new Option(Option::V4, 125));
+ boost::shared_ptr<Option> opt4(new Option(Option::V4, 125));
+
+ // verify setUint8
+ opt1->setUint8(255);
+ EXPECT_EQ(255, opt1->getUint8());
+ opt1->pack4(outBuffer_);
+ EXPECT_EQ(3, opt1->len());
+ EXPECT_EQ(3, outBuffer_.getLength());
+ uint8_t exp1[] = {125, 1, 255};
+ EXPECT_TRUE(0 == memcmp(exp1, outBuffer_.getData(), 3));
+
+ // verify getUint16
+ outBuffer_.clear();
+ opt2->setUint16(12345);
+ opt2->pack4(outBuffer_);
+ EXPECT_EQ(12345, opt2->getUint16());
+ EXPECT_EQ(4, opt2->len());
+ EXPECT_EQ(4, outBuffer_.getLength());
+ uint8_t exp2[] = {125, 2, 12345/256, 12345%256};
+ EXPECT_TRUE(0 == memcmp(exp2, outBuffer_.getData(), 4));
+
+ // verity getUint32
+ outBuffer_.clear();
+ opt4->setUint32(0x12345678);
+ opt4->pack4(outBuffer_);
+ EXPECT_EQ(0x12345678, opt4->getUint32());
+ EXPECT_EQ(6, opt4->len());
+ EXPECT_EQ(6, outBuffer_.getLength());
+ uint8_t exp4[] = {125, 4, 0x12, 0x34, 0x56, 0x78};
+ EXPECT_TRUE(0 == memcmp(exp4, outBuffer_.getData(), 6));
+}
diff --git a/src/lib/dhcp/tests/pkt4_unittest.cc b/src/lib/dhcp/tests/pkt4_unittest.cc
index c1cf376..9936ca4 100644
--- a/src/lib/dhcp/tests/pkt4_unittest.cc
+++ b/src/lib/dhcp/tests/pkt4_unittest.cc
@@ -244,8 +244,18 @@ TEST(Pkt4Test, fixedFieldsPack) {
TEST(Pkt4Test, fixedFieldsUnpack) {
vector<uint8_t> expectedFormat = generateTestPacket2();
+ expectedFormat.push_back(0x63); // magic cookie
+ expectedFormat.push_back(0x82);
+ expectedFormat.push_back(0x53);
+ expectedFormat.push_back(0x63);
+
+ expectedFormat.push_back(0x35); // message-type
+ expectedFormat.push_back(0x1);
+ expectedFormat.push_back(0x1);
+
boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
- Pkt4::DHCPV4_PKT_HDR_LEN));
+ expectedFormat.size()));;
+
EXPECT_NO_THROW(
pkt->unpack()
@@ -441,8 +451,9 @@ static uint8_t v4Opts[] = {
12, 3, 0, 1, 2,
13, 3, 10, 11, 12,
14, 3, 20, 21, 22,
+ 53, 1, 1, // DHCP_MESSAGE_TYPE (required to not throw exception during unpack)
128, 3, 30, 31, 32,
- 254, 3, 40, 41, 42
+ 254, 3, 40, 41, 42,
};
TEST(Pkt4Test, options) {
@@ -458,14 +469,17 @@ TEST(Pkt4Test, options) {
boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
boost::shared_ptr<Option> opt2(new Option(Option::V4, 13, payload[1]));
boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[2]));
+ boost::shared_ptr<Option> optMsgType(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE));
boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[3]));
boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[4]));
+ optMsgType->setUint8(static_cast<uint8_t>(DHCPDISCOVER));
pkt->addOption(opt1);
pkt->addOption(opt2);
pkt->addOption(opt3);
pkt->addOption(opt4);
pkt->addOption(opt5);
+ pkt->addOption(optMsgType);
EXPECT_TRUE(pkt->getOption(12));
EXPECT_TRUE(pkt->getOption(13));
@@ -556,14 +570,14 @@ TEST(Pkt4Test, unpackOptions) {
EXPECT_EQ(128, x->getType()); // this should be option 254
ASSERT_EQ(3, x->getData().size()); // it should be of length 3
EXPECT_EQ(5, x->len()); // total option length 5
- EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+17, 3)); // data len=3
+ EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+20, 3)); // data len=3
x = pkt->getOption(254);
ASSERT_TRUE(x); // option 3 should exist
EXPECT_EQ(254, x->getType()); // this should be option 254
ASSERT_EQ(3, x->getData().size()); // it should be of length 3
EXPECT_EQ(5, x->len()); // total option length 5
- EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+22, 3)); // data len=3
+ EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+25, 3)); // data len=3
}
// This test verifies methods that are used for manipulating meta fields
More information about the bind10-changes
mailing list