dhcp4_test_utils.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // Copyright (C) 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. /// @file dhcp4_test_utils.h
  15. ///
  16. /// @brief This file contains utility classes used for DHCPv4 server testing
  17. #ifndef DHCP4_TEST_UTILS_H
  18. #define DHCP4_TEST_UTILS_H
  19. #include <gtest/gtest.h>
  20. #include <dhcp/pkt4.h>
  21. #include <dhcp/pkt_filter.h>
  22. #include <dhcp/pkt_filter_inet.h>
  23. #include <dhcpsrv/subnet.h>
  24. #include <dhcpsrv/lease.h>
  25. #include <dhcp4/dhcp4_srv.h>
  26. #include <asiolink/io_address.h>
  27. #include <config/ccsession.h>
  28. #include <list>
  29. namespace isc {
  30. namespace dhcp {
  31. namespace test {
  32. /// @brief Dummy Packet Filtering class.
  33. ///
  34. /// This class reports capability to respond directly to the client which
  35. /// doesn't have address configured yet.
  36. ///
  37. /// All packet and socket handling functions do nothing because they are not
  38. /// used in unit tests.
  39. class PktFilterTest : public PktFilter {
  40. public:
  41. /// @brief Reports 'direct response' capability.
  42. ///
  43. /// @return always true.
  44. virtual bool isDirectResponseSupported() const {
  45. return (true);
  46. }
  47. /// Does nothing.
  48. virtual int openSocket(const Iface&, const isc::asiolink::IOAddress&,
  49. const uint16_t, const bool, const bool) {
  50. return (0);
  51. }
  52. /// Does nothing.
  53. virtual Pkt4Ptr receive(const Iface&, const SocketInfo&) {
  54. return Pkt4Ptr();
  55. }
  56. /// Does nothing.
  57. virtual int send(const Iface&, uint16_t, const Pkt4Ptr&) {
  58. return (0);
  59. }
  60. };
  61. class Dhcpv4SrvTest : public ::testing::Test {
  62. public:
  63. /// @brief Constructor
  64. ///
  65. /// Initializes common objects used in many tests.
  66. /// Also sets up initial configuration in CfgMgr.
  67. Dhcpv4SrvTest();
  68. /// @brief destructor
  69. virtual ~Dhcpv4SrvTest();
  70. /// @brief Add 'Parameter Request List' option to the packet.
  71. ///
  72. /// This function adds PRL option comprising the following option codes:
  73. /// - 5 - Name Server
  74. /// - 15 - Domain Name
  75. /// - 7 - Log Server
  76. /// - 8 - Quotes Server
  77. /// - 9 - LPR Server
  78. ///
  79. /// @param pkt packet to add PRL option to.
  80. void addPrlOption(Pkt4Ptr& pkt);
  81. /// @brief Configures options being requested in the PRL option.
  82. ///
  83. /// The lpr-servers option is NOT configured here although it is
  84. /// added to the 'Parameter Request List' option in the
  85. /// \ref addPrlOption. When requested option is not configured
  86. /// the server should not return it in its response. The goal
  87. /// of not configuring the requested option is to verify that
  88. /// the server will not return it.
  89. void configureRequestedOptions();
  90. /// @brief checks that the response matches request
  91. /// @param q query (client's message)
  92. /// @param a answer (server's message)
  93. void messageCheck(const Pkt4Ptr& q, const Pkt4Ptr& a);
  94. /// @brief Check that certain basic (always added when lease is acquired)
  95. /// are present in a message.
  96. ///
  97. /// @param pkt A message to be checked.
  98. /// @return Assertion result which indicates whether test passed or failed.
  99. ::testing::AssertionResult basicOptionsPresent(const Pkt4Ptr& pkt);
  100. /// @brief Check that certain basic (always added when lease is acquired)
  101. /// are not present.
  102. ///
  103. /// @param pkt A packet to be checked.
  104. /// @return Assertion result which indicates whether test passed or failed.
  105. ::testing::AssertionResult noBasicOptions(const Pkt4Ptr& pkt);
  106. /// @brief Check that certain requested options are present in the message.
  107. ///
  108. /// @param pkt A message to be checked.
  109. /// @return Assertion result which indicates whether test passed or failed.
  110. ::testing::AssertionResult requestedOptionsPresent(const Pkt4Ptr& pkt);
  111. /// @brief Check that certain options (requested with PRL option)
  112. /// are not present.
  113. ///
  114. /// @param pkt A packet to be checked.
  115. /// @return Assertion result which indicates whether test passed or failed.
  116. ::testing::AssertionResult noRequestedOptions(const Pkt4Ptr& pkt);
  117. /// @brief generates client-id option
  118. ///
  119. /// Generate client-id option of specified length
  120. /// Ids with different lengths are sufficent to generate
  121. /// unique ids. If more fine grained control is required,
  122. /// tests generate client-ids on their own.
  123. /// Sets client_id_ field.
  124. /// @param size size of the client-id to be generated
  125. OptionPtr generateClientId(size_t size = 4);
  126. /// @brief generate hardware address
  127. ///
  128. /// @param size size of the generated MAC address
  129. /// @param pointer to Hardware Address object
  130. HWAddrPtr generateHWAddr(size_t size = 6);
  131. /// Check that address was returned from proper range, that its lease
  132. /// lifetime is correct, that T1 and T2 are returned properly
  133. /// @param rsp response to be checked
  134. /// @param subnet subnet that should be used to verify assigned address
  135. /// and options
  136. /// @param t1_mandatory is T1 mandatory?
  137. /// @param t2_mandatory is T2 mandatory?
  138. void checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
  139. bool t1_mandatory = false,
  140. bool t2_mandatory = false);
  141. /// @brief Basic checks for generated response (message type and trans-id).
  142. ///
  143. /// @param rsp response packet to be validated
  144. /// @param expected_message_type expected message type
  145. /// @param expected_transid expected transaction-id
  146. void checkResponse(const Pkt4Ptr& rsp, uint8_t expected_message_type,
  147. uint32_t expected_transid);
  148. /// @brief Checks if the lease sent to client is present in the database
  149. ///
  150. /// @param rsp response packet to be validated
  151. /// @param client_id expected client-identifier (or NULL)
  152. /// @param HWAddr expected hardware address (not used now)
  153. /// @param expected_addr expected address
  154. Lease4Ptr checkLease(const Pkt4Ptr& rsp, const OptionPtr& client_id,
  155. const HWAddrPtr&,
  156. const isc::asiolink::IOAddress& expected_addr);
  157. /// @brief Checks if server response (OFFER, ACK, NAK) includes proper server-id
  158. /// @param rsp response packet to be validated
  159. /// @param expected_srvid expected value of server-id
  160. void checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid);
  161. /// @brief Checks if server response (OFFER, ACK, NAK) includes proper client-id
  162. ///
  163. /// This method follows values reported by CfgMgr in echoClientId() method.
  164. /// Depending on its configuration, the client-id is either mandatory or
  165. /// forbidden to appear in the response.
  166. ///
  167. /// @param rsp response packet to be validated
  168. /// @param expected_clientid expected value of client-id
  169. void checkClientId(const Pkt4Ptr& rsp, const OptionPtr& expected_clientid);
  170. /// @brief sets default fields in a captured packet
  171. ///
  172. /// Sets UDP ports, addresses and interface.
  173. ///
  174. /// @param pkt packet to have default fields set
  175. void captureSetDefaultFields(const Pkt4Ptr& pkt);
  176. /// @brief returns captured DISCOVER that went through a relay
  177. ///
  178. /// See method code for a detailed explanation.
  179. ///
  180. /// @return relayed DISCOVER
  181. Pkt4Ptr captureRelayedDiscover();
  182. /// @brief Create packet from output buffer of another packet.
  183. ///
  184. /// This function creates a packet using an output buffer from another
  185. /// packet. This imitates reception of a packet from the wire. The
  186. /// unpack function is then called to parse packet contents and to
  187. /// create a collection of the options carried by this packet.
  188. ///
  189. /// This function is useful for unit tests which verify that the received
  190. /// packet is parsed correctly. In those cases it is usually inappropriate
  191. /// to create an instance of the packet, add options, set packet
  192. /// fields and use such packet as an input to processDiscover or
  193. /// processRequest function. This is because, such a packet has certain
  194. /// options already initialized and there is no way to verify that they
  195. /// have been initialized when packet instance was created or wire buffer
  196. /// processing. By creating a packet from the buffer we guarantee that the
  197. /// new packet is entirely initialized during wire data parsing.
  198. ///
  199. /// @param src_pkt A source packet, to be copied.
  200. /// @param [out] dst_pkt A destination packet.
  201. ///
  202. /// @return assertion result indicating if a function completed with
  203. /// success or failure.
  204. static ::testing::AssertionResult
  205. createPacketFromBuffer(const Pkt4Ptr& src_pkt,
  206. Pkt4Ptr& dst_pkt);
  207. /// @brief generates a DHCPv4 packet based on provided hex string
  208. ///
  209. /// @return created packet
  210. Pkt4Ptr packetFromCapture(const std::string& hex_string);
  211. /// @brief Tests if Discover or Request message is processed correctly
  212. ///
  213. /// This test verifies that the Parameter Request List option is handled
  214. /// correctly, i.e. it checks that certain options are present in the
  215. /// server's response when they are requested and that they are not present
  216. /// when they are not requested or NAK occurs.
  217. ///
  218. /// @todo We need an additional test for PRL option using real traffic
  219. /// capture.
  220. ///
  221. /// @param msg_type DHCPDISCOVER or DHCPREQUEST
  222. void testDiscoverRequest(const uint8_t msg_type);
  223. /// @brief This function cleans up after the test.
  224. virtual void TearDown();
  225. /// @brief A subnet used in most tests
  226. Subnet4Ptr subnet_;
  227. /// @brief A pool used in most tests
  228. Pool4Ptr pool_;
  229. /// @brief A client-id used in most tests
  230. ClientIdPtr client_id_;
  231. int rcode_;
  232. isc::data::ConstElementPtr comment_;
  233. // Name of a valid network interface
  234. std::string valid_iface_;
  235. };
  236. /// @brief "Naked" DHCPv4 server, exposes internal fields
  237. class NakedDhcpv4Srv: public Dhcpv4Srv {
  238. public:
  239. /// @brief Constructor.
  240. ///
  241. /// This constructor disables default modes of operation used by the
  242. /// Dhcpv4Srv class:
  243. /// - Send/receive broadcast messages through sockets on interfaces
  244. /// which support broadcast traffic.
  245. /// - Direct DHCPv4 traffic - communication with clients which do not
  246. /// have IP address assigned yet.
  247. ///
  248. /// Enabling these modes requires root privilges so they must be
  249. /// disabled for unit testing.
  250. ///
  251. /// Note, that disabling broadcast options on sockets does not impact
  252. /// the operation of these tests because they use local loopback
  253. /// interface which doesn't have broadcast capability anyway. It rather
  254. /// prevents setting broadcast options on other (broadcast capable)
  255. /// sockets which are opened on other interfaces in Dhcpv4Srv constructor.
  256. ///
  257. /// The Direct DHCPv4 Traffic capability can be disabled here because
  258. /// it is tested with PktFilterLPFTest unittest. The tests which belong
  259. /// to PktFilterLPFTest can be enabled on demand when root privileges can
  260. /// be guaranteed.
  261. ///
  262. /// @param port port number to listen on; the default value 0 indicates
  263. /// that sockets should not be opened.
  264. NakedDhcpv4Srv(uint16_t port = 0)
  265. : Dhcpv4Srv(port, "type=memfile", false, false) {
  266. }
  267. /// @brief fakes packet reception
  268. /// @param timeout ignored
  269. ///
  270. /// The method receives all packets queued in receive queue, one after
  271. /// another. Once the queue is empty, it initiates the shutdown procedure.
  272. ///
  273. /// See fake_received_ field for description
  274. virtual Pkt4Ptr receivePacket(int /*timeout*/) {
  275. // If there is anything prepared as fake incoming traffic, use it
  276. if (!fake_received_.empty()) {
  277. Pkt4Ptr pkt = fake_received_.front();
  278. fake_received_.pop_front();
  279. return (pkt);
  280. }
  281. // If not, just trigger shutdown and return immediately
  282. shutdown();
  283. return (Pkt4Ptr());
  284. }
  285. /// @brief fake packet sending
  286. ///
  287. /// Pretend to send a packet, but instead just store it in fake_send_ list
  288. /// where test can later inspect server's response.
  289. virtual void sendPacket(const Pkt4Ptr& pkt) {
  290. fake_sent_.push_back(pkt);
  291. }
  292. /// @brief adds a packet to fake receive queue
  293. ///
  294. /// See fake_received_ field for description
  295. void fakeReceive(const Pkt4Ptr& pkt) {
  296. fake_received_.push_back(pkt);
  297. }
  298. virtual ~NakedDhcpv4Srv() {
  299. }
  300. /// @brief packets we pretend to receive
  301. ///
  302. /// Instead of setting up sockets on interfaces that change between OSes, it
  303. /// is much easier to fake packet reception. This is a list of packets that
  304. /// we pretend to have received. You can schedule new packets to be received
  305. /// using fakeReceive() and NakedDhcpv4Srv::receivePacket() methods.
  306. std::list<Pkt4Ptr> fake_received_;
  307. std::list<Pkt4Ptr> fake_sent_;
  308. using Dhcpv4Srv::adjustRemoteAddr;
  309. using Dhcpv4Srv::processDiscover;
  310. using Dhcpv4Srv::processRequest;
  311. using Dhcpv4Srv::processRelease;
  312. using Dhcpv4Srv::processDecline;
  313. using Dhcpv4Srv::processInform;
  314. using Dhcpv4Srv::getServerID;
  315. using Dhcpv4Srv::loadServerID;
  316. using Dhcpv4Srv::generateServerID;
  317. using Dhcpv4Srv::writeServerID;
  318. using Dhcpv4Srv::sanityCheck;
  319. using Dhcpv4Srv::srvidToString;
  320. using Dhcpv4Srv::unpackOptions;
  321. };
  322. }; // end of isc::dhcp::test namespace
  323. }; // end of isc::dhcp namespace
  324. }; // end of isc namespace
  325. #endif // DHCP4_TEST_UTILS_H