123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722 |
- // Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- #include <config.h>
- #include <asiolink/io_address.h>
- #include <dhcp/option.h>
- #include <dhcp/option_int.h>
- #include <dhcp/option6_client_fqdn.h>
- #include <dhcp/tests/iface_mgr_test_config.h>
- #include <dhcpsrv/lease_mgr_factory.h>
- #include <dhcp6/tests/dhcp6_client.h>
- #include <dhcp6/tests/dhcp6_test_utils.h>
- #include <stats/stats_mgr.h>
- #include <boost/pointer_cast.hpp>
- #include <vector>
- using namespace isc;
- using namespace isc::asiolink;
- using namespace isc::dhcp;
- using namespace isc::dhcp::test;
- using namespace isc::stats;
- namespace {
- /// @brief Array of server configurations used throughout the tests.
- const char* NETWORKS_CONFIG[] = {
- // Configuration #0.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ],"
- " \"pd-pools\": ["
- " {"
- " \"prefix\": \"4000::\","
- " \"prefix-len\": 96,"
- " \"delegated-len\": 96"
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ],"
- " \"pd-pools\": ["
- " {"
- " \"prefix\": \"5000::\","
- " \"prefix-len\": 96,"
- " \"delegated-len\": 96"
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ],"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"3000::/96\","
- " \"id\": 1000,"
- " \"interface\": \"eth0\","
- " \"pools\": ["
- " {"
- " \"pool\": \"3000::1 - 3000::1\""
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #1.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"relay\": {"
- " \"ip-address\": \"3001::1\""
- " },"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ],"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 1000,"
- " \"relay\": {"
- " \"ip-address\": \"3001::2\""
- " },"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #2.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"client-classes\": ["
- " {"
- " \"name\": \"a-devices\","
- " \"test\": \"option[1234].hex == 0x0001\""
- " },"
- " {"
- " \"name\": \"b-devices\","
- " \"test\": \"option[1234].hex == 0x0002\""
- " }"
- " ],"
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ],"
- " \"client-class\": \"a-devices\""
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #3.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"client-classes\": ["
- " {"
- " \"name\": \"a-devices\","
- " \"test\": \"option[1234].hex == 0x0001\""
- " },"
- " {"
- " \"name\": \"b-devices\","
- " \"test\": \"option[1234].hex == 0x0002\""
- " }"
- " ],"
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ],"
- " \"client-class\": \"a-devices\""
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ],"
- " \"client-class\": \"b-devices\""
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #4.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
- " }"
- " ],"
- " \"pd-pools\": ["
- " {"
- " \"prefix\": \"4000::\","
- " \"prefix-len\": 96,"
- " \"delegated-len\": 96"
- " }"
- " ],"
- " \"reservations\": ["
- " {"
- " \"duid\": \"00:03:00:01:aa:bb:cc:dd:ee:ff\","
- " \"ip-addresses\": [ \"2001:db8:1::28\" ]"
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::1 - 2001:db8:2::64\""
- " }"
- " ],"
- " \"pd-pools\": ["
- " {"
- " \"prefix\": \"5000::\","
- " \"prefix-len\": 96,"
- " \"delegated-len\": 96"
- " }"
- " ],"
- " \"reservations\": ["
- " {"
- " \"duid\": \"00:03:00:01:11:22:33:44:55:66\","
- " \"ip-addresses\": [ \"2001:db8:2::28\" ],"
- " \"prefixes\": [ \"1234::/64\" ]"
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #5.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
- " }"
- " ],"
- " \"reservations\": ["
- " {"
- " \"duid\": \"00:03:00:01:11:22:33:44:55:66\","
- " \"ip-addresses\": [ \"2001:db8:1::28\" ]"
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::1 - 2001:db8:2::64\""
- " }"
- " ],"
- " \"reservations\": ["
- " {"
- " \"duid\": \"00:03:00:01:aa:bb:cc:dd:ee:ff\","
- " \"ip-addresses\": [ \"2001:db8:2::28\" ]"
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #6.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"client-classes\": ["
- " {"
- " \"name\": \"a-devices\","
- " \"test\": \"option[1234].hex == 0x0001\""
- " }"
- " ],"
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
- " }"
- " ],"
- " \"client-class\": \"a-devices\","
- " \"reservations\": ["
- " {"
- " \"duid\": \"00:03:00:01:aa:bb:cc:dd:ee:ff\","
- " \"ip-addresses\": [ \"2001:db8:1::28\" ]"
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::16 - 2001:db8:2::16\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #7.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"option-data\": ["
- " {"
- " \"name\": \"nis-servers\","
- " \"data\": \"3000::20\""
- " }"
- " ],"
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"option-data\": ["
- " {"
- " \"name\": \"dns-servers\","
- " \"data\": \"3001::21\""
- " },"
- " {"
- " \"name\": \"nisp-servers\","
- " \"data\": \"3002::34\""
- " }"
- " ],"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"option-data\": ["
- " {"
- " \"name\": \"sntp-servers\","
- " \"data\": \"4004::22\""
- " },"
- " {"
- " \"name\": \"nisp-servers\","
- " \"data\": \"3003::33\""
- " }"
- " ],"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ],"
- " \"subnet6\": ["
- " \{"
- " \"subnet\": \"3000::/96\","
- " \"id\": 1000,"
- " \"interface\": \"eth0\","
- " \"option-data\": ["
- " {"
- " \"name\": \"nisp-servers\","
- " \"data\": \"4000::5\""
- " }"
- " ],"
- " \"pools\": ["
- " {"
- " \"pool\": \"3000::1 - 3000::1\""
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #8.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- " },"
- " {"
- " \"name\": \"dog\","
- " \"interface\": \"eth0\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:3::/64\","
- " \"id\": 1000,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:3::20 - 2001:db8:3::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:4::/64\","
- " \"id\": 10000,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:4::20 - 2001:db8:4::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #9.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"relay\": {"
- " \"ip-address\": \"3000::1\""
- " },"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- " },"
- " {"
- " \"name\": \"dog\","
- " \"relay\": {"
- " \"ip-address\": \"3000::2\""
- " },"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:3::/64\","
- " \"id\": 1000,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:3::20 - 2001:db8:3::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:4::/64\","
- " \"id\": 10000,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:4::20 - 2001:db8:4::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #10.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"client-classes\": ["
- " {"
- " \"name\": \"class-with-dns-servers\","
- " \"option-data\": ["
- " {"
- " \"name\": \"dns-servers\","
- " \"data\": \"2001:db8:1::50\""
- " }"
- " ]"
- " }"
- " ],"
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::30\""
- " }"
- " ],"
- " \"reservations\": ["
- " {"
- " \"duid\": \"00:03:00:01:11:22:33:44:55:66\","
- " \"ip-addresses\": [ \"2001:db8:2::20\" ],"
- " \"hostname\": \"test.example.org\","
- " \"client-classes\": [ \"class-with-dns-servers\" ]"
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #11.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"client-classes\": ["
- " {"
- " \"name\": \"a-devices\","
- " \"test\": \"option[1234].hex == 0x0001\""
- " },"
- " {"
- " \"name\": \"b-devices\","
- " \"test\": \"option[1234].hex == 0x0002\""
- " }"
- " ],"
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"client-class\": \"a-devices\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " }"
- " ]"
- " },"
- " {"
- " \"name\": \"dog\","
- " \"interface\": \"eth1\","
- " \"client-class\": \"b-devices\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 1000,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #12.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"client-classes\": ["
- " {"
- " \"name\": \"b-devices\","
- " \"test\": \"option[1234].hex == 0x0002\""
- " }"
- " ],"
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface\": \"eth1\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ],"
- " \"client-class\": \"b-devices\""
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #13.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"relay\": {"
- " \"ip-address\": \"3001::1\""
- " },"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 100,"
- " \"relay\": {"
- " \"ip-address\": \"3001::1\""
- " },"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ],"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:3::/64\","
- " \"id\": 1000,"
- " \"relay\": {"
- " \"ip-address\": \"3001::2\""
- " },"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:3::20 - 2001:db8:3::20\""
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #14.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"interface-id\": \"vlan10\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ],"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 1000,"
- " \"interface-id\": \"vlan1000\","
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- "}",
- // Configuration #15.
- "{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
- " \"shared-networks\": ["
- " {"
- " \"name\": \"frog\","
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:1::/64\","
- " \"id\": 10,"
- " \"interface-id\": \"vlan10\","
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
- " }"
- " ]"
- " },"
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 10,"
- " \"interface-id\": \"vlan10\","
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- " }"
- " ],"
- " \"subnet6\": ["
- " {"
- " \"subnet\": \"2001:db8:2::/64\","
- " \"id\": 1000,"
- " \"interface-id\": \"vlan1000\","
- " \"pools\": ["
- " {"
- " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
- " }"
- " ]"
- " }"
- " ]"
- "}"
- };
- /// @Brief Test fixture class for DHCPv6 server using shared networks.
- class Dhcpv6SharedNetworkTest : public Dhcpv6SrvTest {
- public:
- /// @brief Indicates how test functions should check presence of a lease on
- /// the server.
- enum class LeaseOnServer{
- MUST_EXIST,
- MUST_NOT_EXIST,
- };
- /// @brief Constructor.
- Dhcpv6SharedNetworkTest()
- : Dhcpv6SrvTest(),
- iface_mgr_test_config_(true) {
- IfaceMgr::instance().openSockets6();
- StatsMgr::instance().removeAll();
- }
- /// @brief Conducts 4 packets exchanges for a client
- ///
- /// @param client this client will conduct the exchange
- /// @param exp_addr expected IPv6 address to be assigned
- /// @param iaid the iaid to be used by a client
- /// @param hint hint to be sent (if empty, no hint will be sent)
- void
- doSARR(Dhcp6Client& client, std::string exp_addr, uint32_t iaid,
- std::string hint = "") {
- if (hint.empty()) {
- ASSERT_NO_THROW(client.requestAddress(iaid, IOAddress("::")));
- } else {
- ASSERT_NO_THROW(client.requestAddress(iaid, IOAddress(hint)));
- }
- ASSERT_NO_THROW(client.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress(exp_addr)));
- }
- /// @brief Check if client has a lease for the specified address.
- ///
- /// Apart from checking whether the client has got the lease it also
- /// checks whether this lease is stored in the lease database.
- ///
- /// @param client Reference to the client.
- /// @param address Leased address.
- /// @param lease_on_server Specify whether the lease should be also present or
- /// absent in the lease database.
- ///
- /// @return true if the lease for the client has been found both in the
- /// database and in the server's response.
- bool hasLeaseForAddress(Dhcp6Client& client, const IOAddress& address,
- const LeaseOnServer& lease_on_server = LeaseOnServer::MUST_EXIST) {
- Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, address);
- return ((((lease_on_server == LeaseOnServer::MUST_EXIST) && lease) ||
- ((lease_on_server == LeaseOnServer::MUST_NOT_EXIST) && !lease)) &&
- client.hasLeaseForAddress(address));
- }
- /// @brief Check if client has a lease for the specified prefix.
- ///
- /// Apart from checking whether the client has got the lease it also
- /// checks whether this lease is stored in the lease database.
- ///
- /// @param client Reference to the client.
- /// @param prefix Leased prefix.
- /// @param prefix_len Leased prefix length.
- /// @param lease_on_server Specify whether the lease should be also present or
- /// absent in the lease database.
- ///
- /// @return true if the lease for the client has been found both in the
- /// database and in the server's response.
- bool hasLeaseForPrefix(Dhcp6Client& client, const IOAddress& prefix,
- const uint8_t prefix_len, const IAID& iaid,
- const LeaseOnServer& lease_on_server = LeaseOnServer::MUST_EXIST) {
- Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, prefix);
- return ((((lease_on_server == LeaseOnServer::MUST_EXIST) && lease &&
- (lease->prefixlen_ = prefix_len) && (lease->iaid_ == iaid)) ||
- ((lease_on_server == LeaseOnServer::MUST_NOT_EXIST) && !lease)) &&
- client.hasLeaseForPrefix(prefix, prefix_len, iaid));
- }
- /// @brief Check if client has a lease belonging to address range.
- ///
- /// Apart from checking whether the client has got the lease it also
- /// checks whether this lease is stored in the lease database.
- ///
- /// @param client Reference to the client.
- /// @param first Lower bound of the address range.
- /// @param last Upper bound of the address range.
- /// @param lease_on_server Specify whether the lease should be also present or
- /// absent in the lease database.
- bool hasLeaseForAddressRange(Dhcp6Client& client, const IOAddress& first, const IOAddress& last,
- const LeaseOnServer& lease_on_server = LeaseOnServer::MUST_EXIST) {
- std::vector<Lease6> leases = client.getLeasesByAddressRange(first, last);
- for (auto lease_it = leases.cbegin(); lease_it != leases.cend(); ++lease_it) {
- // Take into account only valid leases.
- if (lease_it->valid_lft_ == 0) {
- continue;
- }
- Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, lease_it->addr_);
- if ((lease && (lease_on_server == LeaseOnServer::MUST_NOT_EXIST)) ||
- (!lease && (lease_on_server == LeaseOnServer::MUST_EXIST))) {
- return (false);
- }
- }
- return (!leases.empty());
- }
- /// @brief Check if client has a lease belonging to a prefix pool.
- ///
- /// Apart from checking whether the client has got the lease it also
- /// checks whether this lease is stored in the lease database.
- ///
- /// @param client Reference to the client.
- /// @param prefix Pool prefix.
- /// @param prefix_len Prefix length.
- /// @param delegated_len Delegated prefix length.
- /// @param lease_on_server Specify whether the lease should be also present or
- /// absent in the lease database.
- ///
- /// @return true if client has a lease belonging to specified pool,
- /// false otherwise.
- bool hasLeaseForPrefixPool(Dhcp6Client& client, const asiolink::IOAddress& prefix,
- const uint8_t prefix_len, const uint8_t delegated_len,
- const LeaseOnServer& lease_on_server = LeaseOnServer::MUST_EXIST) {
- std::vector<Lease6> leases = client.getLeasesByPrefixPool(prefix, prefix_len, delegated_len);
- for (auto lease_it = leases.cbegin(); lease_it != leases.cend(); ++lease_it) {
- // Take into account only valid leases.
- if (lease_it->valid_lft_ == 0) {
- continue;
- }
- Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, lease_it->addr_);
- if ((lease && (lease->prefixlen_ == lease->prefixlen_) &&
- (lease_on_server == LeaseOnServer::MUST_NOT_EXIST)) ||
- (!lease && (lease_on_server == LeaseOnServer::MUST_EXIST))) {
- return (false);
- }
- }
- return (!leases.empty());
- }
- /// @brief Destructor.
- virtual ~Dhcpv6SharedNetworkTest() {
- StatsMgr::instance().removeAll();
- }
- /// @brief Interface Manager's fake configuration control.
- IfaceMgrTestConfig iface_mgr_test_config_;
- };
- // Running out of addresses within a subnet in a shared network.
- TEST_F(Dhcpv6SharedNetworkTest, addressPoolInSharedNetworkShortage) {
- // Create client #1.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- // Configure the server with one shared network including two subnets and
- // one subnet outside of the shared network.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[0], *client1.getServer()));
- // Client #1 requests an address in first subnet within a shared network.
- ASSERT_NO_THROW(client1.requestAddress(0xabca0, IOAddress("2001:db8:1::20")));
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
- // Client #2 The second client will request a lease and should be assigned
- // an address from the second subnet.
- Dhcp6Client client2(client1.getServer());
- client2.setInterface("eth1");
- ASSERT_NO_THROW(client2.requestAddress(0xabca0));
- ASSERT_NO_THROW(client2.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
- // Cient #3. It sends Solicit which should result in NoAddrsAvail status
- // code because all addresses available for this link have been assigned.
- Dhcp6Client client3(client1.getServer());
- client3.setInterface("eth1");
- ASSERT_NO_THROW(client3.requestAddress(0xabca0));
- ASSERT_NO_THROW(client3.doSolicit(true));
- EXPECT_EQ(0, client3.getLeaseNum());
- // Client #3 should be assigned an address if subnet 3 is selected for it.
- client3.setInterface("eth0");
- ASSERT_NO_THROW(client3.doSolicit(true));
- EXPECT_EQ(1, client3.getLeaseNum());
- // Client #1 should be able to renew its lease.
- ASSERT_NO_THROW(client1.doRenew());
- EXPECT_EQ(1, client1.getLeaseNum());
- EXPECT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
- // Client #2 should be able to renew its lease too.
- ASSERT_NO_THROW(client2.doRenew());
- EXPECT_EQ(1, client2.getLeaseNum());
- EXPECT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
- }
- // Shared network is selected based on relay link address.
- TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByRelay) {
- // Create client #1. This is a relayed client which is using relay address
- // matching configured shared network.
- Dhcp6Client client1;
- client1.useRelay(true, IOAddress("3001::1"));
- // Configure the server with one shared network and one subnet outside of the
- // shared network.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[1], *client1.getServer()));
- // Client #1 should be assigned an address from shared network.
- ASSERT_NO_THROW(client1.requestAddress(0xabca0));
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
- // Create client #2. This is a relayed client which is using relay
- // address matching subnet outside of the shared network.
- Dhcp6Client client2(client1.getServer());
- client2.useRelay(true, IOAddress("3001::2"));
- ASSERT_NO_THROW(client2.requestAddress(0xabca0));
- ASSERT_NO_THROW(client2.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
- }
- // Providing a hint for any address belonging to a shared network.
- TEST_F(Dhcpv6SharedNetworkTest, hintWithinSharedNetwork) {
- // Create client #1.
- Dhcp6Client client;
- client.setInterface("eth1");
- // Configure the server with one shared network including two subnets and
- // one subnet outside of the shared network.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[0], *client.getServer()));
- // Provide a hint to an existing address within first subnet. This address
- // should be offered out of this subnet.
- ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
- ASSERT_NO_THROW(client.doSolicit(true));
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20"),
- LeaseOnServer::MUST_NOT_EXIST));
- // Similarly, we should be offerred an address from another subnet within
- // the same shared network when we ask for it.
- client.clearRequestedIAs();
- ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:2::20")));
- ASSERT_NO_THROW(client.doSolicit(true));
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20"),
- LeaseOnServer::MUST_NOT_EXIST));
- // Asking for an address that is not in address pool should result in getting
- // an address from one of the subnets, but generally hard to tell from which one.
- client.clearRequestedIAs();
- ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("3002::123")));
- ASSERT_NO_THROW(client.doSolicit(true));
- std::vector<Lease6> leases = client.getLeasesByType(Lease::TYPE_NA);
- ASSERT_EQ(1, leases.size());
- if (!hasLeaseForAddress(client, IOAddress("2001:db8:1::20"),
- LeaseOnServer::MUST_NOT_EXIST) &&
- !hasLeaseForAddress(client, IOAddress("2001:db8:2::20"),
- LeaseOnServer::MUST_NOT_EXIST)) {
- ADD_FAILURE() << "Unexpected address advertised by the server " << leases.at(0).addr_;
- }
- }
- // Shared network is selected based on the client class specified.
- TEST_F(Dhcpv6SharedNetworkTest, subnetInSharedNetworkSelectedByClass) {
- // Create client #1.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- // Configure the server with one shared network including two subnets and
- // one subnet outside of the shared network.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[2], *client1.getServer()));
- // Client #1 requests an address in the restricted subnet but can't be assigned
- // this address because the client doesn't belong to a certain class.
- ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:2::20")));
- // Release the lease that the client has got, because we'll need this address
- // further in the test.
- client1.doRelease();
- // Add option 1234 which would cause the client to be classified as "a-devices".
- OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0001));
- client1.addExtraOption(option1234);
- // This time, the allocation of the address provided as hint should be successful.
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
- // Client 2 should be assigned an address from the unrestricted subnet.
- Dhcp6Client client2(client1.getServer());
- client2.setInterface("eth1");
- ASSERT_NO_THROW(client2.requestAddress(0xabca0));
- ASSERT_NO_THROW(client2.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
- // Now, let's reconfigure the server to also apply restrictions on the
- // subnet to which client2 now belongs.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[3], *client1.getServer()));
- ASSERT_NO_THROW(client2.doRenew());
- EXPECT_EQ(0, client2.getLeaseNum());
- // If we add option 1234 with a value matching this class, the lease should
- // get renewed.
- OptionPtr option1234_bis(new OptionUint16(Option::V6, 1234, 0x0002));
- client2.addExtraOption(option1234_bis);
- ASSERT_NO_THROW(client2.doRenew());
- EXPECT_EQ(1, client2.getLeaseNum());
- }
- // IPv6 address reservation exists in one of the subnets within shared network.
- TEST_F(Dhcpv6SharedNetworkTest, reservationInSharedNetwork) {
- // Create client #1. Explicitly set client's DUID to the one that has a
- // reservation in the second subnet within shared network.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- client1.setDUID("00:03:00:01:11:22:33:44:55:66");
- // Create server configuration with a shared network including two subnets. There
- // is an IP address reservation in each subnet for two respective clients.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[4], *client1.getServer()));
- // Client #1 should get his reserved address from the second subnet.
- ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:2::28")));
- // Create client #2.
- Dhcp6Client client2;
- client2.setInterface("eth1");
- client2.setDUID("00:03:00:01:aa:bb:cc:dd:ee:ff");
- // Client #2 should get its reserved address from the first subnet.
- ASSERT_NO_THROW(client2.requestAddress(0xabca, IOAddress("2001:db8:1::30")));
- ASSERT_NO_THROW(client2.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:1::28")));
- // Reconfigure the server. Now, the first client get's second client's
- // reservation and vice versa.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[5], *client1.getServer()));
- // The first client is trying to renew the lease but should get a different lease
- // because its lease is now reserved for some other client. The client won't be
- // assigned a lease for which it has a reservation because another client holds
- // this lease.
- ASSERT_NO_THROW(client1.doRenew());
- ASSERT_TRUE(client1.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::28")));
- ASSERT_FALSE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::28")));
- // The client should be allocated a lease from one of the dynamic pools.
- if (!hasLeaseForAddressRange(client1, IOAddress("2001:db8:2::1"), IOAddress("2001:db8:2::64")) &&
- !hasLeaseForAddressRange(client1, IOAddress("2001:db8:1::1"), IOAddress("2001:db8:1::64"))) {
- ADD_FAILURE() << "unexpected lease allocated for renewing client";
- }
- // Client #2 is now renewing its lease and should get its newly reserved address.
- ASSERT_NO_THROW(client2.doRenew());
- ASSERT_TRUE(client2.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::28")));
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::28")));
- // Same for client #1.
- ASSERT_NO_THROW(client1.doRenew());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::28")));
- }
- // Reserved address can't be assigned as long as access to a subnet is
- // restricted by classification.
- TEST_F(Dhcpv6SharedNetworkTest, reservationAccessRestrictedByClass) {
- // Create client #1. Explicitly set client's DUID to the one that has a
- // reservation in the firstsubnet within shared network.
- Dhcp6Client client;
- client.setInterface("eth1");
- client.setDUID("00:03:00:01:aa:bb:cc:dd:ee:ff");
- // Create server configuration with a shared network including two subnets. Access to
- // one of the subnets is restricted by client classification.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[6], *client.getServer()));
- // Assigned address should be allocated from the second subnet, because the
- // client doesn't belong to the "a-devices" class.
- ASSERT_NO_THROW(client.requestAddress(0xabca));
- ASSERT_NO_THROW(client.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::16")));
- // Add option 1234 which would cause the client to be classified as "a-devices".
- OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0001));
- client.addExtraOption(option1234);
- // The client should now be assigned the reserved address from the first subnet.
- ASSERT_NO_THROW(client.doRenew());
- ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::16")));
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::28")));
- }
- // Subnet in which the client is renewing an address is restricted by classification.
- TEST_F(Dhcpv6SharedNetworkTest, renewalRestrictedByClass) {
- // Create client.
- Dhcp6Client client;
- client.setInterface("eth1");
- // Create server configuration with a shared network including two subnets. Access to
- // the second subnet is restricted by client classification.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[12], *client.getServer()));
- // Add option 1234 to cause the client to belong to the class.
- OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0002));
- client.addExtraOption(option1234);
- // Client requests an address from the second subnet which should be successful.
- ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:2::20")));
- ASSERT_NO_THROW(client.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20")));
- // Now remove the client from this class.
- client.clearExtraOptions();
- // The client should not be able to renew the existing lease because it is now
- // prohibited by the classification. Instead, the client should get a lease from the
- // unrestricted subnet.
- ASSERT_NO_THROW(client.doRenew());
- ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::20")));
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20")));
- }
- // Some options are specified on the shared subnet level, some on the
- // subnets level.
- TEST_F(Dhcpv6SharedNetworkTest, optionsDerivation) {
- // Client #1.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[7], *client1.getServer()));
- // Client #1 belongs to shared network. By providing a hint "2001:db8:1::20 we force
- // the server to select first subnet within the shared network for this client.
- ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
- // Request all configured options.
- ASSERT_NO_THROW(client1.requestOption(D6O_NIS_SERVERS));
- ASSERT_NO_THROW(client1.requestOption(D6O_NISP_SERVERS));
- ASSERT_NO_THROW(client1.requestOption(D6O_NAME_SERVERS));
- ASSERT_NO_THROW(client1.requestOption(D6O_SNTP_SERVERS));
- // Perform 4-way exchange and make sure we have been assigned address from the
- // subnet we wanted.
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
- // This option is specified on the global level.
- ASSERT_TRUE(client1.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20"));
- // Subnet specific value should override a value specified on the shared network level.
- ASSERT_TRUE(client1.hasOptionWithAddress(D6O_NISP_SERVERS, "3003::33"));
- // Shared network level value should be derived to the subnet.
- ASSERT_TRUE(client1.hasOptionWithAddress(D6O_NAME_SERVERS, "3001::21"));
- // This option is only specified in the subnet level.
- ASSERT_TRUE(client1.hasOptionWithAddress(D6O_SNTP_SERVERS, "4004::22"));
- // Client #2.
- Dhcp6Client client2(client1.getServer());
- client2.setInterface("eth1");
- // Request an address from the second subnet within the shared network.
- ASSERT_NO_THROW(client2.requestAddress(0xabca, IOAddress("2001:db8:2::20")));
- // Request all configured options.
- ASSERT_NO_THROW(client2.requestOption(D6O_NIS_SERVERS));
- ASSERT_NO_THROW(client2.requestOption(D6O_NISP_SERVERS));
- ASSERT_NO_THROW(client2.requestOption(D6O_NAME_SERVERS));
- ASSERT_NO_THROW(client2.requestOption(D6O_SNTP_SERVERS));
- // Perform 4-way exchange and make sure we have been assigned address from the
- // subnet we wanted.
- ASSERT_NO_THROW(client2.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
- // This option is specified on the global level.
- ASSERT_TRUE(client2.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20"));
- // Shared network level value should be derived to the subnet.
- ASSERT_TRUE(client2.hasOptionWithAddress(D6O_NAME_SERVERS, "3001::21"));
- ASSERT_TRUE(client2.hasOptionWithAddress(D6O_NISP_SERVERS, "3002::34"));
- // Client #3.
- Dhcp6Client client3(client1.getServer());
- client3.setInterface("eth0");
- // Request an address from the subnet outside of the shared network.
- ASSERT_NO_THROW(client3.requestAddress(0xabca, IOAddress("3000::1")));
- // Request all configured options.
- ASSERT_NO_THROW(client3.requestOption(D6O_NIS_SERVERS));
- ASSERT_NO_THROW(client3.requestOption(D6O_NISP_SERVERS));
- ASSERT_NO_THROW(client3.requestOption(D6O_NAME_SERVERS));
- ASSERT_NO_THROW(client3.requestOption(D6O_SNTP_SERVERS));
- // Perform 4-way exchange and make sure we have been assigned address from the
- // subnet we wanted.
- ASSERT_NO_THROW(client3.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client3, IOAddress("3000::1")));
- // This option is specified on the global level.
- ASSERT_TRUE(client3.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20"));
- // Subnet specific value should be assigned.
- ASSERT_TRUE(client3.hasOptionWithAddress(D6O_NISP_SERVERS, "4000::5"));
- }
- // Different shared network is selected for different local interface.
- TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByInterface) {
- // Create client #1. The server receives requests from this client
- // via interface eth1 and should assign shared network "frog" for
- // this client.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- client1.requestAddress(0xabca);
- // Create server configuration with two shared networks selected
- // by the local interface: eth1 and eth0.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[8], *client1.getServer()));
- // Client #1 should be assigned an address from one of the two subnets
- // belonging to the first shared network.
- ASSERT_NO_THROW(client1.doSARR());
- if (!hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")) &&
- !hasLeaseForAddress(client1, IOAddress("2001:db8:2::20"))) {
- ADD_FAILURE() << "unexpected shared network selected for the client";
- }
- // Client #2.
- Dhcp6Client client2;
- client2.setInterface("eth0");
- client2.requestAddress(0xabca);
- // Client #2 should be assigned an address from one of the two subnets
- // belonging to the second shared network.
- ASSERT_NO_THROW(client2.doSARR());
- if (!hasLeaseForAddress(client2, IOAddress("2001:db8:3::20")) &&
- !hasLeaseForAddress(client2, IOAddress("2001:db8:4::20"))) {
- ADD_FAILURE() << "unexpected shared network selected for the client";
- }
- }
- // Different shared network is selected for different relay address.
- TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByRelay) {
- // Create relayed client #1.
- Dhcp6Client client1;
- client1.useRelay(true, IOAddress("3000::1"));
- client1.requestAddress(0xabcd);
- // Create server configuration with two shared networks selected
- // by the relay address.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[9], *client1.getServer()));
- // Client #1 should be assigned an address from one of the two subnets
- // belonging to the first shared network.
- ASSERT_NO_THROW(client1.doSARR());
- if (!hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")) &&
- !hasLeaseForAddress(client1, IOAddress("2001:db8:2::20"))) {
- ADD_FAILURE() << "unexpected shared network selected for the client";
- }
- // Create relayed client #2.
- Dhcp6Client client2;
- client2.useRelay(true, IOAddress("3000::2"));
- client2.requestAddress(0xabca);
- // Client #2 should be assigned an address from one of the two subnets
- // belonging to the second shared network.
- ASSERT_NO_THROW(client2.doSARR());
- if (!hasLeaseForAddress(client2, IOAddress("2001:db8:3::20")) &&
- !hasLeaseForAddress(client2, IOAddress("2001:db8:4::20"))) {
- ADD_FAILURE() << "unexpected shared network selected for the client";
- }
- }
- // Host reservations include hostname and client class.
- TEST_F(Dhcpv6SharedNetworkTest, variousFieldsInReservation) {
- // Create client #1.
- Dhcp6Client client;
- client.setInterface("eth1");
- client.setDUID("00:03:00:01:11:22:33:44:55:66");
- ASSERT_NO_THROW(client.requestAddress(0xabcd));
- ASSERT_NO_THROW(client.requestOption(D6O_NAME_SERVERS));
- ASSERT_NO_THROW(client.useFQDN(Option6ClientFqdn::FLAG_S,
- "bird.example.org",
- Option6ClientFqdn::FULL));
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[10], *client.getServer()));
- // Perform 4-way exchange.
- ASSERT_NO_THROW(client.doSARR());
- // The client should get an FQDN from the reservation, rather than
- // the FQDN it has sent to the server. If there is a logic error,
- // the server would use the first subnet from the shared network to
- // assign the FQDN. This subnet has no reservation so it would
- // return the same FQDN that the client has sent. We expect
- // that the FQDN being sent is the one that is included in the
- // reservations.
- ASSERT_TRUE(client.getContext().response_);
- OptionPtr opt_fqdn = client.getContext().response_->getOption(D6O_CLIENT_FQDN);
- ASSERT_TRUE(opt_fqdn);
- Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<Option6ClientFqdn>(opt_fqdn);
- ASSERT_TRUE(fqdn);
- ASSERT_EQ("test.example.org.", fqdn->getDomainName());
- // Make sure that the correct hostname has been stored in the database.
- Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- IOAddress("2001:db8:2::20"));
- ASSERT_TRUE(lease);
- EXPECT_EQ("test.example.org.", lease->hostname_);
- // The DNS servers option should be derived from the client class based on the
- // static class reservations.
- ASSERT_TRUE(client.hasOptionWithAddress(D6O_NAME_SERVERS, "2001:db8:1::50"));
- }
- // Shared network is selected based on the client class specified.
- TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByClass) {
- // Create client #1.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- client1.requestAddress(0xabcd);
- // Add option 1234 which would cause the client1 to be classified as "b-devices".
- OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0002));
- client1.addExtraOption(option1234);
- // Configure the server with two shared networks which can be accessed
- // by clients belonging to "a-devices" and "b-devices" classes
- // respectively.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[11], *client1.getServer()));
- // The client 1 should be offerred an address from the second subnet.
- ASSERT_NO_THROW(client1.doSolicit(true));
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:2::20"),
- LeaseOnServer::MUST_NOT_EXIST));
- // Create another client which will belong to a different class.
- Dhcp6Client client2;
- client2.setInterface("eth1");
- client2.requestAddress(0xabcd);
- /// Add option 1234 which will cause the client 2 to be classified as "a-devices".
- option1234.reset(new OptionUint16(Option::V6, 1234, 0x0001));
- client2.addExtraOption(option1234);
- // Client 2 should be offerred an address from the first subnet.
- ASSERT_NO_THROW(client2.doSolicit(true));
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:1::20"),
- LeaseOnServer::MUST_NOT_EXIST));
- }
- // Client requests two addresses and two prefixes and obtains them from two
- // different subnets.
- TEST_F(Dhcpv6SharedNetworkTest, assignmentsFromDifferentSubnets) {
- // Create client.
- Dhcp6Client client;
- client.setInterface("eth1");
- client.requestAddress(0xabcd);
- client.requestAddress(0x1234);
- client.requestPrefix(0x1111);
- client.requestPrefix(0x2222);
- // Configure the server with a shared network including two subnets. Each
- // subnet has an address and prefix pool with a single available address
- // and prefix respectively.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[0], *client.getServer()));
- // 4-way exchange.
- ASSERT_NO_THROW(client.doSARR());
- // The two addresses should come from different subnets.
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20")));
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20")));
- // Same for prefixes.
- ASSERT_TRUE(hasLeaseForPrefixPool(client, IOAddress("4000::"), 96, 96));
- ASSERT_TRUE(hasLeaseForPrefixPool(client, IOAddress("5000::"), 96, 96));
- // Try to renew.
- ASSERT_NO_THROW(client.doRenew());
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20")));
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20")));
- ASSERT_TRUE(hasLeaseForPrefixPool(client, IOAddress("4000::"), 96, 96));
- ASSERT_TRUE(hasLeaseForPrefixPool(client, IOAddress("5000::"), 96, 96));
- }
- // Client requests 2 addresses and 2 prefixes. There is one address and one prefix
- // reserved for the client.
- TEST_F(Dhcpv6SharedNetworkTest, reservedAddressAndPrefix) {
- // Create client.
- Dhcp6Client client;
- client.setInterface("eth1");
- client.setDUID("00:03:00:01:11:22:33:44:55:66");
- // Client will request two addresses and two prefixes.
- client.requestAddress(0xabcd);
- client.requestAddress(0x1234);
- client.requestPrefix(0x1111);
- client.requestPrefix(0x2222);
- // The server configuration contains a shared network with two subnets. Each
- // subnet has an address and prefix pool. One of the subnets includes a reservation
- // for an address and prefix.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[4], *client.getServer()));
- // 4-way exchange.
- ASSERT_NO_THROW(client.doSARR());
- ASSERT_EQ(4, client.getLeaseNum());
- // The client should have got one reserved address and one reserved prefix.
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::28")));
- ASSERT_TRUE(hasLeaseForPrefix(client, IOAddress("1234::"), 64, IAID(0x1111)));
- // The client should have got dynamically allocated address too and it must be
- // different than the reserved address.
- std::vector<Lease6> leases_1234 = client.getLeasesByIAID(0x1234);
- ASSERT_EQ(1, leases_1234.size());
- ASSERT_NE("2001:db8:2::28", leases_1234[0].addr_.toText());
- // Same for prefix.
- std::vector<Lease6> leases_2222 = client.getLeasesByIAID(0x2222);
- ASSERT_EQ(1, leases_2222.size());
- ASSERT_NE("1234::", leases_2222[0].addr_.toText());
- // Try to renew and check this again.
- ASSERT_NO_THROW(client.doRenew());
- ASSERT_EQ(4, client.getLeaseNum());
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::28")));
- ASSERT_TRUE(hasLeaseForPrefix(client, IOAddress("1234::"), 64, IAID(0x1111)));
- leases_1234 = client.getLeasesByIAID(0x1234);
- ASSERT_EQ(1, leases_1234.size());
- ASSERT_NE("2001:db8:2::28", leases_1234[0].addr_.toText());
- leases_2222 = client.getLeasesByIAID(0x2222);
- ASSERT_EQ(1, leases_2222.size());
- ASSERT_NE("1234::", leases_2222[0].addr_.toText());
- }
- // Relay address is specified for each subnet within shared network.
- TEST_F(Dhcpv6SharedNetworkTest, relaySpecifiedForEachSubnet) {
- // Create client.
- Dhcp6Client client;
- client.useRelay(true, IOAddress("3001::1"));
- // Client will request two addresses.
- client.requestAddress(0xabcd);
- client.requestAddress(0x1234);
- // Configure the server with three subnets. Two of them belong to a shared network.
- // Each subnet is configured with relay info, i.e. IP address of the relay agent
- // for which the shared network is used.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[13], *client.getServer()));
- // 4-way exchange.
- ASSERT_NO_THROW(client.doSARR());
- ASSERT_EQ(2, client.getLeaseNum());
- // The client should have got two leases, one from each subnet within the
- // shared network.
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20")));
- ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20")));
- }
- // Shared network is selected based on interface id.
- TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByInterfaceId) {
- // Create client #1. This is a relayed client for which interface id
- // has been spefified and this interface id is matching the one specified
- // for the shared network.
- Dhcp6Client client1;
- client1.useRelay(true, IOAddress("3001::1"));
- client1.useInterfaceId("vlan10");
- // Configure the server with one shared network and one subnet outside of the
- // shared network.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[14], *client1.getServer()));
- // Client #1 should be assigned an address from shared network.
- ASSERT_NO_THROW(client1.requestAddress(0xabca0));
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
- // Create client #2. This is a relayed client which is using interface id
- // matching a subnet outside of the shared network.
- Dhcp6Client client2(client1.getServer());
- client2.useRelay(true, IOAddress("3001::2"));
- client2.useInterfaceId("vlan1000");
- ASSERT_NO_THROW(client2.requestAddress(0xabca0));
- ASSERT_NO_THROW(client2.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
- }
- // Shared network is selected based on interface id specified for a subnet
- // belonging to a shared network.
- TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByInterfaceIdInSubnet) {
- // Create client #1. This is a relayed client for which interface id
- // has been spefified and this interface id is matching the one specified
- // for the shared network.
- Dhcp6Client client1;
- client1.useRelay(true, IOAddress("3001::1"));
- client1.useInterfaceId("vlan10");
- // Configure the server with one shared network and one subnet outside of the
- // shared network.
- ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[15], *client1.getServer()));
- // Client #1 should be assigned an address from shared network.
- ASSERT_NO_THROW(client1.requestAddress(0xabca0));
- ASSERT_NO_THROW(client1.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")));
- // Create client #2. This is a relayed client which is using interface id
- // matching a subnet outside of the shared network.
- Dhcp6Client client2(client1.getServer());
- client2.useRelay(true, IOAddress("3001::2"));
- client2.useInterfaceId("vlan1000");
- ASSERT_NO_THROW(client2.requestAddress(0xabca0));
- ASSERT_NO_THROW(client2.doSARR());
- ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
- }
- } // end of anonymous namespace
|