/*
* InspIRCd -- Internet Relay Chat Daemon
*
- * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2019 iwalkalone <iwalkalone69@gmail.com>
+ * Copyright (C) 2017-2021 Sadie Powell <sadie@witchery.services>
+ * Copyright (C) 2016-2017 Attila Molnar <attilamolnar@hush.com>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
#include "iohook.h"
#include "modules/hash.h"
-#include <utf8.h>
-
-typedef std::vector<std::string> OriginList;
+#define UTF_CPP_CPLUSPLUS 199711L
+#include <unchecked.h>
static const char MagicGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
static const char whitespace[] = " \t\r\n";
struct WebSocketConfig
{
+ typedef std::vector<std::string> OriginList;
+ typedef std::vector<std::string> ProxyRanges;
+
// The HTTP origins that can connect to the server.
OriginList allowedorigins;
- // Whether to trust the X-Real-IP or X-Forwarded-For headers.
- bool behindproxy;
+ // The IP ranges which send trustworthy X-Real-IP or X-Forwarded-For headers.
+ ProxyRanges proxyranges;
// Whether to send as UTF-8 text instead of binary data.
bool sendastext;
if (originheader.Find(recvq, "Origin:", 7, reqend))
{
const std::string origin = originheader.ExtractValue(recvq);
- for (OriginList::const_iterator iter = config.allowedorigins.begin(); iter != config.allowedorigins.end(); ++iter)
+ for (WebSocketConfig::OriginList::const_iterator iter = config.allowedorigins.begin(); iter != config.allowedorigins.end(); ++iter)
{
if (InspIRCd::Match(origin, *iter, ascii_case_insensitive_map))
{
}
}
}
+ else
+ {
+ FailHandshake(sock, "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n", "WebSocket: Received HTTP request that did not send the Origin header");
+ return -1;
+ }
if (!allowedorigin)
{
return -1;
}
- if (config.behindproxy && sock->type == StreamSocket::SS_USER)
+ if (!config.proxyranges.empty() && sock->type == StreamSocket::SS_USER)
{
LocalUser* luser = static_cast<UserIOHandler*>(sock)->user;
irc::sockets::sockaddrs realsa(luser->client_sa);
// Nothing to do here.
}
- // Give the user their real IP address.
- if (realsa != luser->client_sa)
- luser->SetClientIP(realsa);
+ for (WebSocketConfig::ProxyRanges::const_iterator iter = config.proxyranges.begin(); iter != config.proxyranges.end(); ++iter)
+ {
+ if (InspIRCd::MatchCIDR(luser->GetIPString(), *iter, ascii_case_insensitive_map))
+ {
+ // Give the user their real IP address.
+ if (realsa != luser->client_sa)
+ luser->SetClientIP(realsa);
+
+ // Error if changing their IP gets them banned.
+ if (luser->quitting)
+ return -1;
+ break;
+ }
+ }
}
{
// If we send messages as text then we need to ensure they are valid UTF-8.
std::string encoded;
- utf8::replace_invalid(message.begin(), message.end(), std::back_inserter(encoded));
+ utf8::unchecked::replace_invalid(message.begin(), message.end(), std::back_inserter(encoded));
mysendq.push_back(PrepareSendQElem(encoded.length(), OP_TEXT));
mysendq.push_back(encoded);
}
ConfigTag* tag = ServerInstance->Config->ConfValue("websocket");
- config.behindproxy = tag->getBool("behindproxy");
config.sendastext = tag->getBool("sendastext", true);
+ irc::spacesepstream proxyranges(tag->getString("proxyranges"));
+ for (std::string proxyrange; proxyranges.GetToken(proxyrange); )
+ config.proxyranges.push_back(proxyrange);
+
// Everything is okay; apply the new config.
hookprov->config = config;
}
Version GetVersion() CXX11_OVERRIDE
{
- return Version("Provides RFC 6455 WebSocket support", VF_VENDOR);
+ return Version("Allows WebSocket clients to connect to the IRC server.", VF_VENDOR);
}
};