aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Sadie Powell2021-09-23 00:24:36 +0100
committerGravatar Sadie Powell2021-09-23 00:24:36 +0100
commitb5d7c564282f0b25458c3ca9dbd6aa9eec7d60d5 (patch)
treef4b687e3ca0c5edfefd3ae7cdd3329012a603486
parentMerge branch 'insp3' into master. (diff)
parentUse CXX11_OVERRIDE instead of the override keyword. (diff)
Merge branch 'insp3' into master.
-rw-r--r--docs/conf/modules.conf.example16
-rw-r--r--docs/conf/opers.conf.example1
-rw-r--r--include/iohook.h3
-rw-r--r--include/modules/ssl.h19
-rw-r--r--src/modules/extra/m_ssl_gnutls.cpp22
-rw-r--r--src/modules/extra/m_ssl_mbedtls.cpp31
-rw-r--r--src/modules/extra/m_ssl_openssl.cpp34
-rw-r--r--src/modules/m_haproxy.cpp5
-rw-r--r--src/modules/m_repeat.cpp3
-rw-r--r--src/modules/m_websocket.cpp46
10 files changed, 114 insertions, 66 deletions
diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example
index 20ead6fd9..40391d71b 100644
--- a/docs/conf/modules.conf.example
+++ b/docs/conf/modules.conf.example
@@ -2361,19 +2361,19 @@
# Requires SHA-1 hash support available in the sha1 module.
#<module name="websocket">
#
+# defaultmode: The default frame mode if a client does not send a
+# WebSocket subprotocol. Potential values are "text" to
+# encode messages as UTF-8 text frames, "binary" to send
+# messages as raw binary frames, or "reject" to close
+# connections which do not request a subprotocol. Defaults
+# to "text".
# proxyranges: A space-delimited list of glob or CIDR matches to trust
# the X-Real-IP or X-Forwarded-For headers from. If enabled
# the server will use the IP address specified by those HTTP
# headers. You should NOT enable this unless you are using
# a HTTP proxy like nginx as it will allow IP spoofing.
-# sendastext: Whether to re-encode messages as UTF-8 before sending to
-# WebSocket clients. This is recommended as the WebSocket
-# protocol requires all text frames to be sent as UTF-8.
-# If you do not have this enabled messages will be sent as
-# binary frames instead. Clients can override this using a
-# WebSocket subprotocol. See the docs page for more info.
-#<websocket proxyranges="192.0.2.0/24 198.51.100.*"
-# sendastext="yes">
+#<websocket defaultmode="text"
+# proxyranges="192.0.2.0/24 198.51.100.*">
#
# If you use the websocket module you MUST specify one or more origins
# which are allowed to connect to the server. You should set this as
diff --git a/docs/conf/opers.conf.example b/docs/conf/opers.conf.example
index 6aa05c792..36133f9dc 100644
--- a/docs/conf/opers.conf.example
+++ b/docs/conf/opers.conf.example
@@ -30,6 +30,7 @@
# - channels/ignore-noctcp: allows opers with this priv to send a CTCP to a +C channel.
# - channels/ignore-nonicks: allows opers with this priv to change their nick when on a +N channel.
# - channels/ignore-opmoderated: allows opers with this priv to ignore +U.
+ # - channels/ignore-repeat: allows opers with this priv to be immune to repeat punishment on a +E channel.
# - channels/restricted-create: allows opers with this priv to create channels if the restrictchans module is loaded.
# - users/flood/increased-buffers: allows opers with this priv to send and receive data without worrying about being disconnected for exceeding limits (*NOTE).
# - users/flood/no-fakelag: prevents opers from being penalized with fake lag for flooding (*NOTE).
diff --git a/include/iohook.h b/include/iohook.h
index 968621323..8055667a8 100644
--- a/include/iohook.h
+++ b/include/iohook.h
@@ -80,6 +80,9 @@ class IOHook : public Cullable
IOHook(std::shared_ptr<IOHookProvider> provider)
: prov(provider) { }
+ /** Determines whether this I/O hook is ready to send and receive data. */
+ virtual bool IsHookReady() const { return true; }
+
/**
* Called when the hooked socket has data to write, or when the socket engine returns it as writable
* @param sock Hooked socket
diff --git a/include/modules/ssl.h b/include/modules/ssl.h
index 66d29aca1..f616b39c8 100644
--- a/include/modules/ssl.h
+++ b/include/modules/ssl.h
@@ -153,10 +153,26 @@ public:
class SSLIOHook : public IOHook
{
protected:
+ /** An enumeration of possible TLS (SSL) socket states. */
+ enum Status
+ {
+ /** The SSL socket has just been opened or has been closed. */
+ STATUS_NONE,
+
+ /** The SSL socket is currently handshaking. */
+ STATUS_HANDSHAKING,
+
+ /** The SSL handshake has completed and data can be sent. */
+ STATUS_OPEN
+ };
+
/** Peer TLS certificate, set by the TLS module
*/
reference<ssl_cert> certificate;
+ /** The status of the TLS (SSL) connection. */
+ Status status = STATUS_NONE;
+
/** Reduce elements in a send queue by appending later elements to the first element until there are no more
* elements to append or a desired length is reached
* @param sendq SendQ to work on
@@ -230,6 +246,9 @@ class SSLIOHook : public IOHook
* returns True if the server name was retrieved; otherwise, false.
*/
virtual bool GetServerName(std::string& out) const = 0;
+
+ /** @copydoc IOHook::IsHookReady */
+ bool IsHookReady() const override { return status == STATUS_OPEN; }
};
/** Helper functions for obtaining TLS client certificates and key fingerprints
diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp
index bb90538f7..79a9747d6 100644
--- a/src/modules/extra/m_ssl_gnutls.cpp
+++ b/src/modules/extra/m_ssl_gnutls.cpp
@@ -53,8 +53,6 @@
# pragma comment(lib, "libgnutls-30.lib")
#endif
-enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_HANDSHAKEN };
-
#if INSPIRCD_GNUTLS_HAS_VERSION(3, 3, 5)
#define INSPIRCD_GNUTLS_HAS_RECV_PACKET
#endif
@@ -611,7 +609,6 @@ class GnuTLSIOHook : public SSLIOHook
{
private:
gnutls_session_t sess = nullptr;
- issl_status status = ISSL_NONE;
#ifdef INSPIRCD_GNUTLS_HAS_CORK
size_t gbuffersize = 0;
#endif
@@ -625,7 +622,7 @@ class GnuTLSIOHook : public SSLIOHook
}
sess = NULL;
certificate = NULL;
- status = ISSL_NONE;
+ status = STATUS_NONE;
}
// Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed
@@ -638,7 +635,7 @@ class GnuTLSIOHook : public SSLIOHook
if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
{
// Handshake needs resuming later, read() or write() would have blocked.
- this->status = ISSL_HANDSHAKING;
+ this->status = STATUS_HANDSHAKING;
if (gnutls_record_get_direction(this->sess) == 0)
{
@@ -663,7 +660,7 @@ class GnuTLSIOHook : public SSLIOHook
else
{
// Change the session state
- this->status = ISSL_HANDSHAKEN;
+ this->status = STATUS_OPEN;
VerifyCertificate();
@@ -765,9 +762,9 @@ info_done_dealloc:
// Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error
int PrepareIO(StreamSocket* sock)
{
- if (status == ISSL_HANDSHAKEN)
+ if (status == STATUS_OPEN)
return 1;
- else if (status == ISSL_HANDSHAKING)
+ else if (status == STATUS_HANDSHAKING)
{
// The handshake isn't finished, try to finish it
return Handshake(sock);
@@ -915,7 +912,7 @@ info_done_dealloc:
if (prepret <= 0)
return prepret;
- // If we resumed the handshake then this->status will be ISSL_HANDSHAKEN.
+ // If we resumed the handshake then this->status will be STATUS_OPEN.
{
GnuTLS::DataReader reader(sess);
ssize_t ret = reader.ret();
@@ -1011,7 +1008,7 @@ info_done_dealloc:
void GetCiphersuite(std::string& out) const override
{
- if (!IsHandshakeDone())
+ if (!IsHookReady())
return;
out.append(UnknownIfNULL(gnutls_protocol_get_name(gnutls_protocol_get_version(sess)))).push_back('-');
out.append(UnknownIfNULL(gnutls_kx_get_name(gnutls_kx_get(sess)))).push_back('-');
@@ -1039,7 +1036,6 @@ info_done_dealloc:
}
GnuTLS::Profile& GetProfile();
- bool IsHandshakeDone() const { return (status == ISSL_HANDSHAKEN); }
};
int GnuTLS::X509Credentials::cert_callback(gnutls_session_t sess, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, gnutls_retr2_st* st)
@@ -1181,7 +1177,7 @@ class ModuleSSLGnuTLS : public Module
}
catch (ModuleException& ex)
{
- ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings.");
+ ServerInstance->SNO.WriteToSnoMask('a', "Failed to reload the GnuTLS TLS (SSL) profiles. " + ex.GetReason());
}
}
@@ -1208,7 +1204,7 @@ class ModuleSSLGnuTLS : public Module
ModResult OnCheckReady(LocalUser* user) override
{
const GnuTLSIOHook* const iohook = static_cast<GnuTLSIOHook*>(user->eh.GetModHook(this));
- if ((iohook) && (!iohook->IsHandshakeDone()))
+ if ((iohook) && (!iohook->IsHookReady()))
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
diff --git a/src/modules/extra/m_ssl_mbedtls.cpp b/src/modules/extra/m_ssl_mbedtls.cpp
index 2c95da3c7..9c025ad56 100644
--- a/src/modules/extra/m_ssl_mbedtls.cpp
+++ b/src/modules/extra/m_ssl_mbedtls.cpp
@@ -523,25 +523,18 @@ namespace mbedTLS
class mbedTLSIOHook : public SSLIOHook
{
- enum Status
- {
- ISSL_NONE,
- ISSL_HANDSHAKING,
- ISSL_HANDSHAKEN
- };
-
+ private:
mbedtls_ssl_context sess;
- Status status;
void CloseSession()
{
- if (status == ISSL_NONE)
+ if (status == STATUS_NONE)
return;
mbedtls_ssl_close_notify(&sess);
mbedtls_ssl_free(&sess);
certificate = NULL;
- status = ISSL_NONE;
+ status = STATUS_NONE;
}
// Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed
@@ -551,7 +544,7 @@ class mbedTLSIOHook : public SSLIOHook
if (ret == 0)
{
// Change the session state
- this->status = ISSL_HANDSHAKEN;
+ this->status = STATUS_OPEN;
VerifyCertificate();
@@ -561,7 +554,7 @@ class mbedTLSIOHook : public SSLIOHook
return 1;
}
- this->status = ISSL_HANDSHAKING;
+ this->status = STATUS_HANDSHAKING;
if (ret == MBEDTLS_ERR_SSL_WANT_READ)
{
SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
@@ -581,9 +574,9 @@ class mbedTLSIOHook : public SSLIOHook
// Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error
int PrepareIO(StreamSocket* sock)
{
- if (status == ISSL_HANDSHAKEN)
+ if (status == STATUS_OPEN)
return 1;
- else if (status == ISSL_HANDSHAKING)
+ else if (status == STATUS_HANDSHAKING)
{
// The handshake isn't finished, try to finish it
return Handshake(sock);
@@ -685,7 +678,6 @@ class mbedTLSIOHook : public SSLIOHook
public:
mbedTLSIOHook(std::shared_ptr<IOHookProvider> hookprov, StreamSocket* sock, bool isserver)
: SSLIOHook(hookprov)
- , status(ISSL_NONE)
{
mbedtls_ssl_init(&sess);
if (isserver)
@@ -711,7 +703,7 @@ class mbedTLSIOHook : public SSLIOHook
if (prepret <= 0)
return prepret;
- // If we resumed the handshake then this->status will be ISSL_HANDSHAKEN.
+ // If we resumed the handshake then this->status will be STATUS_OPEN.
char* const readbuf = ServerInstance->GetReadBuffer();
const size_t readbufsize = ServerInstance->Config->NetBufferSize;
int ret = mbedtls_ssl_read(&sess, reinterpret_cast<unsigned char*>(readbuf), readbufsize);
@@ -802,7 +794,7 @@ class mbedTLSIOHook : public SSLIOHook
void GetCiphersuite(std::string& out) const override
{
- if (!IsHandshakeDone())
+ if (!IsHookReady())
return;
out.append(mbedtls_ssl_get_version(&sess)).push_back('-');
@@ -822,7 +814,6 @@ class mbedTLSIOHook : public SSLIOHook
}
mbedTLS::Profile& GetProfile();
- bool IsHandshakeDone() const { return (status == ISSL_HANDSHAKEN); }
};
class mbedTLSIOHookProvider : public SSLIOHookProvider
@@ -952,7 +943,7 @@ class ModuleSSLmbedTLS : public Module
}
catch (ModuleException& ex)
{
- ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings.");
+ ServerInstance->SNO.WriteToSnoMask('a', "Failed to reload the mbedTLS TLS profiles. " + ex.GetReason());
}
}
@@ -973,7 +964,7 @@ class ModuleSSLmbedTLS : public Module
ModResult OnCheckReady(LocalUser* user) override
{
const mbedTLSIOHook* const iohook = static_cast<mbedTLSIOHook*>(user->eh.GetModHook(this));
- if ((iohook) && (!iohook->IsHandshakeDone()))
+ if ((iohook) && (!iohook->IsHookReady()))
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp
index 75adbd4e3..480a45ce1 100644
--- a/src/modules/extra/m_ssl_openssl.cpp
+++ b/src/modules/extra/m_ssl_openssl.cpp
@@ -52,8 +52,6 @@
# pragma comment(lib, "libeay32.lib")
#endif
-enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
-
static bool SelfSigned = false;
static int exdataindex;
@@ -501,7 +499,6 @@ class OpenSSLIOHook : public SSLIOHook
{
private:
SSL* sess;
- issl_status status;
bool data_to_write = false;
// Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed
@@ -516,13 +513,13 @@ class OpenSSLIOHook : public SSLIOHook
if (err == SSL_ERROR_WANT_READ)
{
SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
- this->status = ISSL_HANDSHAKING;
+ this->status = STATUS_HANDSHAKING;
return 0;
}
else if (err == SSL_ERROR_WANT_WRITE)
{
SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
- this->status = ISSL_HANDSHAKING;
+ this->status = STATUS_HANDSHAKING;
return 0;
}
else
@@ -536,7 +533,7 @@ class OpenSSLIOHook : public SSLIOHook
// Handshake complete.
VerifyCertificate();
- status = ISSL_OPEN;
+ status = STATUS_OPEN;
SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
@@ -558,7 +555,7 @@ class OpenSSLIOHook : public SSLIOHook
}
sess = NULL;
certificate = NULL;
- status = ISSL_NONE;
+ status = STATUS_NONE;
}
void VerifyCertificate()
@@ -621,14 +618,14 @@ class OpenSSLIOHook : public SSLIOHook
void SSLInfoCallback(int where, int rc)
{
- if ((where & SSL_CB_HANDSHAKE_START) && (status == ISSL_OPEN))
+ if ((where & SSL_CB_HANDSHAKE_START) && (status == STATUS_OPEN))
{
if (GetProfile().AllowRenegotiation())
return;
// The other side is trying to renegotiate, kill the connection and change status
- // to ISSL_NONE so CheckRenego() closes the session
- status = ISSL_NONE;
+ // to STATUS_NONE so CheckRenego() closes the session
+ status = STATUS_NONE;
BIO* bio = SSL_get_rbio(sess);
EventHandler* eh = static_cast<StreamSocket*>(BIO_get_data(bio));
SocketEngine::Shutdown(eh, 2);
@@ -637,7 +634,7 @@ class OpenSSLIOHook : public SSLIOHook
bool CheckRenego(StreamSocket* sock)
{
- if (status != ISSL_NONE)
+ if (status != STATUS_NONE)
return true;
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Session %p killed, attempted to renegotiate", (void*)sess);
@@ -649,9 +646,9 @@ class OpenSSLIOHook : public SSLIOHook
// Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error
int PrepareIO(StreamSocket* sock)
{
- if (status == ISSL_OPEN)
+ if (status == STATUS_OPEN)
return 1;
- else if (status == ISSL_HANDSHAKING)
+ else if (status == STATUS_HANDSHAKING)
{
// The handshake isn't finished, try to finish it
return Handshake(sock);
@@ -668,7 +665,7 @@ class OpenSSLIOHook : public SSLIOHook
OpenSSLIOHook(std::shared_ptr<IOHookProvider> hookprov, StreamSocket* sock, SSL* session)
: SSLIOHook(hookprov)
, sess(session)
- , status(ISSL_NONE)
+ , data_to_write(false)
{
// Create BIO instance and store a pointer to the socket in it which will be used by the read and write functions
BIO* bio = BIO_new(biomethods);
@@ -692,7 +689,7 @@ class OpenSSLIOHook : public SSLIOHook
if (prepret <= 0)
return prepret;
- // If we resumed the handshake then this->status will be ISSL_OPEN
+ // If we resumed the handshake then this->status will be STATUS_OPEN
{
ERR_clear_error();
char* buffer = ServerInstance->GetReadBuffer();
@@ -811,7 +808,7 @@ class OpenSSLIOHook : public SSLIOHook
void GetCiphersuite(std::string& out) const override
{
- if (!IsHandshakeDone())
+ if (!IsHookReady())
return;
out.append(SSL_get_version(sess)).push_back('-');
out.append(SSL_get_cipher(sess));
@@ -827,7 +824,6 @@ class OpenSSLIOHook : public SSLIOHook
return true;
}
- bool IsHandshakeDone() const { return (status == ISSL_OPEN); }
OpenSSL::Profile& GetProfile();
};
@@ -1009,7 +1005,7 @@ class ModuleSSLOpenSSL : public Module
}
catch (ModuleException& ex)
{
- ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings.");
+ ServerInstance->SNO.WriteToSnoMask('a', "Failed to reload the OpenSSL TLS (SSL) profiles. " + ex.GetReason());
}
}
@@ -1031,7 +1027,7 @@ class ModuleSSLOpenSSL : public Module
ModResult OnCheckReady(LocalUser* user) override
{
const OpenSSLIOHook* const iohook = static_cast<OpenSSLIOHook*>(user->eh.GetModHook(this));
- if ((iohook) && (!iohook->IsHandshakeDone()))
+ if ((iohook) && (!iohook->IsHookReady()))
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
diff --git a/src/modules/m_haproxy.cpp b/src/modules/m_haproxy.cpp
index b300a15d6..68c99eee1 100644
--- a/src/modules/m_haproxy.cpp
+++ b/src/modules/m_haproxy.cpp
@@ -384,6 +384,11 @@ class HAProxyHook : public IOHookMiddle
sock->AddIOHook(this);
}
+ bool IsHookReady() const override
+ {
+ return state == HPS_CONNECTED;
+ }
+
ssize_t OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& uppersendq) override
{
// We don't need to implement this.
diff --git a/src/modules/m_repeat.cpp b/src/modules/m_repeat.cpp
index af53fb6c2..2b1a82eec 100644
--- a/src/modules/m_repeat.cpp
+++ b/src/modules/m_repeat.cpp
@@ -388,6 +388,9 @@ class RepeatModule : public Module
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
+ if (user->HasPrivPermission("channels/ignore-repeat"))
+ return MOD_RES_PASSTHRU;
+
if (rm.MatchLine(memb, settings, details.text))
{
if (settings->Action == ChannelSettings::ACT_BLOCK)
diff --git a/src/modules/m_websocket.cpp b/src/modules/m_websocket.cpp
index 6cf721424..242ecc372 100644
--- a/src/modules/m_websocket.cpp
+++ b/src/modules/m_websocket.cpp
@@ -35,17 +35,29 @@ static dynamic_reference_nocheck<HashProvider>* sha1;
struct WebSocketConfig
{
+ enum DefaultMode
+ {
+ // Reject connections if a subprotocol is not requested.
+ DM_REJECT,
+
+ // Use binary frames if a subprotocol is not requested.
+ DM_BINARY,
+
+ // Use UTF-8 text frames if a subprotocol is not requested.
+ DM_TEXT
+ };
+
typedef std::vector<std::string> OriginList;
typedef std::vector<std::string> ProxyRanges;
// The HTTP origins that can connect to the server.
OriginList allowedorigins;
+ // The method to use if a subprotocol is not negotiated.
+ DefaultMode defaultmode;
+
// 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
@@ -406,8 +418,10 @@ class WebSocketHook : public IOHookMiddle
irc::spacesepstream protostream(protocolheader.ExtractValue(recvq));
for (std::string proto; protostream.GetToken(proto); )
{
+ bool is_binary = stdalgo::string::equalsci(proto, "binary.inspircd.org");
bool is_text = stdalgo::string::equalsci(proto, "text.inspircd.org");
- if (stdalgo::string::equalsci(proto, "binary.inspircd.org") || is_text)
+
+ if (is_binary || is_text)
{
selectedproto = proto;
sendastext = is_text;
@@ -416,6 +430,12 @@ class WebSocketHook : public IOHookMiddle
}
}
+ if (selectedproto.empty() && config.defaultmode == WebSocketConfig::DM_REJECT)
+ {
+ FailHandshake(sock, "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n", "WebSocket: Received HTTP request that did not send the Sec-WebSocket-Protocol header");
+ return -1;
+ }
+
HTTPHeaderFinder keyheader;
if (!keyheader.Find(recvq, "Sec-WebSocket-Key:", 18, reqend))
{
@@ -452,11 +472,16 @@ class WebSocketHook : public IOHookMiddle
WebSocketHook(std::shared_ptr<IOHookProvider> Prov, StreamSocket* sock, WebSocketConfig& cfg)
: IOHookMiddle(Prov)
, config(cfg)
- , sendastext(cfg.sendastext)
+ , sendastext(config.defaultmode != WebSocketConfig::DM_BINARY)
{
sock->AddIOHook(this);
}
+ bool IsHookReady() const override
+ {
+ return state == STATE_ESTABLISHED;
+ }
+
ssize_t OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& uppersendq) override
{
StreamSocket::SendQueue& mysendq = GetSendQ();
@@ -570,7 +595,16 @@ class ModuleWebSocket : public Module
}
auto tag = ServerInstance->Config->ConfValue("websocket");
- config.sendastext = tag->getBool("sendastext", true);
+
+ const std::string defaultmodestr = tag->getString("defaultmode", tag->getBool("sendastext", true) ? "text" : "binary", 1);
+ if (stdalgo::string::equalsci(defaultmodestr, "reject"))
+ config.defaultmode = WebSocketConfig::DM_REJECT;
+ else if (stdalgo::string::equalsci(defaultmodestr, "binary"))
+ config.defaultmode = WebSocketConfig::DM_BINARY;
+ else if (stdalgo::string::equalsci(defaultmodestr, "text"))
+ config.defaultmode = WebSocketConfig::DM_TEXT;
+ else
+ throw ModuleException(defaultmodestr + " is an invalid value for <websocket:defaultmode>; acceptable values are 'binary', 'text' and 'reject', at " + tag->source.str());
irc::spacesepstream proxyranges(tag->getString("proxyranges"));
for (std::string proxyrange; proxyranges.GetToken(proxyrange); )