dhcp4_test_utils.h 16.2 KB
 Marcin Siodelski committed Aug 28, 2013 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE.  Tomek Mrugalski committed Oct 09, 2013 15 16 17 /// @file dhcp4_test_utils.h /// /// @brief This file contains utility classes used for DHCPv4 server testing  Marcin Siodelski committed Aug 28, 2013 18   Tomek Mrugalski committed Oct 09, 2013 19 20 21 22 #ifndef DHCP4_TEST_UTILS_H #define DHCP4_TEST_UTILS_H #include  Marcin Siodelski committed Nov 25, 2013 23 #include  Tomek Mrugalski committed Oct 09, 2013 24 #include  Marcin Siodelski committed Aug 28, 2013 25 26 #include #include  Tomek Mrugalski committed Oct 09, 2013 27 28 #include #include  Marcin Siodelski committed Aug 28, 2013 29 #include  Tomek Mrugalski committed Oct 09, 2013 30 31 #include #include  Tomek Mrugalski committed Oct 11, 2013 32 #include  Marcin Siodelski committed Aug 28, 2013 33   Marcin Siodelski committed Jan 02, 2014 34 35 #include  Marcin Siodelski committed Aug 28, 2013 36 namespace isc {  Tomek Mrugalski committed Oct 09, 2013 37 namespace dhcp {  Marcin Siodelski committed Aug 28, 2013 38 39 40 41 42 43 44 45 46 47 48 49 namespace test { /// @brief Dummy Packet Filtering class. /// /// This class reports capability to respond directly to the client which /// doesn't have address configured yet. /// /// All packet and socket handling functions do nothing because they are not /// used in unit tests. class PktFilterTest : public PktFilter { public:  Marcin Siodelski committed Jan 03, 2014 50 51 52 53 54 55 56  /// @brief Constructor. /// /// Sets the 'direct response' capability to true. PktFilterTest() : direct_resp_supported_(true) { }  Marcin Siodelski committed Aug 28, 2013 57 58 59 60  /// @brief Reports 'direct response' capability. /// /// @return always true. virtual bool isDirectResponseSupported() const {  Marcin Siodelski committed Jan 03, 2014 61  return (direct_resp_supported_);  Marcin Siodelski committed Aug 28, 2013 62 63 64  } /// Does nothing.  Marcin Siodelski committed Nov 25, 2013 65 66 67 68  virtual SocketInfo openSocket(const Iface&, const isc::asiolink::IOAddress& addr, const uint16_t port, const bool, const bool) { return (SocketInfo(addr, port, 0));  Marcin Siodelski committed Aug 28, 2013 69 70 71 72 73 74 75 76 77 78 79 80  } /// Does nothing. virtual Pkt4Ptr receive(const Iface&, const SocketInfo&) { return Pkt4Ptr(); } /// Does nothing. virtual int send(const Iface&, uint16_t, const Pkt4Ptr&) { return (0); }  Marcin Siodelski committed Jan 03, 2014 81 82 83 84  /// @brief Holds a boolean value which indicates whether direct response /// capability is supported (true) or not (false). bool direct_resp_supported_;  Marcin Siodelski committed Aug 28, 2013 85 86 };  Marcin Siodelski committed Jan 02, 2014 87 88 typedef boost::shared_ptr PktFilterTestPtr;  Marcin Siodelski committed Aug 28, 2013 89 90 91 92 93 94 95 class Dhcpv4SrvTest : public ::testing::Test { public: /// @brief Constructor /// /// Initializes common objects used in many tests. /// Also sets up initial configuration in CfgMgr.  Tomek Mrugalski committed Oct 09, 2013 96  Dhcpv4SrvTest();  Marcin Siodelski committed Aug 28, 2013 97   Tomek Mrugalski committed Oct 10, 2013 98  /// @brief destructor  Marcin Siodelski committed Aug 28, 2013 99 100 101 102 103  virtual ~Dhcpv4SrvTest() { } /// @brief Add 'Parameter Request List' option to the packet. ///  Tomek Mrugalski committed Oct 10, 2013 104  /// This function adds PRL option comprising the following option codes:  Marcin Siodelski committed Aug 28, 2013 105 106 107 108 109 110 111  /// - 5 - Name Server /// - 15 - Domain Name /// - 7 - Log Server /// - 8 - Quotes Server /// - 9 - LPR Server /// /// @param pkt packet to add PRL option to.  Tomek Mrugalski committed Oct 09, 2013 112  void addPrlOption(Pkt4Ptr& pkt);  Marcin Siodelski committed Aug 28, 2013 113 114 115 116 117 118 119 120 121  /// @brief Configures options being requested in the PRL option. /// /// The lpr-servers option is NOT configured here although it is /// added to the 'Parameter Request List' option in the /// \ref addPrlOption. When requested option is not configured /// the server should not return it in its response. The goal /// of not configuring the requested option is to verify that /// the server will not return it.  Tomek Mrugalski committed Oct 09, 2013 122  void configureRequestedOptions();  Marcin Siodelski committed Aug 28, 2013 123 124 125 126  /// @brief checks that the response matches request /// @param q query (client's message) /// @param a answer (server's message)  Tomek Mrugalski committed Oct 09, 2013 127  void messageCheck(const Pkt4Ptr& q, const Pkt4Ptr& a);  Marcin Siodelski committed Aug 28, 2013 128   Marcin Siodelski committed Oct 22, 2013 129 130  /// @brief Check that certain basic (always added when lease is acquired) /// are present in a message.  Tomek Mrugalski committed Oct 09, 2013 131  ///  Marcin Siodelski committed Oct 22, 2013 132 133 134  /// @param pkt A message to be checked. /// @return Assertion result which indicates whether test passed or failed. ::testing::AssertionResult basicOptionsPresent(const Pkt4Ptr& pkt);  Tomek Mrugalski committed Oct 09, 2013 135   Marcin Siodelski committed Oct 22, 2013 136 137  /// @brief Check that certain basic (always added when lease is acquired) /// are not present.  Marcin Siodelski committed Oct 21, 2013 138 139  /// /// @param pkt A packet to be checked.  Marcin Siodelski committed Oct 22, 2013 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154  /// @return Assertion result which indicates whether test passed or failed. ::testing::AssertionResult noBasicOptions(const Pkt4Ptr& pkt); /// @brief Check that certain requested options are present in the message. /// /// @param pkt A message to be checked. /// @return Assertion result which indicates whether test passed or failed. ::testing::AssertionResult requestedOptionsPresent(const Pkt4Ptr& pkt); /// @brief Check that certain options (requested with PRL option) /// are not present. /// /// @param pkt A packet to be checked. /// @return Assertion result which indicates whether test passed or failed. ::testing::AssertionResult noRequestedOptions(const Pkt4Ptr& pkt);  Marcin Siodelski committed Aug 28, 2013 155 156 157 158 159 160 161 162 163  /// @brief generates client-id option /// /// Generate client-id option of specified length /// Ids with different lengths are sufficent to generate /// unique ids. If more fine grained control is required, /// tests generate client-ids on their own. /// Sets client_id_ field. /// @param size size of the client-id to be generated  Tomek Mrugalski committed Oct 09, 2013 164  OptionPtr generateClientId(size_t size = 4);  Marcin Siodelski committed Aug 28, 2013 165 166 167 168 169  /// @brief generate hardware address /// /// @param size size of the generated MAC address /// @param pointer to Hardware Address object  Tomek Mrugalski committed Oct 09, 2013 170  HWAddrPtr generateHWAddr(size_t size = 6);  Marcin Siodelski committed Aug 28, 2013 171 172 173 174 175 176 177 178 179 180  /// Check that address was returned from proper range, that its lease /// lifetime is correct, that T1 and T2 are returned properly /// @param rsp response to be checked /// @param subnet subnet that should be used to verify assigned address /// and options /// @param t1_mandatory is T1 mandatory? /// @param t2_mandatory is T2 mandatory? void checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet, bool t1_mandatory = false,  Tomek Mrugalski committed Oct 09, 2013 181  bool t2_mandatory = false);  Marcin Siodelski committed Aug 28, 2013 182 183 184 185 186 187 188  /// @brief Basic checks for generated response (message type and trans-id). /// /// @param rsp response packet to be validated /// @param expected_message_type expected message type /// @param expected_transid expected transaction-id void checkResponse(const Pkt4Ptr& rsp, uint8_t expected_message_type,  Tomek Mrugalski committed Oct 09, 2013 189  uint32_t expected_transid);  Marcin Siodelski committed Aug 28, 2013 190 191 192 193 194 195 196 197 198  /// @brief Checks if the lease sent to client is present in the database /// /// @param rsp response packet to be validated /// @param client_id expected client-identifier (or NULL) /// @param HWAddr expected hardware address (not used now) /// @param expected_addr expected address Lease4Ptr checkLease(const Pkt4Ptr& rsp, const OptionPtr& client_id, const HWAddrPtr&,  Tomek Mrugalski committed Oct 09, 2013 199  const isc::asiolink::IOAddress& expected_addr);  Marcin Siodelski committed Aug 28, 2013 200 201 202 203  /// @brief Checks if server response (OFFER, ACK, NAK) includes proper server-id /// @param rsp response packet to be validated /// @param expected_srvid expected value of server-id  Tomek Mrugalski committed Oct 09, 2013 204  void checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid);  Marcin Siodelski committed Aug 28, 2013 205 206 207 208  /// @brief Checks if server response (OFFER, ACK, NAK) includes proper client-id /// @param rsp response packet to be validated /// @param expected_clientid expected value of client-id  Tomek Mrugalski committed Oct 09, 2013 209  void checkClientId(const Pkt4Ptr& rsp, const OptionPtr& expected_clientid);  Marcin Siodelski committed Aug 28, 2013 210   Tomek Mrugalski committed Oct 10, 2013 211  /// @brief sets default fields in a captured packet  Marcin Siodelski committed Aug 28, 2013 212  ///  Tomek Mrugalski committed Oct 10, 2013 213 214 215  /// Sets UDP ports, addresses and interface. /// /// @param pkt packet to have default fields set  Tomek Mrugalski committed Oct 10, 2013 216  void captureSetDefaultFields(const Pkt4Ptr& pkt);  Marcin Siodelski committed Aug 28, 2013 217   Tomek Mrugalski committed Oct 10, 2013 218 219 220 221 222  /// @brief returns captured DISCOVER that went through a relay /// /// See method code for a detailed explanation. /// /// @return relayed DISCOVER  Tomek Mrugalski committed Oct 10, 2013 223  Pkt4Ptr captureRelayedDiscover();  Marcin Siodelski committed Aug 28, 2013 224   Marcin Siodelski committed Oct 21, 2013 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249  /// @brief Create packet from output buffer of another packet. /// /// This function creates a packet using an output buffer from another /// packet. This imitates reception of a packet from the wire. The /// unpack function is then called to parse packet contents and to /// create a collection of the options carried by this packet. /// /// This function is useful for unit tests which verify that the received /// packet is parsed correctly. In those cases it is usually inappropriate /// to create an instance of the packet, add options, set packet /// fields and use such packet as an input to processDiscover or /// processRequest function. This is because, such a packet has certain /// options already initialized and there is no way to verify that they /// have been initialized when packet instance was created or wire buffer /// processing. By creating a packet from the buffer we guarantee that the /// new packet is entirely initialized during wire data parsing. /// /// @param src_pkt A source packet, to be copied. /// @param [out] dst_pkt A destination packet. /// /// @return assertion result indicating if a function completed with /// success or failure. static ::testing::AssertionResult createPacketFromBuffer(const Pkt4Ptr& src_pkt, Pkt4Ptr& dst_pkt);  Marcin Siodelski committed Aug 28, 2013 250   Marcin Siodelski committed Jan 02, 2014 251   Tomek Mrugalski committed Oct 11, 2013 252 253 254 255  /// @brief generates a DHCPv4 packet based on provided hex string /// /// @return created packet Pkt4Ptr packetFromCapture(const std::string& hex_string);  Marcin Siodelski committed Aug 28, 2013 256 257  /// @brief This function cleans up after the test.  Tomek Mrugalski committed Oct 09, 2013 258  virtual void TearDown();  Marcin Siodelski committed Aug 28, 2013 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274  /// @brief A subnet used in most tests Subnet4Ptr subnet_; /// @brief A pool used in most tests Pool4Ptr pool_; /// @brief A client-id used in most tests ClientIdPtr client_id_; int rcode_; isc::data::ConstElementPtr comment_; };  Marcin Siodelski committed Jan 02, 2014 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 /// @brief Test fixture class to be used for tests which require fake /// interfaces. /// /// The DHCPv4 server must always append the server identifier to its response. /// The server identifier is typically an IP address assigned to the interface /// on which the query has been received. The DHCPv4 server uses IfaceMgr to /// check this address. In order to test this functionality, a set of interfaces /// must be known to the test. This test fixture class creates a set of well /// known (fake) interfaces which can be assigned to the test DHCPv4 messages /// so as the response (including server identifier) can be validated. /// The real interfaces are removed from the IfaceMgr in the constructor and /// they are re-assigned in the destructor. class Dhcpv4SrvFakeIfaceTest : public Dhcpv4SrvTest { public: /// @brief Constructor. /// /// Creates a set of fake interfaces: /// - lo, index: 0, address: 127.0.0.1 /// - eth0, index: 1, address: 192.0.3.1 /// - eth1, index: 2, address: 10.0.0.1 /// /// These interfaces replace the real interfaces detected by the IfaceMgr. Dhcpv4SrvFakeIfaceTest();  Marcin Siodelski committed Jan 02, 2014 299 300  /// @brief Restores the original interface configuration. virtual void TearDown();  Marcin Siodelski committed Jan 02, 2014 301 302 303 304 305 306 307 308 309 310  /// @brief Creates an instance of the interface. /// /// @param name Name of the interface. /// @param ifindex Index of the interface. /// @param addr IP address assigned to the interface, represented as string. /// /// @return Iface Instance of the interface. static Iface createIface(const std::string& name, const int ifindex, const std::string& addr);  Marcin Siodelski committed Jan 02, 2014 311 312 313 314 315 316 317 318 319 320 321 322 323 324  /// @brief Tests if Discover or Request message is processed correctly /// /// This test verifies that the Parameter Request List option is handled /// correctly, i.e. it checks that certain options are present in the /// server's response when they are requested and that they are not present /// when they are not requested or NAK occurs. /// /// @todo We need an additional test for PRL option using real traffic /// capture. /// /// @param msg_type DHCPDISCOVER or DHCPREQUEST void testDiscoverRequest(const uint8_t msg_type);  Marcin Siodelski committed Jan 03, 2014 325 326 327 328  /// @brief Holds a pointer to the packet filter object currently used /// by the IfaceMgr. PktFilterTestPtr current_pkt_filter_;  Marcin Siodelski committed Jan 02, 2014 329 330 };  Tomek Mrugalski committed Oct 11, 2013 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 /// @brief "Naked" DHCPv4 server, exposes internal fields class NakedDhcpv4Srv: public Dhcpv4Srv { public: /// @brief Constructor. /// /// This constructor disables default modes of operation used by the /// Dhcpv4Srv class: /// - Send/receive broadcast messages through sockets on interfaces /// which support broadcast traffic. /// - Direct DHCPv4 traffic - communication with clients which do not /// have IP address assigned yet. /// /// Enabling these modes requires root privilges so they must be /// disabled for unit testing. /// /// Note, that disabling broadcast options on sockets does not impact /// the operation of these tests because they use local loopback /// interface which doesn't have broadcast capability anyway. It rather /// prevents setting broadcast options on other (broadcast capable) /// sockets which are opened on other interfaces in Dhcpv4Srv constructor. /// /// The Direct DHCPv4 Traffic capability can be disabled here because /// it is tested with PktFilterLPFTest unittest. The tests which belong /// to PktFilterLPFTest can be enabled on demand when root privileges can /// be guaranteed. /// /// @param port port number to listen on; the default value 0 indicates /// that sockets should not be opened. NakedDhcpv4Srv(uint16_t port = 0) : Dhcpv4Srv(port, "type=memfile", false, false) { } /// @brief fakes packet reception /// @param timeout ignored /// /// The method receives all packets queued in receive queue, one after /// another. Once the queue is empty, it initiates the shutdown procedure. /// /// See fake_received_ field for description virtual Pkt4Ptr receivePacket(int /*timeout*/) { // If there is anything prepared as fake incoming traffic, use it if (!fake_received_.empty()) { Pkt4Ptr pkt = fake_received_.front(); fake_received_.pop_front(); return (pkt); } // If not, just trigger shutdown and return immediately shutdown(); return (Pkt4Ptr()); } /// @brief fake packet sending /// /// Pretend to send a packet, but instead just store it in fake_send_ list /// where test can later inspect server's response. virtual void sendPacket(const Pkt4Ptr& pkt) { fake_sent_.push_back(pkt); } /// @brief adds a packet to fake receive queue /// /// See fake_received_ field for description void fakeReceive(const Pkt4Ptr& pkt) {  Marcin Siodelski committed Jan 02, 2014 397  pkt->setIface("eth0");  Tomek Mrugalski committed Oct 11, 2013 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413  fake_received_.push_back(pkt); } virtual ~NakedDhcpv4Srv() { } /// @brief packets we pretend to receive /// /// Instead of setting up sockets on interfaces that change between OSes, it /// is much easier to fake packet reception. This is a list of packets that /// we pretend to have received. You can schedule new packets to be received /// using fakeReceive() and NakedDhcpv4Srv::receivePacket() methods. std::list fake_received_; std::list fake_sent_;  Marcin Siodelski committed Jan 03, 2014 414 415  using Dhcpv4Srv::adjustIfaceData; using Dhcpv4Srv::appendServerID;  Tomek Mrugalski committed Oct 11, 2013 416 417 418 419 420  using Dhcpv4Srv::processDiscover; using Dhcpv4Srv::processRequest; using Dhcpv4Srv::processRelease; using Dhcpv4Srv::processDecline; using Dhcpv4Srv::processInform;  Marcin Siodelski committed Nov 21, 2013 421 422 423  using Dhcpv4Srv::processClientName; using Dhcpv4Srv::computeDhcid; using Dhcpv4Srv::createNameChangeRequests;  Tomek Mrugalski committed Oct 11, 2013 424 425 426 427 428 429  using Dhcpv4Srv::getServerID; using Dhcpv4Srv::loadServerID; using Dhcpv4Srv::generateServerID; using Dhcpv4Srv::writeServerID; using Dhcpv4Srv::sanityCheck; using Dhcpv4Srv::srvidToString;  Tomek Mrugalski committed Oct 11, 2013 430  using Dhcpv4Srv::unpackOptions;  Marcin Siodelski committed Nov 21, 2013 431  using Dhcpv4Srv::name_change_reqs_;  Tomek Mrugalski committed Oct 11, 2013 432 433 };  Tomek Mrugalski committed Oct 09, 2013 434 435 436 }; // end of isc::dhcp::test namespace }; // end of isc::dhcp namespace }; // end of isc namespace  Marcin Siodelski committed Aug 28, 2013 437   Tomek Mrugalski committed Oct 11, 2013 438 #endif // DHCP4_TEST_UTILS_H