-
Notifications
You must be signed in to change notification settings - Fork 23
/
listener.cpp
161 lines (135 loc) · 4.43 KB
/
listener.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
This file is part of FlashMQ (https://www.flashmq.org)
Copyright (C) 2021-2023 Wiebe Cazemier
FlashMQ is free software: you can redistribute it and/or modify
it under the terms of The Open Software License 3.0 (OSL-3.0).
See LICENSE for license details.
*/
#include <openssl/err.h>
#include "listener.h"
#include "utils.h"
#include "exceptions.h"
#include "logger.h"
void Listener::isValid()
{
if (isSsl())
{
if (port == 0)
{
if (websocket)
port = 4443;
else
port = 8883;
}
testSsl(sslFullchain, sslPrivkey);
testSslVerifyLocations(clientVerificationCaFile, clientVerificationCaDir, "Loading client_verification_ca_dir/client_verification_ca_file failed.");
}
else
{
if (port == 0)
{
if (websocket)
port = 8080;
else
port = 1883;
}
}
if ((!clientVerificationCaDir.empty() || !clientVerificationCaFile.empty()) && !isSsl())
{
throw ConfigFileException("X509 client verification can only be done on TLS listeners.");
}
if (port <= 0 || port > 65534)
{
throw ConfigFileException(formatString("Port nr %d is not valid", port));
}
}
bool Listener::isSsl() const
{
return (!sslFullchain.empty() || !sslPrivkey.empty());
}
bool Listener::isTcpNoDelay() const
{
return this->tcpNoDelay;
}
bool Listener::isHaProxy() const
{
return this->haproxy;
}
std::string Listener::getProtocolName() const
{
if (isSsl())
{
if (websocket)
return "SSL websocket";
else
return "SSL TCP";
}
else
{
if (websocket)
return "non-SSL websocket";
else
return "non-SSL TCP";
}
return "whoops";
}
void Listener::loadCertAndKeyFromConfig()
{
if (!isSsl())
return;
if (!sslctx)
{
sslctx = std::make_unique<SslCtxManager>();
SSL_CTX_set_options(sslctx->get(), SSL_OP_NO_SSLv3); // TODO: config option
SSL_CTX_set_options(sslctx->get(), SSL_OP_NO_TLSv1); // TODO: config option
SSL_CTX_set_mode(sslctx->get(), SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
/*
* Session cache requires active shutdown of SSL connections, which we don't have right now. We
* might as well just turn the session cache off, at least until we do have session shutdown.
*/
SSL_CTX_set_session_cache_mode(sslctx->get(), SSL_SESS_CACHE_OFF);
}
if (SSL_CTX_use_certificate_chain_file(sslctx->get(), sslFullchain.c_str()) != 1)
throw std::runtime_error("Loading cert failed. This was after test loading the certificate, so is very unexpected.");
if (SSL_CTX_use_PrivateKey_file(sslctx->get(), sslPrivkey.c_str(), SSL_FILETYPE_PEM) != 1)
throw std::runtime_error("Loading key failed. This was after test loading the certificate, so is very unexpected.");
{
const char *ca_file = clientVerificationCaFile.empty() ? nullptr : clientVerificationCaFile.c_str();
const char *ca_dir = clientVerificationCaDir.empty() ? nullptr : clientVerificationCaDir.c_str();
if (ca_file || ca_dir)
{
if (SSL_CTX_load_verify_locations(sslctx->get(), ca_file, ca_dir) != 1)
{
ERR_print_errors_cb(logSslError, NULL);
throw std::runtime_error("Loading client_verification_ca_dir/client_verification_ca_file failed. "
"This was after test loading the certificate, so is very unexpected.");
}
}
}
}
X509ClientVerification Listener::getX509ClientVerficationMode() const
{
X509ClientVerification result = X509ClientVerification::None;
const bool clientCADefined = !clientVerificationCaDir.empty() || !clientVerificationCaFile.empty();
if (clientCADefined)
result = X509ClientVerification::X509IsEnough;
if (result >= X509ClientVerification::X509IsEnough && clientVerifictionStillDoAuthn)
result = X509ClientVerification::X509AndUsernamePassword;
return result;
}
std::string Listener::getBindAddress(ListenerProtocol p)
{
if (p == ListenerProtocol::IPv4)
{
if (inet4BindAddress.empty())
return "0.0.0.0";
return inet4BindAddress;
}
if (p == ListenerProtocol::IPv6)
{
if (inet6BindAddress.empty())
return "::";
return inet6BindAddress;
}
return "";
}