]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_websocket.cpp
Sync helpop chmodes s and p with docs
[user/henk/code/inspircd.git] / src / modules / m_websocket.cpp
index 79cabf4e58957bc01359087a8579207453c0ab87..1b6aa7b8f03dc9ef8517863452b91ceeb0ff9ad0 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-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
@@ -23,9 +25,8 @@
 #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";
@@ -33,11 +34,14 @@ static dynamic_reference_nocheck<HashProvider>* sha1;
 
 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;
@@ -327,7 +331,7 @@ class WebSocketHook : public IOHookMiddle
                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))
                                {
@@ -336,6 +340,11 @@ class WebSocketHook : public IOHookMiddle
                                }
                        }
                }
+               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)
                {
@@ -343,7 +352,7 @@ class WebSocketHook : public IOHookMiddle
                        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);
@@ -360,9 +369,20 @@ class WebSocketHook : public IOHookMiddle
                                // 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;
+                               }
+                       }
                }
 
 
@@ -425,7 +445,7 @@ class WebSocketHook : public IOHookMiddle
                                        {
                                                // 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);
@@ -518,9 +538,12 @@ class ModuleWebSocket : public Module
                }
 
                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;
        }
@@ -537,7 +560,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);
        }
 };