dhcp6_srv_unittest.cc 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542
  1. // Copyright (C) 2011-2013 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 <asiolink/io_address.h>
  16. #include <config/ccsession.h>
  17. #include <dhcp/dhcp6.h>
  18. #include <dhcp/duid.h>
  19. #include <dhcp/option.h>
  20. #include <dhcp/option_custom.h>
  21. #include <dhcp/option6_addrlst.h>
  22. #include <dhcp/option6_ia.h>
  23. #include <dhcp/option6_iaaddr.h>
  24. #include <dhcp/option_int_array.h>
  25. #include <dhcp/iface_mgr.h>
  26. #include <dhcp6/config_parser.h>
  27. #include <dhcp6/dhcp6_srv.h>
  28. #include <dhcp/dhcp6.h>
  29. #include <dhcpsrv/cfgmgr.h>
  30. #include <dhcpsrv/lease_mgr.h>
  31. #include <dhcpsrv/lease_mgr_factory.h>
  32. #include <dhcpsrv/utils.h>
  33. #include <util/buffer.h>
  34. #include <util/range_utilities.h>
  35. #include <hooks/server_hooks.h>
  36. #include <hooks/hooks_manager.h>
  37. #include <boost/scoped_ptr.hpp>
  38. #include <gtest/gtest.h>
  39. #include <unistd.h>
  40. #include <fstream>
  41. #include <iostream>
  42. #include <sstream>
  43. #include <list>
  44. using namespace isc;
  45. using namespace isc::asiolink;
  46. using namespace isc::config;
  47. using namespace isc::data;
  48. using namespace isc::dhcp;
  49. using namespace isc::util;
  50. using namespace isc::hooks;
  51. using namespace std;
  52. // namespace has to be named, because friends are defined in Dhcpv6Srv class
  53. // Maybe it should be isc::test?
  54. namespace {
  55. class NakedDhcpv6Srv: public Dhcpv6Srv {
  56. // "naked" Interface Manager, exposes internal members
  57. public:
  58. NakedDhcpv6Srv(uint16_t port) : Dhcpv6Srv(port) {
  59. // Open the "memfile" database for leases
  60. std::string memfile = "type=memfile";
  61. LeaseMgrFactory::create(memfile);
  62. }
  63. /// @brief fakes packet reception
  64. /// @param timeout ignored
  65. ///
  66. /// The method receives all packets queued in receive
  67. /// queue, one after another. Once the queue is empty,
  68. /// it initiates the shutdown procedure.
  69. ///
  70. /// See fake_received_ field for description
  71. virtual Pkt6Ptr receivePacket(int /*timeout*/) {
  72. // If there is anything prepared as fake incoming
  73. // traffic, use it
  74. if (!fake_received_.empty()) {
  75. Pkt6Ptr pkt = fake_received_.front();
  76. fake_received_.pop_front();
  77. return (pkt);
  78. }
  79. // If not, just trigger shutdown and
  80. // return immediately
  81. shutdown();
  82. return (Pkt6Ptr());
  83. }
  84. /// @brief fake packet sending
  85. ///
  86. /// Pretend to send a packet, but instead just store
  87. /// it in fake_send_ list where test can later inspect
  88. /// server's response.
  89. virtual void sendPacket(const Pkt6Ptr& pkt) {
  90. fake_sent_.push_back(pkt);
  91. }
  92. /// @brief adds a packet to fake receive queue
  93. ///
  94. /// See fake_received_ field for description
  95. void fakeReceive(const Pkt6Ptr& pkt) {
  96. fake_received_.push_back(pkt);
  97. }
  98. virtual ~NakedDhcpv6Srv() {
  99. // Close the lease database
  100. LeaseMgrFactory::destroy();
  101. }
  102. using Dhcpv6Srv::processSolicit;
  103. using Dhcpv6Srv::processRequest;
  104. using Dhcpv6Srv::processRenew;
  105. using Dhcpv6Srv::processRelease;
  106. using Dhcpv6Srv::createStatusCode;
  107. using Dhcpv6Srv::selectSubnet;
  108. using Dhcpv6Srv::sanityCheck;
  109. using Dhcpv6Srv::loadServerID;
  110. using Dhcpv6Srv::writeServerID;
  111. /// @brief packets we pretend to receive
  112. ///
  113. /// Instead of setting up sockets on interfaces that change between OSes, it
  114. /// is much easier to fake packet reception. This is a list of packets that
  115. /// we pretend to have received. You can schedule new packets to be received
  116. /// using fakeReceive() and NakedDhcpv6Srv::receivePacket() methods.
  117. list<Pkt6Ptr> fake_received_;
  118. list<Pkt6Ptr> fake_sent_;
  119. };
  120. static const char* DUID_FILE = "server-id-test.txt";
  121. // test fixture for any tests requiring blank/empty configuration
  122. // serves as base class for additional tests
  123. class NakedDhcpv6SrvTest : public ::testing::Test {
  124. public:
  125. NakedDhcpv6SrvTest() : rcode_(-1) {
  126. // it's ok if that fails. There should not be such a file anyway
  127. unlink(DUID_FILE);
  128. const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
  129. // There must be some interface detected
  130. if (ifaces.empty()) {
  131. // We can't use ASSERT in constructor
  132. ADD_FAILURE() << "No interfaces detected.";
  133. }
  134. valid_iface_ = ifaces.begin()->getName();
  135. }
  136. // Generate IA_NA option with specified parameters
  137. boost::shared_ptr<Option6IA> generateIA(uint32_t iaid, uint32_t t1, uint32_t t2) {
  138. boost::shared_ptr<Option6IA> ia =
  139. boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, iaid));
  140. ia->setT1(t1);
  141. ia->setT2(t2);
  142. return (ia);
  143. }
  144. /// @brief generates interface-id option, based on text
  145. ///
  146. /// @param iface_id textual representation of the interface-id content
  147. ///
  148. /// @return pointer to the option object
  149. OptionPtr generateInterfaceId(const string& iface_id) {
  150. OptionBuffer tmp(iface_id.begin(), iface_id.end());
  151. return OptionPtr(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
  152. }
  153. // Generate client-id option
  154. OptionPtr generateClientId(size_t duid_size = 32) {
  155. OptionBuffer clnt_duid(duid_size);
  156. for (int i = 0; i < duid_size; i++) {
  157. clnt_duid[i] = 100 + i;
  158. }
  159. duid_ = DuidPtr(new DUID(clnt_duid));
  160. return (OptionPtr(new Option(Option::V6, D6O_CLIENTID,
  161. clnt_duid.begin(),
  162. clnt_duid.begin() + duid_size)));
  163. }
  164. // Checks if server response (ADVERTISE or REPLY) includes proper server-id.
  165. void checkServerId(const Pkt6Ptr& rsp, const OptionPtr& expected_srvid) {
  166. // check that server included its server-id
  167. OptionPtr tmp = rsp->getOption(D6O_SERVERID);
  168. EXPECT_EQ(tmp->getType(), expected_srvid->getType() );
  169. ASSERT_EQ(tmp->len(), expected_srvid->len() );
  170. EXPECT_TRUE(tmp->getData() == expected_srvid->getData());
  171. }
  172. // Checks if server response (ADVERTISE or REPLY) includes proper client-id.
  173. void checkClientId(const Pkt6Ptr& rsp, const OptionPtr& expected_clientid) {
  174. // check that server included our own client-id
  175. OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
  176. ASSERT_TRUE(tmp);
  177. EXPECT_EQ(expected_clientid->getType(), tmp->getType());
  178. ASSERT_EQ(expected_clientid->len(), tmp->len());
  179. // check that returned client-id is valid
  180. EXPECT_TRUE(expected_clientid->getData() == tmp->getData());
  181. }
  182. // Checks if server response is a NAK
  183. void checkNakResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
  184. uint32_t expected_transid,
  185. uint16_t expected_status_code) {
  186. // Check if we get response at all
  187. checkResponse(rsp, expected_message_type, expected_transid);
  188. // Check that IA_NA was returned
  189. OptionPtr option_ia_na = rsp->getOption(D6O_IA_NA);
  190. ASSERT_TRUE(option_ia_na);
  191. // check that the status is no address available
  192. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(option_ia_na);
  193. ASSERT_TRUE(ia);
  194. checkIA_NAStatusCode(ia, expected_status_code);
  195. }
  196. // Checks that server rejected IA_NA, i.e. that it has no addresses and
  197. // that expected status code really appears there. In some limited cases
  198. // (reply to RELEASE) it may be used to verify positive case, where
  199. // IA_NA response is expected to not include address.
  200. //
  201. // Status code indicates type of error encountered (in theory it can also
  202. // indicate success, but servers typically don't send success status
  203. // as this is the default result and it saves bandwidth)
  204. void checkIA_NAStatusCode(const boost::shared_ptr<Option6IA>& ia,
  205. uint16_t expected_status_code) {
  206. // Make sure there is no address assigned.
  207. EXPECT_FALSE(ia->getOption(D6O_IAADDR));
  208. // T1, T2 should be zeroed
  209. EXPECT_EQ(0, ia->getT1());
  210. EXPECT_EQ(0, ia->getT2());
  211. OptionCustomPtr status =
  212. boost::dynamic_pointer_cast<OptionCustom>(ia->getOption(D6O_STATUS_CODE));
  213. // It is ok to not include status success as this is the default behavior
  214. if (expected_status_code == STATUS_Success && !status) {
  215. return;
  216. }
  217. EXPECT_TRUE(status);
  218. if (status) {
  219. // We don't have dedicated class for status code, so let's just interpret
  220. // first 2 bytes as status. Remainder of the status code option content is
  221. // just a text explanation what went wrong.
  222. EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
  223. status->readInteger<uint16_t>(0));
  224. }
  225. }
  226. void checkMsgStatusCode(const Pkt6Ptr& msg, uint16_t expected_status) {
  227. OptionCustomPtr status =
  228. boost::dynamic_pointer_cast<OptionCustom>(msg->getOption(D6O_STATUS_CODE));
  229. // It is ok to not include status success as this is the default behavior
  230. if (expected_status == STATUS_Success && !status) {
  231. return;
  232. }
  233. EXPECT_TRUE(status);
  234. if (status) {
  235. // We don't have dedicated class for status code, so let's just interpret
  236. // first 2 bytes as status. Remainder of the status code option content is
  237. // just a text explanation what went wrong.
  238. EXPECT_EQ(static_cast<uint16_t>(expected_status),
  239. status->readInteger<uint16_t>(0));
  240. }
  241. }
  242. // Basic checks for generated response (message type and transaction-id).
  243. void checkResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
  244. uint32_t expected_transid) {
  245. ASSERT_TRUE(rsp);
  246. EXPECT_EQ(expected_message_type, rsp->getType());
  247. EXPECT_EQ(expected_transid, rsp->getTransid());
  248. }
  249. virtual ~NakedDhcpv6SrvTest() {
  250. // Let's clean up if there is such a file.
  251. unlink(DUID_FILE);
  252. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
  253. "pkt6_receive");
  254. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
  255. "pkt6_send");
  256. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
  257. "subnet6_select");
  258. };
  259. // A DUID used in most tests (typically as client-id)
  260. DuidPtr duid_;
  261. int rcode_;
  262. ConstElementPtr comment_;
  263. // Name of a valid network interface
  264. string valid_iface_;
  265. };
  266. // Provides suport for tests against a preconfigured subnet6
  267. // extends upon NakedDhcp6SrvTest
  268. class Dhcpv6SrvTest : public NakedDhcpv6SrvTest {
  269. public:
  270. /// Name of the server-id file (used in server-id tests)
  271. // these are empty for now, but let's keep them around
  272. Dhcpv6SrvTest() {
  273. subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
  274. 2000, 3000, 4000));
  275. pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
  276. subnet_->addPool(pool_);
  277. CfgMgr::instance().deleteSubnets6();
  278. CfgMgr::instance().addSubnet6(subnet_);
  279. }
  280. // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
  281. // It returns IAADDR option for each chaining with checkIAAddr method.
  282. boost::shared_ptr<Option6IAAddr> checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
  283. uint32_t expected_t1, uint32_t expected_t2) {
  284. OptionPtr tmp = rsp->getOption(D6O_IA_NA);
  285. // Can't use ASSERT_TRUE() in method that returns something
  286. if (!tmp) {
  287. ADD_FAILURE() << "IA_NA option not present in response";
  288. return (boost::shared_ptr<Option6IAAddr>());
  289. }
  290. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  291. if (!ia) {
  292. ADD_FAILURE() << "IA_NA cannot convert option ptr to Option6";
  293. return (boost::shared_ptr<Option6IAAddr>());
  294. }
  295. EXPECT_EQ(expected_iaid, ia->getIAID());
  296. EXPECT_EQ(expected_t1, ia->getT1());
  297. EXPECT_EQ(expected_t2, ia->getT2());
  298. tmp = ia->getOption(D6O_IAADDR);
  299. boost::shared_ptr<Option6IAAddr> addr = boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
  300. return (addr);
  301. }
  302. // Check that generated IAADDR option contains expected address
  303. // and lifetime values match the configured subnet
  304. void checkIAAddr(const boost::shared_ptr<Option6IAAddr>& addr,
  305. const IOAddress& expected_addr,
  306. uint32_t /* expected_preferred */,
  307. uint32_t /* expected_valid */) {
  308. // Check that the assigned address is indeed from the configured pool.
  309. // Note that when comparing addresses, we compare the textual
  310. // representation. IOAddress does not support being streamed to
  311. // an ostream, which means it can't be used in EXPECT_EQ.
  312. EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
  313. EXPECT_EQ(expected_addr.toText(), addr->getAddress().toText());
  314. EXPECT_EQ(addr->getPreferred(), subnet_->getPreferred());
  315. EXPECT_EQ(addr->getValid(), subnet_->getValid());
  316. }
  317. // Checks if the lease sent to client is present in the database
  318. // and is valid when checked agasint the configured subnet
  319. Lease6Ptr checkLease(const DuidPtr& duid, const OptionPtr& ia_na,
  320. boost::shared_ptr<Option6IAAddr> addr) {
  321. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(ia_na);
  322. Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(addr->getAddress());
  323. if (!lease) {
  324. cout << "Lease for " << addr->getAddress().toText()
  325. << " not found in the database backend.";
  326. return (Lease6Ptr());
  327. }
  328. EXPECT_EQ(addr->getAddress().toText(), lease->addr_.toText());
  329. EXPECT_TRUE(*lease->duid_ == *duid);
  330. EXPECT_EQ(ia->getIAID(), lease->iaid_);
  331. EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
  332. return (lease);
  333. }
  334. ~Dhcpv6SrvTest() {
  335. CfgMgr::instance().deleteSubnets6();
  336. };
  337. // A subnet used in most tests
  338. Subnet6Ptr subnet_;
  339. // A pool used in most tests
  340. Pool6Ptr pool_;
  341. };
  342. // This test verifies that incoming SOLICIT can be handled properly when
  343. // there are no subnets configured.
  344. //
  345. // This test sends a SOLICIT and the expected response
  346. // is an ADVERTISE with STATUS_NoAddrsAvail and no address provided in the
  347. // response
  348. TEST_F(NakedDhcpv6SrvTest, SolicitNoSubnet) {
  349. NakedDhcpv6Srv srv(0);
  350. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  351. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  352. sol->addOption(generateIA(234, 1500, 3000));
  353. OptionPtr clientid = generateClientId();
  354. sol->addOption(clientid);
  355. // Pass it to the server and get an advertise
  356. Pkt6Ptr reply = srv.processSolicit(sol);
  357. // check that we get the right NAK
  358. checkNakResponse (reply, DHCPV6_ADVERTISE, 1234, STATUS_NoAddrsAvail);
  359. }
  360. // This test verifies that incoming REQUEST can be handled properly when
  361. // there are no subnets configured.
  362. //
  363. // This test sends a REQUEST and the expected response
  364. // is an REPLY with STATUS_NoAddrsAvail and no address provided in the
  365. // response
  366. TEST_F(NakedDhcpv6SrvTest, RequestNoSubnet) {
  367. NakedDhcpv6Srv srv(0);
  368. // Let's create a REQUEST
  369. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
  370. req->setRemoteAddr(IOAddress("fe80::abcd"));
  371. boost::shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
  372. // with a hint
  373. IOAddress hint("2001:db8:1:1::dead:beef");
  374. OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
  375. ia->addOption(hint_opt);
  376. req->addOption(ia);
  377. OptionPtr clientid = generateClientId();
  378. req->addOption(clientid);
  379. // server-id is mandatory in REQUEST
  380. req->addOption(srv.getServerID());
  381. // Pass it to the server and hope for a REPLY
  382. Pkt6Ptr reply = srv.processRequest(req);
  383. // check that we get the right NAK
  384. checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail);
  385. }
  386. // This test verifies that incoming RENEW can be handled properly, even when
  387. // no subnets are configured.
  388. //
  389. // This test sends a RENEW and the expected response
  390. // is an REPLY with STATUS_NoBinding and no address provided in the
  391. // response
  392. TEST_F(NakedDhcpv6SrvTest, RenewNoSubnet) {
  393. NakedDhcpv6Srv srv(0);
  394. const IOAddress addr("2001:db8:1:1::cafe:babe");
  395. const uint32_t iaid = 234;
  396. // Generate client-id also duid_
  397. OptionPtr clientid = generateClientId();
  398. // Let's create a RENEW
  399. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
  400. req->setRemoteAddr(IOAddress("fe80::abcd"));
  401. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  402. OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  403. ia->addOption(renewed_addr_opt);
  404. req->addOption(ia);
  405. req->addOption(clientid);
  406. // Server-id is mandatory in RENEW
  407. req->addOption(srv.getServerID());
  408. // Pass it to the server and hope for a REPLY
  409. Pkt6Ptr reply = srv.processRenew(req);
  410. // check that we get the right NAK
  411. checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
  412. }
  413. // This test verifies that incoming RELEASE can be handled properly, even when
  414. // no subnets are configured.
  415. //
  416. // This test sends a RELEASE and the expected response
  417. // is an REPLY with STATUS_NoBinding and no address provided in the
  418. // response
  419. TEST_F(NakedDhcpv6SrvTest, ReleaseNoSubnet) {
  420. NakedDhcpv6Srv srv(0);
  421. const IOAddress addr("2001:db8:1:1::cafe:babe");
  422. const uint32_t iaid = 234;
  423. // Generate client-id also duid_
  424. OptionPtr clientid = generateClientId();
  425. // Let's create a RELEASE
  426. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
  427. req->setRemoteAddr(IOAddress("fe80::abcd"));
  428. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  429. OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  430. ia->addOption(released_addr_opt);
  431. req->addOption(ia);
  432. req->addOption(clientid);
  433. // Server-id is mandatory in RELEASE
  434. req->addOption(srv.getServerID());
  435. // Pass it to the server and hope for a REPLY
  436. Pkt6Ptr reply = srv.processRelease(req);
  437. // check that we get the right NAK
  438. checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
  439. }
  440. // Test verifies that the Dhcpv6_srv class can be instantiated. It checks a mode
  441. // without open sockets and with sockets opened on a high port (to not require
  442. // root privileges).
  443. TEST_F(Dhcpv6SrvTest, basic) {
  444. // srv has stubbed interface detection. It will read
  445. // interfaces.txt instead. It will pretend to have detected
  446. // fe80::1234 link-local address on eth0 interface. Obviously
  447. // an attempt to bind this socket will fail.
  448. boost::scoped_ptr<Dhcpv6Srv> srv;
  449. ASSERT_NO_THROW( {
  450. // Skip opening any sockets
  451. srv.reset(new Dhcpv6Srv(0));
  452. });
  453. srv.reset();
  454. ASSERT_NO_THROW({
  455. // open an unpriviledged port
  456. srv.reset(new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000));
  457. });
  458. }
  459. // Test checks that DUID is generated properly
  460. TEST_F(Dhcpv6SrvTest, DUID) {
  461. boost::scoped_ptr<Dhcpv6Srv> srv;
  462. ASSERT_NO_THROW( {
  463. srv.reset(new NakedDhcpv6Srv(0));
  464. });
  465. OptionPtr srvid = srv->getServerID();
  466. ASSERT_TRUE(srvid);
  467. EXPECT_EQ(D6O_SERVERID, srvid->getType());
  468. OutputBuffer buf(32);
  469. srvid->pack(buf);
  470. // length of the actual DUID
  471. size_t len = buf.getLength() - srvid->getHeaderLen();
  472. InputBuffer data(buf.getData(), buf.getLength());
  473. // ignore first four bytes (standard DHCPv6 header)
  474. data.readUint32();
  475. uint16_t duid_type = data.readUint16();
  476. cout << "Duid-type=" << duid_type << endl;
  477. switch(duid_type) {
  478. case DUID::DUID_LLT: {
  479. // DUID must contain at least 6 bytes long MAC
  480. // + 8 bytes of fixed header
  481. EXPECT_GE(14, len);
  482. uint16_t hw_type = data.readUint16();
  483. // there's no real way to find out "correct"
  484. // hardware type
  485. EXPECT_GT(hw_type, 0);
  486. // check that timer is counted since 1.1.2000,
  487. // not from 1.1.1970.
  488. uint32_t seconds = data.readUint32();
  489. EXPECT_LE(seconds, DUID_TIME_EPOCH);
  490. // this test will start failing after 2030.
  491. // Hopefully we will be at BIND12 by then.
  492. // MAC must not be zeros
  493. vector<uint8_t> mac(len-8);
  494. vector<uint8_t> zeros(len-8, 0);
  495. data.readVector(mac, len-8);
  496. EXPECT_TRUE(mac != zeros);
  497. break;
  498. }
  499. case DUID::DUID_EN: {
  500. // there's not much we can check. Just simple
  501. // check if it is not all zeros
  502. vector<uint8_t> content(len-2);
  503. data.readVector(content, len-2);
  504. EXPECT_FALSE(isRangeZero(content.begin(), content.end()));
  505. break;
  506. }
  507. case DUID::DUID_LL: {
  508. // not supported yet
  509. cout << "Test not implemented for DUID-LL." << endl;
  510. // No failure here. There's really no way for test LL DUID. It doesn't
  511. // even make sense to check if that Link Layer is actually present on
  512. // a physical interface. RFC3315 says a server should write its DUID
  513. // and keep it despite hardware changes.
  514. break;
  515. }
  516. case DUID::DUID_UUID: // not supported yet
  517. default:
  518. ADD_FAILURE() << "Not supported duid type=" << duid_type << endl;
  519. break;
  520. }
  521. }
  522. // This test checks if Option Request Option (ORO) is parsed correctly
  523. // and the requested options are actually assigned.
  524. TEST_F(Dhcpv6SrvTest, advertiseOptions) {
  525. ConstElementPtr x;
  526. string config = "{ \"interface\": [ \"all\" ],"
  527. "\"preferred-lifetime\": 3000,"
  528. "\"rebind-timer\": 2000, "
  529. "\"renew-timer\": 1000, "
  530. "\"subnet6\": [ { "
  531. " \"pool\": [ \"2001:db8:1::/64\" ],"
  532. " \"subnet\": \"2001:db8:1::/48\", "
  533. " \"option-data\": [ {"
  534. " \"name\": \"dns-servers\","
  535. " \"space\": \"dhcp6\","
  536. " \"code\": 23,"
  537. " \"data\": \"2001:db8:1234:FFFF::1, 2001:db8:1234:FFFF::2\","
  538. " \"csv-format\": True"
  539. " },"
  540. " {"
  541. " \"name\": \"subscriber-id\","
  542. " \"space\": \"dhcp6\","
  543. " \"code\": 38,"
  544. " \"data\": \"1234\","
  545. " \"csv-format\": False"
  546. " } ]"
  547. " } ],"
  548. "\"valid-lifetime\": 4000 }";
  549. ElementPtr json = Element::fromJSON(config);
  550. NakedDhcpv6Srv srv(0);
  551. EXPECT_NO_THROW(x = configureDhcp6Server(srv, json));
  552. ASSERT_TRUE(x);
  553. comment_ = parseAnswer(rcode_, x);
  554. ASSERT_EQ(0, rcode_);
  555. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  556. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  557. sol->addOption(generateIA(234, 1500, 3000));
  558. OptionPtr clientid = generateClientId();
  559. sol->addOption(clientid);
  560. // Pass it to the server and get an advertise
  561. Pkt6Ptr adv = srv.processSolicit(sol);
  562. // check if we get response at all
  563. ASSERT_TRUE(adv);
  564. // We have not requested any options so they should not
  565. // be included in the response.
  566. ASSERT_FALSE(adv->getOption(D6O_SUBSCRIBER_ID));
  567. ASSERT_FALSE(adv->getOption(D6O_NAME_SERVERS));
  568. // Let's now request some options. We expect that the server
  569. // will include them in its response.
  570. boost::shared_ptr<OptionIntArray<uint16_t> >
  571. option_oro(new OptionIntArray<uint16_t>(Option::V6, D6O_ORO));
  572. // Create vector with two option codes.
  573. std::vector<uint16_t> codes(2);
  574. codes[0] = D6O_SUBSCRIBER_ID;
  575. codes[1] = D6O_NAME_SERVERS;
  576. // Pass this code to option.
  577. option_oro->setValues(codes);
  578. // Append ORO to SOLICIT message.
  579. sol->addOption(option_oro);
  580. // Need to process SOLICIT again after requesting new option.
  581. adv = srv.processSolicit(sol);
  582. ASSERT_TRUE(adv);
  583. OptionPtr tmp = adv->getOption(D6O_NAME_SERVERS);
  584. ASSERT_TRUE(tmp);
  585. boost::shared_ptr<Option6AddrLst> reply_nameservers =
  586. boost::dynamic_pointer_cast<Option6AddrLst>(tmp);
  587. ASSERT_TRUE(reply_nameservers);
  588. Option6AddrLst::AddressContainer addrs = reply_nameservers->getAddresses();
  589. ASSERT_EQ(2, addrs.size());
  590. EXPECT_TRUE(addrs[0] == IOAddress("2001:db8:1234:FFFF::1"));
  591. EXPECT_TRUE(addrs[1] == IOAddress("2001:db8:1234:FFFF::2"));
  592. // There is a dummy option with code 1000 we requested from a server.
  593. // Expect that this option is in server's response.
  594. tmp = adv->getOption(D6O_SUBSCRIBER_ID);
  595. ASSERT_TRUE(tmp);
  596. // Check that the option contains valid data (from configuration).
  597. std::vector<uint8_t> data = tmp->getData();
  598. ASSERT_EQ(2, data.size());
  599. const uint8_t foo_expected[] = {
  600. 0x12, 0x34
  601. };
  602. EXPECT_EQ(0, memcmp(&data[0], foo_expected, 2));
  603. // more checks to be implemented
  604. }
  605. // There are no dedicated tests for Dhcpv6Srv::handleIA_NA and Dhcpv6Srv::assignLeases
  606. // as they are indirectly tested in Solicit and Request tests.
  607. // This test verifies that incoming SOLICIT can be handled properly, that an
  608. // ADVERTISE is generated, that the response has an address and that address
  609. // really belongs to the configured pool.
  610. //
  611. // This test sends a SOLICIT without any hint in IA_NA.
  612. //
  613. // constructed very simple SOLICIT message with:
  614. // - client-id option (mandatory)
  615. // - IA option (a request for address, without any addresses)
  616. //
  617. // expected returned ADVERTISE message:
  618. // - copy of client-id
  619. // - server-id
  620. // - IA that includes IAADDR
  621. TEST_F(Dhcpv6SrvTest, SolicitBasic) {
  622. NakedDhcpv6Srv srv(0);
  623. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  624. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  625. sol->addOption(generateIA(234, 1500, 3000));
  626. OptionPtr clientid = generateClientId();
  627. sol->addOption(clientid);
  628. // Pass it to the server and get an advertise
  629. Pkt6Ptr reply = srv.processSolicit(sol);
  630. // check if we get response at all
  631. checkResponse(reply, DHCPV6_ADVERTISE, 1234);
  632. // check that IA_NA was returned and that there's an address included
  633. boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
  634. subnet_->getT2());
  635. ASSERT_TRUE(addr);
  636. // Check that the assigned address is indeed from the configured pool
  637. checkIAAddr(addr, addr->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  638. // check DUIDs
  639. checkServerId(reply, srv.getServerID());
  640. checkClientId(reply, clientid);
  641. }
  642. // This test verifies that incoming SOLICIT can be handled properly, that an
  643. // ADVERTISE is generated, that the response has an address and that address
  644. // really belongs to the configured pool.
  645. //
  646. // This test sends a SOLICIT with IA_NA that contains a valid hint.
  647. //
  648. // constructed very simple SOLICIT message with:
  649. // - client-id option (mandatory)
  650. // - IA option (a request for address, with an address that belongs to the
  651. // configured pool, i.e. is valid as hint)
  652. //
  653. // expected returned ADVERTISE message:
  654. // - copy of client-id
  655. // - server-id
  656. // - IA that includes IAADDR
  657. TEST_F(Dhcpv6SrvTest, SolicitHint) {
  658. NakedDhcpv6Srv srv(0);
  659. // Let's create a SOLICIT
  660. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  661. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  662. boost::shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
  663. // with a valid hint
  664. IOAddress hint("2001:db8:1:1::dead:beef");
  665. ASSERT_TRUE(subnet_->inPool(hint));
  666. OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
  667. ia->addOption(hint_opt);
  668. sol->addOption(ia);
  669. OptionPtr clientid = generateClientId();
  670. sol->addOption(clientid);
  671. // Pass it to the server and get an advertise
  672. Pkt6Ptr reply = srv.processSolicit(sol);
  673. // check if we get response at all
  674. checkResponse(reply, DHCPV6_ADVERTISE, 1234);
  675. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  676. ASSERT_TRUE(tmp);
  677. // check that IA_NA was returned and that there's an address included
  678. boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
  679. subnet_->getT2());
  680. ASSERT_TRUE(addr);
  681. // check that we've got the address we requested
  682. checkIAAddr(addr, hint, subnet_->getPreferred(), subnet_->getValid());
  683. // check DUIDs
  684. checkServerId(reply, srv.getServerID());
  685. checkClientId(reply, clientid);
  686. }
  687. // This test verifies that incoming SOLICIT can be handled properly, that an
  688. // ADVERTISE is generated, that the response has an address and that address
  689. // really belongs to the configured pool.
  690. //
  691. // This test sends a SOLICIT with IA_NA that contains an invalid hint.
  692. //
  693. // constructed very simple SOLICIT message with:
  694. // - client-id option (mandatory)
  695. // - IA option (a request for address, with an address that does not
  696. // belong to the configured pool, i.e. is valid as hint)
  697. //
  698. // expected returned ADVERTISE message:
  699. // - copy of client-id
  700. // - server-id
  701. // - IA that includes IAADDR
  702. TEST_F(Dhcpv6SrvTest, SolicitInvalidHint) {
  703. NakedDhcpv6Srv srv(0);
  704. // Let's create a SOLICIT
  705. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  706. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  707. boost::shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
  708. IOAddress hint("2001:db8:1::cafe:babe");
  709. ASSERT_FALSE(subnet_->inPool(hint));
  710. OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
  711. ia->addOption(hint_opt);
  712. sol->addOption(ia);
  713. OptionPtr clientid = generateClientId();
  714. sol->addOption(clientid);
  715. // Pass it to the server and get an advertise
  716. Pkt6Ptr reply = srv.processSolicit(sol);
  717. // check if we get response at all
  718. checkResponse(reply, DHCPV6_ADVERTISE, 1234);
  719. // check that IA_NA was returned and that there's an address included
  720. boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
  721. subnet_->getT2());
  722. ASSERT_TRUE(addr);
  723. // Check that the assigned address is indeed from the configured pool
  724. checkIAAddr(addr, addr->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  725. EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
  726. // check DUIDs
  727. checkServerId(reply, srv.getServerID());
  728. checkClientId(reply, clientid);
  729. }
  730. /// @todo: Add a test that client sends hint that is in pool, but currently
  731. /// being used by a different client.
  732. // This test checks that the server is offering different addresses to different
  733. // clients in ADVERTISEs. Please note that ADVERTISE is not a guarantee that such
  734. // an address will be assigned. Had the pool was very small and contained only
  735. // 2 addresses, the third client would get the same advertise as the first one
  736. // and this is a correct behavior. It is REQUEST that will fail for the third
  737. // client. ADVERTISE is basically saying "if you send me a request, you will
  738. // probably get an address like this" (there are no guarantees).
  739. TEST_F(Dhcpv6SrvTest, ManySolicits) {
  740. NakedDhcpv6Srv srv(0);
  741. Pkt6Ptr sol1 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  742. Pkt6Ptr sol2 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 2345));
  743. Pkt6Ptr sol3 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 3456));
  744. sol1->setRemoteAddr(IOAddress("fe80::abcd"));
  745. sol2->setRemoteAddr(IOAddress("fe80::1223"));
  746. sol3->setRemoteAddr(IOAddress("fe80::3467"));
  747. sol1->addOption(generateIA(1, 1500, 3000));
  748. sol2->addOption(generateIA(2, 1500, 3000));
  749. sol3->addOption(generateIA(3, 1500, 3000));
  750. // different client-id sizes
  751. OptionPtr clientid1 = generateClientId(12);
  752. OptionPtr clientid2 = generateClientId(14);
  753. OptionPtr clientid3 = generateClientId(16);
  754. sol1->addOption(clientid1);
  755. sol2->addOption(clientid2);
  756. sol3->addOption(clientid3);
  757. // Pass it to the server and get an advertise
  758. Pkt6Ptr reply1 = srv.processSolicit(sol1);
  759. Pkt6Ptr reply2 = srv.processSolicit(sol2);
  760. Pkt6Ptr reply3 = srv.processSolicit(sol3);
  761. // check if we get response at all
  762. checkResponse(reply1, DHCPV6_ADVERTISE, 1234);
  763. checkResponse(reply2, DHCPV6_ADVERTISE, 2345);
  764. checkResponse(reply3, DHCPV6_ADVERTISE, 3456);
  765. // check that IA_NA was returned and that there's an address included
  766. boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
  767. subnet_->getT2());
  768. boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
  769. subnet_->getT2());
  770. boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
  771. subnet_->getT2());
  772. ASSERT_TRUE(addr1);
  773. ASSERT_TRUE(addr2);
  774. ASSERT_TRUE(addr3);
  775. // Check that the assigned address is indeed from the configured pool
  776. checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  777. checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  778. checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  779. // check DUIDs
  780. checkServerId(reply1, srv.getServerID());
  781. checkServerId(reply2, srv.getServerID());
  782. checkServerId(reply3, srv.getServerID());
  783. checkClientId(reply1, clientid1);
  784. checkClientId(reply2, clientid2);
  785. checkClientId(reply3, clientid3);
  786. // Finally check that the addresses offered are different
  787. EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
  788. EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
  789. EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
  790. cout << "Offered address to client1=" << addr1->getAddress().toText() << endl;
  791. cout << "Offered address to client2=" << addr2->getAddress().toText() << endl;
  792. cout << "Offered address to client3=" << addr3->getAddress().toText() << endl;
  793. }
  794. // This test verifies that incoming REQUEST can be handled properly, that a
  795. // REPLY is generated, that the response has an address and that address
  796. // really belongs to the configured pool.
  797. //
  798. // This test sends a REQUEST with IA_NA that contains a valid hint.
  799. //
  800. // constructed very simple REQUEST message with:
  801. // - client-id option (mandatory)
  802. // - IA option (a request for address, with an address that belongs to the
  803. // configured pool, i.e. is valid as hint)
  804. //
  805. // expected returned REPLY message:
  806. // - copy of client-id
  807. // - server-id
  808. // - IA that includes IAADDR
  809. TEST_F(Dhcpv6SrvTest, RequestBasic) {
  810. NakedDhcpv6Srv srv(0);
  811. // Let's create a REQUEST
  812. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
  813. req->setRemoteAddr(IOAddress("fe80::abcd"));
  814. boost::shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
  815. // with a valid hint
  816. IOAddress hint("2001:db8:1:1::dead:beef");
  817. ASSERT_TRUE(subnet_->inPool(hint));
  818. OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
  819. ia->addOption(hint_opt);
  820. req->addOption(ia);
  821. OptionPtr clientid = generateClientId();
  822. req->addOption(clientid);
  823. // server-id is mandatory in REQUEST
  824. req->addOption(srv.getServerID());
  825. // Pass it to the server and hope for a REPLY
  826. Pkt6Ptr reply = srv.processRequest(req);
  827. // check if we get response at all
  828. checkResponse(reply, DHCPV6_REPLY, 1234);
  829. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  830. ASSERT_TRUE(tmp);
  831. // check that IA_NA was returned and that there's an address included
  832. boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
  833. subnet_->getT2());
  834. ASSERT_TRUE(addr);
  835. // check that we've got the address we requested
  836. checkIAAddr(addr, hint, subnet_->getPreferred(), subnet_->getValid());
  837. // check DUIDs
  838. checkServerId(reply, srv.getServerID());
  839. checkClientId(reply, clientid);
  840. // check that the lease is really in the database
  841. Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
  842. EXPECT_TRUE(l);
  843. LeaseMgrFactory::instance().deleteLease(addr->getAddress());
  844. }
  845. // This test checks that the server is offering different addresses to different
  846. // clients in REQUEST. Please note that ADVERTISE is not a guarantee that such
  847. // and address will be assigned. Had the pool was very small and contained only
  848. // 2 addresses, the third client would get the same advertise as the first one
  849. // and this is a correct behavior. It is REQUEST that will fail for the third
  850. // client. ADVERTISE is basically saying "if you send me a request, you will
  851. // probably get an address like this" (there are no guarantees).
  852. TEST_F(Dhcpv6SrvTest, ManyRequests) {
  853. NakedDhcpv6Srv srv(0);
  854. ASSERT_TRUE(subnet_);
  855. Pkt6Ptr req1 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
  856. Pkt6Ptr req2 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 2345));
  857. Pkt6Ptr req3 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 3456));
  858. req1->setRemoteAddr(IOAddress("fe80::abcd"));
  859. req2->setRemoteAddr(IOAddress("fe80::1223"));
  860. req3->setRemoteAddr(IOAddress("fe80::3467"));
  861. req1->addOption(generateIA(1, 1500, 3000));
  862. req2->addOption(generateIA(2, 1500, 3000));
  863. req3->addOption(generateIA(3, 1500, 3000));
  864. // different client-id sizes
  865. OptionPtr clientid1 = generateClientId(12);
  866. OptionPtr clientid2 = generateClientId(14);
  867. OptionPtr clientid3 = generateClientId(16);
  868. req1->addOption(clientid1);
  869. req2->addOption(clientid2);
  870. req3->addOption(clientid3);
  871. // server-id is mandatory in REQUEST
  872. req1->addOption(srv.getServerID());
  873. req2->addOption(srv.getServerID());
  874. req3->addOption(srv.getServerID());
  875. // Pass it to the server and get an advertise
  876. Pkt6Ptr reply1 = srv.processRequest(req1);
  877. Pkt6Ptr reply2 = srv.processRequest(req2);
  878. Pkt6Ptr reply3 = srv.processRequest(req3);
  879. // check if we get response at all
  880. checkResponse(reply1, DHCPV6_REPLY, 1234);
  881. checkResponse(reply2, DHCPV6_REPLY, 2345);
  882. checkResponse(reply3, DHCPV6_REPLY, 3456);
  883. // check that IA_NA was returned and that there's an address included
  884. boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
  885. subnet_->getT2());
  886. boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
  887. subnet_->getT2());
  888. boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
  889. subnet_->getT2());
  890. ASSERT_TRUE(addr1);
  891. ASSERT_TRUE(addr2);
  892. ASSERT_TRUE(addr3);
  893. // Check that the assigned address is indeed from the configured pool
  894. checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  895. checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  896. checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
  897. // check DUIDs
  898. checkServerId(reply1, srv.getServerID());
  899. checkServerId(reply2, srv.getServerID());
  900. checkServerId(reply3, srv.getServerID());
  901. checkClientId(reply1, clientid1);
  902. checkClientId(reply2, clientid2);
  903. checkClientId(reply3, clientid3);
  904. // Finally check that the addresses offered are different
  905. EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
  906. EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
  907. EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
  908. cout << "Assigned address to client1=" << addr1->getAddress().toText() << endl;
  909. cout << "Assigned address to client2=" << addr2->getAddress().toText() << endl;
  910. cout << "Assigned address to client3=" << addr3->getAddress().toText() << endl;
  911. }
  912. // This test verifies that incoming (positive) RENEW can be handled properly, that a
  913. // REPLY is generated, that the response has an address and that address
  914. // really belongs to the configured pool and that lease is actually renewed.
  915. //
  916. // expected:
  917. // - returned REPLY message has copy of client-id
  918. // - returned REPLY message has server-id
  919. // - returned REPLY message has IA that includes IAADDR
  920. // - lease is actually renewed in LeaseMgr
  921. TEST_F(Dhcpv6SrvTest, RenewBasic) {
  922. NakedDhcpv6Srv srv(0);
  923. const IOAddress addr("2001:db8:1:1::cafe:babe");
  924. const uint32_t iaid = 234;
  925. // Generate client-id also duid_
  926. OptionPtr clientid = generateClientId();
  927. // Check that the address we are about to use is indeed in pool
  928. ASSERT_TRUE(subnet_->inPool(addr));
  929. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  930. // value on purpose. They should be updated during RENEW.
  931. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
  932. 501, 502, 503, 504, subnet_->getID(), 0));
  933. lease->cltt_ = 1234;
  934. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  935. // Check that the lease is really in the database
  936. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  937. ASSERT_TRUE(l);
  938. // Check that T1, T2, preferred, valid and cltt really set and not using
  939. // previous (500, 501, etc.) values
  940. EXPECT_NE(l->t1_, subnet_->getT1());
  941. EXPECT_NE(l->t2_, subnet_->getT2());
  942. EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
  943. EXPECT_NE(l->valid_lft_, subnet_->getValid());
  944. EXPECT_NE(l->cltt_, time(NULL));
  945. // Let's create a RENEW
  946. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
  947. req->setRemoteAddr(IOAddress("fe80::abcd"));
  948. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  949. OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  950. ia->addOption(renewed_addr_opt);
  951. req->addOption(ia);
  952. req->addOption(clientid);
  953. // Server-id is mandatory in RENEW
  954. req->addOption(srv.getServerID());
  955. // Pass it to the server and hope for a REPLY
  956. Pkt6Ptr reply = srv.processRenew(req);
  957. // Check if we get response at all
  958. checkResponse(reply, DHCPV6_REPLY, 1234);
  959. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  960. ASSERT_TRUE(tmp);
  961. // Check that IA_NA was returned and that there's an address included
  962. boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
  963. subnet_->getT2());
  964. ASSERT_TRUE(addr_opt);
  965. // Check that we've got the address we requested
  966. checkIAAddr(addr_opt, addr, subnet_->getPreferred(), subnet_->getValid());
  967. // Check DUIDs
  968. checkServerId(reply, srv.getServerID());
  969. checkClientId(reply, clientid);
  970. // Check that the lease is really in the database
  971. l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
  972. ASSERT_TRUE(l);
  973. // Check that T1, T2, preferred, valid and cltt were really updated
  974. EXPECT_EQ(l->t1_, subnet_->getT1());
  975. EXPECT_EQ(l->t2_, subnet_->getT2());
  976. EXPECT_EQ(l->preferred_lft_, subnet_->getPreferred());
  977. EXPECT_EQ(l->valid_lft_, subnet_->getValid());
  978. // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
  979. int32_t cltt = static_cast<int32_t>(l->cltt_);
  980. int32_t expected = static_cast<int32_t>(time(NULL));
  981. // equality or difference by 1 between cltt and expected is ok.
  982. EXPECT_GE(1, abs(cltt - expected));
  983. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr_opt->getAddress()));
  984. }
  985. // This test verifies that incoming (invalid) RENEW can be handled properly.
  986. //
  987. // This test checks 3 scenarios:
  988. // 1. there is no such lease at all
  989. // 2. there is such a lease, but it is assigned to a different IAID
  990. // 3. there is such a lease, but it belongs to a different client
  991. //
  992. // expected:
  993. // - returned REPLY message has copy of client-id
  994. // - returned REPLY message has server-id
  995. // - returned REPLY message has IA that includes STATUS-CODE
  996. // - No lease in LeaseMgr
  997. TEST_F(Dhcpv6SrvTest, RenewReject) {
  998. NakedDhcpv6Srv srv(0);
  999. const IOAddress addr("2001:db8:1:1::dead");
  1000. const uint32_t transid = 1234;
  1001. const uint32_t valid_iaid = 234;
  1002. const uint32_t bogus_iaid = 456;
  1003. // Quick sanity check that the address we're about to use is ok
  1004. ASSERT_TRUE(subnet_->inPool(addr));
  1005. // GenerateClientId() also sets duid_
  1006. OptionPtr clientid = generateClientId();
  1007. // Check that the lease is NOT in the database
  1008. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  1009. ASSERT_FALSE(l);
  1010. // Let's create a RENEW
  1011. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, transid));
  1012. req->setRemoteAddr(IOAddress("fe80::abcd"));
  1013. boost::shared_ptr<Option6IA> ia = generateIA(bogus_iaid, 1500, 3000);
  1014. OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  1015. ia->addOption(renewed_addr_opt);
  1016. req->addOption(ia);
  1017. req->addOption(clientid);
  1018. // Server-id is mandatory in RENEW
  1019. req->addOption(srv.getServerID());
  1020. // Case 1: No lease known to server
  1021. // Pass it to the server and hope for a REPLY
  1022. Pkt6Ptr reply = srv.processRenew(req);
  1023. // Check if we get response at all
  1024. checkResponse(reply, DHCPV6_REPLY, transid);
  1025. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  1026. ASSERT_TRUE(tmp);
  1027. // Check that IA_NA was returned and that there's an address included
  1028. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  1029. ASSERT_TRUE(ia);
  1030. checkIA_NAStatusCode(ia, STATUS_NoBinding);
  1031. // Check that there is no lease added
  1032. l = LeaseMgrFactory::instance().getLease6(addr);
  1033. ASSERT_FALSE(l);
  1034. // CASE 2: Lease is known and belongs to this client, but to a different IAID
  1035. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  1036. // value on purpose. They should be updated during RENEW.
  1037. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, valid_iaid,
  1038. 501, 502, 503, 504, subnet_->getID(), 0));
  1039. lease->cltt_ = 123; // Let's use it as an indicator that the lease
  1040. // was NOT updated.
  1041. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  1042. // Pass it to the server and hope for a REPLY
  1043. reply = srv.processRenew(req);
  1044. checkResponse(reply, DHCPV6_REPLY, transid);
  1045. tmp = reply->getOption(D6O_IA_NA);
  1046. ASSERT_TRUE(tmp);
  1047. // Check that IA_NA was returned and that there's an address included
  1048. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  1049. ASSERT_TRUE(ia);
  1050. checkIA_NAStatusCode(ia, STATUS_NoBinding);
  1051. // There is a iaid mis-match, so server should respond that there is
  1052. // no such address to renew.
  1053. // CASE 3: Lease belongs to a client with different client-id
  1054. req->delOption(D6O_CLIENTID);
  1055. ia = boost::dynamic_pointer_cast<Option6IA>(req->getOption(D6O_IA_NA));
  1056. ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
  1057. req->addOption(generateClientId(13)); // generate different DUID
  1058. // (with length 13)
  1059. reply = srv.processRenew(req);
  1060. checkResponse(reply, DHCPV6_REPLY, transid);
  1061. tmp = reply->getOption(D6O_IA_NA);
  1062. ASSERT_TRUE(tmp);
  1063. // Check that IA_NA was returned and that there's an address included
  1064. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  1065. ASSERT_TRUE(ia);
  1066. checkIA_NAStatusCode(ia, STATUS_NoBinding);
  1067. lease = LeaseMgrFactory::instance().getLease6(addr);
  1068. ASSERT_TRUE(lease);
  1069. // Verify that the lease was not updated.
  1070. EXPECT_EQ(123, lease->cltt_);
  1071. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  1072. }
  1073. // This test verifies that incoming (positive) RELEASE can be handled properly,
  1074. // that a REPLY is generated, that the response has status code and that the
  1075. // lease is indeed removed from the database.
  1076. //
  1077. // expected:
  1078. // - returned REPLY message has copy of client-id
  1079. // - returned REPLY message has server-id
  1080. // - returned REPLY message has IA that does not include an IAADDR
  1081. // - lease is actually removed from LeaseMgr
  1082. TEST_F(Dhcpv6SrvTest, ReleaseBasic) {
  1083. NakedDhcpv6Srv srv(0);
  1084. const IOAddress addr("2001:db8:1:1::cafe:babe");
  1085. const uint32_t iaid = 234;
  1086. // Generate client-id also duid_
  1087. OptionPtr clientid = generateClientId();
  1088. // Check that the address we are about to use is indeed in pool
  1089. ASSERT_TRUE(subnet_->inPool(addr));
  1090. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  1091. // value on purpose. They should be updated during RENEW.
  1092. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
  1093. 501, 502, 503, 504, subnet_->getID(), 0));
  1094. lease->cltt_ = 1234;
  1095. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  1096. // Check that the lease is really in the database
  1097. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  1098. ASSERT_TRUE(l);
  1099. // Let's create a RELEASE
  1100. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
  1101. req->setRemoteAddr(IOAddress("fe80::abcd"));
  1102. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  1103. OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  1104. ia->addOption(released_addr_opt);
  1105. req->addOption(ia);
  1106. req->addOption(clientid);
  1107. // Server-id is mandatory in RELEASE
  1108. req->addOption(srv.getServerID());
  1109. // Pass it to the server and hope for a REPLY
  1110. Pkt6Ptr reply = srv.processRelease(req);
  1111. // Check if we get response at all
  1112. checkResponse(reply, DHCPV6_REPLY, 1234);
  1113. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  1114. ASSERT_TRUE(tmp);
  1115. // Check that IA_NA was returned and that there's an address included
  1116. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  1117. checkIA_NAStatusCode(ia, STATUS_Success);
  1118. checkMsgStatusCode(reply, STATUS_Success);
  1119. // There should be no address returned in RELEASE (see RFC3315, 18.2.6)
  1120. EXPECT_FALSE(tmp->getOption(D6O_IAADDR));
  1121. // Check DUIDs
  1122. checkServerId(reply, srv.getServerID());
  1123. checkClientId(reply, clientid);
  1124. // Check that the lease is really gone in the database
  1125. // get lease by address
  1126. l = LeaseMgrFactory::instance().getLease6(addr);
  1127. ASSERT_FALSE(l);
  1128. // get lease by subnetid/duid/iaid combination
  1129. l = LeaseMgrFactory::instance().getLease6(*duid_, iaid, subnet_->getID());
  1130. ASSERT_FALSE(l);
  1131. }
  1132. // This test verifies that incoming (invalid) RELEASE can be handled properly.
  1133. //
  1134. // This test checks 3 scenarios:
  1135. // 1. there is no such lease at all
  1136. // 2. there is such a lease, but it is assigned to a different IAID
  1137. // 3. there is such a lease, but it belongs to a different client
  1138. //
  1139. // expected:
  1140. // - returned REPLY message has copy of client-id
  1141. // - returned REPLY message has server-id
  1142. // - returned REPLY message has IA that includes STATUS-CODE
  1143. // - No lease in LeaseMgr
  1144. TEST_F(Dhcpv6SrvTest, ReleaseReject) {
  1145. NakedDhcpv6Srv srv(0);
  1146. const IOAddress addr("2001:db8:1:1::dead");
  1147. const uint32_t transid = 1234;
  1148. const uint32_t valid_iaid = 234;
  1149. const uint32_t bogus_iaid = 456;
  1150. // Quick sanity check that the address we're about to use is ok
  1151. ASSERT_TRUE(subnet_->inPool(addr));
  1152. // GenerateClientId() also sets duid_
  1153. OptionPtr clientid = generateClientId();
  1154. // Check that the lease is NOT in the database
  1155. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  1156. ASSERT_FALSE(l);
  1157. // Let's create a RELEASE
  1158. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, transid));
  1159. req->setRemoteAddr(IOAddress("fe80::abcd"));
  1160. boost::shared_ptr<Option6IA> ia = generateIA(bogus_iaid, 1500, 3000);
  1161. OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  1162. ia->addOption(released_addr_opt);
  1163. req->addOption(ia);
  1164. req->addOption(clientid);
  1165. // Server-id is mandatory in RENEW
  1166. req->addOption(srv.getServerID());
  1167. // Case 1: No lease known to server
  1168. SCOPED_TRACE("CASE 1: No lease known to server");
  1169. // Pass it to the server and hope for a REPLY
  1170. Pkt6Ptr reply = srv.processRelease(req);
  1171. // Check if we get response at all
  1172. checkResponse(reply, DHCPV6_REPLY, transid);
  1173. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  1174. ASSERT_TRUE(tmp);
  1175. // Check that IA_NA was returned and that there's an address included
  1176. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  1177. ASSERT_TRUE(ia);
  1178. checkIA_NAStatusCode(ia, STATUS_NoBinding);
  1179. checkMsgStatusCode(reply, STATUS_NoBinding);
  1180. // Check that the lease is not there
  1181. l = LeaseMgrFactory::instance().getLease6(addr);
  1182. ASSERT_FALSE(l);
  1183. // CASE 2: Lease is known and belongs to this client, but to a different IAID
  1184. SCOPED_TRACE("CASE 2: Lease is known and belongs to this client, but to a different IAID");
  1185. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, valid_iaid,
  1186. 501, 502, 503, 504, subnet_->getID(), 0));
  1187. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  1188. // Pass it to the server and hope for a REPLY
  1189. reply = srv.processRelease(req);
  1190. checkResponse(reply, DHCPV6_REPLY, transid);
  1191. tmp = reply->getOption(D6O_IA_NA);
  1192. ASSERT_TRUE(tmp);
  1193. // Check that IA_NA was returned and that there's an address included
  1194. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  1195. ASSERT_TRUE(ia);
  1196. checkIA_NAStatusCode(ia, STATUS_NoBinding);
  1197. checkMsgStatusCode(reply, STATUS_NoBinding);
  1198. // Check that the lease is still there
  1199. l = LeaseMgrFactory::instance().getLease6(addr);
  1200. ASSERT_TRUE(l);
  1201. // CASE 3: Lease belongs to a client with different client-id
  1202. SCOPED_TRACE("CASE 3: Lease belongs to a client with different client-id");
  1203. req->delOption(D6O_CLIENTID);
  1204. ia = boost::dynamic_pointer_cast<Option6IA>(req->getOption(D6O_IA_NA));
  1205. ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
  1206. req->addOption(generateClientId(13)); // generate different DUID
  1207. // (with length 13)
  1208. reply = srv.processRelease(req);
  1209. checkResponse(reply, DHCPV6_REPLY, transid);
  1210. tmp = reply->getOption(D6O_IA_NA);
  1211. ASSERT_TRUE(tmp);
  1212. // Check that IA_NA was returned and that there's an address included
  1213. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  1214. ASSERT_TRUE(ia);
  1215. checkIA_NAStatusCode(ia, STATUS_NoBinding);
  1216. checkMsgStatusCode(reply, STATUS_NoBinding);
  1217. // Check that the lease is still there
  1218. l = LeaseMgrFactory::instance().getLease6(addr);
  1219. ASSERT_TRUE(l);
  1220. // Finally, let's cleanup the database
  1221. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  1222. }
  1223. // This test verifies if the status code option is generated properly.
  1224. TEST_F(Dhcpv6SrvTest, StatusCode) {
  1225. NakedDhcpv6Srv srv(0);
  1226. // a dummy content for client-id
  1227. uint8_t expected[] = {
  1228. 0x0, 0xD, // option code = 13
  1229. 0x0, 0x7, // option length = 7
  1230. 0x0, 0x3, // status code = 3
  1231. 0x41, 0x42, 0x43, 0x44, 0x45 // string value ABCDE
  1232. };
  1233. // Create the option.
  1234. OptionPtr status = srv.createStatusCode(3, "ABCDE");
  1235. // Allocate an output buffer. We will store the option
  1236. // in wire format here.
  1237. OutputBuffer buf(sizeof(expected));
  1238. // Prepare the wire format.
  1239. ASSERT_NO_THROW(status->pack(buf));
  1240. // Check that the option buffer has valid length (option header + data).
  1241. ASSERT_EQ(sizeof(expected), buf.getLength());
  1242. // Verify the contents of the option.
  1243. EXPECT_EQ(0, memcmp(expected, buf.getData(), sizeof(expected)));
  1244. }
  1245. // This test verifies if the sanityCheck() really checks options presence.
  1246. TEST_F(Dhcpv6SrvTest, sanityCheck) {
  1247. NakedDhcpv6Srv srv(0);
  1248. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  1249. // Set link-local sender address, so appropriate subnet can be
  1250. // selected for this packet.
  1251. pkt->setRemoteAddr(IOAddress("fe80::abcd"));
  1252. // client-id is optional for information-request, so
  1253. EXPECT_NO_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::OPTIONAL, Dhcpv6Srv::OPTIONAL));
  1254. // empty packet, no client-id, no server-id
  1255. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::MANDATORY, Dhcpv6Srv::FORBIDDEN),
  1256. RFCViolation);
  1257. // This doesn't make much sense, but let's check it for completeness
  1258. EXPECT_NO_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::FORBIDDEN, Dhcpv6Srv::FORBIDDEN));
  1259. OptionPtr clientid = generateClientId();
  1260. pkt->addOption(clientid);
  1261. // client-id is mandatory, server-id is forbidden (as in SOLICIT or REBIND)
  1262. EXPECT_NO_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::MANDATORY, Dhcpv6Srv::FORBIDDEN));
  1263. pkt->addOption(srv.getServerID());
  1264. // both client-id and server-id are mandatory (as in REQUEST, RENEW, RELEASE, DECLINE)
  1265. EXPECT_NO_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::MANDATORY, Dhcpv6Srv::MANDATORY));
  1266. // sane section ends here, let's do some negative tests as well
  1267. pkt->addOption(clientid);
  1268. pkt->addOption(clientid);
  1269. // with more than one client-id it should throw, no matter what
  1270. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::OPTIONAL, Dhcpv6Srv::OPTIONAL),
  1271. RFCViolation);
  1272. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::MANDATORY, Dhcpv6Srv::OPTIONAL),
  1273. RFCViolation);
  1274. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::OPTIONAL, Dhcpv6Srv::MANDATORY),
  1275. RFCViolation);
  1276. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::MANDATORY, Dhcpv6Srv::MANDATORY),
  1277. RFCViolation);
  1278. pkt->delOption(D6O_CLIENTID);
  1279. pkt->delOption(D6O_CLIENTID);
  1280. // again we have only one client-id
  1281. // let's try different type of insanity - several server-ids
  1282. pkt->addOption(srv.getServerID());
  1283. pkt->addOption(srv.getServerID());
  1284. // with more than one server-id it should throw, no matter what
  1285. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::OPTIONAL, Dhcpv6Srv::OPTIONAL),
  1286. RFCViolation);
  1287. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::MANDATORY, Dhcpv6Srv::OPTIONAL),
  1288. RFCViolation);
  1289. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::OPTIONAL, Dhcpv6Srv::MANDATORY),
  1290. RFCViolation);
  1291. EXPECT_THROW(srv.sanityCheck(pkt, Dhcpv6Srv::MANDATORY, Dhcpv6Srv::MANDATORY),
  1292. RFCViolation);
  1293. }
  1294. // This test verifies if selectSubnet() selects proper subnet for a given
  1295. // source address.
  1296. TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
  1297. NakedDhcpv6Srv srv(0);
  1298. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
  1299. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
  1300. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
  1301. // CASE 1: We have only one subnet defined and we received local traffic.
  1302. // The only available subnet should be selected
  1303. CfgMgr::instance().deleteSubnets6();
  1304. CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
  1305. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  1306. pkt->setRemoteAddr(IOAddress("fe80::abcd"));
  1307. Subnet6Ptr selected = srv.selectSubnet(pkt);
  1308. EXPECT_EQ(selected, subnet1);
  1309. // CASE 2: We have only one subnet defined and we received relayed traffic.
  1310. // We should NOT select it.
  1311. // Identical steps as in case 1, but repeated for clarity
  1312. CfgMgr::instance().deleteSubnets6();
  1313. CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
  1314. pkt->setRemoteAddr(IOAddress("2001:db8:abcd::2345"));
  1315. selected = srv.selectSubnet(pkt);
  1316. EXPECT_FALSE(selected);
  1317. // CASE 3: We have three subnets defined and we received local traffic.
  1318. // Nothing should be selected.
  1319. CfgMgr::instance().deleteSubnets6();
  1320. CfgMgr::instance().addSubnet6(subnet1);
  1321. CfgMgr::instance().addSubnet6(subnet2);
  1322. CfgMgr::instance().addSubnet6(subnet3);
  1323. pkt->setRemoteAddr(IOAddress("fe80::abcd"));
  1324. selected = srv.selectSubnet(pkt);
  1325. EXPECT_FALSE(selected);
  1326. // CASE 4: We have three subnets defined and we received relayed traffic
  1327. // that came out of subnet 2. We should select subnet2 then
  1328. CfgMgr::instance().deleteSubnets6();
  1329. CfgMgr::instance().addSubnet6(subnet1);
  1330. CfgMgr::instance().addSubnet6(subnet2);
  1331. CfgMgr::instance().addSubnet6(subnet3);
  1332. pkt->setRemoteAddr(IOAddress("2001:db8:2::baca"));
  1333. selected = srv.selectSubnet(pkt);
  1334. EXPECT_EQ(selected, subnet2);
  1335. // CASE 5: We have three subnets defined and we received relayed traffic
  1336. // that came out of undefined subnet. We should select nothing
  1337. CfgMgr::instance().deleteSubnets6();
  1338. CfgMgr::instance().addSubnet6(subnet1);
  1339. CfgMgr::instance().addSubnet6(subnet2);
  1340. CfgMgr::instance().addSubnet6(subnet3);
  1341. pkt->setRemoteAddr(IOAddress("2001:db8:4::baca"));
  1342. selected = srv.selectSubnet(pkt);
  1343. EXPECT_FALSE(selected);
  1344. }
  1345. // This test verifies if selectSubnet() selects proper subnet for a given
  1346. // network interface name.
  1347. TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
  1348. NakedDhcpv6Srv srv(0);
  1349. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
  1350. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
  1351. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
  1352. subnet1->setIface("eth0");
  1353. subnet3->setIface("wifi1");
  1354. // CASE 1: We have only one subnet defined and it is available via eth0.
  1355. // Packet came from eth0. The only available subnet should be selected
  1356. CfgMgr::instance().deleteSubnets6();
  1357. CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
  1358. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  1359. pkt->setIface("eth0");
  1360. Subnet6Ptr selected = srv.selectSubnet(pkt);
  1361. EXPECT_EQ(selected, subnet1);
  1362. // CASE 2: We have only one subnet defined and it is available via eth0.
  1363. // Packet came from eth1. We should not select it
  1364. CfgMgr::instance().deleteSubnets6();
  1365. CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
  1366. pkt->setIface("eth1");
  1367. selected = srv.selectSubnet(pkt);
  1368. EXPECT_FALSE(selected);
  1369. // CASE 3: We have only 3 subnets defined, one over eth0, one remote and
  1370. // one over wifi1.
  1371. // Packet came from eth1. We should not select it
  1372. CfgMgr::instance().deleteSubnets6();
  1373. CfgMgr::instance().addSubnet6(subnet1);
  1374. CfgMgr::instance().addSubnet6(subnet2);
  1375. CfgMgr::instance().addSubnet6(subnet3);
  1376. pkt->setIface("eth0");
  1377. EXPECT_EQ(subnet1, srv.selectSubnet(pkt));
  1378. pkt->setIface("eth3"); // no such interface
  1379. EXPECT_EQ(Subnet6Ptr(), srv.selectSubnet(pkt)); // nothing selected
  1380. pkt->setIface("wifi1");
  1381. EXPECT_EQ(subnet3, srv.selectSubnet(pkt));
  1382. }
  1383. // This test verifies if selectSubnet() selects proper subnet for a given
  1384. // linkaddr in RELAY-FORW message
  1385. TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
  1386. NakedDhcpv6Srv srv(0);
  1387. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
  1388. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
  1389. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
  1390. Pkt6::RelayInfo relay;
  1391. relay.linkaddr_ = IOAddress("2001:db8:2::1234");
  1392. relay.peeraddr_ = IOAddress("fe80::1");
  1393. // CASE 1: We have only one subnet defined and we received relayed traffic.
  1394. // The only available subnet should NOT be selected.
  1395. CfgMgr::instance().deleteSubnets6();
  1396. CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
  1397. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  1398. pkt->relay_info_.push_back(relay);
  1399. Subnet6Ptr selected = srv.selectSubnet(pkt);
  1400. EXPECT_FALSE(selected);
  1401. // CASE 2: We have three subnets defined and we received relayed traffic.
  1402. // Nothing should be selected.
  1403. CfgMgr::instance().deleteSubnets6();
  1404. CfgMgr::instance().addSubnet6(subnet1);
  1405. CfgMgr::instance().addSubnet6(subnet2);
  1406. CfgMgr::instance().addSubnet6(subnet3);
  1407. selected = srv.selectSubnet(pkt);
  1408. EXPECT_EQ(selected, subnet2);
  1409. // CASE 3: We have three subnets defined and we received relayed traffic
  1410. // that came out of subnet 2. We should select subnet2 then
  1411. CfgMgr::instance().deleteSubnets6();
  1412. CfgMgr::instance().addSubnet6(subnet1);
  1413. CfgMgr::instance().addSubnet6(subnet2);
  1414. CfgMgr::instance().addSubnet6(subnet3);
  1415. // Source of the packet should have no meaning. Selection is based
  1416. // on linkaddr field in the relay
  1417. pkt->setRemoteAddr(IOAddress("2001:db8:1::baca"));
  1418. selected = srv.selectSubnet(pkt);
  1419. EXPECT_EQ(selected, subnet2);
  1420. // CASE 4: We have three subnets defined and we received relayed traffic
  1421. // that came out of undefined subnet. We should select nothing
  1422. CfgMgr::instance().deleteSubnets6();
  1423. CfgMgr::instance().addSubnet6(subnet1);
  1424. CfgMgr::instance().addSubnet6(subnet2);
  1425. CfgMgr::instance().addSubnet6(subnet3);
  1426. pkt->relay_info_.clear();
  1427. relay.linkaddr_ = IOAddress("2001:db8:4::1234");
  1428. pkt->relay_info_.push_back(relay);
  1429. selected = srv.selectSubnet(pkt);
  1430. EXPECT_FALSE(selected);
  1431. }
  1432. // This test verifies if selectSubnet() selects proper subnet for a given
  1433. // interface-id option
  1434. TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
  1435. NakedDhcpv6Srv srv(0);
  1436. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
  1437. Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
  1438. Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
  1439. subnet1->setInterfaceId(generateInterfaceId("relay1"));
  1440. subnet2->setInterfaceId(generateInterfaceId("relay2"));
  1441. // CASE 1: We have only one subnet defined and it is for interface-id "relay1"
  1442. // Packet came with interface-id "relay2". We should not select subnet1
  1443. CfgMgr::instance().deleteSubnets6();
  1444. CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
  1445. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  1446. Pkt6::RelayInfo relay;
  1447. relay.linkaddr_ = IOAddress("2001:db8:2::1234");
  1448. relay.peeraddr_ = IOAddress("fe80::1");
  1449. OptionPtr opt = generateInterfaceId("relay2");
  1450. relay.options_.insert(make_pair(opt->getType(), opt));
  1451. pkt->relay_info_.push_back(relay);
  1452. // There is only one subnet configured and we are outside of that subnet
  1453. Subnet6Ptr selected = srv.selectSubnet(pkt);
  1454. EXPECT_FALSE(selected);
  1455. // CASE 2: We have only one subnet defined and it is for interface-id "relay2"
  1456. // Packet came with interface-id "relay2". We should select it
  1457. CfgMgr::instance().deleteSubnets6();
  1458. CfgMgr::instance().addSubnet6(subnet2); // just a single subnet
  1459. selected = srv.selectSubnet(pkt);
  1460. EXPECT_EQ(selected, subnet2);
  1461. // CASE 3: We have only 3 subnets defined: one remote for interface-id "relay1",
  1462. // one remote for interface-id "relay2" and third local
  1463. // packet comes with interface-id "relay2". We should select subnet2
  1464. CfgMgr::instance().deleteSubnets6();
  1465. CfgMgr::instance().addSubnet6(subnet1);
  1466. CfgMgr::instance().addSubnet6(subnet2);
  1467. CfgMgr::instance().addSubnet6(subnet3);
  1468. EXPECT_EQ(subnet2, srv.selectSubnet(pkt));
  1469. }
  1470. // This test verifies if the server-id disk operations (read, write) are
  1471. // working properly.
  1472. TEST_F(Dhcpv6SrvTest, ServerID) {
  1473. NakedDhcpv6Srv srv(0);
  1474. string duid1_text = "01:ff:02:03:06:80:90:ab:cd:ef";
  1475. uint8_t duid1[] = { 0x01, 0xff, 2, 3, 6, 0x80, 0x90, 0xab, 0xcd, 0xef };
  1476. OptionBuffer expected_duid1(duid1, duid1 + sizeof(duid1));
  1477. fstream file1(DUID_FILE, ios::out | ios::trunc);
  1478. file1 << duid1_text;
  1479. file1.close();
  1480. // Test reading from a file
  1481. EXPECT_TRUE(srv.loadServerID(DUID_FILE));
  1482. ASSERT_TRUE(srv.getServerID());
  1483. ASSERT_EQ(sizeof(duid1) + Option::OPTION6_HDR_LEN, srv.getServerID()->len());
  1484. ASSERT_TRUE(expected_duid1 == srv.getServerID()->getData());
  1485. // Now test writing to a file
  1486. EXPECT_EQ(0, unlink(DUID_FILE));
  1487. EXPECT_NO_THROW(srv.writeServerID(DUID_FILE));
  1488. fstream file2(DUID_FILE, ios::in);
  1489. ASSERT_TRUE(file2.good());
  1490. string text;
  1491. file2 >> text;
  1492. file2.close();
  1493. EXPECT_EQ(duid1_text, text);
  1494. }
  1495. // Checks if hooks are implemented properly.
  1496. TEST_F(Dhcpv6SrvTest, Hooks) {
  1497. NakedDhcpv6Srv srv(0);
  1498. // check if appropriate hooks are registered
  1499. int hook_index_pkt6_received = -1;
  1500. int hook_index_select_subnet = -1;
  1501. int hook_index_pkt6_send = -1;
  1502. // check if appropriate indexes are set
  1503. EXPECT_NO_THROW(hook_index_pkt6_received = ServerHooks::getServerHooks()
  1504. .getIndex("pkt6_receive"));
  1505. EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
  1506. .getIndex("subnet6_select"));
  1507. EXPECT_NO_THROW(hook_index_pkt6_send = ServerHooks::getServerHooks()
  1508. .getIndex("pkt6_send"));
  1509. EXPECT_TRUE(hook_index_pkt6_received > 0);
  1510. EXPECT_TRUE(hook_index_select_subnet > 0);
  1511. EXPECT_TRUE(hook_index_pkt6_send > 0);
  1512. }
  1513. // This function returns buffer for empty packet (just DHCPv6 header)
  1514. Pkt6* captureEmpty() {
  1515. Pkt6* pkt;
  1516. uint8_t data[4];
  1517. data[0] = 1; // type 1 = SOLICIT
  1518. data[1] = 0xca; // trans-id = 0xcafe01
  1519. data[2] = 0xfe;
  1520. data[3] = 0x01;
  1521. pkt = new Pkt6(data, sizeof(data));
  1522. pkt->setRemotePort(546);
  1523. pkt->setRemoteAddr(IOAddress("fe80::1"));
  1524. pkt->setLocalPort(0);
  1525. pkt->setLocalAddr(IOAddress("ff02::1:2"));
  1526. pkt->setIndex(2);
  1527. pkt->setIface("eth0");
  1528. return (pkt);
  1529. }
  1530. // This function returns buffer for very simple Solicit
  1531. Pkt6* captureSimpleSolicit() {
  1532. Pkt6* pkt;
  1533. uint8_t data[] = {
  1534. 1, // type 1 = SOLICIT
  1535. 0xca, 0xfe, 0x01, // trans-id = 0xcafe01
  1536. 0, 1, // option type 1 (client-id)
  1537. 0, 10, // option lenth 10
  1538. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // DUID
  1539. 0, 3, // option type 3 (IA_NA)
  1540. 0, 12, // option length 12
  1541. 0, 0, 0, 1, // iaid = 1
  1542. 0, 0, 0, 0, // T1 = 0
  1543. 0, 0, 0, 0 // T2 = 0
  1544. };
  1545. pkt = new Pkt6(data, sizeof(data));
  1546. pkt->setRemotePort(546);
  1547. pkt->setRemoteAddr(IOAddress("fe80::1"));
  1548. pkt->setLocalPort(0);
  1549. pkt->setLocalAddr(IOAddress("ff02::1:2"));
  1550. pkt->setIndex(2);
  1551. pkt->setIface("eth0");
  1552. return (pkt);
  1553. }
  1554. /// @brief a class dedicated to Hooks testing in DHCPv6 server
  1555. ///
  1556. /// This class has a number of static members, because each non-static
  1557. /// method has implicit 'this' parameter, so it does not match callout
  1558. /// signature and couldn't be registered. Furthermore, static methods
  1559. /// can't modify non-static members (for obvious reasons), so many
  1560. /// fields are declared static. It is still better to keep them as
  1561. /// one class rather than unrelated collection of global objects.
  1562. class HooksDhcpv6SrvTest : public Dhcpv6SrvTest {
  1563. public:
  1564. /// @brief creates Dhcpv6Srv and prepares buffers for callouts
  1565. HooksDhcpv6SrvTest() {
  1566. // Allocate new DHCPv6 Server
  1567. srv_ = new NakedDhcpv6Srv(0);
  1568. // clear static buffers
  1569. resetCalloutBuffers();
  1570. }
  1571. /// @brief destructor (deletes Dhcpv6Srv)
  1572. ~HooksDhcpv6SrvTest() {
  1573. delete srv_;
  1574. }
  1575. /// @brief creates an option with specified option code
  1576. ///
  1577. /// This method is static, because it is used from callouts
  1578. /// that do not have a pointer to HooksDhcpv6SSrvTest object
  1579. ///
  1580. /// @param option_code code of option to be created
  1581. ///
  1582. /// @return pointer to create option object
  1583. static OptionPtr createOption(uint16_t option_code) {
  1584. char payload[] = {
  1585. 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
  1586. };
  1587. OptionBuffer tmp(payload, payload + sizeof(payload));
  1588. return OptionPtr(new Option(Option::V6, option_code, tmp));
  1589. }
  1590. /// test callback that stores received callout name and pkt6 value
  1591. /// @param callout_handle handle passed by the hooks framework
  1592. /// @return always 0
  1593. static int
  1594. pkt6_receive_callout(CalloutHandle& callout_handle) {
  1595. callback_name_ = string("pkt6_receive");
  1596. callout_handle.getArgument("query6", callback_pkt6_);
  1597. callback_argument_names_ = callout_handle.getArgumentNames();
  1598. return (0);
  1599. }
  1600. /// test callback that changes client-id value
  1601. /// @param callout_handle handle passed by the hooks framework
  1602. /// @return always 0
  1603. static int
  1604. pkt6_receive_change_clientid(CalloutHandle& callout_handle) {
  1605. Pkt6Ptr pkt;
  1606. callout_handle.getArgument("query6", pkt);
  1607. // get rid of the old client-id
  1608. pkt->delOption(D6O_CLIENTID);
  1609. // add a new option
  1610. pkt->addOption(createOption(D6O_CLIENTID));
  1611. // carry on as usual
  1612. return pkt6_receive_callout(callout_handle);
  1613. }
  1614. /// test callback that deletes client-id
  1615. /// @param callout_handle handle passed by the hooks framework
  1616. /// @return always 0
  1617. static int
  1618. pkt6_receive_delete_clientid(CalloutHandle& callout_handle) {
  1619. Pkt6Ptr pkt;
  1620. callout_handle.getArgument("query6", pkt);
  1621. // get rid of the old client-id
  1622. pkt->delOption(D6O_CLIENTID);
  1623. // carry on as usual
  1624. return pkt6_receive_callout(callout_handle);
  1625. }
  1626. /// test callback that sets skip flag
  1627. /// @param callout_handle handle passed by the hooks framework
  1628. /// @return always 0
  1629. static int
  1630. pkt6_receive_skip(CalloutHandle& callout_handle) {
  1631. Pkt6Ptr pkt;
  1632. callout_handle.getArgument("query6", pkt);
  1633. callout_handle.setSkip(true);
  1634. // carry on as usual
  1635. return pkt6_receive_callout(callout_handle);
  1636. }
  1637. /// Test callback that stores received callout name and pkt6 value
  1638. /// @param callout_handle handle passed by the hooks framework
  1639. /// @return always 0
  1640. static int
  1641. pkt6_send_callout(CalloutHandle& callout_handle) {
  1642. callback_name_ = string("pkt6_send");
  1643. callout_handle.getArgument("response6", callback_pkt6_);
  1644. callback_argument_names_ = callout_handle.getArgumentNames();
  1645. return (0);
  1646. }
  1647. // Test callback that changes server-id
  1648. /// @param callout_handle handle passed by the hooks framework
  1649. /// @return always 0
  1650. static int
  1651. pkt6_send_change_serverid(CalloutHandle& callout_handle) {
  1652. Pkt6Ptr pkt;
  1653. callout_handle.getArgument("response6", pkt);
  1654. // get rid of the old server-id
  1655. pkt->delOption(D6O_SERVERID);
  1656. // add a new option
  1657. pkt->addOption(createOption(D6O_SERVERID));
  1658. // carry on as usual
  1659. return pkt6_send_callout(callout_handle);
  1660. }
  1661. /// test callback that deletes server-id
  1662. /// @param callout_handle handle passed by the hooks framework
  1663. /// @return always 0
  1664. static int
  1665. pkt6_send_delete_serverid(CalloutHandle& callout_handle) {
  1666. Pkt6Ptr pkt;
  1667. callout_handle.getArgument("response6", pkt);
  1668. // get rid of the old client-id
  1669. pkt->delOption(D6O_SERVERID);
  1670. // carry on as usual
  1671. return pkt6_send_callout(callout_handle);
  1672. }
  1673. /// Test callback that sets skip flag
  1674. /// @param callout_handle handle passed by the hooks framework
  1675. /// @return always 0
  1676. static int
  1677. pkt6_send_skip(CalloutHandle& callout_handle) {
  1678. Pkt6Ptr pkt;
  1679. callout_handle.getArgument("response6", pkt);
  1680. callout_handle.setSkip(true);
  1681. // carry on as usual
  1682. return pkt6_send_callout(callout_handle);
  1683. }
  1684. /// Test callback that stores received callout name and subnet6 values
  1685. /// @param callout_handle handle passed by the hooks framework
  1686. /// @return always 0
  1687. static int
  1688. subnet6_select_callout(CalloutHandle& callout_handle) {
  1689. callback_name_ = string("subnet6_select");
  1690. callout_handle.getArgument("query6", callback_pkt6_);
  1691. callout_handle.getArgument("subnet6", callback_subnet6_);
  1692. callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
  1693. callback_argument_names_ = callout_handle.getArgumentNames();
  1694. return (0);
  1695. }
  1696. /// Test callback that picks the other subnet if possible.
  1697. /// @param callout_handle handle passed by the hooks framework
  1698. /// @return always 0
  1699. static int
  1700. subnet6_select_different_subnet_callout(CalloutHandle& callout_handle) {
  1701. // Call the basic calllout to record all passed values
  1702. subnet6_select_callout(callout_handle);
  1703. const Subnet6Collection* subnets;
  1704. Subnet6Ptr subnet;
  1705. callout_handle.getArgument("subnet6", subnet);
  1706. callout_handle.getArgument("subnet6collection", subnets);
  1707. // Let's change to a different subnet
  1708. if (subnets->size() > 1) {
  1709. subnet = (*subnets)[1]; // Let's pick the other subnet
  1710. callout_handle.setArgument("subnet6", subnet);
  1711. }
  1712. return (0);
  1713. }
  1714. /// resets buffers used to store data received by callouts
  1715. void resetCalloutBuffers() {
  1716. callback_name_ = string("");
  1717. callback_pkt6_.reset();
  1718. callback_subnet6_.reset();
  1719. callback_subnet6collection_ = NULL;
  1720. callback_argument_names_.clear();
  1721. }
  1722. /// pointer to Dhcpv6Srv that is used in tests
  1723. NakedDhcpv6Srv* srv_;
  1724. // The following fields are used in testing pkt6_receive_callout
  1725. /// String name of the received callout
  1726. static string callback_name_;
  1727. /// Pkt6 structure returned in the callout
  1728. static Pkt6Ptr callback_pkt6_;
  1729. /// Pointer to a subnet received by callout
  1730. static Subnet6Ptr callback_subnet6_;
  1731. /// A list of all available subnets (received by callout)
  1732. static const Subnet6Collection* callback_subnet6collection_;
  1733. /// A list of all received arguments
  1734. static vector<string> callback_argument_names_;
  1735. };
  1736. // The following fields are used in testing pkt6_receive_callout.
  1737. // See fields description in the class for details
  1738. string HooksDhcpv6SrvTest::callback_name_;
  1739. Pkt6Ptr HooksDhcpv6SrvTest::callback_pkt6_;
  1740. Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
  1741. const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
  1742. vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
  1743. // Checks if callouts installed on pkt6_received are indeed called and the
  1744. // all necessary parameters are passed.
  1745. //
  1746. // Note that the test name does not follow test naming convention,
  1747. // but the proper hook name is "pkt6_receive".
  1748. TEST_F(HooksDhcpv6SrvTest, simple_pkt6_receive) {
  1749. // Install pkt6_receive_callout
  1750. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1751. "pkt6_receive", pkt6_receive_callout));
  1752. // Let's create a simple SOLICIT
  1753. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1754. // Simulate that we have received that traffic
  1755. srv_->fakeReceive(sol);
  1756. // Server will now process to run its normal loop, but instead of calling
  1757. // IfaceMgr::receive6(), it will read all packets from the list set by
  1758. // fakeReceive()
  1759. // In particular, it should call registered pkt6_receive callback.
  1760. srv_->run();
  1761. // check that the callback called is indeed the one we installed
  1762. EXPECT_EQ("pkt6_receive", callback_name_);
  1763. // check that pkt6 argument passing was successful and returned proper value
  1764. EXPECT_TRUE(callback_pkt6_.get() == sol.get());
  1765. // Check that all expected parameters are there
  1766. vector<string> expected_argument_names;
  1767. expected_argument_names.push_back(string("query6"));
  1768. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1769. }
  1770. // Checks if callouts installed on pkt6_received is able to change
  1771. // the values and the parameters are indeed used by the server.
  1772. TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_receive) {
  1773. // Install pkt6_receive_callout
  1774. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1775. "pkt6_receive", pkt6_receive_change_clientid));
  1776. // Let's create a simple SOLICIT
  1777. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1778. // Simulate that we have received that traffic
  1779. srv_->fakeReceive(sol);
  1780. // Server will now process to run its normal loop, but instead of calling
  1781. // IfaceMgr::receive6(), it will read all packets from the list set by
  1782. // fakeReceive()
  1783. // In particular, it should call registered pkt6_receive callback.
  1784. srv_->run();
  1785. // check that the server did send a reposonce
  1786. ASSERT_EQ(1, srv_->fake_sent_.size());
  1787. // Make sure that we received a response
  1788. Pkt6Ptr adv = srv_->fake_sent_.front();
  1789. ASSERT_TRUE(adv);
  1790. // Get client-id...
  1791. OptionPtr clientid = adv->getOption(D6O_CLIENTID);
  1792. // ... and check if it is the modified value
  1793. OptionPtr expected = createOption(D6O_CLIENTID);
  1794. EXPECT_TRUE(clientid->equal(expected));
  1795. }
  1796. // Checks if callouts installed on pkt6_received is able to delete
  1797. // existing options and that change impacts server processing (mandatory
  1798. // client-id option is deleted, so the packet is expected to be dropped)
  1799. TEST_F(HooksDhcpv6SrvTest, deleteClientId_pkt6_receive) {
  1800. // Install pkt6_receive_callout
  1801. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1802. "pkt6_receive", pkt6_receive_delete_clientid));
  1803. // Let's create a simple SOLICIT
  1804. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1805. // Simulate that we have received that traffic
  1806. srv_->fakeReceive(sol);
  1807. // Server will now process to run its normal loop, but instead of calling
  1808. // IfaceMgr::receive6(), it will read all packets from the list set by
  1809. // fakeReceive()
  1810. // In particular, it should call registered pkt6_receive callback.
  1811. srv_->run();
  1812. // Check that the server dropped the packet and did not send a response
  1813. ASSERT_EQ(0, srv_->fake_sent_.size());
  1814. }
  1815. // Checks if callouts installed on pkt6_received is able to set skip flag that
  1816. // will cause the server to not process the packet (drop), even though it is valid.
  1817. TEST_F(HooksDhcpv6SrvTest, skip_pkt6_receive) {
  1818. // Install pkt6_receive_callout
  1819. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1820. "pkt6_receive", pkt6_receive_skip));
  1821. // Let's create a simple SOLICIT
  1822. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1823. // Simulate that we have received that traffic
  1824. srv_->fakeReceive(sol);
  1825. // Server will now process to run its normal loop, but instead of calling
  1826. // IfaceMgr::receive6(), it will read all packets from the list set by
  1827. // fakeReceive()
  1828. // In particular, it should call registered pkt6_receive callback.
  1829. srv_->run();
  1830. // check that the server dropped the packet and did not produce any response
  1831. ASSERT_EQ(0, srv_->fake_sent_.size());
  1832. }
  1833. // Checks if callouts installed on pkt6_send are indeed called and the
  1834. // all necessary parameters are passed.
  1835. TEST_F(HooksDhcpv6SrvTest, simple_pkt6_send) {
  1836. // Install pkt6_receive_callout
  1837. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1838. "pkt6_send", pkt6_send_callout));
  1839. // Let's create a simple SOLICIT
  1840. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1841. // Simulate that we have received that traffic
  1842. srv_->fakeReceive(sol);
  1843. // Server will now process to run its normal loop, but instead of calling
  1844. // IfaceMgr::receive6(), it will read all packets from the list set by
  1845. // fakeReceive()
  1846. // In particular, it should call registered pkt6_receive callback.
  1847. srv_->run();
  1848. // Check that the callback called is indeed the one we installed
  1849. EXPECT_EQ("pkt6_send", callback_name_);
  1850. // Check that there is one packet sent
  1851. ASSERT_EQ(1, srv_->fake_sent_.size());
  1852. Pkt6Ptr adv = srv_->fake_sent_.front();
  1853. // Check that pkt6 argument passing was successful and returned proper value
  1854. EXPECT_TRUE(callback_pkt6_.get() == adv.get());
  1855. // Check that all expected parameters are there
  1856. vector<string> expected_argument_names;
  1857. expected_argument_names.push_back(string("response6"));
  1858. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1859. }
  1860. // Checks if callouts installed on pkt6_send is able to change
  1861. // the values and the packet sent contains those changes
  1862. TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_send) {
  1863. // Install pkt6_receive_callout
  1864. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1865. "pkt6_send", pkt6_send_change_serverid));
  1866. // Let's create a simple SOLICIT
  1867. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1868. // Simulate that we have received that traffic
  1869. srv_->fakeReceive(sol);
  1870. // Server will now process to run its normal loop, but instead of calling
  1871. // IfaceMgr::receive6(), it will read all packets from the list set by
  1872. // fakeReceive()
  1873. // In particular, it should call registered pkt6_receive callback.
  1874. srv_->run();
  1875. // check that the server did send a reposonce
  1876. ASSERT_EQ(1, srv_->fake_sent_.size());
  1877. // Make sure that we received a response
  1878. Pkt6Ptr adv = srv_->fake_sent_.front();
  1879. ASSERT_TRUE(adv);
  1880. // Get client-id...
  1881. OptionPtr clientid = adv->getOption(D6O_SERVERID);
  1882. // ... and check if it is the modified value
  1883. OptionPtr expected = createOption(D6O_SERVERID);
  1884. EXPECT_TRUE(clientid->equal(expected));
  1885. }
  1886. // Checks if callouts installed on pkt6_send is able to delete
  1887. // existing options and that server applies those changes. In particular,
  1888. // we are trying to send a packet without server-id. The packet should
  1889. // be sent
  1890. TEST_F(HooksDhcpv6SrvTest, deleteServerId_pkt6_send) {
  1891. // Install pkt6_receive_callout
  1892. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1893. "pkt6_send", pkt6_send_delete_serverid));
  1894. // Let's create a simple SOLICIT
  1895. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1896. // Simulate that we have received that traffic
  1897. srv_->fakeReceive(sol);
  1898. // Server will now process to run its normal loop, but instead of calling
  1899. // IfaceMgr::receive6(), it will read all packets from the list set by
  1900. // fakeReceive()
  1901. // In particular, it should call registered pkt6_receive callback.
  1902. srv_->run();
  1903. // Check that the server indeed sent a malformed ADVERTISE
  1904. ASSERT_EQ(1, srv_->fake_sent_.size());
  1905. // Get that ADVERTISE
  1906. Pkt6Ptr adv = srv_->fake_sent_.front();
  1907. ASSERT_TRUE(adv);
  1908. // Make sure that it does not have server-id
  1909. EXPECT_FALSE(adv->getOption(D6O_SERVERID));
  1910. }
  1911. // Checks if callouts installed on pkt6_skip is able to set skip flag that
  1912. // will cause the server to not process the packet (drop), even though it is valid.
  1913. TEST_F(HooksDhcpv6SrvTest, skip_pkt6_send) {
  1914. // Install pkt6_receive_callout
  1915. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1916. "pkt6_send", pkt6_send_skip));
  1917. // Let's create a simple REQUEST
  1918. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  1919. // Simulate that we have received that traffic
  1920. srv_->fakeReceive(sol);
  1921. // Server will now process to run its normal loop, but instead of calling
  1922. // IfaceMgr::receive6(), it will read all packets from the list set by
  1923. // fakeReceive()
  1924. // In particular, it should call registered pkt6_receive callback.
  1925. srv_->run();
  1926. // check that the server dropped the packet and did not produce any response
  1927. ASSERT_EQ(0, srv_->fake_sent_.size());
  1928. }
  1929. // This test checks if subnet6_select callout is triggered and reports
  1930. // valid parameters
  1931. TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
  1932. // Install pkt6_receive_callout
  1933. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1934. "subnet6_select", subnet6_select_callout));
  1935. // Configure 2 subnets, both directly reachable over local interface
  1936. // (let's not complicate the matter with relays)
  1937. string config = "{ \"interface\": [ \"all\" ],"
  1938. "\"preferred-lifetime\": 3000,"
  1939. "\"rebind-timer\": 2000, "
  1940. "\"renew-timer\": 1000, "
  1941. "\"subnet6\": [ { "
  1942. " \"pool\": [ \"2001:db8:1::/64\" ],"
  1943. " \"subnet\": \"2001:db8:1::/48\", "
  1944. " \"interface\": \"" + valid_iface_ + "\" "
  1945. " }, {"
  1946. " \"pool\": [ \"2001:db8:2::/64\" ],"
  1947. " \"subnet\": \"2001:db8:2::/48\" "
  1948. " } ],"
  1949. "\"valid-lifetime\": 4000 }";
  1950. ElementPtr json = Element::fromJSON(config);
  1951. ConstElementPtr status;
  1952. // Configure the server and make sure the config is accepted
  1953. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
  1954. ASSERT_TRUE(status);
  1955. comment_ = parseAnswer(rcode_, status);
  1956. ASSERT_EQ(0, rcode_);
  1957. // Prepare solicit packet. Server should select first subnet for it
  1958. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  1959. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  1960. sol->setIface(valid_iface_);
  1961. sol->addOption(generateIA(234, 1500, 3000));
  1962. OptionPtr clientid = generateClientId();
  1963. sol->addOption(clientid);
  1964. // Pass it to the server and get an advertise
  1965. Pkt6Ptr adv = srv_->processSolicit(sol);
  1966. // check if we get response at all
  1967. ASSERT_TRUE(adv);
  1968. // Check that the callback called is indeed the one we installed
  1969. EXPECT_EQ("subnet6_select", callback_name_);
  1970. // Check that pkt6 argument passing was successful and returned proper value
  1971. EXPECT_TRUE(callback_pkt6_.get() == sol.get());
  1972. const Subnet6Collection* exp_subnets = CfgMgr::instance().getSubnets6();
  1973. // The server is supposed to pick the first subnet, because of matching
  1974. // interface. Check that the value is reported properly.
  1975. ASSERT_TRUE(callback_subnet6_);
  1976. EXPECT_EQ(callback_subnet6_.get(), exp_subnets->front().get());
  1977. // Server is supposed to report two subnets
  1978. ASSERT_EQ(exp_subnets->size(), callback_subnet6collection_->size());
  1979. // Compare that the available subnets are reported as expected
  1980. EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet6collection_)[0].get());
  1981. EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet6collection_)[1].get());
  1982. }
  1983. // This test checks if callout installed on subnet6_select hook point can pick
  1984. // a different subnet.
  1985. TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
  1986. // Install pkt6_receive_callout
  1987. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1988. "subnet6_select", subnet6_select_different_subnet_callout));
  1989. // Configure 2 subnets, both directly reachable over local interface
  1990. // (let's not complicate the matter with relays)
  1991. string config = "{ \"interface\": [ \"all\" ],"
  1992. "\"preferred-lifetime\": 3000,"
  1993. "\"rebind-timer\": 2000, "
  1994. "\"renew-timer\": 1000, "
  1995. "\"subnet6\": [ { "
  1996. " \"pool\": [ \"2001:db8:1::/64\" ],"
  1997. " \"subnet\": \"2001:db8:1::/48\", "
  1998. " \"interface\": \"" + valid_iface_ + "\" "
  1999. " }, {"
  2000. " \"pool\": [ \"2001:db8:2::/64\" ],"
  2001. " \"subnet\": \"2001:db8:2::/48\" "
  2002. " } ],"
  2003. "\"valid-lifetime\": 4000 }";
  2004. ElementPtr json = Element::fromJSON(config);
  2005. ConstElementPtr status;
  2006. // Configure the server and make sure the config is accepted
  2007. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
  2008. ASSERT_TRUE(status);
  2009. comment_ = parseAnswer(rcode_, status);
  2010. ASSERT_EQ(0, rcode_);
  2011. // Prepare solicit packet. Server should select first subnet for it
  2012. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  2013. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  2014. sol->setIface(valid_iface_);
  2015. sol->addOption(generateIA(234, 1500, 3000));
  2016. OptionPtr clientid = generateClientId();
  2017. sol->addOption(clientid);
  2018. // Pass it to the server and get an advertise
  2019. Pkt6Ptr adv = srv_->processSolicit(sol);
  2020. // check if we get response at all
  2021. ASSERT_TRUE(adv);
  2022. // The response should have an address from second pool, so let's check it
  2023. OptionPtr tmp = adv->getOption(D6O_IA_NA);
  2024. ASSERT_TRUE(tmp);
  2025. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  2026. ASSERT_TRUE(ia);
  2027. tmp = ia->getOption(D6O_IAADDR);
  2028. ASSERT_TRUE(tmp);
  2029. boost::shared_ptr<Option6IAAddr> addr_opt =
  2030. boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
  2031. ASSERT_TRUE(addr_opt);
  2032. // Get all subnets and use second subnet for verification
  2033. const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
  2034. ASSERT_EQ(2, subnets->size());
  2035. // Advertised address must belong to the second pool (in subnet's range,
  2036. // in dynamic pool)
  2037. EXPECT_TRUE((*subnets)[1]->inRange(addr_opt->getAddress()));
  2038. EXPECT_TRUE((*subnets)[1]->inPool(addr_opt->getAddress()));
  2039. }
  2040. /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
  2041. /// to call processX() methods.
  2042. } // end of anonymous namespace