ICMPSocket does not check reply address #1921

This commit is contained in:
Alex Fabijanic 2017-10-05 14:01:41 -05:00
parent 3732c8e13f
commit f68e0174b6
7 changed files with 85 additions and 32 deletions

View File

@ -69,6 +69,9 @@ public:
int dataSize() const;
/// Returns the data size in bytes.
int packetSize() const;
/// Returns the packet size in bytes.
int ttl() const;
/// Returns the Time-To-Live value.

View File

@ -51,6 +51,9 @@ public:
int dataSize() const;
/// Returns the data size in bytes.
int packetSize() const;
/// Returns the packet size in bytes.
int ttl() const;
/// Returns the Time-To-Live value.
@ -70,6 +73,12 @@ private:
//
// inlines
//
inline int ICMPSocketImpl::packetSize() const
{
return _icmpPacket.packetSize();
}
inline int ICMPSocketImpl::dataSize() const
{
return _icmpPacket.getDataSize();

View File

@ -14,11 +14,10 @@
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/ICMPClient.h"
#include "Poco/Net/ICMPSocket.h"
#include "Poco/Net/NetException.h"
#include "Poco/Channel.h"
#include "Poco/Message.h"
#include "Poco/Exception.h"
#include "Poco/Format.h"
#include <sstream>
@ -62,21 +61,27 @@ int ICMPClient::ping(SocketAddress& address, int repeat) const
if (repeat <= 0) return 0;
ICMPSocket icmpSocket(_family, _dataSize, _ttl, _timeout);
SocketAddress returnAddress;
ICMPEventArgs eventArgs(address, repeat, icmpSocket.dataSize(), icmpSocket.ttl());
pingBegin.notify(this, eventArgs);
for (int i = 0; i < repeat; ++i)
{
icmpSocket.sendTo(address);
++eventArgs;
try
{
int t = icmpSocket.receiveFrom(returnAddress);
eventArgs.setReplyTime(i, t);
pingReply.notify(this, eventArgs);
int sent = icmpSocket.sendTo(address);
if (icmpSocket.packetSize() == sent)
{
SocketAddress requestAddress(address);
++eventArgs;
int t = icmpSocket.receiveFrom(address);
poco_assert (address.host() == requestAddress.host());
eventArgs.setReplyTime(i, t);
pingReply.notify(this, eventArgs);
}
else
throw ICMPException(Poco::format("Error sending ICMP packet "
"(sent=%d, expected=%d)", sent, icmpSocket.packetSize()));
}
catch (TimeoutException&)
{
@ -89,16 +94,14 @@ int ICMPClient::ping(SocketAddress& address, int repeat) const
catch (ICMPException& ex)
{
std::ostringstream os;
os << address.host().toString() << ": " << ex.what();
os << address.host().toString() << ": " << ex.displayText();
eventArgs.setError(i, os.str());
pingError.notify(this, eventArgs);
continue;
}
catch (Exception& ex)
{
std::ostringstream os;
os << ex.displayText();
eventArgs.setError(i, os.str());
eventArgs.setError(i, ex.displayText());
pingError.notify(this, eventArgs);
continue;
}
@ -125,23 +128,21 @@ int ICMPClient::ping(SocketAddress& address,
if (repeat <= 0) return 0;
ICMPSocket icmpSocket(family, dataSize, ttl, timeout);
SocketAddress returnAddress;
int received = 0;
for (int i = 0; i < repeat; ++i)
{
icmpSocket.sendTo(address);
try
{
icmpSocket.receiveFrom(returnAddress);
++received;
}
catch (TimeoutException&)
{
}
catch (ICMPException&)
{
SocketAddress requestAddress(address);
if (icmpSocket.sendTo(address) == icmpSocket.packetSize())
{
icmpSocket.receiveFrom(address);
poco_assert (address.host() == requestAddress.host());
++received;
}
}
catch (Exception&) { }
}
return received;
}

View File

@ -79,6 +79,12 @@ int ICMPSocket::dataSize() const
}
int ICMPSocket::packetSize() const
{
return static_cast<ICMPSocketImpl*>(impl())->packetSize();
}
int ICMPSocket::ttl() const
{
return static_cast<ICMPSocketImpl*>(impl())->ttl();

View File

@ -14,9 +14,7 @@
#include "Poco/Net/ICMPSocketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Timespan.h"
#include "Poco/Timestamp.h"
#include "Poco/Exception.h"
#include "Poco/Format.h"
#include "Poco/Buffer.h"
@ -36,6 +34,7 @@ ICMPSocketImpl::ICMPSocketImpl(IPAddress::Family family, int dataSize, int ttl,
_timeout(timeout)
{
setOption(IPPROTO_IP, IP_TTL, ttl);
setBlocking(true);
setReceiveTimeout(Timespan(timeout));
}
@ -60,18 +59,40 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags)
try
{
Poco::Timestamp ts;
int rc;
int expected = _icmpPacket.packetSize();
do
{
if (ts.isElapsed(_timeout))
// guard against a DoS attack
if (ts.isElapsed(_timeout)) throw TimeoutException();
buffer.clear();
SocketAddress respAddr;
rc = SocketImpl::receiveFrom(buffer.begin(), expected, respAddr, flags);
if (rc == 0) break;
if (respAddr == address)
{
// This guards against a possible DoS attack, where sending
// fake ping responses will cause an endless loop.
throw TimeoutException();
expected -= rc;
if (expected == 0)
{
if (_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)) break;
std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize);
if (!err.empty()) throw ICMPException(err);
throw ICMPException("Invalid ICMP reply");
}
}
else
{
throw ICMPException(Poco::format("Reply from an unknown IP address "
"(requested %s, received %s).",
address.host().toString(), respAddr.host().toString()));
}
SocketImpl::receiveFrom(buffer.begin(), maxPacketSize, address, flags);
}
while (!_icmpPacket.validReplyID(buffer.begin(), maxPacketSize));
while (expected && !_icmpPacket.validReplyID(buffer.begin(), maxPacketSize));
}
catch (ICMPException&)
{
throw;
}
catch (Exception&)
{
std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize);

View File

@ -32,6 +32,9 @@ using Poco::Delegate;
using Poco::AutoPtr;
Poco::FastMutex ICMPClientTest::_mutex;
ICMPClientTest::ICMPClientTest(const std::string& name):
CppUnit::TestCase(name)
{
@ -60,6 +63,8 @@ void ICMPClientTest::testPing()
assert(0 == icmpClient.ping("10.11.12.13"));
unregisterDelegates(icmpClient);
// wait for delegates to finish printing
Poco::FastMutex::ScopedLock l(_mutex);
}
@ -80,6 +85,8 @@ void ICMPClientTest::testBigPing()
assert(0 == icmpClient.ping("10.11.12.13"));
unregisterDelegates(icmpClient);
// wait for delegates to finish printing
Poco::FastMutex::ScopedLock l(_mutex);
}
@ -113,6 +120,7 @@ void ICMPClientTest::tearDown()
void ICMPClientTest::onBegin(const void* pSender, ICMPEventArgs& args)
{
Poco::FastMutex::ScopedLock l(_mutex);
std::ostringstream os;
os << std::endl << "Pinging " << args.hostName() << " [" << args.hostAddress() << "] with "
<< args.dataSize() << " bytes of data:"
@ -123,6 +131,7 @@ void ICMPClientTest::onBegin(const void* pSender, ICMPEventArgs& args)
void ICMPClientTest::onReply(const void* pSender, ICMPEventArgs& args)
{
Poco::FastMutex::ScopedLock l(_mutex);
std::ostringstream os;
os << "Reply from " << args.hostAddress()
<< " bytes=" << args.dataSize()
@ -134,6 +143,7 @@ void ICMPClientTest::onReply(const void* pSender, ICMPEventArgs& args)
void ICMPClientTest::onError(const void* pSender, ICMPEventArgs& args)
{
Poco::FastMutex::ScopedLock l(_mutex);
std::ostringstream os;
os << args.error();
std::cerr << os.str() << std::endl;
@ -142,6 +152,7 @@ void ICMPClientTest::onError(const void* pSender, ICMPEventArgs& args)
void ICMPClientTest::onEnd(const void* pSender, ICMPEventArgs& args)
{
Poco::FastMutex::ScopedLock l(_mutex);
std::ostringstream os;
int received = args.received();
os << std::endl << "--- Ping statistics for " << args.hostAddress() << " ---"

View File

@ -18,6 +18,7 @@
#include "Poco/CppUnit/TestCase.h"
#include "Poco/Net/ICMPClient.h"
#include "Poco/Net/ICMPEventArgs.h"
#include "Poco/Mutex.h"
class ICMPClientTest: public CppUnit::TestCase
@ -42,6 +43,7 @@ public:
private:
void registerDelegates(const Poco::Net::ICMPClient& icmpClient);
void unregisterDelegates(const Poco::Net::ICMPClient& icmpClient);
static Poco::FastMutex _mutex;
};