Commit 85d28a85 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2902] Do not allow to set new packet filter when there are sockets open.

parent 80f01bc6
......@@ -203,6 +203,36 @@ IfaceMgr::isDirectResponseSupported() const {
return (packet_filter_->isDirectResponseSupported());
}
void
IfaceMgr::setPacketFilter(const boost::shared_ptr<PktFilter>& packet_filter) {
// Do not allow NULL pointer.
if (!packet_filter) {
isc_throw(InvalidPacketFilter, "NULL packet filter object specified");
}
// Different packet filters use different socket types. It does not make
// sense to allow the change of packet filter when there are IPv4 sockets
// open because they can't be used by the receive/send functions of the
// new packet filter. Below, we check that there are no open IPv4 sockets.
// If we find at least one, we have to fail. However, caller still has a
// chance to replace the packet filter if he closes sockets explicitly.
for (IfaceCollection::const_iterator iface = ifaces_.begin();
iface != ifaces_.end(); ++iface) {
const Iface::SocketCollection& sockets = iface->getSockets();
for (Iface::SocketCollection::const_iterator sock = sockets.begin();
sock != sockets.end(); ++sock) {
// There is at least one socket open, so we have to fail.
if (sock->family_ == AF_INET) {
isc_throw(PacketFilterChangeDenied, "it is not allowed to set new packet"
<< " filter when there are open IPv4 sockets - need"
<< " to close them first");
}
}
}
// Everything is fine, so replace packet filter.
packet_filter_ = packet_filter;
}
void IfaceMgr::stubDetectIfaces() {
string ifaceName;
const string v4addr("127.0.0.1"), v6addr("::1");
......
......@@ -39,6 +39,13 @@ public:
isc::Exception(file, line, what) { };
};
/// @brief Exception thrown when it is not allowed to set new Packet Filter.
class PacketFilterChangeDenied : public Exception {
public:
PacketFilterChangeDenied(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when socket opening
/// or configuration failed.
class SocketConfigError : public Exception {
......@@ -602,18 +609,16 @@ public:
/// Packet Filters expose low-level functions handling sockets opening
/// and sending/receiving packets through those sockets. This function
/// sets custom Packet Filter (represented by a class derived from PktFilter)
/// to be used by IfaceMgr.
/// to be used by IfaceMgr. Note that, there must be no IPv4 sockets
/// when this function is called. Call closeSockets(AF_INET) to close
/// all hanging IPv4 sockets opened by the current packet filter object.
///
/// @param packet_filter new packet filter to be used by IfaceMgr to send/receive
/// packets and open sockets.
///
/// @throw InvalidPacketFilter if provided packet filter object is NULL.
void setPacketFilter(const boost::shared_ptr<PktFilter>& packet_filter) {
if (!packet_filter) {
isc_throw(InvalidPacketFilter, "NULL packet filter object specified");
}
packet_filter_ = packet_filter;
}
/// @throw PacketFilterChangeDenied if there are open IPv4 sockets
void setPacketFilter(const boost::shared_ptr<PktFilter>& packet_filter);
/// @brief Set Packet Filter object to handle send/receive packets.
///
......
......@@ -689,19 +689,23 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
// open sockets on the same ports.
ifacemgr->closeSockets();
// The following test is currently disabled for OSes other than
// Linux because interface detection is not implemented on them.
// @todo enable this test for all OSes once interface detection
// is implemented.
#if defined(OS_LINUX)
// The check below has been commented out. It verified the ability
// to open suitable socket for sending broadcast request. However,
// there is no guarantee for such test to work on all systems
// because some systems may have no broadcast capable interfaces at all.
/* #if defined(OS_LINUX)
// Open v4 socket to connect to broadcast address.
int socket3 = 0;
IOAddress bcastAddr("255.255.255.255");
EXPECT_NO_THROW(
try {
socket3 = ifacemgr->openSocketFromRemoteAddress(bcastAddr, PORT2);
);
} catch (const Exception& ex) {
std::cout << ex.what() << std::endl;
FAIL();
}
EXPECT_GT(socket3, 0);
#endif
#endif */
// Do not call closeSockets() because it is called by IfaceMgr's
// virtual destructor.
......@@ -919,6 +923,15 @@ TEST_F(IfaceMgrTest, setPacketFilter) {
EXPECT_TRUE(custom_packet_filter->open_socket_called_);
// This function always returns fake socket descriptor equal to 1024.
EXPECT_EQ(1024, socket1);
// Replacing current packet filter object while there are IPv4
// sockets open is not allowed!
EXPECT_THROW(iface_mgr->setPacketFilter(custom_packet_filter),
PacketFilterChangeDenied);
// So, let's close the open IPv4 sockets and retry. Now it should succeed.
iface_mgr->closeSockets(AF_INET);
EXPECT_NO_THROW(iface_mgr->setPacketFilter(custom_packet_filter));
}
#if defined OS_LINUX
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment