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