1 // Copyright (C) 2013-2017 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 PKT_FILTER_TEST_UTILS_H
8 #define PKT_FILTER_TEST_UTILS_H
9 
10 #include <asiolink/io_address.h>
11 #include <dhcp/iface_mgr.h>
12 #include <dhcp/pkt_filter.h>
13 #include <gtest/gtest.h>
14 
15 namespace isc {
16 namespace dhcp {
17 namespace test {
18 
19 /// @brief Test fixture class for testing classes derived from PktFilter class.
20 ///
21 /// This class implements a simple algorithm checking presence of the loopback
22 /// interface and initializing its index. It assumes that the loopback interface
23 /// name is one of 'lo' or 'lo0'. If none of those interfaces is found, the
24 /// constructor will report a failure.
25 ///
26 /// @todo The interface detection algorithm should be more generic. This will
27 /// be possible once the cross-OS interface detection is implemented.
28 class PktFilterTest : public ::testing::Test {
29 public:
30 
31     /// @brief Constructor
32     ///
33     /// This constructor initializes sock_info_ structure to a default value.
34     /// The socket descriptors should be set to a negative value to indicate
35     /// that no socket has been opened. Specific tests will reinitialize this
36     /// structure with the values of the open sockets. For non-negative socket
37     /// descriptors, the class destructor will close associated sockets.
38     PktFilterTest(const uint16_t port);
39 
40     /// @brief Destructor
41     ///
42     /// Closes open sockets (if any).
43     virtual ~PktFilterTest();
44 
45     /// @brief Initializes DHCPv4 message used by tests.
46     void initTestMessage();
47 
48     /// @brief Detect loopback interface.
49     ///
50     /// @todo this function will be removed once cross-OS interface
51     /// detection is implemented
52     void loInit();
53 
54     /// @brief Sends a single DHCPv4 message to the loopback address.
55     ///
56     /// This function opens a datagram socket and binds it to the local loopback
57     /// address and client port. The client's port is assumed to be port_ + 1.
58     /// The send_msg_sock_ member holds the socket descriptor so as the socket
59     /// is closed automatically in the destructor. If the function succeeds to
60     /// send a DHCPv4 message, the socket is closed so as the function can be
61     /// called again within the same test.
62     ///
63     /// @param dest Destination address for the packet.
64     void sendMessage(const asiolink::IOAddress& dest =
65                      asiolink::IOAddress("127.0.0.1"));
66 
67     /// @brief Test that the datagram socket is opened correctly.
68     ///
69     /// This function is used by multiple tests.
70     ///
71     /// @param sock A descriptor of the open socket.
72     void testDgramSocket(const int sock) const;
73 
74     /// @brief Checks if a received message matches the test_message_.
75     ///
76     /// @param rcvd_msg An instance of the message to be tested.
77     void testRcvdMessage(const Pkt4Ptr& rcvd_msg) const;
78 
79     /// @brief Checks if received message has appropriate addresses and
80     /// port values set.
81     ///
82     /// @param rcvd_msg An instance of the message to be tested.
83     void testRcvdMessageAddressPort(const Pkt4Ptr& rcvd_msg) const;
84 
85     std::string ifname_;   ///< Loopback interface name
86     uint16_t ifindex_;     ///< Loopback interface index.
87     uint16_t port_;        ///< A port number used for the test.
88     isc::dhcp::SocketInfo sock_info_; ///< A structure holding socket info.
89     int send_msg_sock_;    ///< Holds a descriptor of the socket used by
90                            ///< sendMessage function.
91     Pkt4Ptr test_message_; ///< A DHCPv4 message used by tests.
92 
93 };
94 
95 /// @brief A stub implementation of the PktFilter class.
96 ///
97 /// This class implements abstract methods of the @c isc::dhcp::PktFilter
98 /// class. It is used by unit tests, which test protected methods of the
99 /// @c isc::dhcp::test::PktFilter class. The implemented abstract methods are
100 /// no-op.
101 class PktFilterStub : public PktFilter {
102 public:
103 
104     /// @brief Checks if the direct DHCPv4 response is supported.
105     ///
106     /// This function checks if the direct response capability is supported,
107     /// i.e. if the server can respond to the client which doesn't have an
108     /// address yet. For this dummy class, the true is always returned.
109     ///
110     /// @return always true.
111     virtual bool isDirectResponseSupported() const;
112 
113     /// @brief Simulate opening of the socket.
114     ///
115     /// This function simulates opening a primary socket. In reality, it doesn't
116     /// open a socket but the socket descriptor returned in the SocketInfo
117     /// structure is always set to 0.
118     ///
119     /// @param iface An interface descriptor.
120     /// @param addr Address on the interface to be used to send packets.
121     /// @param port Port number to bind socket to.
122     /// @param receive_bcast A flag which indicates if socket should be
123     /// configured to receive broadcast packets (if true).
124     /// @param send_bcast A flag which indicates if the socket should be
125     /// configured to send broadcast packets (if true).
126     ///
127     /// @note All parameters are ignored.
128     ///
129     /// @return A SocketInfo structure with the socket descriptor set to 0. The
130     /// fallback socket descriptor is set to a negative value.
131     virtual SocketInfo openSocket(Iface& iface,
132                                   const isc::asiolink::IOAddress& addr,
133                                   const uint16_t port,
134                                   const bool receive_bcast,
135                                   const bool send_bcast);
136 
137     /// @brief Simulate reception of the DHCPv4 message.
138     ///
139     /// @param iface An interface to be used to receive DHCPv4 message.
140     /// @param sock_info A descriptor of the primary and fallback sockets.
141     ///
142     /// @note All parameters are ignored.
143     ///
144     /// @return always a NULL object.
145     virtual Pkt4Ptr receive(Iface& iface, const SocketInfo& sock_info);
146 
147     /// @brief Simulates sending a DHCPv4 message.
148     ///
149     /// This function does nothing.
150     ///
151     /// @param iface An interface to be used to send DHCPv4 message.
152     /// @param port A port used to send a message.
153     /// @param pkt A DHCPv4 to be sent.
154     ///
155     /// @note All parameters are ignored.
156     ///
157     /// @return 0.
158     virtual int send(const Iface& iface, uint16_t port, const Pkt4Ptr& pkt);
159 
160     // Change the scope of the protected function so as they can be unit tested.
161     using PktFilter::openFallbackSocket;
162 
163 };
164 
165 
166 }; // end of isc::dhcp::test namespace
167 }; // end of isc::dhcp namespace
168 }; // end of isc namespace
169 
170 #endif // PKT_FILTER_TEST_UTILS_H
171