1 // message_port.cpp
2
3
4 /**
5 * Copyright (C) 2018-present MongoDB, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the Server Side Public License, version 1,
9 * as published by MongoDB, Inc.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * Server Side Public License for more details.
15 *
16 * You should have received a copy of the Server Side Public License
17 * along with this program. If not, see
18 * <http://www.mongodb.com/licensing/server-side-public-license>.
19 *
20 * As a special exception, the copyright holders give permission to link the
21 * code of portions of this program with the OpenSSL library under certain
22 * conditions as described in each individual source file and distribute
23 * linked combinations including the program with the OpenSSL library. You
24 * must comply with the Server Side Public License in all respects for
25 * all of the code used other than as permitted herein. If you modify file(s)
26 * with this exception, you may extend this exception to your version of the
27 * file(s), but you are not obligated to do so. If you do not wish to do so,
28 * delete this exception statement from your version. If you delete this
29 * exception statement from all source files in the program, then also delete
30 * it in the license file.
31 */
32
33 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork
34
35 #include "mongo/platform/basic.h"
36
37 #include "mongo/util/net/message_port.h"
38
39 #include <fcntl.h>
40 #include <time.h>
41
42 #include "mongo/config.h"
43 #include "mongo/util/allocator.h"
44 #include "mongo/util/background.h"
45 #include "mongo/util/log.h"
46 #include "mongo/util/net/listen.h"
47 #include "mongo/util/net/message.h"
48 #include "mongo/util/net/socket_exception.h"
49 #include "mongo/util/net/ssl_manager.h"
50 #include "mongo/util/net/ssl_options.h"
51 #include "mongo/util/scopeguard.h"
52 #include "mongo/util/time_support.h"
53
54 #ifndef _WIN32
55 #ifndef __sun
56 #include <ifaddrs.h>
57 #endif
58 #include <sys/resource.h>
59 #include <sys/stat.h>
60 #endif
61
62 namespace mongo {
63
64 using std::shared_ptr;
65 using std::string;
66
67 /* messagingport -------------------------------------------------------------- */
68
MessagingPort(int fd,const SockAddr & remote)69 MessagingPort::MessagingPort(int fd, const SockAddr& remote)
70 : MessagingPort(std::make_shared<Socket>(fd, remote)) {}
71
MessagingPort(double timeout,logger::LogSeverity ll)72 MessagingPort::MessagingPort(double timeout, logger::LogSeverity ll)
73 : MessagingPort(std::make_shared<Socket>(timeout, ll)) {}
74
MessagingPort(std::shared_ptr<Socket> sock)75 MessagingPort::MessagingPort(std::shared_ptr<Socket> sock)
76 : _x509PeerInfo(), _connectionId(), _tag(), _psock(std::move(sock)) {
77 SockAddr sa = _psock->remoteAddr();
78 _remoteParsed = HostAndPort(sa.getAddr(), sa.getPort());
79 }
80
setTimeout(Milliseconds millis)81 void MessagingPort::setTimeout(Milliseconds millis) {
82 double timeout = double(millis.count()) / 1000;
83 _psock->setTimeout(timeout);
84 }
85
shutdown()86 void MessagingPort::shutdown() {
87 _psock->close();
88 }
89
~MessagingPort()90 MessagingPort::~MessagingPort() {
91 shutdown();
92 }
93
recv(Message & m)94 bool MessagingPort::recv(Message& m) {
95 try {
96 #ifdef MONGO_CONFIG_SSL
97 again:
98 #endif
99 MSGHEADER::Value header;
100 _psock->recv((char*)&header, sizeof(header));
101 int len = header.constView().getMessageLength();
102
103 if (len == 542393671) {
104 // an http GET
105 string msg =
106 "It looks like you are trying to access MongoDB over HTTP on the native driver "
107 "port.\n";
108 LOG(_psock->getLogLevel()) << msg;
109 std::stringstream ss;
110 ss << "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: "
111 "text/plain\r\nContent-Length: "
112 << msg.size() << "\r\n\r\n"
113 << msg;
114 string s = ss.str();
115 send(s.c_str(), s.size(), "http");
116 return false;
117 }
118 // If responseTo is not 0 or -1 for first packet assume SSL
119 else if (_psock->isAwaitingHandshake()) {
120 #ifndef MONGO_CONFIG_SSL
121 if (header.constView().getResponseToMsgId() != 0 &&
122 header.constView().getResponseToMsgId() != -1) {
123 uasserted(17133,
124 "SSL handshake requested, SSL feature not available in this build");
125 }
126 #else
127 if (header.constView().getResponseToMsgId() != 0 &&
128 header.constView().getResponseToMsgId() != -1) {
129 uassert(17132,
130 "SSL handshake received but server is started without SSL support",
131 sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled);
132
133 auto tlsAlert = checkTLSRequest(
134 ConstDataRange(reinterpret_cast<const char*>(&header), sizeof(header)));
135
136 if (tlsAlert) {
137 _psock->send(reinterpret_cast<const char*>(tlsAlert->data()),
138 tlsAlert->size(),
139 "tls protocol mismatch");
140 log() << "SSL handshake failed, as client requested disabled protocol";
141 return false;
142 }
143
144 setX509PeerInfo(
145 _psock->doSSLHandshake(reinterpret_cast<const char*>(&header), sizeof(header)));
146 LOG(1) << "new ssl connection, SNI server name [" << _psock->getSNIServerName()
147 << "]";
148 _psock->setHandshakeReceived();
149
150 goto again;
151 }
152
153 auto sslMode = sslGlobalParams.sslMode.load();
154
155 uassert(17189,
156 "The server is configured to only allow SSL connections",
157 sslMode != SSLParams::SSLMode_requireSSL);
158
159 // For users attempting to upgrade their applications from no SSL to SSL, provide
160 // information about connections that still aren't using SSL (but only once per
161 // connection)
162 if (!sslGlobalParams.disableNonSSLConnectionLogging &&
163 (sslMode == SSLParams::SSLMode_preferSSL)) {
164 LOG(0) << "SSL mode is set to 'preferred' and connection " << _connectionId
165 << " to " << remote() << " is not using SSL.";
166 }
167
168 #endif // MONGO_CONFIG_SSL
169 }
170 if (static_cast<size_t>(len) < sizeof(header) ||
171 static_cast<size_t>(len) > MaxMessageSizeBytes) {
172 LOG(0) << "recv(): message len " << len << " is invalid. "
173 << "Min " << sizeof(header) << " Max: " << MaxMessageSizeBytes;
174 return false;
175 }
176
177 _psock->setHandshakeReceived();
178
179 auto buf = SharedBuffer::allocate(len);
180 MsgData::View md = buf.get();
181 memcpy(md.view2ptr(), &header, sizeof(header));
182
183 const int left = len - sizeof(header);
184 if (left)
185 _psock->recv(md.data(), left);
186
187 m.setData(std::move(buf));
188 return true;
189
190 } catch (const SocketException& e) {
191 logger::LogSeverity severity = _psock->getLogLevel();
192 if (!e.shouldPrint())
193 severity = severity.lessSevere();
194 LOG(severity) << "SocketException: remote: " << remote() << " error: " << e;
195 m.reset();
196 return false;
197 }
198 }
199
call(const Message & toSend,Message & response)200 bool MessagingPort::call(const Message& toSend, Message& response) {
201 say(toSend);
202 bool success = recv(response);
203 if (success) {
204 invariant(!response.empty());
205 if (response.header().getResponseToMsgId() != toSend.header().getId()) {
206 response.reset();
207 uasserted(40134, "Response ID did not match the sent message ID.");
208 }
209 }
210 return success;
211 }
212
say(const Message & toSend)213 void MessagingPort::say(const Message& toSend) {
214 invariant(!toSend.empty());
215 auto buf = toSend.buf();
216 if (buf) {
217 send(buf, MsgData::ConstView(buf).getLen(), "say");
218 }
219 }
220
remote() const221 HostAndPort MessagingPort::remote() const {
222 return _remoteParsed;
223 }
224
remoteAddr() const225 SockAddr MessagingPort::remoteAddr() const {
226 return _psock->remoteAddr();
227 }
228
localAddr() const229 SockAddr MessagingPort::localAddr() const {
230 return _psock->localAddr();
231 }
232
setX509PeerInfo(SSLPeerInfo x509PeerInfo)233 void MessagingPort::setX509PeerInfo(SSLPeerInfo x509PeerInfo) {
234 _x509PeerInfo = std::move(x509PeerInfo);
235 }
236
getX509PeerInfo() const237 const SSLPeerInfo& MessagingPort::getX509PeerInfo() const {
238 return _x509PeerInfo;
239 }
240
setConnectionId(const long long connectionId)241 void MessagingPort::setConnectionId(const long long connectionId) {
242 _connectionId = connectionId;
243 }
244
connectionId() const245 long long MessagingPort::connectionId() const {
246 return _connectionId;
247 }
248
setTag(const AbstractMessagingPort::Tag tag)249 void MessagingPort::setTag(const AbstractMessagingPort::Tag tag) {
250 _tag = tag;
251 }
252
getTag() const253 AbstractMessagingPort::Tag MessagingPort::getTag() const {
254 return _tag;
255 }
256
257 } // namespace mongo
258