iface_mgr_unittest.cc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <iostream>
  16. #include <fstream>
  17. #include <sstream>
  18. #include <arpa/inet.h>
  19. #include <gtest/gtest.h>
  20. #include <asiolink/io_address.h>
  21. #include <dhcp/pkt6.h>
  22. #include <dhcp/iface_mgr.h>
  23. #include <dhcp/dhcp4.h>
  24. using namespace std;
  25. using namespace isc;
  26. using namespace isc::asiolink;
  27. using namespace isc::dhcp;
  28. // name of loopback interface detection
  29. const size_t buf_size = 32;
  30. char LOOPBACK[buf_size] = "lo";
  31. namespace {
  32. const char* const INTERFACE_FILE = TEST_DATA_BUILDDIR "/interfaces.txt";
  33. class NakedIfaceMgr: public IfaceMgr {
  34. // "naked" Interface Manager, exposes internal fields
  35. public:
  36. NakedIfaceMgr() { }
  37. IfaceCollection & getIfacesLst() { return ifaces_; }
  38. };
  39. // dummy class for now, but this will be expanded when needed
  40. class IfaceMgrTest : public ::testing::Test {
  41. public:
  42. IfaceMgrTest() {
  43. }
  44. void createLoInterfacesTxt() {
  45. unlink(INTERFACE_FILE);
  46. fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
  47. fakeifaces << LOOPBACK << " ::1";
  48. fakeifaces.close();
  49. }
  50. ~IfaceMgrTest() {
  51. unlink(INTERFACE_FILE);
  52. }
  53. };
  54. // We need some known interface to work reliably. Loopback interface
  55. // is named lo on Linux and lo0 on BSD boxes. We need to find out
  56. // which is available. This is not a real test, but rather a workaround
  57. // that will go away when interface detection is implemented.
  58. // NOTE: At this stage of development, write access to current directory
  59. // during running tests is required.
  60. TEST_F(IfaceMgrTest, loDetect) {
  61. // poor man's interface detection
  62. // it will go away as soon as proper interface detection
  63. // is implemented
  64. if (if_nametoindex("lo") > 0) {
  65. cout << "This is Linux, using lo as loopback." << endl;
  66. snprintf(LOOPBACK, buf_size - 1, "lo");
  67. } else if (if_nametoindex("lo0") > 0) {
  68. cout << "This is BSD, using lo0 as loopback." << endl;
  69. snprintf(LOOPBACK, buf_size - 1, "lo0");
  70. } else {
  71. cout << "Failed to detect loopback interface. Neither "
  72. << "lo nor lo0 worked. I give up." << endl;
  73. FAIL();
  74. }
  75. }
  76. // uncomment this test to create packet writer. It will
  77. // write incoming DHCPv6 packets as C arrays. That is useful
  78. // for generating test sequences based on actual traffic
  79. //
  80. // TODO: this potentially should be moved to a separate tool
  81. //
  82. #if 0
  83. TEST_F(IfaceMgrTest, dhcp6Sniffer) {
  84. // testing socket operation in a portable way is tricky
  85. // without interface detection implemented
  86. unlink("interfaces.txt");
  87. ofstream interfaces("interfaces.txt", ios::ate);
  88. interfaces << "eth0 fe80::21e:8cff:fe9b:7349";
  89. interfaces.close();
  90. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  91. Pkt6* pkt = NULL;
  92. int cnt = 0;
  93. cout << "---8X-----------------------------------------" << endl;
  94. while (true) {
  95. pkt = ifacemgr->receive();
  96. cout << "// this code is autogenerated. Do NOT edit." << endl;
  97. cout << "// Received " << pkt->data_len_ << " bytes packet:" << endl;
  98. cout << "Pkt6 *capture" << cnt++ << "() {" << endl;
  99. cout << " Pkt6* pkt;" << endl;
  100. cout << " pkt = new Pkt6(" << pkt->data_len_ << ");" << endl;
  101. cout << " pkt->remote_port_ = " << pkt-> remote_port_ << ";" << endl;
  102. cout << " pkt->remote_addr_ = IOAddress(\""
  103. << pkt->remote_addr_.toText() << "\");" << endl;
  104. cout << " pkt->local_port_ = " << pkt-> local_port_ << ";" << endl;
  105. cout << " pkt->local_addr_ = IOAddress(\""
  106. << pkt->local_addr_.toText() << "\");" << endl;
  107. cout << " pkt->ifindex_ = " << pkt->ifindex_ << ";" << endl;
  108. cout << " pkt->iface_ = \"" << pkt->iface_ << "\";" << endl;
  109. // TODO it is better to declare an array and then memcpy it to
  110. // packet.
  111. for (int i=0; i< pkt->data_len_; i++) {
  112. cout << " pkt->data_[" << i << "]="
  113. << (int)(unsigned char)pkt->data_[i] << "; ";
  114. if (!(i%4))
  115. cout << endl;
  116. }
  117. cout << endl;
  118. cout << " return (pkt);" << endl;
  119. cout << "}" << endl << endl;
  120. delete pkt;
  121. }
  122. cout << "---8X-----------------------------------------" << endl;
  123. // never happens. Infinite loop is infinite
  124. delete pkt;
  125. delete ifacemgr;
  126. }
  127. #endif
  128. TEST_F(IfaceMgrTest, basic) {
  129. // checks that IfaceManager can be instantiated
  130. createLoInterfacesTxt();
  131. createLoInterfacesTxt();
  132. IfaceMgr & ifacemgr = IfaceMgr::instance();
  133. ASSERT_TRUE(&ifacemgr != 0);
  134. }
  135. TEST_F(IfaceMgrTest, ifaceClass) {
  136. // basic tests for Iface inner class
  137. IfaceMgr::Iface* iface = new IfaceMgr::Iface("eth5", 7);
  138. EXPECT_STREQ("eth5/7", iface->getFullName().c_str());
  139. delete iface;
  140. }
  141. // TODO: Implement getPlainMac() test as soon as interface detection
  142. // is implemented.
  143. TEST_F(IfaceMgrTest, getIface) {
  144. createLoInterfacesTxt();
  145. cout << "Interface checks. Please ignore socket binding errors." << endl;
  146. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  147. // interface name, ifindex
  148. IfaceMgr::Iface iface1("lo1", 1);
  149. IfaceMgr::Iface iface2("eth5", 2);
  150. IfaceMgr::Iface iface3("en3", 5);
  151. IfaceMgr::Iface iface4("e1000g0", 3);
  152. // note: real interfaces may be detected as well
  153. ifacemgr->getIfacesLst().push_back(iface1);
  154. ifacemgr->getIfacesLst().push_back(iface2);
  155. ifacemgr->getIfacesLst().push_back(iface3);
  156. ifacemgr->getIfacesLst().push_back(iface4);
  157. cout << "There are " << ifacemgr->getIfacesLst().size()
  158. << " interfaces." << endl;
  159. for (IfaceMgr::IfaceCollection::iterator iface=ifacemgr->getIfacesLst().begin();
  160. iface != ifacemgr->getIfacesLst().end();
  161. ++iface) {
  162. cout << " " << iface->getFullName() << endl;
  163. }
  164. // check that interface can be retrieved by ifindex
  165. IfaceMgr::Iface* tmp = ifacemgr->getIface(5);
  166. // ASSERT_NE(NULL, tmp); is not supported. hmmmm.
  167. ASSERT_TRUE( tmp != NULL );
  168. EXPECT_EQ( "en3", tmp->getName() );
  169. EXPECT_EQ(5, tmp->getIndex());
  170. // check that interface can be retrieved by name
  171. tmp = ifacemgr->getIface("lo1");
  172. ASSERT_TRUE( tmp != NULL );
  173. EXPECT_EQ( "lo1", tmp->getName() );
  174. EXPECT_EQ(1, tmp->getIndex());
  175. // check that non-existing interfaces are not returned
  176. EXPECT_EQ(static_cast<void*>(NULL), ifacemgr->getIface("wifi0") );
  177. delete ifacemgr;
  178. }
  179. #if !defined(OS_LINUX)
  180. TEST_F(IfaceMgrTest, detectIfaces_stub) {
  181. // test detects that interfaces can be detected
  182. // there is no code for that now, but interfaces are
  183. // read from file
  184. fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
  185. fakeifaces << "eth0 fe80::1234";
  186. fakeifaces.close();
  187. // this is not usable on systems that don't have eth0
  188. // interfaces. Nevertheless, this fake interface should
  189. // be on list, but if_nametoindex() will fail.
  190. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  191. ASSERT_TRUE( ifacemgr->getIface("eth0") != NULL );
  192. IfaceMgr::Iface* eth0 = ifacemgr->getIface("eth0");
  193. // there should be one address
  194. IfaceMgr::AddressCollection addrs = eth0->getAddresses();
  195. ASSERT_EQ(1, addrs.size());
  196. IOAddress addr = *addrs.begin();
  197. EXPECT_STREQ( "fe80::1234", addr.toText().c_str() );
  198. delete ifacemgr;
  199. }
  200. #endif
  201. TEST_F(IfaceMgrTest, sockets6) {
  202. // testing socket operation in a portable way is tricky
  203. // without interface detection implemented
  204. createLoInterfacesTxt();
  205. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  206. IOAddress loAddr("::1");
  207. Pkt6 pkt6(128);
  208. pkt6.iface_ = LOOPBACK;
  209. // bind multicast socket to port 10547
  210. int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
  211. EXPECT_GT(socket1, 0); // socket > 0
  212. EXPECT_EQ(socket1, ifacemgr->getSocket(pkt6));
  213. // bind unicast socket to port 10548
  214. int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10548);
  215. EXPECT_GT(socket2, 0);
  216. // removed code for binding socket twice to the same address/port
  217. // as it caused problems on some platforms (e.g. Mac OS X)
  218. close(socket1);
  219. close(socket2);
  220. delete ifacemgr;
  221. }
  222. // TODO: disabled due to other naming on various systems
  223. // (lo in Linux, lo0 in BSD systems)
  224. TEST_F(IfaceMgrTest, DISABLED_sockets6Mcast) {
  225. // testing socket operation in a portable way is tricky
  226. // without interface detection implemented
  227. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  228. IOAddress loAddr("::1");
  229. IOAddress mcastAddr("ff02::1:2");
  230. // bind multicast socket to port 10547
  231. int socket1 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
  232. EXPECT_GT(socket1, 0); // socket > 0
  233. // expect success. This address/port is already bound, but
  234. // we are using SO_REUSEADDR, so we can bind it twice
  235. int socket2 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
  236. EXPECT_GT(socket2, 0);
  237. // there's no good way to test negative case here.
  238. // we would need non-multicast interface. We will be able
  239. // to iterate thru available interfaces and check if there
  240. // are interfaces without multicast-capable flag.
  241. close(socket1);
  242. close(socket2);
  243. delete ifacemgr;
  244. }
  245. TEST_F(IfaceMgrTest, sendReceive6) {
  246. // testing socket operation in a portable way is tricky
  247. // without interface detection implemented
  248. createLoInterfacesTxt();
  249. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  250. // let's assume that every supported OS have lo interface
  251. IOAddress loAddr("::1");
  252. int socket1 = 0, socket2 = 0;
  253. EXPECT_NO_THROW(
  254. socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
  255. socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
  256. );
  257. EXPECT_GT(socket1, 0);
  258. EXPECT_GT(socket2, 0);
  259. boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
  260. // prepare dummy payload
  261. for (int i=0;i<128; i++) {
  262. sendPkt->data_[i] = i;
  263. }
  264. sendPkt->remote_port_ = 10547;
  265. sendPkt->remote_addr_ = IOAddress("::1");
  266. sendPkt->ifindex_ = 1;
  267. sendPkt->iface_ = LOOPBACK;
  268. boost::shared_ptr<Pkt6> rcvPkt;
  269. EXPECT_EQ(true, ifacemgr->send(sendPkt));
  270. rcvPkt = ifacemgr->receive6();
  271. ASSERT_TRUE( rcvPkt ); // received our own packet
  272. // let's check that we received what was sent
  273. EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
  274. EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
  275. rcvPkt->data_len_) );
  276. EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
  277. // since we opened 2 sockets on the same interface and none of them is multicast,
  278. // none is preferred over the other for sending data, so we really should not
  279. // assume the one or the other will always be choosen for sending data. Therefore
  280. // we should accept both values as source ports.
  281. EXPECT_TRUE( (rcvPkt->remote_port_ == 10546) || (rcvPkt->remote_port_ == 10547) );
  282. delete ifacemgr;
  283. }
  284. TEST_F(IfaceMgrTest, sendReceive4) {
  285. // testing socket operation in a portable way is tricky
  286. // without interface detection implemented
  287. createLoInterfacesTxt();
  288. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  289. // let's assume that every supported OS have lo interface
  290. IOAddress loAddr("127.0.0.1");
  291. int socket1 = 0, socket2 = 0;
  292. EXPECT_NO_THROW(
  293. socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000);
  294. socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000 + 1);
  295. );
  296. EXPECT_GE(socket1, 0);
  297. EXPECT_GE(socket2, 0);
  298. boost::shared_ptr<Pkt4> sendPkt(new Pkt4(DHCPDISCOVER, 1234) );
  299. sendPkt->setLocalAddr(IOAddress("127.0.0.1"));
  300. sendPkt->setLocalPort(DHCP4_SERVER_PORT + 10000 + 1);
  301. sendPkt->setRemotePort(DHCP4_SERVER_PORT + 10000);
  302. sendPkt->setRemoteAddr(IOAddress("127.0.0.1"));
  303. sendPkt->setIndex(1);
  304. sendPkt->setIface(string(LOOPBACK));
  305. sendPkt->setHops(6);
  306. sendPkt->setSecs(42);
  307. sendPkt->setCiaddr(IOAddress("192.0.2.1"));
  308. sendPkt->setSiaddr(IOAddress("192.0.2.2"));
  309. sendPkt->setYiaddr(IOAddress("192.0.2.3"));
  310. sendPkt->setGiaddr(IOAddress("192.0.2.4"));
  311. uint8_t sname[] = "That's just a string that will act as SNAME";
  312. sendPkt->setSname(sname, strlen((const char*)sname));
  313. uint8_t file[] = "/another/string/that/acts/as/a/file_name.txt";
  314. sendPkt->setFile(file, strlen((const char*)file));
  315. ASSERT_NO_THROW(
  316. sendPkt->pack();
  317. );
  318. boost::shared_ptr<Pkt4> rcvPkt;
  319. EXPECT_EQ(true, ifacemgr->send(sendPkt));
  320. rcvPkt = ifacemgr->receive4();
  321. ASSERT_TRUE( rcvPkt ); // received our own packet
  322. ASSERT_NO_THROW(
  323. rcvPkt->unpack();
  324. );
  325. // let's check that we received what was sent
  326. EXPECT_EQ(sendPkt->len(), rcvPkt->len());
  327. EXPECT_EQ("127.0.0.1", rcvPkt->getRemoteAddr().toText());
  328. EXPECT_EQ(sendPkt->getRemotePort(), rcvPkt->getLocalPort());
  329. // now let's check content
  330. EXPECT_EQ(sendPkt->getHops(), rcvPkt->getHops());
  331. EXPECT_EQ(sendPkt->getOp(), rcvPkt->getOp());
  332. EXPECT_EQ(sendPkt->getSecs(), rcvPkt->getSecs());
  333. EXPECT_EQ(sendPkt->getFlags(), rcvPkt->getFlags());
  334. EXPECT_EQ(sendPkt->getCiaddr(), rcvPkt->getCiaddr());
  335. EXPECT_EQ(sendPkt->getSiaddr(), rcvPkt->getSiaddr());
  336. EXPECT_EQ(sendPkt->getYiaddr(), rcvPkt->getYiaddr());
  337. EXPECT_EQ(sendPkt->getGiaddr(), rcvPkt->getGiaddr());
  338. EXPECT_EQ(sendPkt->getTransid(), rcvPkt->getTransid());
  339. EXPECT_EQ(sendPkt->getType(), rcvPkt->getType());
  340. EXPECT_TRUE(sendPkt->getSname() == rcvPkt->getSname());
  341. EXPECT_TRUE(sendPkt->getFile() == rcvPkt->getFile());
  342. EXPECT_EQ(sendPkt->getHtype(), rcvPkt->getHtype());
  343. EXPECT_EQ(sendPkt->getHlen(), rcvPkt->getHlen());
  344. // since we opened 2 sockets on the same interface and none of them is multicast,
  345. // none is preferred over the other for sending data, so we really should not
  346. // assume the one or the other will always be choosen for sending data. We should
  347. // skip checking source port of sent address.
  348. delete ifacemgr;
  349. }
  350. TEST_F(IfaceMgrTest, socket4) {
  351. createLoInterfacesTxt();
  352. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  353. // Let's assume that every supported OS have lo interface.
  354. IOAddress loAddr("127.0.0.1");
  355. // Use unprivileged port (it's convenient for running tests as non-root).
  356. int socket1 = 0;
  357. EXPECT_NO_THROW(
  358. socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000);
  359. );
  360. EXPECT_GT(socket1, 0);
  361. Pkt4 pkt(DHCPDISCOVER, 1234);
  362. pkt.setIface(LOOPBACK);
  363. // Expect that we get the socket that we just opened.
  364. EXPECT_EQ(socket1, ifacemgr->getSocket(pkt));
  365. close(socket1);
  366. delete ifacemgr;
  367. }
  368. // Test the Iface structure itself
  369. TEST_F(IfaceMgrTest, iface) {
  370. IfaceMgr::Iface* iface = NULL;
  371. EXPECT_NO_THROW(
  372. iface = new IfaceMgr::Iface("eth0",1);
  373. );
  374. EXPECT_EQ("eth0", iface->getName());
  375. EXPECT_EQ(1, iface->getIndex());
  376. EXPECT_EQ("eth0/1", iface->getFullName());
  377. // Let's make a copy of this address collection.
  378. IfaceMgr::AddressCollection addrs = iface->getAddresses();
  379. EXPECT_EQ(0, addrs.size());
  380. IOAddress addr1("192.0.2.6");
  381. iface->addAddress(addr1);
  382. addrs = iface->getAddresses();
  383. ASSERT_EQ(1, addrs.size());
  384. EXPECT_EQ("192.0.2.6", addrs.at(0).toText());
  385. // No such address, should return false.
  386. EXPECT_FALSE(iface->delAddress(IOAddress("192.0.8.9")));
  387. // This address is present, delete it!
  388. EXPECT_TRUE(iface->delAddress(IOAddress("192.0.2.6")));
  389. // Not really necessary, previous reference still points to the same
  390. // collection. Let's do it anyway, as test code may serve as example
  391. // usage code as well.
  392. addrs = iface->getAddresses();
  393. EXPECT_EQ(0, addrs.size());
  394. EXPECT_NO_THROW(
  395. delete iface;
  396. );
  397. }
  398. TEST_F(IfaceMgrTest, socketInfo) {
  399. // check that socketinfo for IPv4 socket is functional
  400. IfaceMgr::SocketInfo sock1(7, IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7);
  401. EXPECT_EQ(7, sock1.sockfd_);
  402. EXPECT_EQ("192.0.2.56", sock1.addr_.toText());
  403. EXPECT_EQ(AF_INET, sock1.family_);
  404. EXPECT_EQ(DHCP4_SERVER_PORT + 7, sock1.port_);
  405. // check that socketinfo for IPv6 socket is functional
  406. IfaceMgr::SocketInfo sock2(9, IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9);
  407. EXPECT_EQ(9, sock2.sockfd_);
  408. EXPECT_EQ("2001:db8:1::56", sock2.addr_.toText());
  409. EXPECT_EQ(AF_INET6, sock2.family_);
  410. EXPECT_EQ(DHCP4_SERVER_PORT + 9, sock2.port_);
  411. // now let's test if IfaceMgr handles socket info properly
  412. createLoInterfacesTxt();
  413. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  414. IfaceMgr::Iface* loopback = ifacemgr->getIface(LOOPBACK);
  415. ASSERT_TRUE(loopback);
  416. loopback->addSocket(sock1);
  417. loopback->addSocket(sock2);
  418. Pkt6 pkt6(100);
  419. // pkt6 dos not have interface set yet
  420. EXPECT_THROW(
  421. ifacemgr->getSocket(pkt6),
  422. BadValue
  423. );
  424. // try to send over non-existing interface
  425. pkt6.iface_ = "nosuchinterface45";
  426. EXPECT_THROW(
  427. ifacemgr->getSocket(pkt6),
  428. BadValue
  429. );
  430. // this will work
  431. pkt6.iface_ = LOOPBACK;
  432. EXPECT_EQ(9, ifacemgr->getSocket(pkt6));
  433. bool deleted = false;
  434. EXPECT_NO_THROW(
  435. deleted = ifacemgr->getIface(LOOPBACK)->delSocket(9);
  436. );
  437. EXPECT_EQ(true, deleted);
  438. // it should throw again, there's no usable socket anymore
  439. EXPECT_THROW(
  440. ifacemgr->getSocket(pkt6),
  441. Unexpected
  442. );
  443. // repeat for pkt4
  444. Pkt4 pkt4(DHCPDISCOVER, 1);
  445. // pkt4 does not have interface set yet.
  446. EXPECT_THROW(
  447. ifacemgr->getSocket(pkt4),
  448. BadValue
  449. );
  450. // Try to send over non-existing interface.
  451. pkt4.setIface("nosuchinterface45");
  452. EXPECT_THROW(
  453. ifacemgr->getSocket(pkt4),
  454. BadValue
  455. );
  456. // Socket info is set, packet has well defined interface. It should work.
  457. pkt4.setIface(LOOPBACK);
  458. EXPECT_EQ(7, ifacemgr->getSocket(pkt4));
  459. EXPECT_NO_THROW(
  460. ifacemgr->getIface(LOOPBACK)->delSocket(7);
  461. );
  462. // It should throw again, there's no usable socket anymore.
  463. EXPECT_THROW(
  464. ifacemgr->getSocket(pkt4),
  465. Unexpected
  466. );
  467. delete ifacemgr;
  468. }
  469. #if defined(OS_LINUX)
  470. /// @brief parses text representation of MAC address
  471. ///
  472. /// This function parses text representation of a MAC address and stores
  473. /// it in binary format. Text format is expecte to be separate with
  474. /// semicolons, e.g. f4:6d:04:96:58:f2
  475. ///
  476. /// TODO: IfaceMgr::Iface::mac_ uses uint8_t* type, should be vector<uint8_t>
  477. ///
  478. /// @param textMac string with MAC address to parse
  479. /// @param mac pointer to output buffer
  480. /// @param macLen length of output buffer
  481. ///
  482. /// @return number of bytes filled in output buffer
  483. size_t parse_mac(const std::string& textMac, uint8_t* mac, size_t macLen) {
  484. stringstream tmp(textMac);
  485. tmp.flags(ios::hex);
  486. int i = 0;
  487. uint8_t octet = 0; // output octet
  488. uint8_t byte; // parsed charater from text representation
  489. while (!tmp.eof()) {
  490. tmp >> byte; // hex value
  491. if (byte == ':') {
  492. mac[i++] = octet;
  493. if (i == macLen) {
  494. // parsing aborted. We hit output buffer size
  495. return(i);
  496. }
  497. octet = 0;
  498. continue;
  499. }
  500. if (isalpha(byte)) {
  501. byte = toupper(byte) - 'A' + 10;
  502. } else if (isdigit(byte)) {
  503. byte -= '0';
  504. } else {
  505. // parse error. Let's return what we were able to parse so far
  506. break;
  507. }
  508. octet <<= 4;
  509. octet += byte;
  510. }
  511. mac[i++] = octet;
  512. return (i);
  513. }
  514. /// @brief Parses 'ifconfig -a' output and creates list of interfaces
  515. ///
  516. /// This method tries to parse ifconfig output. Note that there are some
  517. /// oddities in recent versions of ifconfig, like putting extra spaces
  518. /// after MAC address, inconsistent naming and spacing between inet and inet6.
  519. /// This is an attempt to find a balance between tight parsing of every piece
  520. /// of text that ifconfig prints and robustness to handle slight differences
  521. /// in ifconfig output.
  522. ///
  523. /// @param textFile name of a text file that holds output of ifconfig -a
  524. /// @param ifaces empty list of interfaces to be filled
  525. void parse_ifconfig(const std::string textFile, IfaceMgr::IfaceCollection& ifaces) {
  526. fstream f(textFile.c_str());
  527. bool first_line = true;
  528. IfaceMgr::IfaceCollection::iterator iface;
  529. while (!f.eof()) {
  530. string line;
  531. getline(f, line);
  532. // interfaces are separated by empty line
  533. if (line.length() == 0) {
  534. first_line = true;
  535. continue;
  536. }
  537. // uncomment this for ifconfig output debug
  538. // cout << "line[" << line << "]" << endl;
  539. // this is first line of a new interface
  540. if (first_line) {
  541. first_line = false;
  542. size_t offset;
  543. offset = line.find_first_of(" ");
  544. if (offset == string::npos) {
  545. isc_throw(BadValue, "Malformed output of ifconfig");
  546. }
  547. string name = line.substr(0, offset);
  548. // sadly, ifconfig does not return ifindex
  549. ifaces.push_back(IfaceMgr::Iface(name, 0));
  550. iface = ifaces.end();
  551. --iface; // points to the last element
  552. offset = line.find(string("HWaddr"));
  553. string mac = "";
  554. if (offset != string::npos) { // some interfaces don't have MAC (e.g. lo)
  555. offset += 7;
  556. mac = line.substr(offset, string::npos);
  557. mac = mac.substr(0, mac.find_first_of(" "));
  558. iface->mac_len_ = parse_mac(mac, iface->mac_, IfaceMgr::MAX_MAC_LEN);
  559. }
  560. }
  561. if (line.find("inet6") != string::npos) {
  562. // IPv6 address
  563. string addr = line.substr(line.find("inet6")+12, string::npos);
  564. addr = addr.substr(0, addr.find("/"));
  565. IOAddress a(addr);
  566. iface->addAddress(a);
  567. } else if(line.find("inet") != string::npos) {
  568. // IPv4 address
  569. string addr = line.substr(line.find("inet")+10, string::npos);
  570. addr = addr.substr(0, addr.find_first_of(" "));
  571. IOAddress a(addr);
  572. iface->addAddress(a);
  573. } else if(line.find("Metric")) {
  574. // flags
  575. if (line.find("UP") != string::npos) {
  576. iface->flag_up_ = true;
  577. }
  578. if (line.find("LOOPBACK") != string::npos) {
  579. iface->flag_loopback_ = true;
  580. }
  581. if (line.find("RUNNING") != string::npos) {
  582. iface->flag_running_ = true;
  583. }
  584. if (line.find("BROADCAST") != string::npos) {
  585. iface->flag_broadcast_ = true;
  586. }
  587. if (line.find("MULTICAST") != string::npos) {
  588. iface->flag_multicast_ = true;
  589. }
  590. }
  591. }
  592. }
  593. // This test compares implemented detection routines to output of "ifconfig -a" command.
  594. // It is far from perfect, but it is able to verify that interface names, flags,
  595. // MAC address, IPv4 and IPv6 addresses are detected properly. Interface list completeness
  596. // (check that each interface is reported, i.e. no missing or extra interfaces) and
  597. // address completeness is verified.
  598. //
  599. // Things that are not tested:
  600. // - ifindex (ifconfig does not print it out)
  601. // - address scopes and lifetimes (we don't need it, so it is not implemented in IfaceMgr)
  602. TEST_F(IfaceMgrTest, detectIfaces_linux) {
  603. NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
  604. IfaceMgr::IfaceCollection& detectedIfaces = ifacemgr->getIfacesLst();
  605. const std::string textFile = "ifconfig.txt";
  606. unlink(textFile.c_str());
  607. int result = system( ("/sbin/ifconfig -a > " + textFile).c_str());
  608. ASSERT_EQ(0, result);
  609. // list of interfaces parsed from ifconfig
  610. IfaceMgr::IfaceCollection parsedIfaces;
  611. EXPECT_NO_THROW(
  612. parse_ifconfig(textFile, parsedIfaces);
  613. );
  614. unlink(textFile.c_str());
  615. cout << "------Parsed interfaces---" << endl;
  616. for (IfaceMgr::IfaceCollection::iterator i = parsedIfaces.begin();
  617. i != parsedIfaces.end(); ++i) {
  618. cout << i->getName() << ": ifindex=" << i->getIndex() << ", mac=" << i->getPlainMac();
  619. cout << ", flags:";
  620. if (i->flag_up_) {
  621. cout << " UP";
  622. }
  623. if (i->flag_running_) {
  624. cout << " RUNNING";
  625. }
  626. if (i->flag_multicast_) {
  627. cout << " MULTICAST";
  628. }
  629. if (i->flag_broadcast_) {
  630. cout << " BROADCAST";
  631. }
  632. cout << ", addrs:";
  633. const IfaceMgr::AddressCollection& addrs = i->getAddresses();
  634. for (IfaceMgr::AddressCollection::const_iterator a= addrs.begin();
  635. a != addrs.end(); ++a) {
  636. cout << a->toText() << " ";
  637. }
  638. cout << endl;
  639. }
  640. // Ok, now we have 2 lists of interfaces. Need to compare them
  641. ASSERT_EQ(detectedIfaces.size(), parsedIfaces.size());
  642. // TODO: This could could probably be written simple with find()
  643. for (IfaceMgr::IfaceCollection::iterator detected = detectedIfaces.begin();
  644. detected != detectedIfaces.end(); ++detected) {
  645. // let's find out if this interface is
  646. bool found = false;
  647. for (IfaceMgr::IfaceCollection::iterator i = parsedIfaces.begin();
  648. i != parsedIfaces.end(); ++i) {
  649. if (detected->getName() != i->getName()) {
  650. continue;
  651. }
  652. found = true;
  653. cout << "Checking interface " << detected->getName() << endl;
  654. // start with checking flags
  655. EXPECT_EQ(detected->flag_loopback_, i->flag_loopback_);
  656. EXPECT_EQ(detected->flag_up_, i->flag_up_);
  657. EXPECT_EQ(detected->flag_running_, i->flag_running_);
  658. EXPECT_EQ(detected->flag_multicast_, i->flag_multicast_);
  659. EXPECT_EQ(detected->flag_broadcast_, i->flag_broadcast_);
  660. // skip MAC comparison for loopback as netlink returns MAC
  661. // 00:00:00:00:00:00 for lo
  662. if (!detected->flag_loopback_) {
  663. ASSERT_EQ(detected->mac_len_, i->mac_len_);
  664. EXPECT_EQ(0, memcmp(detected->mac_, i->mac_, i->mac_len_));
  665. }
  666. EXPECT_EQ(detected->getAddresses().size(), i->getAddresses().size());
  667. // now compare addresses
  668. const IfaceMgr::AddressCollection& addrs = detected->getAddresses();
  669. for (IfaceMgr::AddressCollection::const_iterator addr = addrs.begin();
  670. addr != addrs.end(); ++addr) {
  671. bool addr_found = false;
  672. const IfaceMgr::AddressCollection& addrs2 = detected->getAddresses();
  673. for (IfaceMgr::AddressCollection::const_iterator a = addrs2.begin();
  674. a != addrs2.end(); ++a) {
  675. if (*addr != *a) {
  676. continue;
  677. }
  678. addr_found = true;
  679. }
  680. if (!addr_found) {
  681. cout << "ifconfig does not seem to report " << addr->toText()
  682. << " address on " << detected->getFullName() << " interface." << endl;
  683. FAIL();
  684. }
  685. cout << "Address " << addr->toText() << " on iterface " << detected->getFullName()
  686. << " matched with 'ifconfig -a' output." << endl;
  687. }
  688. }
  689. if (!found) { // corresponding interface was not found
  690. FAIL();
  691. }
  692. }
  693. delete ifacemgr;
  694. }
  695. #endif
  696. }