bool
Dhcpv4Srv::run() {
while (!shutdown_) {
- Pkt4Ptr query; // client's message
- Pkt4Ptr rsp; // server's response
- query = IfaceMgr::instance().receive4();
+ // client's message
+ Pkt4Ptr query = IfaceMgr::instance().receive4();
+ Pkt4Ptr rsp; // server's response
if (query) {
try {
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <time.h>
#include <dhcp/dhcp6.h>
#include <dhcp/pkt6.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/option6_addrlst.h>
#include <asiolink/io_address.h>
#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
using namespace std;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::asiolink;
+using namespace isc::util;
const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
const uint32_t HARDCODED_T1 = 1500; // in seconds
IfaceMgr::instance().closeSockets();
}
-bool
-Dhcpv6Srv::run() {
+bool Dhcpv6Srv::run() {
while (!shutdown) {
- Pkt6Ptr query; // client's message
- Pkt6Ptr rsp; // server's response
- query = IfaceMgr::instance().receive6();
+ Pkt6Ptr query = IfaceMgr::instance().receive6(); // client's message
+ Pkt6Ptr rsp; // server's response
if (query) {
if (!query->unpack()) {
return (true);
}
-void
-Dhcpv6Srv::setServerID() {
- /// TODO implement this for real once interface detection is done.
- /// Use hardcoded server-id for now
-
- OptionBuffer srvid(14);
- srvid[0] = 0;
- srvid[1] = 1; // DUID type 1 = DUID-LLT (see section 9.2 of RFC3315)
- srvid[2] = 0;
- srvid[3] = 6; // HW type = ethernet (I think. I'm typing this from my head
- // in hotel, without Internet connection)
- for (int i=4; i<14; i++) {
- srvid[i]=i-4;
+void Dhcpv6Srv::setServerID() {
+
+ /// @todo: DUID should be generated once and then stored, rather
+ /// than generated each time
+
+ /// @todo: This code implements support for DUID-LLT (the recommended one).
+ /// We should eventually add support for other DUID types: DUID-LL, DUID-EN
+ /// and DUID-UUID
+
+ const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+ // let's find suitable interface
+ for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
+ iface != ifaces.end(); ++iface) {
+ // all those conditions could be merged into one multi-condition
+ // statement, but let's keep them separated as perhaps one day
+ // we will grow knobs to selectively turn them on or off. Also,
+ // this code is used only *once* during first start on a new machine
+ // and then server-id is stored. (or at least it will be once
+ // DUID storage is implemente
+
+ // I wish there was a this_is_a_real_physical_interface flag...
+
+ // mac at least 6 bytes. All decent physical interfaces (Ethernet,
+ // WiFi, Infiniband, etc.) have 6 bytes long MAC address
+ if (iface->mac_len_ < 6) {
+ continue;
+ }
+
+ // let's don't use loopback
+ if (iface->flag_loopback_) {
+ continue;
+ }
+
+ // let's skip downed interfaces. It is better to use working ones.
+ if (!iface->flag_up_) {
+ continue;
+ }
+
+ uint8_t zeros[IfaceMgr::MAX_MAC_LEN];
+ memset(zeros, 0, IfaceMgr::MAX_MAC_LEN);
+
+ // some interfaces (like lo on Linux) report 6-bytes long
+ // MAC adress 00:00:00:00:00:00. Let's not use such weird interfaces
+ // to generate DUID.
+ if (!memcmp(iface->mac_, zeros, iface->mac_len_)) {
+ continue;
+ }
+
+ // Ok, we have useful MAC. Let's generate DUID-LLT based on
+ // it. See RFC3315, Section 9.2 for details.
+
+ // DUID uses seconds since midnight of 01-01-2000, time() returns
+ // seconds since 01-01-1970. DUID_TIME_EPOCH substution corrects that.
+ time_t seconds = time(NULL);
+ seconds -= DUID_TIME_EPOCH;
+
+ OptionBuffer srvid(8 + iface->mac_len_);
+ writeUint16(DUID_LLT, &srvid[0]);
+ writeUint16(HWTYPE_ETHERNET, &srvid[2]);
+ writeUint32(static_cast<uint32_t>(seconds), &srvid[4]);
+ memcpy(&srvid[0]+8, iface->mac_, iface->mac_len_);
+
+ serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID,
+ srvid.begin(), srvid.end()));
+ return;
}
- serverid_ = boost::shared_ptr<Option>(new Option(Option::V6,
- D6O_SERVERID,
- srvid.begin(),
- srvid.end()));
+
+ // if we reached here, there are no suitable interfaces found.
+ // Either interface detection is not supported on this platform or
+ // this is really weird box. Let's use DUID-EN instead.
+ // See Section 9.3 of RFC3315 for details.
+
+ OptionBuffer srvid(12);
+ srand(time(NULL));
+ writeUint16(DUID_EN, &srvid[0]);
+ writeUint32(ENTERPRISE_ID_ISC, &srvid[2]);
+
+ // length of the identifier is company specific. I hereby declare
+ // ISC standard of 6 bytes long random numbers.
+ for (int i = 6; i < 12; i++) {
+ srvid[i] = static_cast<uint8_t>(rand());
+ }
+ serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID,
+ srvid.begin(), srvid.end()));
}
void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
}
Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
-
Pkt6Ptr advertise(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
copyDefaultOptions(solicit, advertise);
}
Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
-
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid()));
copyDefaultOptions(request, reply);
}
Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
+ /// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid()));
return reply;
}
Pkt6Ptr Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
- Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY,
- rebind->getTransid(),
- Pkt6::UDP));
+ /// @todo: Implement this
+ Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
return reply;
}
Pkt6Ptr Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
+ /// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
return reply;
}
Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
+ /// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
return reply;
}
Pkt6Ptr Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
+ /// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
return reply;
}
Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
+ /// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, infRequest->getTransid()));
return reply;
}
#include <arpa/inet.h>
#include <gtest/gtest.h>
-#include "dhcp/dhcp6.h"
-#include "dhcp6/dhcp6_srv.h"
-#include "dhcp/option6_ia.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp6/dhcp6_srv.h>
+#include <util/buffer.h>
using namespace std;
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::util;
// namespace has to be named, because friends are defined in Dhcpv6Srv class
// Maybe it should be isc::test?
delete srv;
}
+TEST_F(Dhcpv6SrvTest, DUID) {
+ // tests that DUID is generated properly
+
+ Dhcpv6Srv* srv = NULL;
+ ASSERT_NO_THROW( {
+ srv = new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000);
+ });
+
+ OptionPtr srvid = srv->getServerID();
+ ASSERT_TRUE(srvid);
+
+ EXPECT_EQ(D6O_SERVERID, srvid->getType());
+
+ OutputBuffer buf(32);
+ srvid->pack(buf);
+
+ // length of the actual DUID
+ size_t len = buf.getLength() - srvid->getHeaderLen();
+
+ InputBuffer data(buf.getData(), buf.getLength());
+
+ // ignore first four bytes (standard DHCPv6 header)
+ data.readUint32();
+
+ uint16_t duid_type = data.readUint16();
+ cout << "Duid-type=" << duid_type << endl;
+ switch(duid_type) {
+ case DUID_LLT: {
+ // DUID must contain at least 6 bytes long MAC
+ // + 8 bytes of fixed header
+ EXPECT_GE(14, len);
+
+ uint16_t hw_type = data.readUint16();
+ // there's no real way to find out "correct"
+ // hardware type
+ EXPECT_GT(hw_type, 0);
+
+ // check that timer is counted since 1.1.2000,
+ // not from 1.1.1970.
+ uint32_t seconds = data.readUint32();
+ EXPECT_LE(seconds, DUID_TIME_EPOCH);
+ // this test will start failing after 2030.
+ // Hopefully we will be at BIND12 by then.
+
+ // MAC must not be zeros
+ vector<uint8_t> mac(len-8);
+ vector<uint8_t> zeros(len-8, 0);
+ data.readVector(mac, len-8);
+ EXPECT_NE(mac, zeros);
+ break;
+ }
+ case DUID_EN: {
+ // there's not much we can check. Just simple
+ // check if it is not all zeros
+ vector<uint8_t> content(len-2);
+ vector<uint8_t> zeros(0, len-2);
+ data.readVector(content, len-2);
+ EXPECT_NE(content, zeros);
+ }
+ case DUID_LL: // not supported yet
+ case DUID_UUID: // not supported yet
+ default:
+ cout << "Not supported duid type=" << duid_type << endl;
+ FAIL();
+ }
+}
+
TEST_F(Dhcpv6SrvTest, Solicit_basic) {
NakedDhcpv6Srv* srv = NULL;
ASSERT_NO_THROW( srv = new NakedDhcpv6Srv(); );
// a dummy content for client-id
OptionBuffer clntDuid(32);
- for (int i = 0; i < 32; i++)
+ for (int i = 0; i < 32; i++) {
clntDuid[i] = 100 + i;
+ }
- Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234, Pkt6::UDP));
+ Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
boost::shared_ptr<Option6IA> ia =
boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
OptionPtr clientid = OptionPtr(new Option(Option::V6, D6O_CLIENTID,
clntDuid.begin(),
- clntDuid.begin()+16));
+ clntDuid.begin() + 16));
sol->addOption(clientid);
boost::shared_ptr<Pkt6> reply = srv->processSolicit(sol);
#define DUID_LLT 1
#define DUID_EN 2
#define DUID_LL 3
+#define DUID_UUID 4
+
+// Define hardware types
+// Taken from http://www.iana.org/assignments/arp-parameters/
+#define HWTYPE_ETHERNET 0x0001
+#define HWTYPE_INIFINIBAND 0x0020
+
+// Taken from http://www.iana.org/assignments/enterprise-numbers
+#define ENTERPRISE_ID_ISC 2495
/* Offsets into IA_*'s where Option spaces commence. */
#define IA_NA_OFFSET 12 /* IAID, T1, T2, all 4 octets each */
cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
+ iface.flag_up_ = true;
+ iface.flag_running_ = true;
+ iface.flag_loopback_ = false;
+ iface.flag_multicast_ = true;
+ iface.flag_broadcast_ = true;
+ iface.hardware_type_ = HWTYPE_ETHERNET;
IOAddress addr(linkLocal);
iface.addAddress(addr);
addInterface(iface);
return (NULL); // not found
}
-int IfaceMgr::openSocket(const std::string& ifname,
- const IOAddress& addr,
- int port) {
+int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr, uint16_t port) {
Iface* iface = getIface(ifname);
if (!iface) {
isc_throw(BadValue, "There is no " << ifname << " interface present.");
}
}
-int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
+int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
cout << "Creating UDP4 socket on " << iface.getFullName()
<< " " << addr.toText() << "/port=" << port << endl;
return (sock);
}
-int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
+int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
cout << "Creating UDP6 socket on " << iface.getFullName()
<< " " << addr.toText() << "/port=" << port << endl;
}
bool
-IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
+IfaceMgr::send(const Pkt6Ptr& pkt) {
struct msghdr m;
struct iovec v;
int result;
// Set the data buffer we're sending. (Using this wacky
// "scatter-gather" stuff... we only have a single chunk
// of data to send, so we declare a single vector entry.)
- v.iov_base = (char *) pkt->getBuffer().getData();
+ v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
v.iov_len = pkt->getBuffer().getLength();
m.msg_iov = &v;
m.msg_iovlen = 1;
}
bool
-IfaceMgr::send(boost::shared_ptr<Pkt4>& pkt)
+IfaceMgr::send(const Pkt4Ptr& pkt)
{
struct msghdr m;
struct iovec v;
- int result;
Iface* iface = getIface(pkt->getIface());
if (!iface) {
m.msg_iov = &v;
m.msg_iovlen = 1;
-// OS_LINUX defines are part of ticket #1237
#if defined(OS_LINUX)
// Setting the interface is a bit more involved.
//
// define the IPv4 packet information. We could set the
// source address if we wanted, but we can safely let the
// kernel decide what that should be.
- struct in_pktinfo *pktinfo;
- struct cmsghdr *cmsg;
m.msg_control = &control_buf_[0];
m.msg_controllen = control_buf_len_;
- cmsg = CMSG_FIRSTHDR(&m);
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
- pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
- memset(pktinfo, 0, sizeof(*pktinfo));
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ struct in_pktinfo* pktinfo =(struct in_pktinfo *)CMSG_DATA(cmsg);
+ memset(pktinfo, 0, sizeof(struct in_pktinfo));
pktinfo->ipi_ifindex = pkt->getIndex();
m.msg_controllen = cmsg->cmsg_len;
#endif
<< " over socket " << getSocket(*pkt) << " on interface "
<< getIface(pkt->getIface())->getFullName() << endl;
- result = sendmsg(getSocket(*pkt), &m, 0);
+ int result = sendmsg(getSocket(*pkt), &m, 0);
if (result < 0) {
isc_throw(Unexpected, "Pkt4 send failed.");
}
IfaceCollection::const_iterator iface;
for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
-#if 0
- // uncomment this once #1237 is merged
- // Let's skip loopback and downed interfaces.
- if (iface->flag_loopback_ ||
- !iface->flag_up_ ||
- !iface->flag_running_) {
- continue;
- }
-#endif
-
- SocketCollection::const_iterator s = iface->sockets_.begin();
- while (s != iface->sockets_.end()) {
+ /// @todo: rewrite this as part of #1555
+ for (SocketCollection::const_iterator s = iface->sockets_.begin();
+ s != iface->sockets_.end(); ++s) {
// We don't want IPv6 addresses here.
if (s->addr_.getFamily() != AF_INET) {
- ++s;
continue;
}
candidate = &(*s);
break;
}
-
- ++s;
}
if (candidate) {
<< iface->getFullName() << endl;
// Now we have a socket, let's get some data from it!
-
- struct msghdr m;
- struct iovec v;
- int result;
struct sockaddr_in from_addr;
struct in_addr to_addr;
- boost::shared_ptr<Pkt4> pkt;
const uint32_t RCVBUFSIZE = 1500;
static uint8_t buf[RCVBUFSIZE];
memset(&to_addr, 0, sizeof(to_addr));
// Initialize our message header structure.
+ struct msghdr m;
memset(&m, 0, sizeof(m));
// Point so we can get the from address.
m.msg_name = &from_addr;
m.msg_namelen = sizeof(from_addr);
- v.iov_base = (void*)buf;
+ struct iovec v;
+ v.iov_base = static_cast<void*>(buf);
v.iov_len = RCVBUFSIZE;
m.msg_iov = &v;
m.msg_iovlen = 1;
m.msg_control = &control_buf_[0];
m.msg_controllen = control_buf_len_;
- result = recvmsg(candidate->sockfd_, &m, 0);
-
+ int result = recvmsg(candidate->sockfd_, &m, 0);
if (result < 0) {
cout << "Failed to receive UDP4 data." << endl;
- return (boost::shared_ptr<Pkt4>()); // NULL
+ return (Pkt4Ptr()); // NULL
}
unsigned int ifindex = iface->getIndex();
-// OS_LINUX defines are part of ticket #1237
#if defined(OS_LINUX)
struct cmsghdr* cmsg;
struct in_pktinfo* pktinfo;
<< iface->getFullName() << endl;
// we have all data let's create Pkt4 object
- pkt = boost::shared_ptr<Pkt4>(new Pkt4(buf, result));
+ Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf, result));
pkt->setIface(iface->getName());
pkt->setIndex(ifindex);
struct in6_pktinfo* pktinfo;
struct sockaddr_in6 from;
struct in6_addr to_addr;
- int ifindex;
+ int ifindex = -1;
Pkt6Ptr pkt;
// RFC3315 states that server responses may be
IfaceCollection::const_iterator iface = ifaces_.begin();
const SocketInfo* candidate = 0;
while (iface != ifaces_.end()) {
- SocketCollection::const_iterator s = iface->sockets_.begin();
- while (s != iface->sockets_.end()) {
+ for (SocketCollection::const_iterator s = iface->sockets_.begin();
+ s != iface->sockets_.end(); ++s) {
if (s->addr_.getFamily() != AF_INET6) {
- ++s;
continue;
}
if (s->addr_.getAddress().to_v6().is_multicast()) {
if (!candidate) {
candidate = &(*s); // it's not multicast, but it's better than nothing
}
- ++s;
}
if (candidate) {
break;
++iface;
}
if (iface == ifaces_.end()) {
- isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
+ isc_throw(Unexpected, "No suitable IPv6 interfaces detected. Can't receive anything.");
}
if (!candidate) {
}
if (!found_pktinfo) {
cout << "Unable to find pktinfo" << endl;
- return (boost::shared_ptr<Pkt6>()); // NULL
+ return (Pkt6Ptr()); // NULL
}
} else {
cout << "Failed to receive data." << endl;
- return (boost::shared_ptr<Pkt6>()); // NULL
+ return (Pkt6Ptr()); // NULL
}
pkt = Pkt6Ptr(new Pkt6(buf, result));
} catch (const std::exception& ex) {
cout << "Failed to create new packet." << endl;
- return (boost::shared_ptr<Pkt6>()); // NULL
+ return (Pkt6Ptr()); // NULL
}
- pkt->setLocalAddr(IOAddress::from_bytes(AF_INET6, (const uint8_t*)&to_addr));
- pkt->setRemoteAddr(IOAddress::from_bytes(AF_INET6, (const uint8_t*)&from.sin6_addr));
+ pkt->setLocalAddr(IOAddress::from_bytes(AF_INET6, reinterpret_cast<const uint8_t*>(&to_addr)));
+ pkt->setRemoteAddr(IOAddress::from_bytes(AF_INET6, reinterpret_cast<const uint8_t*>(&from.sin6_addr)));
pkt->setRemotePort(ntohs(from.sin6_port));
return (pkt);
}
-uint16_t IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
+uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
Iface* iface = getIface(pkt.getIface());
if (!iface) {
isc_throw(BadValue, "Tried to find socket for non-existent interface "
SocketCollection::const_iterator s;
for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
- if (s->family_ != AF_INET6) {
- // don't use IPv4 sockets
- continue;
- }
- if (s->addr_.getAddress().to_v6().is_multicast()) {
- // don't use IPv6 sockets bound to multicast address
- continue;
+ if ( (s->family_ == AF_INET6) &&
+ (!s->addr_.getAddress().to_v6().is_multicast()) ) {
+ return (s->sockfd_);
}
/// TODO: Add more checks here later. If remote address is
/// not link-local, we can't use link local bound socket
/// to send data.
-
- return (s->sockfd_);
}
isc_throw(Unexpected, "Interface " << iface->getFullName()
SocketCollection::const_iterator s;
for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
- if (s->family_ != AF_INET) {
- // don't use IPv6 sockets
- continue;
+ if (s->family_ == AF_INET) {
+ return (s->sockfd_);
}
-
/// TODO: Add more checks here later. If remote address is
/// not link-local, we can't use link local bound socket
/// to send data.
-
- return (s->sockfd_);
}
isc_throw(Unexpected, "Interface " << iface->getFullName()
Iface*
getIface(const std::string& ifname);
+ /// @brief Returns container with all interfaces.
+ ///
+ /// @return container with all interfaces.
+ const IfaceCollection& getIfaces() { return ifaces_; }
+
/// @brief Return most suitable socket for transmitting specified IPv6 packet.
///
/// This method takes Pkt6 (see overloaded implementation that takes
/// @param pkt packet to be sent
///
/// @return true if sending was successful
- bool send(boost::shared_ptr<Pkt6>& pkt);
+ bool send(const Pkt6Ptr& pkt);
/// @brief Sends an IPv4 packet.
///
/// @param pkt a packet to be sent
///
/// @return true if sending was successful
- bool send(boost::shared_ptr<Pkt4>& pkt);
+ bool send(const Pkt4Ptr& pkt);
/// @brief Tries to receive IPv6 packet over open IPv6 sockets.
///
/// @return socket descriptor, if socket creation, binding and multicast
/// group join were all successful.
int openSocket(const std::string& ifname,
- const isc::asiolink::IOAddress& addr, int port);
+ const isc::asiolink::IOAddress& addr, uint16_t port);
/// Opens IPv6 sockets on detected interfaces.
///
/// @param port a port that created socket should be bound to
///
/// @return socket descriptor
- int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
+ int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr, uint16_t port);
/// @brief Opens IPv6 socket.
///
/// @param port a port that created socket should be bound to
///
/// @return socket descriptor
- int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
+ int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, uint16_t port);
/// @brief Adds an interface to list of known interfaces.
///
std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
-uint32_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
- isc::dhcp::Option::OptionCollection& options) {
- uint32_t offset = 0;
- unsigned int end = buf.size();
+size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
+ isc::dhcp::Option::OptionCollection& options) {
+ size_t offset = 0;
+ size_t end = buf.size();
while (offset +4 <= end) {
uint16_t opt_type = buf[offset]*256 + buf[offset+1];
return (offset);
}
-uint32_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
+size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
isc::dhcp::Option::OptionCollection& options) {
size_t offset = 0;
- // 2 - header of DHCPv4 option
+ // 2 byte - header of DHCPv4 option
while (offset + 1 <= buf.size()) {
uint8_t opt_type = buf[offset++];
+ // DHO_END is a special, one octet long option
if (opt_type == DHO_END)
return (offset); // just return. Don't need to add DHO_END option
+ // DHO_PAD is just a padding after DHO_END. Let's continue parsing
+ // in case we receive a message without DHO_END.
+ if (opt_type == DHO_PAD)
+ continue;
+
if (offset + 1 >= buf.size()) {
isc_throw(OutOfRange, "Attempt to parse truncated option "
<< opt_type);
/// @param buf Buffer to be parsed.
/// @param options Reference to option container. Options will be
/// put here.
- static uint32_t unpackOptions4(const OptionBuffer& buf,
- isc::dhcp::Option::OptionCollection& options);
+ static size_t unpackOptions4(const OptionBuffer& buf,
+ isc::dhcp::Option::OptionCollection& options);
/// @brief Parses provided buffer as DHCPv6 options and creates Option objects.
///
/// @param buf Buffer to be parsed.
/// @param options Reference to option container. Options will be
/// put here.
- static uint32_t unpackOptions6(const OptionBuffer& buf,
- isc::dhcp::Option::OptionCollection& options);
+ static size_t unpackOptions6(const OptionBuffer& buf,
+ isc::dhcp::Option::OptionCollection& options);
/// Registers factory method that produces options of specific option types.
///
/// TODO: Migrate DHCPv6 code to pack(OutputBuffer& buf) version
///
/// @param buf pointer to a buffer
- ///
- /// @return offset to first unused byte after stored option
- ///
virtual void pack(isc::util::OutputBuffer& buf);
/// @brief Writes option in a wire-format to a buffer.
/// @param buf output buffer (option will be stored there)
virtual void pack4(isc::util::OutputBuffer& buf);
- /// @brief Parses buffer.
- ///
- /// Parses received buffer, returns offset to the first unused byte after
- /// parsed option.
+ /// @brief Parses received buffer.
///
/// @param begin iterator to first byte of option data
/// @param end iterator to end of option data (first byte after option end)
/// @param indent number of spaces before printing text
///
/// @return string with text representation.
- virtual std::string
- toText(int indent = 0);
+ virtual std::string toText(int indent = 0);
/// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
///
/// @return option type
- unsigned short getType() { return (type_); }
+ uint16_t getType() { return (type_); }
/// Returns length of the complete option (data length + DHCPv4/DHCPv6
/// option header)
///
/// @return length of the option
- virtual uint16_t
- len();
+ virtual uint16_t len();
/// @brief Returns length of header (2 for v4, 4 for v6)
///
/// @return length of option header
- virtual uint16_t
- getHeaderLen();
+ virtual uint16_t getHeaderLen();
/// returns if option is valid (e.g. option may be truncated)
///
/// @return true, if option is valid
- virtual bool
- valid();
+ virtual bool valid();
/// Returns pointer to actual data.
///
/// @param buf pointer to a buffer
void pack(isc::util::OutputBuffer& buf);
- /// @brief Parses buffer.
- ///
- /// Parses received buffer, returns offset to the first unused byte after
- /// parsed option.
+ /// @brief Parses received buffer.
///
/// @param begin iterator to first byte of option data
/// @param end iterator to end of option data (first byte after option end)