iface_mgr_unittest.cc 33 KB

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