+6XX. [func] dclink, tomek
+ libdhcp++: Interface detection implemented for FreeBSD, NetBSD,
+ OpenBSD, Mac OS X and Solaris 11. Thanks to David Carlier for
+ contributing a patch.
+ (Trac #2246, git abcd)
+
691. [bug] marcin
libdhcp++: Created definitions for standard DHCPv4 options:
tftp-server-name (66) and boot-file-name (67). Also, fixed definition
available from <ulink url="http://www.isc.org/software/dhcp"/>.</simpara>
</listitem>
<listitem>
- <simpara>Interface detection is currently working on Linux
+ <simpara>Raw sockets operation is working on Linux
only. See <xref linkend="iface-detect"/> for details.</simpara>
</listitem>
<listitem>
<listitem>
<simpara>DNS Update is not supported.</simpara>
</listitem>
- <listitem>
- <simpara>Interface detection is currently working on Linux
- only. See <xref linkend="iface-detect"/> for details.</simpara>
- </listitem>
</itemizedlist>
</section>
<!-- TODO: point to doxygen docs -->
<section id="iface-detect">
- <title>Interface detection</title>
+ <title>Interface detection and Socket handling</title>
<para>Both the DHCPv4 and DHCPv6 components share network
interface detection routines. Interface detection is
- currently only supported on Linux systems.</para>
-
- <para>For non-Linux systems, there is currently a stub
- implementation provided. The interface manager detects loopback
- interfaces only as their name (lo or lo0) can be easily predicted.
- Please contact the BIND 10 development team if you are interested
- in running DHCP components on systems other than Linux.</para>
+ currently supported on Linux, all BSD family (FreeBSD, NetBSD,
+ OpenBSD), Mac OS X and Solaris 11 systems.</para>
+
+ <para>DHCPv4 requires special raw socket processing to send and receive
+ packets from hosts that do not have IPv4 address assigned yet. Support
+ for this operation is implemented on Linux only, so it is likely that
+ DHCPv4 component will not work in certain cases on systems other than
+ Linux.</para>
</section>
<!--
}
typedef map<string, Iface> ifaceLst;
- ifaceLst::iterator itf;
+ ifaceLst::iterator iface_iter;
ifaceLst ifaces;
// First lookup for getting interfaces ...
- for(ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
+ for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
const char * ifname = ifptr->ifa_name;
uint ifindex = 0;
- if(!(ifindex = if_nametoindex(ifname))) {
+ if (!(ifindex = if_nametoindex(ifname))) {
// Interface name does not have corresponding index ...
freeifaddrs(iflist);
isc_throw(Unexpected, "Interface " << ifname << " has no index");
}
- if((itf = ifaces.find(ifname)) != ifaces.end()) {
+ if ((iface_iter = ifaces.find(ifname)) != ifaces.end()) {
continue;
}
}
// Second lookup to get MAC and IP addresses
- for(ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
- if((itf = ifaces.find(ifptr->ifa_name)) == ifaces.end()) {
+ for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
+ if ((iface_iter = ifaces.find(ifptr->ifa_name)) == ifaces.end()) {
continue;
}
// Common byte pointer for following data
reinterpret_cast<struct sockaddr_dl *>(ifptr->ifa_addr);
ptr = reinterpret_cast<uint8_t *>(LLADDR(ldata));
- itf->second.setHWType(ldata->sdl_type);
- itf->second.setMac(ptr, ldata->sdl_alen);
+ iface_iter->second.setHWType(ldata->sdl_type);
+ iface_iter->second.setMac(ptr, ldata->sdl_alen);
} else if(ifptr->ifa_addr->sa_family == AF_INET6) {
// IPv6 Addr
struct sockaddr_in6 * adata =
ptr = reinterpret_cast<uint8_t *>(&adata->sin6_addr);
IOAddress a = IOAddress::fromBytes(AF_INET6, ptr);
- itf->second.addAddress(a);
+ iface_iter->second.addAddress(a);
} else {
// IPv4 Addr
struct sockaddr_in * adata =
ptr = reinterpret_cast<uint8_t *>(&adata->sin_addr);
IOAddress a = IOAddress::fromBytes(AF_INET, ptr);
- itf->second.addAddress(a);
+ iface_iter->second.addAddress(a);
}
}
freeifaddrs(iflist);
- // Registers interfaces with at least an IP addresses
- for(ifaceLst::const_iterator itf = ifaces.begin();
- itf != ifaces.end(); ++ itf) {
- if(itf->second.getAddresses().size() > 0) {
- ifaces_.push_back(itf->second);
- }
+ // Interfaces registering
+ for(ifaceLst::const_iterator iface_iter = ifaces.begin();
+ iface_iter != ifaces.end(); ++iface_iter) {
+ ifaces_.push_back(iface_iter->second);
}
}
/// Like Linux version, os specific flags
///
/// @params flags
-void Iface::setFlags(uint32_t flags) {
+void Iface::setFlags(uint64_t flags) {
flags_ = flags;
flag_loopback_ = flags & IFF_LOOPBACK;
}
typedef std::map<string, Iface> ifaceLst;
- ifaceLst::iterator itf;
+ ifaceLst::iterator iface_iter;
ifaceLst ifaces;
// First lookup for getting interfaces ...
isc_throw(Unexpected, "Interface " << ifname << " has no index");
}
- if((itf = ifaces.find(ifname)) != iface.end()) {
+ if((iface_iter = ifaces.find(ifname)) != iface.end()) {
continue;
}
}
// Second lookup to get MAC and IP addresses
- for(ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
- if((itf = ifaces.find(ifptr->ifa_name)) == ifaces.end()) {
+ for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
+ if ((itf = ifaces.find(ifptr->ifa_name)) == ifaces.end()) {
continue;
}
// Common byte pointer for following data
reinterpret_cast<struct sockaddr_dl *>(ifptr->ifa_addr);
ptr = reinterpret_cast<uint8_t *>(LLADDR(ldata));
- itf->second.setHWType(ldata->sdl_type);
- itf->second.setMac(ptr, ldata->sdl_alen);
+ iface_iter->second.setHWType(ldata->sdl_type);
+ iface_iter->second.setMac(ptr, ldata->sdl_alen);
} else if(ifptr->ifa_addr->sa_family == AF_INET6) {
// IPv6 Addr
struct sockaddr_in6 * adata =
ptr = reinterpret_cast<uint8_t *>(& adata->sin6_addr);
IOAddress a = IOAddress::fromBytes(AF_INET6, ptr);
- itf->second.addAddress(a);
+ iface_iter->second.addAddress(a);
} else {
// IPv4 Addr
struct sockaddr_in * adata =
ptr = reinterpret_cast<uint8_t *>(& adata->sin_addr);
IOAddress a = IOAddress::fromBytes(AF_INET, ptr);
- itf->second.addAddress(a);
+ iface_iter->second.addAddress(a);
}
}
freeifaddrs(iflist);
- // Registers interfaces with at least an IP addresses
- for(ifaceLst::const_iterator itf = ifaces.begin();
- itf != ifaces.end(); ++ itf) {
- if(itf->second.getAddresses().size() > 0) {
- ifaces_.push_back(itf->second);
- }
+ // Interfaces registering
+ for (ifaceLst::const_iterator iface_iter = ifaces.begin();
+ iface_iter != ifaces.end(); ++iface_iter) {
+ ifaces_.push_back(iface_iter->second);
}
}
libdhcp++ is an all-purpose DHCP-manipulation library, written in
C++. It offers packet parsing and assembly, DHCPv4 and DHCPv6
-options parsing and ssembly, interface detection (currently on
-Linux systems only) and socket operations. It is a generic purpose library that
+options parsing and assembly, interface detection (currently on
+Linux, FreeBSD, NetBSD, OpenBSD, Max OS X, and Solaris 11) and socket operations.
+It is a generic purpose library that
can be used by server, client, relay, performance tools and other DHCP-related
tools. For server specific library, see \ref libdhcpsrv. Please do not
add any server-specific code to libdhcp++ and use \ref libdhcpsrv instead.
// TODO: temporarily disabled, see ticket #1529
TEST_F(IfaceMgrTest, DISABLED_detectIfaces_linux) {
- NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+ scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
IfaceMgr::IfaceCollection& detectedIfaces = ifacemgr->getIfacesLst();
const std::string textFile = "ifconfig.txt";
FAIL();
}
}
-
- delete ifacemgr;
}
#endif
-#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SUN)
-
#if defined(OS_BSD)
#include <net/if_dl.h>
#endif
#include <net/if.h>
#include <ifaddrs.h>
-// Checks the index of this interface
+/// @brief Checks the index of this interface
+/// @param iface Kea interface structure to be checked
+/// @param ifptr original structure returned by getifaddrs
+/// @return true if index is returned properly
bool
checkIfIndex(const Iface & iface,
struct ifaddrs *& ifptr) {
- cout << "Checks index of " << iface.getName() << endl;
return (iface.getIndex() == if_nametoindex(ifptr->ifa_name));
}
-// Checks if the interface has proper flags set
+/// @brief Checks if the interface has proper flags set
+/// @param iface Kea interface structure to be checked
+/// @param ifptr original structure returned by getifaddrs
+/// @return true if flags are set properly
bool
checkIfFlags(const Iface & iface,
struct ifaddrs *& ifptr) {
- cout << "Checks flags of " << iface.getName() << endl;
bool flag_loopback_ = ifptr->ifa_flags & IFF_LOOPBACK;
bool flag_up_ = ifptr->ifa_flags & IFF_UP;
bool flag_running_ = ifptr->ifa_flags & IFF_RUNNING;
/// @brief Checks if MAC Address/IP Addresses are properly well formed
/// @param iface Kea interface structure to be checked
/// @param ifptr original structure returned by getifaddrs
+/// @return true if addresses are returned properly
bool
checkIfAddrs(const Iface & iface, struct ifaddrs *& ifptr) {
const unsigned char * p = 0;
// Workaround for Linux ...
if(ifptr->ifa_data != 0) {
// We avoid localhost as it has no MAC Address
- if(!strncmp(iface.getName().c_str(), "lo", 2)) {
+ if (!strncmp(iface.getName().c_str(), "lo", 2)) {
return (true);
}
- // Typically unit-tests try to be silent. But interface detection is
- // tricky enough to warrant additional prints.
- cout << "Checks MAC Addr of " << iface.getName() << endl;
struct ifreq ifr;
memset(& ifr.ifr_name, 0, sizeof ifr.ifr_name);
strncpy(ifr.ifr_name, iface.getName().c_str(), sizeof ifr.ifr_name);
int s = -1; // Socket descriptor
- if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
isc_throw(Unexpected, "Cannot create AF_INET socket");
}
- if(ioctl(s, SIOCGIFHWADDR, & ifr) < 0) {
+ if (ioctl(s, SIOCGIFHWADDR, & ifr) < 0) {
close(s);
isc_throw(Unexpected, "Cannot set SIOCGIFHWADDR flag");
}
/// @todo: Check MAC address length. For some interfaces it is
/// different than 6. Some have 0, while some exotic ones (like
/// infiniband) have 20.
- int i = 0;
- while(i < 6) {
- if(* (p + i) != * (iface.getMac() + i)) {
- return (false);
- }
- ++ i;
- }
-
- return (true);
+ return (!memcmp(p, iface.getMac(), iface.getMacLen()));
}
#endif
#if defined(OS_BSD)
case AF_LINK: {
// We avoid localhost as it has no MAC Address
- if(!strncmp(iface.getName().c_str(), "lo", 2)) {
+ if (!strncmp(iface.getName().c_str(), "lo", 2)) {
return (true);
}
- cout << "Checks MAC Addr of " << iface.getName() << endl;
struct sockaddr_dl * hwdata =
reinterpret_cast<struct sockaddr_dl *>(ifptr->ifa_addr);
p = reinterpret_cast<uint8_t *>(LLADDR(hwdata));
// Extract MAC address length
- if(hwdata->sdl_alen != iface.getMacLen()) {
+ if (hwdata->sdl_alen != iface.getMacLen()) {
return (false);
}
- int i = 0;
- while(i < hwdata->sdl_alen) {
- if(* (p + i) != * (iface.getMac() + i)) {
- return (false);
- }
- ++ i;
- }
-
- return (true);
+ return (!memcmp(p, iface.getMac(), hwdata->sdl_alen));
}
#endif
case AF_INET: {
- cout << "Checks IPv4 address of " << iface.getName() << endl;
struct sockaddr_in * v4data =
reinterpret_cast<struct sockaddr_in *>(ifptr->ifa_addr);
p = reinterpret_cast<uint8_t *>(& v4data->sin_addr);
IOAddress addrv4 = IOAddress::fromBytes(AF_INET, p);
- for(Iface::AddressCollection::const_iterator a = iface.getAddresses().begin();
- a != iface.getAddresses().end(); ++ a) {
- if((* a).isV4() && (* a) == addrv4) {
+ for (Iface::AddressCollection::const_iterator a =
+ iface.getAddresses().begin();
+ a != iface.getAddresses().end(); ++ a) {
+ if(a->isV4() && (*a) == addrv4) {
return (true);
}
}
return (false);
}
case AF_INET6: {
- cout << "Checks IPv6 address of " << iface.getName() << endl;
struct sockaddr_in6 * v6data =
reinterpret_cast<struct sockaddr_in6 *>(ifptr->ifa_addr);
p = reinterpret_cast<uint8_t *>(& v6data->sin6_addr);
IOAddress addrv6 = IOAddress::fromBytes(AF_INET6, p);
- for(Iface::AddressCollection::const_iterator a = iface.getAddresses().begin();
+ for(Iface::AddressCollection::const_iterator a =
+ iface.getAddresses().begin();
a != iface.getAddresses().end(); ++ a) {
- if((* a).isV6() && (* a) == addrv6) {
+ if(a->isV6() && (*a) == addrv6) {
return (true);
}
}
isc_throw(Unexpected, "Cannot detect interfaces");
}
- for(ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
- for(IfaceMgr::IfaceCollection::const_iterator i = detectedIfaces.begin();
+ for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
+ for (IfaceMgr::IfaceCollection::const_iterator i = detectedIfaces.begin();
i != detectedIfaces.end(); ++ i) {
- if(!strncmp(ifptr->ifa_name, (*i).getName().c_str(),
- (*i).getName().size())) {
+ if (!strncmp(ifptr->ifa_name, (*i).getName().c_str(),
+ (*i).getName().size())) {
+
+ // Typically unit-tests try to be silent. But interface detection
+ // is tricky enough to warrant additional prints.
+ std::cout << "Checking interface " << i->getName() << std::endl;
+
+ // Check if interface index is reported properly
+ EXPECT_TRUE(checkIfIndex(*i, ifptr));
- checkIfIndex(*i, ifptr);
- checkIfFlags(*i, ifptr);
- checkIfAddrs(*i, ifptr);
+ // Check if flags are reported properly
+ EXPECT_TRUE(checkIfFlags(*i, ifptr));
+
+ // Check if addresses are reported properly
+ EXPECT_TRUE(checkIfAddrs(*i, ifptr));
}
}
delete ifacemgr;
}
-#endif
volatile bool callback_ok;