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 #include <config.h>
8
9 #include <dhcp/pkt_filter.h>
10 #include <dhcp/pkt_filter_inet.h>
11 #include <dhcp/pkt_filter_inet6.h>
12 #include <dhcp/tests/iface_mgr_test_config.h>
13 #include <dhcp/tests/pkt_filter_test_stub.h>
14 #include <dhcp/tests/pkt_filter6_test_stub.h>
15
16 #include <boost/foreach.hpp>
17
18 using namespace isc::asiolink;
19
20 namespace isc {
21 namespace dhcp {
22 namespace test {
23
IfaceMgrTestConfig(const bool default_config)24 IfaceMgrTestConfig::IfaceMgrTestConfig(const bool default_config) {
25 IfaceMgr::instance().setTestMode(true);
26 IfaceMgr::instance().closeSockets();
27 IfaceMgr::instance().clearIfaces();
28 IfaceMgr::instance().getPacketQueueMgr4()->destroyPacketQueue();
29 IfaceMgr::instance().getPacketQueueMgr6()->destroyPacketQueue();
30 packet_filter4_ = PktFilterPtr(new PktFilterTestStub());
31 packet_filter6_ = PktFilter6Ptr(new PktFilter6TestStub());
32 IfaceMgr::instance().setPacketFilter(packet_filter4_);
33 IfaceMgr::instance().setPacketFilter(packet_filter6_);
34
35 // Create default set of fake interfaces: lo, eth0, eth1 and eth1961.
36 if (default_config) {
37 createIfaces();
38 }
39 }
40
~IfaceMgrTestConfig()41 IfaceMgrTestConfig::~IfaceMgrTestConfig() {
42 IfaceMgr::instance().stopDHCPReceiver();
43 IfaceMgr::instance().closeSockets();
44 IfaceMgr::instance().getPacketQueueMgr4()->destroyPacketQueue();
45 IfaceMgr::instance().getPacketQueueMgr6()->destroyPacketQueue();
46 IfaceMgr::instance().clearIfaces();
47 IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));
48 IfaceMgr::instance().setPacketFilter(PktFilter6Ptr(new PktFilterInet6()));
49 IfaceMgr::instance().setTestMode(false);
50 IfaceMgr::instance().detectIfaces();
51 }
52
53 void
addAddress(const std::string & iface_name,const IOAddress & address)54 IfaceMgrTestConfig::addAddress(const std::string& iface_name,
55 const IOAddress& address) {
56 IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
57 if (!iface) {
58 isc_throw(isc::BadValue, "interface '" << iface_name
59 << "' doesn't exist");
60 }
61 iface->addAddress(address);
62 }
63
64 void
addIface(const IfacePtr & iface)65 IfaceMgrTestConfig::addIface(const IfacePtr& iface) {
66 IfaceMgr::instance().addInterface(iface);
67 }
68
69 void
addIface(const std::string & name,const int ifindex)70 IfaceMgrTestConfig::addIface(const std::string& name, const int ifindex) {
71 IfaceMgr::instance().addInterface(createIface(name, ifindex));
72 }
73
74 IfacePtr
createIface(const std::string & name,const int ifindex)75 IfaceMgrTestConfig::createIface(const std::string &name, const int ifindex) {
76 IfacePtr iface(new Iface(name, ifindex));
77 if (name == "lo") {
78 iface->flag_loopback_ = true;
79 // Don't open sockets on the loopback interface.
80 iface->inactive4_ = true;
81 iface->inactive6_ = true;
82 } else {
83 iface->inactive4_ = false;
84 iface->inactive6_ = false;
85 }
86 iface->flag_multicast_ = true;
87 // On BSD systems, the SO_BINDTODEVICE option is not supported.
88 // Therefore the IfaceMgr will throw an exception on attempt to
89 // open sockets on more than one broadcast-capable interface at
90 // the same time. In order to prevent this error, we mark all
91 // interfaces broadcast-incapable for unit testing.
92 iface->flag_broadcast_ = false;
93 iface->flag_up_ = true;
94 iface->flag_running_ = true;
95
96 // Set MAC address to 08:08:08:08:08:08.
97 std::vector<uint8_t> mac_vec(6, 8);
98 iface->setMac(&mac_vec[0], mac_vec.size());
99 iface->setHWType(HTYPE_ETHER);
100
101 return (iface);
102 }
103
104 void
createIfaces()105 IfaceMgrTestConfig::createIfaces() {
106 // local loopback
107 addIface("lo", LO_INDEX);
108 addAddress("lo", IOAddress("127.0.0.1"));
109 addAddress("lo", IOAddress("::1"));
110 // eth0
111 addIface("eth0", ETH0_INDEX);
112 addAddress("eth0", IOAddress("10.0.0.1"));
113 addAddress("eth0", IOAddress("fe80::3a60:77ff:fed5:cdef"));
114 addAddress("eth0", IOAddress("2001:db8:1::1"));
115 // eth1
116 addIface("eth1", ETH1_INDEX);
117 addAddress("eth1", IOAddress("192.0.2.3"));
118 addAddress("eth1", IOAddress("192.0.2.5"));
119 addAddress("eth1", IOAddress("fe80::3a60:77ff:fed5:abcd"));
120 // eth1961
121 addIface("eth1961", ETH1961_INDEX);
122 addAddress("eth1961", IOAddress("198.51.100.1"));
123 addAddress("eth1961", IOAddress("fe80::3a60:77ff:fed5:9876"));
124
125 }
126
127 void
setDirectResponse(const bool direct_resp)128 IfaceMgrTestConfig::setDirectResponse(const bool direct_resp) {
129 boost::shared_ptr<PktFilterTestStub> stub =
130 boost::dynamic_pointer_cast<PktFilterTestStub>(getPacketFilter4());
131 if (!stub) {
132 isc_throw(isc::Unexpected, "unable to set direct response capability for"
133 " test packet filter - current packet filter is not"
134 " of a PktFilterTestStub");
135 }
136 stub->direct_response_supported_ = direct_resp;
137 }
138
139 void
setIfaceFlags(const std::string & name,const FlagLoopback & loopback,const FlagUp & up,const FlagRunning & running,const FlagInactive4 & inactive4,const FlagInactive6 & inactive6)140 IfaceMgrTestConfig::setIfaceFlags(const std::string& name,
141 const FlagLoopback& loopback,
142 const FlagUp& up,
143 const FlagRunning& running,
144 const FlagInactive4& inactive4,
145 const FlagInactive6& inactive6) {
146 IfacePtr iface = IfaceMgr::instance().getIface(name);
147 if (iface == NULL) {
148 isc_throw(isc::BadValue, "interface '" << name << "' doesn't exist");
149 }
150 iface->flag_loopback_ = loopback.flag_;
151 iface->flag_up_ = up.flag_;
152 iface->flag_running_ = running.flag_;
153 iface->inactive4_ = inactive4.flag_;
154 iface->inactive6_ = inactive6.flag_;
155 }
156
157 bool
socketOpen(const std::string & iface_name,const int family) const158 IfaceMgrTestConfig::socketOpen(const std::string& iface_name,
159 const int family) const {
160 IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
161 if (iface == NULL) {
162 isc_throw(Unexpected, "No such interface '" << iface_name << "'");
163 }
164
165 BOOST_FOREACH(SocketInfo sock, iface->getSockets()) {
166 if (sock.family_ == family) {
167 return (true);
168 }
169 }
170 return (false);
171 }
172
173 bool
socketOpen(const std::string & iface_name,const std::string & address) const174 IfaceMgrTestConfig::socketOpen(const std::string& iface_name,
175 const std::string& address) const {
176 IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
177 if (!iface) {
178 isc_throw(Unexpected, "No such interface '" << iface_name << "'");
179 }
180
181 BOOST_FOREACH(SocketInfo sock, iface->getSockets()) {
182 if ((sock.family_ == AF_INET) &&
183 (sock.addr_ == IOAddress(address))) {
184 return (true);
185 }
186 }
187 return (false);
188 }
189
190 bool
unicastOpen(const std::string & iface_name) const191 IfaceMgrTestConfig::unicastOpen(const std::string& iface_name) const {
192 IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
193 if (!iface) {
194 isc_throw(Unexpected, "No such interface '" << iface_name << "'");
195 }
196
197 BOOST_FOREACH(SocketInfo sock, iface->getSockets()) {
198 if ((!sock.addr_.isV6LinkLocal()) &&
199 (!sock.addr_.isV6Multicast())) {
200 return (true);
201 }
202 }
203 return (false);
204 }
205
206 }
207 }
208 }
209