1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// Copyright (C) 2014-2023 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/.

#ifndef IFACE_MGR_TEST_CONFIG_H
#define IFACE_MGR_TEST_CONFIG_H

#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
#include <boost/noncopyable.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace dhcp {
namespace test {

//@{
/// @brief Index of the lo fake interface.
const uint32_t LO_INDEX = 0;

/// @brief Index of the eth0 fake interface.
const uint32_t ETH0_INDEX = 1;

/// @brief Index of the eth1 fake interface.
const uint32_t ETH1_INDEX = 2;

/// @brief Index of the eth1961 fake interface.
const uint32_t ETH1961_INDEX = 1962;
//@}

///
/// @name Set of structures describing interface flags.
///
/// These flags encapsulate the boolean type to pass the flags values
/// to @c IfaceMgrTestConfig methods. If the values passed to these methods
/// were not encapsulated by the types defined here, the API would become
/// prone to errors like swapping parameters being passed to specific functions.
/// For example, in the call to @c IfaceMgrTestConfig::setIfaceFlags:
/// @code
///     IfaceMgrTestConfig test_config(true);
///     test_config.setIfaceFlags("eth1", false, false, true, false, false);
/// @endcode
///
/// it is quite likely that the developer by mistake swaps the values and
/// assigns them to wrong flags. When the flags are encapsulated with dedicated
/// structs, the compiler will return an error if values are swapped. For
/// example:
/// @code
///     IfaceMgrTestConfig test_config(true);
///     test_config.setIfaceFlags("eth1", FlagLoopback(false), FlagUp(false),
///                               FlagRunning(true), FlagInactive4(false),
///                               FlagInactive6(false));
/// @endcode
/// will succeed, but the following code will result in the compilation error
/// and thus protect a developer from making an error:
/// @code
///     IfaceMgrTestConfig test_config(true);
///     test_config.setIfaceFlags("eth1", FlagLoopback(false),
///                               FlagRunning(true), FlagUp(false),
///                               FlagInactive4(false), FlagInactive6(false));
/// @endcode
///
//@{
/// @brief Structure describing the loopback interface flag.
struct FlagLoopback {
    explicit FlagLoopback(bool flag) : flag_(flag) { }
    bool flag_;
};

/// @brief Structure describing the up interface flag.
struct FlagUp {
    explicit FlagUp(bool flag) : flag_(flag) { }
    bool flag_;
};

/// @brief Structure describing the running interface flag.
struct FlagRunning {
    explicit FlagRunning(bool flag) : flag_(flag) { }
    bool flag_;
};

/// @brief Structure describing the inactive4 interface flag.
struct FlagInactive4 {
    explicit FlagInactive4(bool flag) : flag_(flag) { }
    bool flag_;
};

/// @brief Structure describing the inactive6 interface flag.
struct FlagInactive6 {
    explicit FlagInactive6(bool flag) : flag_(flag) { }
    bool flag_;
};
//@}

/// @brief Convenience class for configuring @c IfaceMgr for unit testing.
///
/// This class is used by various unit tests which test the code relaying
/// on IfaceMgr. The use of this class is not limited to libdhcp++ validation.
/// There are other libraries and applications (e.g. DHCP servers) which
/// depend on @c IfaceMgr.
///
/// During the normal operation, the @c IfaceMgr detects interfaces present
/// on the machine where it is running. It also provides the means for
/// applications to open sockets on these interfaces and perform other
/// IO operations. This however creates dependency of the applications
/// using @c IfaceMgr on the physical properties of the system and effectively
/// makes it very hard to unit test the dependent code.
///
/// Unit tests usually require that @c IfaceMgr holds a list of well known
/// interfaces with the well known set of IP addresses and other properties
/// (a.k.a. interface flags). The solution which works for many test scenarios
/// is to provide a set of well known fake interfaces, by bypassing the
/// standard interface detection procedure and manually adding @c Iface objects
/// which encapsulate the fake interfaces. As a consequence, it becomes
/// impossible to test IO operations (e.g. sending packets) because real sockets
/// can't be opened on these interfaces. The @c PktFilterTestStub class
/// is used by this class to mimic behavior of IO operations on fake sockets.
///
/// This class provides a set of convenience functions that should be called
/// by unit tests to configure the @c IfaceMgr with fake interfaces.
///
/// The class allows the caller to create custom fake interfaces (with custom
/// IPv4 and IPv6 addresses, flags etc.), but it also provides a default
/// test configuration for interfaces as follows:
/// - lo #0
///   - 127.0.0.1
///   - ::1
/// - eth0 #1
///   - 10.0.0.1
///   - fe80::3a60:77ff:fed5:cdef
///   - 2001:db8:1::1
/// - eth1 #2
///   - 192.0.2.3
///   - fe80::3a60:77ff:fed5:abcd
/// - eth1961 #1962
///   - 198.51.100.1
///   - fe80::3a60:77ff:fed5:9876
///
/// For all interfaces the following flags are set:
/// - multicast
/// - up
/// - running
class IfaceMgrTestConfig : public boost::noncopyable {
public:

    /// @brief Constructor.
    ///
    /// It closes all sockets opened by @c IfaceMgr and removes all interfaces
    /// being used by @c IfaceMgr.
    IfaceMgrTestConfig(const bool default_config = false);

    /// @brief Destructor.
    ///
    /// Closes all currently opened sockets, removes current interfaces and
    /// sets the default packet filtering classes. The default packet filtering
    /// classes are used for IO operations on real sockets/interfaces.
    /// Receiver is stopped.
    ///
    /// Destructor also re-detects real interfaces.
    ~IfaceMgrTestConfig();

    /// @brief Adds new IPv4 or IPv6 address to the interface.
    ///
    /// @param iface_name Name of the interface on which new address should
    /// be configured.
    /// @param address IPv4 or IPv6 address to be configured on the interface.
    void addAddress(const std::string& iface_name,
                    const asiolink::IOAddress& address);

    /// @brief Configures new interface for the @c IfaceMgr.
    ///
    /// @param iface Object encapsulating interface to be added.
    void addIface(const IfacePtr& iface);

    /// @brief Configures new interface for the @c IfaceMgr.
    ///
    /// @param name Name of the new interface.
    /// @param ifindex Index for a new interface.
    void addIface(const std::string& name, const unsigned int ifindex);

    /// @brief Create an object representing interface.
    ///
    /// Apart from creating an interface, this function also sets the
    /// interface flags:
    /// - loopback flag if interface name is "lo"
    /// - up always true
    /// - running always true
    /// - inactive4 set to false for non-loopback interface
    /// - inactive6 set to false for non-loopback interface
    /// - multicast always to true
    /// - broadcast always to false
    ///
    /// @param name A name of the interface to be created.
    /// @param ifindex An index of the interface to be created.
    /// @param mac The mac of the interface.
    ///
    /// @return An object representing interface.
    static IfacePtr createIface(const std::string& name,
                                const unsigned int ifindex,
                                const std::string& mac = "08:08:08:08:08:08");

    /// @brief Creates a default (example) set of fake interfaces.
    void createIfaces();

    /// @brief Returns currently used packet filter for DHCPv4.
    PktFilterPtr getPacketFilter4() const {
        return (packet_filter4_);
    }

    /// @brief Sets the direct response capability for current packet filter.
    ///
    /// The test uses stub implementation of packet filter object. It is
    /// possible to configure that object to report having a capability
    /// to directly respond to clients which don't have an address yet.
    /// This function sets this property for packet filter object.
    ///
    /// @param direct_resp Value to be set.
    ///
    /// @throw isc::Unexpected if unable to set the property.
    void setDirectResponse(const bool direct_resp);

    /// @brief Sets various flags on the specified interface.
    ///
    /// This function configures interface with new values for flags.
    ///
    /// @param name Interface name.
    /// @param loopback Specifies if interface is a loopback interface.
    /// @param up Specifies if the interface is up.
    /// @param running Specifies if the interface is running.
    /// @param inactive4 Specifies if the interface is inactive for V4
    /// traffic, i.e. @c IfaceMgr opens V4 sockets on this interface.
    /// @param inactive6 Specifies if the interface is inactive for V6
    /// traffic, i.e. @c IfaceMgr opens V6 sockets on this interface.
    void setIfaceFlags(const std::string& name,
                       const FlagLoopback& loopback,
                       const FlagUp& up,
                       const FlagRunning& running,
                       const FlagInactive4& inactive4,
                       const FlagInactive6& inactive6);

    /// @brief Checks if socket of the specified family is opened on interface.
    ///
    /// @param iface_name Interface name.
    /// @param family One of: AF_INET or AF_INET6
    bool socketOpen(const std::string& iface_name, const int family) const;

    /// @brief Checks is socket is opened on the interface and bound to a
    /// specified address.
    ///
    /// @param iface_name Interface name.
    /// @param address Address to which the socket is bound.
    bool socketOpen(const std::string& iface_name,
                    const std::string& address) const;

    /// @brief Checks if unicast socket is opened on interface.
    ///
    /// @param iface_name Interface name.
    bool unicastOpen(const std::string& iface_name) const;

private:
    /// @brief Currently used packet filter for DHCPv4.
    PktFilterPtr packet_filter4_;

    /// @brief Currently used packet filter for DHCPv6.
    PktFilter6Ptr packet_filter6_;
};

} // end of namespace isc::dhcp::test
} // end of namespace isc::dhcp
} // end of namespace isc

#endif // IFACE_MGR_TEST_CONFIG_H