iface_mgr_unittest.cc 32 KB

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