Commit f89dbf48 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[1186] Changes in reply to review comment 13.

parent a91fbbe9
299. [func]* tomek
libdhcp: DHCP packet library was implemented. Currently it handles
packet reception, option parsing, option generation and output
packet building. Generic and specialized classes for several
DHCPv6 options (IA_NA, IAADDR, address-list) are available. A
simple code was added that leverages libdhcp. It is a skeleton
DHCPv6 server. It receives incoming SOLICIT and REQUEST messages
and responds with proper ADVERTISE and REPLY. Note that since
LeaseManager is not implemented, server assigns a the same
hardcoded lease for every client.
bind10-devel-20111014 released on October 14, 2011
298. [doc] jreed
......
......@@ -23,143 +23,134 @@
namespace isc {
namespace dhcp {
/// @brief DHCPv6 server service.
///
/// This singleton class represents DHCPv6 server. It contains all
/// top-level methods and routines necessary for server operation.
/// In particular, it instantiates IfaceMgr, loads or generates DUID
/// that is going to be used as server-identifier, receives incoming
/// packets, processes them, manages leases assignment and generates
/// appropriate responses.
class Dhcpv6Srv : public boost::noncopyable {
private:
/// @brief A private copy constructor.
///
/// Creates a single Dhcpv6Srv instance and all required objects,
/// including interface manager (IfaceMgr). It is defined private on
/// purpose. We don't want to have more than one copy of Dhcpv6Srv.
///
/// It may throw exceptions if server creation failed, e.g. due to
/// failures in IfaceMgr (e.g. socket creation) or unavailable
/// interfaces when attempting to create new DUID.
Dhcpv6Srv(const Dhcpv6Srv& src);
/// @brief A private assignment operator.
///
/// Note that there is no implementation of this assignment operator.
/// Its definition is here to prevent creation of any copies.
///
Dhcpv6Srv& operator=(const Dhcpv6Srv& src);
/// @brief Sets server-identifier.
///
/// This method attempts to set server-identifier DUID. It loads it
/// from a file. If file load fails, it generates new DUID using
/// interface link-layer addresses (EUI-64) + timestamp (DUID type
/// duid-llt, see RFC3315, section 9.2). If there are no suitable
/// interfaces present, exception it thrown
///
/// @throws isc::Unexpected Failed to read DUID file and no suitable
/// interfaces for new DUID generation are detected.
void setServerID();
/// server DUID (to be sent in server-identifier option)
boost::shared_ptr<isc::dhcp::Option> serverid_;
public:
/// @brief Default constructor.
///
/// Instantiates necessary services, required to run DHCPv6 server.
/// In particular, creates IfaceMgr that will be responsible for
/// network interaction. Will instantiate lease manager, and load
/// old or create new DUID.
Dhcpv6Srv();
/// @brief Destructor. Shuts down DHCPv6 service.
~Dhcpv6Srv();
/// @brief Returns server-intentifier option
///
/// @return reference to server-id option
///
boost::shared_ptr<isc::dhcp::Option>&
getServerID() { return serverid_; }
/// @brief Main server processing loop.
///
/// Main server processing loop. Receives incoming packets, verifies
/// their correctness, generates appropriate answer (if needed) and
/// transmits respones.
///
/// @return true, if being shut down gracefully, fail if experienced
/// critical error.
bool run();
protected:
/// @brief Processes incoming SOLICIT and returns response.
///
/// Processes received SOLICIT message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with to-be assinged addresses, temporary addresses and delegated
/// prefixes, respectively. In the usual 4 message exchange, server is
/// expected to respond with ADVERTISE message. However, if client
/// requests rapid-commit and server supports it, REPLY will be sent
/// instead of ADVERTISE and requested leases will be assigned
/// immediately.
///
/// @param solicit SOLICIT message received from client
///
/// @return ADVERTISE, REPLY message or NULL
///
boost::shared_ptr<Pkt6>
processSolicit(boost::shared_ptr<Pkt6> solicit);
/// @brief Processes incoming REQUEST and returns REPLY response.
///
/// Processes incoming REQUEST message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with assinged addresses, temporary addresses and delegated
/// prefixes, respectively. Uses LeaseMgr to allocate or update existing
/// leases.
///
/// @param request REQUEST message received from client
///
/// @return REPLY message or NULL
boost::shared_ptr<Pkt6>
processRequest(boost::shared_ptr<Pkt6> request);
/// @brief Stub function that will handle incoming RENEW messages.
boost::shared_ptr<Pkt6>
processRenew(boost::shared_ptr<Pkt6> renew);
/// @brief Stub function that will handle incoming REBIND messages.
boost::shared_ptr<Pkt6>
processRebind(boost::shared_ptr<Pkt6> rebind);
/// @brief Stub function that will handle incoming CONFIRM messages.
boost::shared_ptr<Pkt6>
processConfirm(boost::shared_ptr<Pkt6> confirm);
/// @brief Stub function that will handle incoming RELEASE messages.
boost::shared_ptr<Pkt6>
processRelease(boost::shared_ptr<Pkt6> release);
/// @brief Stub function that will handle incoming DECLINE messages.
boost::shared_ptr<Pkt6>
processDecline(boost::shared_ptr<Pkt6> decline);
/// @brief Stub function that will handle incoming INF-REQUEST messages.
boost::shared_ptr<Pkt6>
processInfRequest(boost::shared_ptr<Pkt6> infRequest);
/// indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
volatile bool shutdown;
};
}; // namespace isc::dhcp
namespace dhcp {
/// @brief DHCPv6 server service.
///
/// This singleton class represents DHCPv6 server. It contains all
/// top-level methods and routines necessary for server operation.
/// In particular, it instantiates IfaceMgr, loads or generates DUID
/// that is going to be used as server-identifier, receives incoming
/// packets, processes them, manages leases assignment and generates
/// appropriate responses.
class Dhcpv6Srv : public boost::noncopyable {
public:
/// @brief Default constructor.
///
/// Instantiates necessary services, required to run DHCPv6 server.
/// In particular, creates IfaceMgr that will be responsible for
/// network interaction. Will instantiate lease manager, and load
/// old or create new DUID.
Dhcpv6Srv();
/// @brief Destructor. Used during DHCPv6 service shutdown.
~Dhcpv6Srv();
/// @brief Returns server-intentifier option
///
/// @return server-id option
boost::shared_ptr<isc::dhcp::Option>
getServerID() { return serverid_; }
/// @brief Main server processing loop.
///
/// Main server processing loop. Receives incoming packets, verifies
/// their correctness, generates appropriate answer (if needed) and
/// transmits respones.
///
/// @return true, if being shut down gracefully, fail if experienced
/// critical error.
bool run();
protected:
/// @brief Processes incoming SOLICIT and returns response.
///
/// Processes received SOLICIT message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with to-be assinged addresses, temporary addresses and delegated
/// prefixes, respectively. In the usual 4 message exchange, server is
/// expected to respond with ADVERTISE message. However, if client
/// requests rapid-commit and server supports it, REPLY will be sent
/// instead of ADVERTISE and requested leases will be assigned
/// immediately.
///
/// @param solicit SOLICIT message received from client
///
/// @return ADVERTISE, REPLY message or NULL
boost::shared_ptr<Pkt6>
processSolicit(boost::shared_ptr<Pkt6> solicit);
/// @brief Processes incoming REQUEST and returns REPLY response.
///
/// Processes incoming REQUEST message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with assinged addresses, temporary addresses and delegated
/// prefixes, respectively. Uses LeaseMgr to allocate or update existing
/// leases.
///
/// @param request a message received from client
///
/// @return REPLY message or NULL
boost::shared_ptr<Pkt6>
processRequest(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);
/// @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);
/// @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);
/// @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);
/// @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);
/// @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);
/// @brief Sets server-identifier.
///
/// This method attempts to set server-identifier DUID. It loads it
/// from a file. If file load fails, it generates new DUID using
/// interface link-layer addresses (EUI-64) + timestamp (DUID type
/// duid-llt, see RFC3315, section 9.2). If there are no suitable
/// interfaces present, exception it thrown
///
/// @throws isc::Unexpected Failed to read DUID file and no suitable
/// interfaces for new DUID generation are detected.
void setServerID();
/// server DUID (to be sent in server-identifier option)
boost::shared_ptr<isc::dhcp::Option> serverid_;
/// indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
volatile bool shutdown;
};
}; // namespace isc::dhcp
}; // namespace isc
#endif // DHCP6_SRV_H
......@@ -69,10 +69,10 @@ IfaceMgr::Iface::getPlainMac() const {
ostringstream tmp;
tmp.fill('0');
tmp << hex;
for (int i=0; i<mac_len_; i++) {
for (int i = 0; i < mac_len_; i++) {
tmp.width(2);
tmp << mac_[i];
if (i<mac_len_-1) {
if (i < mac_len_-1) {
tmp << ":";
}
}
......
......@@ -23,190 +23,201 @@
namespace isc {
namespace dhcp {
/// @brief handles network interfaces, transmission and reception
namespace dhcp {
/// @brief handles network interfaces, transmission and reception
///
/// IfaceMgr is an interface manager class that detects available network
/// interfaces, configured addresses, link-local addresses, and provides
/// API for using sockets.
///
class IfaceMgr : public boost::noncopyable {
public:
/// type that defines list of addresses
typedef std::list<isc::asiolink::IOAddress> Addr6Lst;
/// maximum MAC address length (Infiniband uses 20 bytes)
static const unsigned int MAX_MAC_LEN = 20;
/// @brief represents a single network interface
///
/// IfaceMgr is an interface manager class that detects available network
/// interfaces, configured addresses, link-local addresses, and provides
/// API for using sockets.
///
class IfaceMgr : public boost::noncopyable {
public:
/// type that defines list of addresses
typedef std::list<isc::asiolink::IOAddress> Addr6Lst;
/// Iface structure represents network interface with all useful
/// information, like name, interface index, MAC address and
/// list of assigned addresses
struct Iface {
/// constructor
Iface(const std::string& name, int ifindex);
/// returns full interface name in format ifname/ifindex
std::string getFullName() const;
/// returns link-layer address a plain text
std::string getPlainMac() const;
/// maximum MAC address length (Infiniband uses 20 bytes)
static const unsigned int MAX_MAC_LEN = 20;
/// network interface name
std::string name_;
/// interface index (a value that uniquely indentifies an interface)
int ifindex_;
/// @brief represents a single network interface
///
/// Iface structure represents network interface with all useful
/// information, like name, interface index, MAC address and
/// list of assigned addresses
struct Iface {
/// constructor
Iface(const std::string& name, int ifindex);
/// returns full interface name in format ifname/ifindex
std::string getFullName() const;
/// returns link-layer address a plain text
std::string getPlainMac() const;
std::string name_; /// network interface name
int ifindex_; /// interface index (a value that uniquely
/// indentifies an interface
Addr6Lst addrs_; /// list of assigned addresses
uint8_t mac_[MAX_MAC_LEN]; /// link-layer address
int mac_len_; /// length of link-layer address (usually 6)
int sendsock_; /// socket used to sending data
int recvsock_; /// socket used for receiving data
// next field is not needed, let's keep it in cointainers
};
// TODO performance improvement: we may change this into
// 2 maps (ifindex-indexed and name-indexed) and
// also hide it (make it public make tests easier for now)
typedef std::list<Iface> IfaceLst;
/// IfaceMgr is a singleton class. This method returns reference
/// to its sole instance.
///
/// @return the only existing instance of interface manager
static IfaceMgr& instance();
/// @brief Returns interface with specified interface index
///
/// @param ifindex index of searched interface
///
/// @return interface with requested index (or NULL if no such
/// interface is present)
///
Iface*
getIface(int ifindex);
/// @brief Returns interface with specified interface name
///
/// @param ifname name of searched interface
///
/// @return interface with requested name (or NULL if no such
/// interface is present)
///
Iface*
getIface(const std::string& ifname);
/// debugging method that prints out all available interfaces
///
/// @param out specifies stream to print list of interfaces to
void
printIfaces(std::ostream& out = std::cout);
/// @brief Sends a packet.
///
/// Sends a packet. All parameters regarding interface, destination
/// address are set in pkt object.
///
/// @param pkt packet to be sent
///
/// @return true if sending was successful
///
bool
send(boost::shared_ptr<Pkt6> pkt);
/// @brief Tries to receive packet over open sockets.
///
/// Attempts to receive a single packet of any of the open sockets.
/// If reception is successful and all information about its sender
/// are obtained, Pkt6 object is created and returned.
///
/// @return Pkt6 object representing received packet (or NULL)
///
boost::shared_ptr<Pkt6> receive();
// don't use private, we need derived classes in tests
protected:
/// @brief Protected constructor.
///
/// Protected constructor. This is a singleton class. We don't want
/// anyone to create instances of IfaceMgr. Use instance() method
IfaceMgr();
~IfaceMgr();
/// @brief Detects network interfaces.
///
/// This method will eventually detect available interfaces. For now
/// it offers stub implementation. First interface name and link-local
/// IPv6 address is read from intefaces.txt file.
void
detectIfaces();
///
/// Opens UDP/IPv6 socket and binds it to address, interface nad port.
///
/// @param ifname name of the interface
/// @param addr address to be bound.
/// @param port UDP port.
///
/// @return socket descriptor, if socket creation, binding and multicast
/// group join were all successful. -1 otherwise.
int openSocket(const std::string& ifname,
const isc::asiolink::IOAddress& addr,
int port);
// TODO: having 2 maps (ifindex->iface and ifname->iface would)
// probably be better for performance reasons
/// List of available interfaces
IfaceLst ifaces_;
/// a pointer to a sole instance of this class (a singleton)
static IfaceMgr * instance_;
// TODO: Also keep this interface on Iface once interface detection
// is implemented. We may need it e.g. to close all sockets on
// specific interface
int recvsock_; // TODO: should be fd_set eventually, but we have only
int sendsock_; // 2 sockets for now. Will do for until next release
// we can't use the same socket, as receiving socket
// is bound to multicast address. And we all know what happens
// to people who try to use multicast as source address.
/// control-buffer, used in transmission and reception
char * control_buf_;
int control_buf_len_;
private:
/// Opens sockets on detected interfaces.
bool
openSockets();
/// creates a single instance of this class (a singleton implementation)
static void
instanceCreate();
/// @brief Joins IPv6 multicast group on a socket.
///
/// Socket must be created and bound to an address. Note that this
/// address is different than the multicast address. For example DHCPv6
/// server should bind its socket to link-local address (fe80::1234...)
/// and later join ff02::1:2 multicast group.
///
/// @param sock socket fd (socket must be bound)
/// @param ifname interface name (for link-scoped multicast groups)
/// @param mcast multicast address to join (e.g. "ff02::1:2")
///
/// @return true if multicast join was successful
///
bool
joinMcast(int sock, const std::string& ifname,
const std::string& mcast);
Addr6Lst addrs_;
/// link-layer address
uint8_t mac_[MAX_MAC_LEN];
/// length of link-layer address (usually 6)
int mac_len_;
/// socket used to sending data
int sendsock_;
/// socket used for receiving data
int recvsock_;
};
}; // namespace isc::dhcp
// TODO performance improvement: we may change this into
// 2 maps (ifindex-indexed and name-indexed) and
// also hide it (make it public make tests easier for now)
/// type that holds a list of interfaces
typedef std::list<Iface> IfaceLst;
/// IfaceMgr is a singleton class. This method returns reference
/// to its sole instance.
///
/// @return the only existing instance of interface manager
static IfaceMgr& instance();
/// @brief Returns interface with specified interface index
///
/// @param ifindex index of searched interface
///
/// @return interface with requested index (or NULL if no such
/// interface is present)
///
Iface*
getIface(int ifindex);
/// @brief Returns interface with specified interface name
///
/// @param ifname name of searched interface
///
/// @return interface with requested name (or NULL if no such
/// interface is present)
///
Iface*
getIface(const std::string& ifname);
/// debugging method that prints out all available interfaces
///
/// @param out specifies stream to print list of interfaces to
void
printIfaces(std::ostream& out = std::cout);
/// @brief Sends a packet.
///
/// Sends a packet. All parameters regarding interface, destination
/// address are set in pkt object.
///
/// @param pkt packet to be sent
///
/// @return true if sending was successful
///
bool
send(boost::shared_ptr<Pkt6> pkt);
/// @brief Tries to receive packet over open sockets.
///
/// Attempts to receive a single packet of any of the open sockets.
/// If reception is successful and all information about its sender
/// are obtained, Pkt6 object is created and returned.
///
/// @return Pkt6 object representing received packet (or NULL)
///
boost::shared_ptr<Pkt6> receive();
// don't use private, we need derived classes in tests
protected:
/// @brief Protected constructor.
///
/// Protected constructor. This is a singleton class. We don't want
/// anyone to create instances of IfaceMgr. Use instance() method
IfaceMgr();
~IfaceMgr();
/// @brief Detects network interfaces.
///
/// This method will eventually detect available interfaces. For now
/// it offers stub implementation. First interface name and link-local
/// IPv6 address is read from intefaces.txt file.
void
detectIfaces();
///
/// Opens UDP/IPv6 socket and binds it to address, interface and port.
///
/// @param ifname name of the interface
/// @param addr address to be bound.
/// @param port UDP port.
///
/// @return socket descriptor, if socket creation, binding and multicast
/// group join were all successful. -1 otherwise.
int openSocket(const std::string& ifname,
const isc::asiolink::IOAddress& addr,
int port);
// TODO: having 2 maps (ifindex->iface and ifname->iface would)
// probably be better for performance reasons
/// List of available interfaces
IfaceLst ifaces_;
/// a pointer to a sole instance of this class (a singleton)
static IfaceMgr *