]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_websocket.cpp
Fix the cloaking module on C++98 compilers.
[user/henk/code/inspircd.git] / src / modules / m_websocket.cpp
index 51dada299e77efbd3990918a410ce8c50a828f06..05a9ce2e82952e1ef2682db31a23406cb4ff2b72 100644 (file)
@@ -1,7 +1,9 @@
 /*
  * InspIRCd -- Internet Relay Chat Daemon
  *
- *   Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2019 iwalkalone <iwalkalone69@gmail.com>
+ *   Copyright (C) 2017-2020 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 <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 +123,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 +330,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 +346,40 @@ 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);
+
+                                       // Error if changing their IP gets them banned.
+                                       if (luser->quitting)
+                                               return -1;
+                                       break;
+                               }
+                       }
+               }
+
+
                HTTPHeaderFinder keyheader;
                if (!keyheader.Find(recvq, "Sec-WebSocket-Key:", 18, reqend))
                {
@@ -364,12 +410,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 +435,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 +496,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 +518,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 +528,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) CXX11_OVERRIDE
@@ -503,7 +554,7 @@ class ModuleWebSocket : public Module
 
        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);
        }
 };