diff options
| author | 2019-12-08 17:38:47 +0000 | |
|---|---|---|
| committer | 2019-12-08 17:47:07 +0000 | |
| commit | 034dad6ab0df48172a70de70a9d0de4a9092112e (patch) | |
| tree | 0e852f3554dbce37d8e2e360fa099148155e8cab /src/modules/m_websocket.cpp | |
| parent | Move the nationalchars locale files to the docs directory. (diff) | |
| parent | Clean up the initialisation of the InspIRCd class. (diff) | |
| download | inspircd++-034dad6ab0df48172a70de70a9d0de4a9092112e.tar.gz inspircd++-034dad6ab0df48172a70de70a9d0de4a9092112e.tar.bz2 inspircd++-034dad6ab0df48172a70de70a9d0de4a9092112e.zip | |
Merge branch 'insp3' into master.
Diffstat (limited to 'src/modules/m_websocket.cpp')
| -rw-r--r-- | src/modules/m_websocket.cpp | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/src/modules/m_websocket.cpp b/src/modules/m_websocket.cpp index fece5fdb1..69e01914b 100644 --- a/src/modules/m_websocket.cpp +++ b/src/modules/m_websocket.cpp @@ -25,18 +25,29 @@ #include <utf8.h> -typedef std::vector<std::string> OriginList; - static const char MagicGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; static const char whitespace[] = " \t\r\n"; static dynamic_reference_nocheck<HashProvider>* sha1; -class WebSocketHookProvider : public IOHookProvider +struct WebSocketConfig { - public: + typedef std::vector<std::string> OriginList; + typedef std::vector<std::string> ProxyRanges; + + // The HTTP origins that can connect to the server. OriginList allowedorigins; + + // 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; +}; +class WebSocketHookProvider : public IOHookProvider +{ + public: + WebSocketConfig config; WebSocketHookProvider(Module* mod) : IOHookProvider(mod, "websocket", IOHookProvider::IOH_UNKNOWN, true) { @@ -110,8 +121,7 @@ class WebSocketHook : public IOHookMiddle State state; time_t lastpingpong; - OriginList& allowedorigins; - bool& sendastext; + WebSocketConfig& config; static size_t FillHeader(unsigned char* outbuf, size_t sendlength, OpCode opcode) { @@ -318,7 +328,7 @@ class WebSocketHook : public IOHookMiddle if (originheader.Find(recvq, "Origin:", 7, reqend)) { const std::string origin = originheader.ExtractValue(recvq); - for (OriginList::const_iterator iter = allowedorigins.begin(); iter != 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)) { @@ -334,6 +344,36 @@ class WebSocketHook : public IOHookMiddle return -1; } + if (!config.proxyranges.empty() && sock->type == StreamSocket::SS_USER) + { + LocalUser* luser = static_cast<UserIOHandler*>(sock)->user; + irc::sockets::sockaddrs realsa(luser->client_sa); + + HTTPHeaderFinder proxyheader; + if (proxyheader.Find(recvq, "X-Real-IP:", 10, reqend) + && irc::sockets::aptosa(proxyheader.ExtractValue(recvq), realsa.port(), realsa)) + { + // Nothing to do here. + } + else if (proxyheader.Find(recvq, "X-Forwarded-For:", 16, reqend) + && irc::sockets::aptosa(proxyheader.ExtractValue(recvq), realsa.port(), realsa)) + { + // Nothing to do here. + } + + 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); + break; + } + } + } + + HTTPHeaderFinder keyheader; if (!keyheader.Find(recvq, "Sec-WebSocket-Key:", 18, reqend)) { @@ -364,12 +404,11 @@ class WebSocketHook : public IOHookMiddle } public: - WebSocketHook(IOHookProvider* Prov, StreamSocket* sock, OriginList& AllowedOrigins, bool& SendAsText) + WebSocketHook(IOHookProvider* Prov, StreamSocket* sock, WebSocketConfig& cfg) : IOHookMiddle(Prov) , state(STATE_HTTPREQ) , lastpingpong(0) - , allowedorigins(AllowedOrigins) - , sendastext(SendAsText) + , config(cfg) { sock->AddIOHook(this); } @@ -390,7 +429,7 @@ class WebSocketHook : public IOHookMiddle if (*chr == '\n') { // We have found an entire message. Send it in its own frame. - if (sendastext) + if (config.sendastext) { // If we send messages as text then we need to ensure they are valid UTF-8. std::string encoded; @@ -451,7 +490,7 @@ class WebSocketHook : public IOHookMiddle void WebSocketHookProvider::OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { - new WebSocketHook(this, sock, allowedorigins, sendastext); + new WebSocketHook(this, sock, config); } class ModuleWebSocket : public Module @@ -473,7 +512,7 @@ class ModuleWebSocket : public Module if (tags.first == tags.second) throw ModuleException("You have loaded the websocket module but not configured any allowed origins!"); - OriginList allowedorigins; + WebSocketConfig config; for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; @@ -483,12 +522,18 @@ class ModuleWebSocket : public Module if (allow.empty()) throw ModuleException("<wsorigin:allow> is a mandatory field, at " + tag->getTagLocation()); - allowedorigins.push_back(allow); + config.allowedorigins.push_back(allow); } ConfigTag* tag = ServerInstance->Config->ConfValue("websocket"); - hookprov->sendastext = tag->getBool("sendastext", true); - hookprov->allowedorigins.swap(allowedorigins); + 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; } void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) override |
