From: Tomek Mrugalski Date: Fri, 23 Dec 2011 12:52:12 +0000 (+0100) Subject: Merge branch 'trac1237' X-Git-Tag: trac2351_base~299^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d82df10e192238851799070520e23f753db6c2ee;p=thirdparty%2Fkea.git Merge branch 'trac1237' Conflicts: ChangeLog src/bin/dhcp4/dhcp4_srv.cc src/bin/dhcp6/dhcp6_srv.cc src/lib/dhcp/iface_mgr.cc src/lib/dhcp/iface_mgr.h src/lib/dhcp/tests/iface_mgr_unittest.cc --- d82df10e192238851799070520e23f753db6c2ee diff --cc ChangeLog index a88f9e107e,5109c2692b..ff15bf746b --- a/ChangeLog +++ b/ChangeLog @@@ -1,25 -1,8 +1,31 @@@ -3XX. [func] tomek ++362. [func] tomek + libdhcp++: Interface detection in Linux implemented. libdhcp++ + if now able to detect available network interfaces, its link-layer + addresses, flags and configured IPv4 and IPv6 addresses. - (Trac #1237, git TBD) ++ (Trac #1237, git 8a040737426aece7cc92a795f2b712d7c3407513) ++ +361. [func] tomek + libdhcp++: Transmission and reception of DHCPv4 packets is now + implemented. Low-level hacks are not implemented for transmission + to hosts that don't have IPv4 address yet, so currently the code + is usable for communication with relays only, not hosts on the + same link. + (Trac #1239, #1240, git f382050248b5b7ed1881b086d89be2d9dd8fe385) + +360. [func] fdupont + Alpha version of DHCP benchmarking tool added. "perfdhcp" is able to + test both IPv4 and IPv6 servers: it can time the four-packet exchange + (DORA and SARR) as well as time the initial two-packet exchange (DO and + SA). More information can be obtained by invoking the utility (in + tests/tools/perfdhcp) with the "-h" flag. + (Trac #1450, git 85083a76107ba2236732b45524ce7018eefbaf90) + +359. [func]* vorner + The target parameter of ZoneFinder::find is no longer present, as the + interface was awkward. To get all the RRsets of a single domain, use + the new findAll method (the same applies to python version, the method + is named find_all). + (Trac #1483,#1484, git 0020456f8d118c9f3fd6fc585757c822b79a96f6) 349. [bug] dvv resolver: If an upstream server responds with FORMERR to an EDNS query, diff --cc src/bin/dhcp6/dhcp6_srv.cc index c559d8cbb3,9e77f8c548..7d1b549bdc --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@@ -27,16 -27,28 +27,24 @@@ using namespace isc::dhcp using namespace isc::asiolink; Dhcpv6Srv::Dhcpv6Srv(uint16_t port) { - - //void Dhcpv6Srv::Dhcpv6Srv_impl(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. - IfaceMgr::instance(); + // first call to instance() will create IfaceMgr (it's a singleton) + // it may throw something if things go wrong + try { + IfaceMgr::instance(); + } catch (const std::exception &e) { + 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; + } // Now try to open IPv6 sockets on detected interfaces. - cout << "Opening sockets on port " << port << endl; -#if 0 - // uncomment this once #1238, #992 and #1239 are merged IfaceMgr::instance().openSockets6(port); -#endif /// @todo: instantiate LeaseMgr here once it is imlpemented. diff --cc src/lib/dhcp/iface_mgr.cc index bb8981386d,2a8c0010a4..c086e46fc3 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@@ -192,23 -194,17 +195,29 @@@ IfaceMgr::stubDetectIfaces() } } + #if !defined(OS_LINUX) && !defined(OS_BSD) + void IfaceMgr::detectIfaces() { + stubDetectIfaces(); + } + #endif + -void IfaceMgr::openSockets6(uint16_t port) { - int sock1, sock2; +bool IfaceMgr::openSockets4(uint16_t port) { + int sock; + int count = 0; - for (IfaceCollection::iterator iface = ifaces_.begin(); - iface != ifaces_.end(); ++iface) { + for (IfaceCollection::iterator iface=ifaces_.begin(); + iface!=ifaces_.end(); + ++iface) { + + cout << "Trying interface " << iface->getFullName() << endl; + +#if 0 + if (iface->flag_loopback_ || + !iface->flag_up_ || + !iface->flag_running_) { + continue; + } +#endif AddressCollection addrs = iface->getAddresses(); @@@ -216,52 -212,15 +225,52 @@@ addr != addrs.end(); ++addr) { - sock1 = openSocket(iface->getName(), *addr, port); - if (sock1 < 0) { - isc_throw(Unexpected, "Failed to open unicast socket on " - << " interface " << iface->getFullName()); + // skip IPv4 addresses + if (addr->getFamily() != AF_INET) { + continue; } - if ( !joinMulticast(sock1, iface->getName(), - string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) { - close(sock1); + sock = openSocket(iface->getName(), *addr, port); + if (sock<0) { + cout << "Failed to open unicast socket." << endl; + return (false); + } + + count++; + } + } + return (count > 0); + +} + +bool IfaceMgr::openSockets6(uint16_t port) { + int sock; + int count = 0; + + for (IfaceCollection::iterator iface=ifaces_.begin(); + iface!=ifaces_.end(); + ++iface) { + + AddressCollection addrs = iface->getAddresses(); + + for (AddressCollection::iterator addr= addrs.begin(); + addr != addrs.end(); + ++addr) { + + // skip IPv4 addresses + if (addr->getFamily() != AF_INET6) { + continue; + } + + sock = openSocket(iface->getName(), *addr, port); + if (sock<0) { + cout << "Failed to open unicast socket." << endl; + return (false); + } + - if ( !joinMcast(sock, iface->getName(), - string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) { ++ if ( !joinMulticast(sock, iface->getName(), ++ string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) { + close(sock); isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS << " multicast group."); } diff --cc src/lib/dhcp/iface_mgr.h index e937967045,39024b5a82..2cfd1ee5c6 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@@ -308,14 -337,11 +340,19 @@@ public /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes. void closeSockets(); + /// Opens IPv4 sockets on detected interfaces. + /// Will throw exception if socket creation fails. + /// + /// @param port specifies port number (usually DHCP6_SERVER_PORT) + /// + /// @return true if any sockets were open + bool openSockets4(uint16_t port = DHCP4_SERVER_PORT); + + /// @brief returns number of detected interfaces + /// + /// @return number of detected interfaces + uint16_t countIfaces() { return ifaces_.size(); } + // don't use private, we need derived classes in tests protected: diff --cc src/lib/dhcp/tests/iface_mgr_unittest.cc index 9ccc55d1ab,9abbe1343b..f2d8016b8b --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@@ -151,9 -151,8 +151,10 @@@ TEST_F(IfaceMgrTest, dhcp6Sniffer) TEST_F(IfaceMgrTest, basic) { // checks that IfaceManager can be instantiated + createLoInterfacesTxt(); + createLoInterfacesTxt(); + IfaceMgr & ifacemgr = IfaceMgr::instance(); ASSERT_TRUE(&ifacemgr != 0); } @@@ -217,10 -217,10 +218,11 @@@ TEST_F(IfaceMgrTest, getIface) EXPECT_EQ(static_cast(NULL), ifacemgr->getIface("wifi0") ); delete ifacemgr; + } - TEST_F(IfaceMgrTest, detectIfaces) { + #if !defined(OS_LINUX) + TEST_F(IfaceMgrTest, detectIfaces_stub) { // test detects that interfaces can be detected // there is no code for that now, but interfaces are @@@ -368,93 -367,8 +369,92 @@@ TEST_F(IfaceMgrTest, sendReceive6) EXPECT_TRUE( (rcvPkt->remote_port_ == 10546) || (rcvPkt->remote_port_ == 10547) ); delete ifacemgr; - unlink(INTERFACE_FILE); } +TEST_F(IfaceMgrTest, sendReceive4) { + + // testing socket operation in a portable way is tricky + // without interface detection implemented + createLoInterfacesTxt(); + + NakedIfaceMgr* ifacemgr = new NakedIfaceMgr(); + + // let's assume that every supported OS have lo interface + IOAddress loAddr("127.0.0.1"); + int socket1 = 0, socket2 = 0; + EXPECT_NO_THROW( + socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000); + socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000 + 1); + ); + + boost::shared_ptr sendPkt(new Pkt4(DHCPDISCOVER, 1234) ); + + sendPkt->setLocalAddr(IOAddress("127.0.0.1")); + + sendPkt->setLocalPort(DHCP4_SERVER_PORT + 10000 + 1); + sendPkt->setRemotePort(DHCP4_SERVER_PORT + 10000); + sendPkt->setRemoteAddr(IOAddress("127.0.0.1")); + sendPkt->setIndex(1); + sendPkt->setIface(string(LOOPBACK)); + sendPkt->setHops(6); + sendPkt->setSecs(42); + sendPkt->setCiaddr(IOAddress("192.0.2.1")); + sendPkt->setSiaddr(IOAddress("192.0.2.2")); + sendPkt->setYiaddr(IOAddress("192.0.2.3")); + sendPkt->setGiaddr(IOAddress("192.0.2.4")); + + 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"; + sendPkt->setFile(file, strlen((const char*)file)); + + ASSERT_NO_THROW( + sendPkt->pack(); + ); + + boost::shared_ptr rcvPkt; + + EXPECT_EQ(true, ifacemgr->send(sendPkt)); + + rcvPkt = ifacemgr->receive4(); + + ASSERT_TRUE( rcvPkt ); // received our own packet + + ASSERT_NO_THROW( + rcvPkt->unpack(); + ); + + // let's check that we received what was sent + EXPECT_EQ(sendPkt->len(), rcvPkt->len()); + + EXPECT_EQ("127.0.0.1", rcvPkt->getRemoteAddr().toText()); + EXPECT_EQ(sendPkt->getRemotePort(), rcvPkt->getLocalPort()); + + // now let's check content + EXPECT_EQ(sendPkt->getHops(), rcvPkt->getHops()); + EXPECT_EQ(sendPkt->getOp(), rcvPkt->getOp()); + EXPECT_EQ(sendPkt->getSecs(), rcvPkt->getSecs()); + EXPECT_EQ(sendPkt->getFlags(), rcvPkt->getFlags()); + EXPECT_EQ(sendPkt->getCiaddr(), rcvPkt->getCiaddr()); + EXPECT_EQ(sendPkt->getSiaddr(), rcvPkt->getSiaddr()); + EXPECT_EQ(sendPkt->getYiaddr(), rcvPkt->getYiaddr()); + EXPECT_EQ(sendPkt->getGiaddr(), rcvPkt->getGiaddr()); + EXPECT_EQ(sendPkt->getTransid(), rcvPkt->getTransid()); + EXPECT_EQ(sendPkt->getType(), rcvPkt->getType()); + EXPECT_TRUE(sendPkt->getSname() == rcvPkt->getSname()); + EXPECT_TRUE(sendPkt->getFile() == rcvPkt->getFile()); + EXPECT_EQ(sendPkt->getHtype(), rcvPkt->getHtype()); + EXPECT_EQ(sendPkt->getHlen(), rcvPkt->getHlen()); + + // since we opened 2 sockets on the same interface and none of them is multicast, + // none is preferred over the other for sending data, so we really should not + // assume the one or the other will always be choosen for sending data. We should + // skip checking source port of sent address. + + delete ifacemgr; +} + + TEST_F(IfaceMgrTest, socket4) { createLoInterfacesTxt();