1 // Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef IFACE_MGR_TEST_CONFIG_H 8 #define IFACE_MGR_TEST_CONFIG_H 9 10 #include <asiolink/io_address.h> 11 #include <dhcp/iface_mgr.h> 12 #include <boost/noncopyable.hpp> 13 14 namespace isc { 15 namespace dhcp { 16 namespace test { 17 18 //@{ 19 /// @brief Index of the lo fake interface. 20 const uint32_t LO_INDEX = 0; 21 22 /// @brief Index of the eth0 fake interface. 23 const uint32_t ETH0_INDEX = 1; 24 25 /// @brief Index of the eth1 fake interface. 26 const uint32_t ETH1_INDEX = 2; 27 28 /// @brief Index of the eth1961 fake interface. 29 const uint32_t ETH1961_INDEX = 1962; 30 //@} 31 32 /// 33 /// @name Set of structures describing interface flags. 34 /// 35 /// These flags encapsulate the boolean type to pass the flags values 36 /// to @c IfaceMgrTestConfig methods. If the values passed to these methods 37 /// were not encapsulated by the types defined here, the API would become 38 /// prone to errors like swapping parameters being passed to specific functions. 39 /// For example, in the call to @c IfaceMgrTestConfig::setIfaceFlags: 40 /// @code 41 /// IfaceMgrTestConfig test_config(true); 42 /// test_config.setIfaceFlags("eth1", false, false, true, false, false); 43 /// @endcode 44 /// 45 /// it is quite likely that the developer by mistake swaps the values and 46 /// assigns them to wrong flags. When the flags are encapsulated with dedicated 47 /// structs, the compiler will return an error if values are swapped. For 48 /// example: 49 /// @code 50 /// IfaceMgrTestConfig test_config(true); 51 /// test_config.setIfaceFlags("eth1", FlagLoopback(false), FlagUp(false), 52 /// FlagRunning(true), FlagInactive4(false), 53 /// FlagInactive6(false)); 54 /// @endcode 55 /// will succeed, but the following code will result in the compilation error 56 /// and thus protect a developer from making an error: 57 /// @code 58 /// IfaceMgrTestConfig test_config(true); 59 /// test_config.setIfaceFlags("eth1", FlagLoopback(false), 60 /// FlagRunning(true), FlagUp(false), 61 /// FlagInactive4(false), FlagInactive6(false)); 62 /// @endcode 63 /// 64 //@{ 65 /// @brief Structure describing the loopback interface flag. 66 struct FlagLoopback { FlagLoopbackFlagLoopback67 explicit FlagLoopback(bool flag) : flag_(flag) { } 68 bool flag_; 69 }; 70 71 /// @brief Structure describing the up interface flag. 72 struct FlagUp { FlagUpFlagUp73 explicit FlagUp(bool flag) : flag_(flag) { } 74 bool flag_; 75 }; 76 77 /// @brief Structure describing the running interface flag. 78 struct FlagRunning { FlagRunningFlagRunning79 explicit FlagRunning(bool flag) : flag_(flag) { } 80 bool flag_; 81 }; 82 83 /// @brief Structure describing the inactive4 interface flag. 84 struct FlagInactive4 { FlagInactive4FlagInactive485 explicit FlagInactive4(bool flag) : flag_(flag) { } 86 bool flag_; 87 }; 88 89 /// @brief Structure describing the inactive6 interface flag. 90 struct FlagInactive6 { FlagInactive6FlagInactive691 explicit FlagInactive6(bool flag) : flag_(flag) { } 92 bool flag_; 93 }; 94 //@} 95 96 /// @brief Convenience class for configuring @c IfaceMgr for unit testing. 97 /// 98 /// This class is used by various unit tests which test the code relaying 99 /// on IfaceMgr. The use of this class is not limited to libdhcp++ validation. 100 /// There are other libraries and applications (e.g. DHCP servers) which 101 /// depend on @c IfaceMgr. 102 /// 103 /// During the normal operation, the @c IfaceMgr detects interfaces present 104 /// on the machine where it is running. It also provides the means for 105 /// applications to open sockets on these interfaces and perform other 106 /// IO operations. This however creates dependency of the applications 107 /// using @c IfaceMgr on the physical properties of the system and effectively 108 /// makes it very hard to unit test the dependent code. 109 /// 110 /// Unit tests usually require that @c IfaceMgr holds a list of well known 111 /// interfaces with the well known set of IP addresses and other properties 112 /// (a.k.a. interface flags). The solution which works for many test scenarios 113 /// is to provide a set of well known fake interfaces, by bypassing the 114 /// standard interface detection procedure and manually adding @c Iface objects 115 /// which encapsulate the fake interfaces. As a consequence, it becomes 116 /// impossible to test IO operations (e.g. sending packets) because real sockets 117 /// can't be opened on these interfaces. The @c PktFilterTestStub class 118 /// is used by this class to mimic behavior of IO operations on fake sockets. 119 /// 120 /// This class provides a set of convenience functions that should be called 121 /// by unit tests to configure the @c IfaceMgr with fake interfaces. 122 /// 123 /// The class allows the caller to create custom fake interfaces (with custom 124 /// IPv4 and IPv6 addresses, flags etc.), but it also provides a default 125 /// test configuration for interfaces as follows: 126 /// - lo #0 127 /// - 127.0.0.1 128 /// - ::1 129 /// - eth0 #1 130 /// - 10.0.0.1 131 /// - fe80::3a60:77ff:fed5:cdef 132 /// - 2001:db8:1::1 133 /// - eth1 #2 134 /// - 192.0.2.3 135 /// - fe80::3a60:77ff:fed5:abcd 136 /// - eth1961 #1962 137 /// - 198.51.100.1 138 /// - fe80::3a60:77ff:fed5:9876 139 /// 140 /// For all interfaces the following flags are set: 141 /// - multicast 142 /// - up 143 /// - running 144 class IfaceMgrTestConfig : public boost::noncopyable { 145 public: 146 147 /// @brief Constructor. 148 /// 149 /// It closes all sockets opened by @c IfaceMgr and removes all interfaces 150 /// being used by @c IfaceMgr. 151 IfaceMgrTestConfig(const bool default_config = false); 152 153 /// @brief Destructor. 154 /// 155 /// Closes all currently opened sockets, removes current interfaces and 156 /// sets the default packet filtering classes. The default packet filtering 157 /// classes are used for IO operations on real sockets/interfaces. 158 /// Receiver is stopped. 159 /// 160 /// Destructor also re-detects real interfaces. 161 ~IfaceMgrTestConfig(); 162 163 /// @brief Adds new IPv4 or IPv6 address to the interface. 164 /// 165 /// @param iface_name Name of the interface on which new address should 166 /// be configured. 167 /// @param address IPv4 or IPv6 address to be configured on the interface. 168 void addAddress(const std::string& iface_name, 169 const asiolink::IOAddress& address); 170 171 /// @brief Configures new interface for the @c IfaceMgr. 172 /// 173 /// @param iface Object encapsulating interface to be added. 174 void addIface(const IfacePtr& iface); 175 176 /// @brief Configures new interface for the @c IfaceMgr. 177 /// 178 /// @param name Name of the new interface. 179 /// @param ifindex Index for a new interface. 180 void addIface(const std::string& name, const int ifindex); 181 182 /// @brief Create an object representing interface. 183 /// 184 /// Apart from creating an interface, this function also sets the 185 /// interface flags: 186 /// - loopback flag if interface name is "lo" 187 /// - up always true 188 /// - running always true 189 /// - inactive4 set to false for non-loopback interface 190 /// - inactive6 set to false for non-loopback interface 191 /// - multicast always to true 192 /// - broadcast always to false 193 /// 194 /// If one needs to modify the default flag settings, the setIfaceFlags 195 /// function should be used. 196 /// 197 /// @param name A name of the interface to be created. 198 /// @param ifindex An index of the interface to be created. 199 /// 200 /// @return An object representing interface. 201 static IfacePtr createIface(const std::string& name, const int ifindex); 202 203 /// @brief Creates a default (example) set of fake interfaces. 204 void createIfaces(); 205 206 /// @brief Returns currently used packet filter for DHCPv4. getPacketFilter4()207 PktFilterPtr getPacketFilter4() const { 208 return (packet_filter4_); 209 } 210 211 /// @brief Sets the direct response capability for current packet filter. 212 /// 213 /// The test uses stub implementation of packet filter object. It is 214 /// possible to configure that object to report having a capability 215 /// to directly respond to clients which don't have an address yet. 216 /// This function sets this property for packet filter object. 217 /// 218 /// @param direct_resp Value to be set. 219 /// 220 /// @throw isc::Unexpected if unable to set the property. 221 void setDirectResponse(const bool direct_resp); 222 223 /// @brief Sets various flags on the specified interface. 224 /// 225 /// This function configures interface with new values for flags. 226 /// 227 /// @param name Interface name. 228 /// @param loopback Specifies if interface is a loopback interface. 229 /// @param up Specifies if the interface is up. 230 /// @param running Specifies if the interface is running. 231 /// @param inactive4 Specifies if the interface is inactive for V4 232 /// traffic, i.e. @c IfaceMgr opens V4 sockets on this interface. 233 /// @param inactive6 Specifies if the interface is inactive for V6 234 /// traffic, i.e. @c IfaceMgr opens V6 sockets on this interface. 235 void setIfaceFlags(const std::string& name, 236 const FlagLoopback& loopback, 237 const FlagUp& up, 238 const FlagRunning& running, 239 const FlagInactive4& inactive4, 240 const FlagInactive6& inactive6); 241 242 /// @brief Checks if socket of the specified family is opened on interface. 243 /// 244 /// @param iface_name Interface name. 245 /// @param family One of: AF_INET or AF_INET6 246 bool socketOpen(const std::string& iface_name, const int family) const; 247 248 /// @brief Checks is socket is opened on the interface and bound to a 249 /// specified address. 250 /// 251 /// @param iface_name Interface name. 252 /// @param address Address to which the socket is bound. 253 bool socketOpen(const std::string& iface_name, 254 const std::string& address) const; 255 256 /// @brief Checks if unicast socket is opened on interface. 257 /// 258 /// @param iface_name Interface name. 259 bool unicastOpen(const std::string& iface_name) const; 260 261 262 private: 263 /// @brief Currently used packet filter for DHCPv4. 264 PktFilterPtr packet_filter4_; 265 266 /// @brief Currently used packet filter for DHCPv6. 267 PktFilter6Ptr packet_filter6_; 268 }; 269 270 }; 271 }; 272 }; 273 274 #endif // IFACE_MGR_TEST_CONFIG_H 275