wsd: to filter clientAddress before POST action.

Change-Id: I293580f041bc46b36c57f63fe4a2c0131763b3c1
Reviewed-on: https://gerrit.libreoffice.org/50977
Reviewed-by: pranavk <pranavk@collabora.co.uk>
Tested-by: pranavk <pranavk@collabora.co.uk>
private/kendy/monitoring-rebased
YiiChang Yen 2017-12-13 13:31:29 +08:00 committed by pranavk
parent a9c053fba4
commit 910ae806ef
4 changed files with 57 additions and 5 deletions

View File

@ -64,6 +64,9 @@
<net desc="Network settings">
<proto type="string" default="all" desc="Protocol to use IPv4, IPv6 or all for both">all</proto>
<post_allow desc="Allow/deny client IP address for POST(REST)." allow="true">
<host desc="Regex pattern of ip address to allow.">192\.168\.[0-9]{1,3}\.[0-9]{1,3}</host>
</post_allow>
</net>
<ssl desc="SSL settings">

View File

@ -60,13 +60,22 @@ public:
std::shared_ptr<Socket> accept()
{
// Accept a connection (if any) and set it to non-blocking.
// We don't care about the client's address, so ignored.
const int rc = ::accept4(getFD(), nullptr, nullptr, SOCK_NONBLOCK);
// There still need the client's address to filter request from POST(call from REST) here.
struct sockaddr_in clientInfo;
socklen_t addrlen = sizeof(struct sockaddr_in);
const int rc = ::accept4(getFD(), (struct sockaddr *)&clientInfo, &addrlen, SOCK_NONBLOCK);
LOG_DBG("Accepted socket #" << rc << ", creating socket object.");
try
{
// Create a socket object using the factory.
return rc != -1 ? _sockFactory->create(rc) : std::shared_ptr<Socket>(nullptr);
if (rc != -1)
{
std::string ip = inet_ntoa(clientInfo.sin_addr);
std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
_socket->_clientAddress = ip;
return _socket;
}
return std::shared_ptr<Socket>(nullptr);
}
catch (const std::exception& ex)
{

View File

@ -95,6 +95,7 @@ public:
static const int DefaultSendBufferSize = 16 * 1024;
static const int MaximumSendBufferSize = 128 * 1024;
static std::atomic<bool> InhibitThreadChecks;
std::string _clientAddress;
enum Type { IPv4, IPv6, All };
@ -838,6 +839,11 @@ public:
recv = _bytesRecvd;
}
const std::string clientAddress()
{
return _clientAddress;
}
protected:
/// Called when a polling event is received.

View File

@ -1877,8 +1877,42 @@ private:
if (!(request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0) &&
reqPathTokens.count() > 0 && reqPathTokens[0] == "lool")
{
// All post requests have url prefix 'lool'.
handlePostRequest(request, message, disposition);
// allow/deny for POST
const auto& app = Poco::Util::Application::instance();
Util::RegexListMatcher hosts;
// Parse the host allow settings.
for (size_t i = 0; ; ++i)
{
const std::string path = "post_allow.host[" + std::to_string(i) + "]";
const auto host = app.config().getString(path, "");
if (!host.empty())
{
LOG_INF("Adding trusted POST_ALLOW host: [" << host << "].");
hosts.allow(host);
}
else if (!app.config().has(path))
{
break;
}
}
if (!hosts.match(socket->clientAddress()))
{
LOG_ERR("client address DENY: " << socket->clientAddress().c_str());
std::ostringstream oss;
oss << "HTTP/1.1 403\r\n"
<< "Date: " << Poco::DateTimeFormatter::format(Poco::Timestamp(), Poco::DateTimeFormat::HTTP_FORMAT) << "\r\n"
<< "User-Agent: " << HTTP_AGENT_STRING << "\r\n"
<< "Content-Length: 0\r\n"
<< "\r\n";
socket->send(oss.str());
socket->shutdown();
}
else
{
// All post requests have url prefix 'lool'.
handlePostRequest(request, message, disposition);
}
}
else if (reqPathTokens.count() > 2 && reqPathTokens[0] == "lool" && reqPathTokens[2] == "ws" &&
request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)