rippled
Loading...
Searching...
No Matches
Port.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/BasicConfig.h>
21#include <xrpl/basics/contract.h>
22#include <xrpl/basics/safe_cast.h>
23#include <xrpl/beast/core/LexicalCast.h>
24#include <xrpl/beast/net/IPEndpoint.h>
25#include <xrpl/beast/rfc2616.h>
26#include <xrpl/server/Port.h>
27
28#include <boost/algorithm/string/predicate.hpp>
29#include <boost/algorithm/string/trim.hpp>
30#include <boost/asio/ip/address.hpp>
31#include <boost/asio/ip/impl/network_v4.ipp>
32#include <boost/asio/ip/impl/network_v6.ipp>
33#include <boost/system/system_error.hpp>
34
35#include <cstdint>
36#include <exception>
37#include <ostream>
38#include <sstream>
39#include <stdexcept>
40#include <string>
41#include <vector>
42
43namespace ripple {
44
45bool
47{
48 return protocol.count("peer") > 0 || protocol.count("https") > 0 ||
49 protocol.count("wss") > 0 || protocol.count("wss2") > 0;
50}
51
54{
56 for (auto iter = protocol.cbegin(); iter != protocol.cend(); ++iter)
57 s += (iter != protocol.cbegin() ? "," : "") + *iter;
58 return s;
59}
60
62operator<<(std::ostream& os, Port const& p)
63{
64 os << "'" << p.name << "' (ip=" << p.ip << ":" << p.port << ", ";
65
66 if (p.admin_nets_v4.size() || p.admin_nets_v6.size())
67 {
68 os << "admin nets:";
69 for (auto const& net : p.admin_nets_v4)
70 {
71 os << net.to_string();
72 os << ", ";
73 }
74 for (auto const& net : p.admin_nets_v6)
75 {
76 os << net.to_string();
77 os << ", ";
78 }
79 }
80
82 {
83 os << "secure_gateway nets:";
84 for (auto const& net : p.secure_gateway_nets_v4)
85 {
86 os << net.to_string();
87 os << ", ";
88 }
89 for (auto const& net : p.secure_gateway_nets_v6)
90 {
91 os << net.to_string();
92 os << ", ";
93 }
94 }
95
96 os << p.protocols() << ")";
97 return os;
98}
99
100//------------------------------------------------------------------------------
101
102static void
104 Section const& section,
105 std::string const& field,
106 std::ostream& log,
109{
110 auto const optResult = section.get(field);
111 if (!optResult)
112 return;
113
114 std::stringstream ss(*optResult);
115 std::string ip;
116
117 while (std::getline(ss, ip, ','))
118 {
119 boost::algorithm::trim(ip);
120 bool v4;
121 boost::asio::ip::network_v4 v4Net;
122 boost::asio::ip::network_v6 v6Net;
123
124 try
125 {
126 // First, check to see if 0.0.0.0 or ipv6 equivalent was configured,
127 // which means all IP addresses.
128 auto const addr = beast::IP::Endpoint::from_string_checked(ip);
129 if (addr)
130 {
131 if (is_unspecified(*addr))
132 {
133 nets4.push_back(
134 boost::asio::ip::make_network_v4("0.0.0.0/0"));
135 nets6.push_back(boost::asio::ip::make_network_v6("::/0"));
136 // No reason to allow more IPs--it would be redundant.
137 break;
138 }
139
140 // The configured address is a single IP (or else addr would
141 // be unset). We need this to be a subnet, so append
142 // the number of network bits to make a subnet of 1,
143 // depending on type.
144 v4 = addr->is_v4();
145 std::string addressString = addr->to_string();
146 if (v4)
147 {
148 addressString += "/32";
149 v4Net = boost::asio::ip::make_network_v4(addressString);
150 }
151 else
152 {
153 addressString += "/128";
154 v6Net = boost::asio::ip::make_network_v6(addressString);
155 }
156 }
157 else
158 {
159 // Since addr is empty, assume that the entry is
160 // for a subnet which includes trailing /0-32 or /0-128
161 // depending on ip type.
162 // First, see if it's an ipv4 subnet. If not, try ipv6.
163 // If that throws, then there's nothing we can do with
164 // the entry.
165 try
166 {
167 v4Net = boost::asio::ip::make_network_v4(ip);
168 v4 = true;
169 }
170 catch (boost::system::system_error const&)
171 {
172 v6Net = boost::asio::ip::make_network_v6(ip);
173 v4 = false;
174 }
175 }
176
177 // Confirm that the address entry is the same as the subnet's
178 // underlying network address.
179 // 10.1.2.3/24 makes no sense. The underlying network address
180 // is 10.1.2.0/24.
181 if (v4)
182 {
183 if (v4Net != v4Net.canonical())
184 {
185 log << "The configured subnet " << v4Net.to_string()
186 << " is not the same as the network address, which is "
187 << v4Net.canonical().to_string();
188 Throw<std::exception>();
189 }
190 nets4.push_back(v4Net);
191 }
192 else
193 {
194 if (v6Net != v6Net.canonical())
195 {
196 log << "The configured subnet " << v6Net.to_string()
197 << " is not the same as the network address, which is "
198 << v6Net.canonical().to_string();
199 Throw<std::exception>();
200 }
201 nets6.push_back(v6Net);
202 }
203 }
204 catch (boost::system::system_error const& e)
205 {
206 log << "Invalid value '" << ip << "' for key '" << field << "' in ["
207 << section.name() << "]: " << e.what();
208 Throw<std::exception>();
209 }
210 }
211}
212
213void
214parse_Port(ParsedPort& port, Section const& section, std::ostream& log)
215{
216 port.name = section.name();
217 {
218 auto const optResult = section.get("ip");
219 if (optResult)
220 {
221 try
222 {
223 port.ip = boost::asio::ip::make_address(*optResult);
224 }
225 catch (std::exception const&)
226 {
227 log << "Invalid value '" << *optResult << "' for key 'ip' in ["
228 << section.name() << "]";
229 Rethrow();
230 }
231 }
232 }
233
234 {
235 auto const optResult = section.get("port");
236 if (optResult)
237 {
238 try
239 {
240 port.port = beast::lexicalCastThrow<std::uint16_t>(*optResult);
241
242 // Port 0 is not supported for [server]
243 if ((*port.port == 0) && (port.name == "server"))
244 Throw<std::exception>();
245 }
246 catch (std::exception const&)
247 {
248 log << "Invalid value '" << *optResult << "' for key "
249 << "'port' in [" << section.name() << "]";
250 Rethrow();
251 }
252 }
253 }
254
255 {
256 auto const optResult = section.get("protocol");
257 if (optResult)
258 {
259 for (auto const& s : beast::rfc2616::split_commas(
260 optResult->begin(), optResult->end()))
261 port.protocol.insert(s);
262 }
263 }
264
265 {
266 auto const lim = get(section, "limit", "unlimited");
267
268 if (!boost::iequals(lim, "unlimited"))
269 {
270 try
271 {
272 port.limit =
273 safe_cast<int>(beast::lexicalCastThrow<std::uint16_t>(lim));
274 }
275 catch (std::exception const&)
276 {
277 log << "Invalid value '" << lim << "' for key "
278 << "'limit' in [" << section.name() << "]";
279 Rethrow();
280 }
281 }
282 }
283
284 {
285 auto const optResult = section.get("send_queue_limit");
286 if (optResult)
287 {
288 try
289 {
290 port.ws_queue_limit =
291 beast::lexicalCastThrow<std::uint16_t>(*optResult);
292
293 // Queue must be greater than 0
294 if (port.ws_queue_limit == 0)
295 Throw<std::exception>();
296 }
297 catch (std::exception const&)
298 {
299 log << "Invalid value '" << *optResult << "' for key "
300 << "'send_queue_limit' in [" << section.name() << "]";
301 Rethrow();
302 }
303 }
304 else
305 {
306 // Default Websocket send queue size limit
307 port.ws_queue_limit = 100;
308 }
309 }
310
311 populate(section, "admin", log, port.admin_nets_v4, port.admin_nets_v6);
312 populate(
313 section,
314 "secure_gateway",
315 log,
318
319 set(port.user, "user", section);
320 set(port.password, "password", section);
321 set(port.admin_user, "admin_user", section);
322 set(port.admin_password, "admin_password", section);
323 set(port.ssl_key, "ssl_key", section);
324 set(port.ssl_cert, "ssl_cert", section);
325 set(port.ssl_chain, "ssl_chain", section);
326 set(port.ssl_ciphers, "ssl_ciphers", section);
327
328 port.pmd_options.server_enable =
329 section.value_or("permessage_deflate", true);
330 port.pmd_options.client_max_window_bits =
331 section.value_or("client_max_window_bits", 15);
332 port.pmd_options.server_max_window_bits =
333 section.value_or("server_max_window_bits", 15);
334 port.pmd_options.client_no_context_takeover =
335 section.value_or("client_no_context_takeover", false);
336 port.pmd_options.server_no_context_takeover =
337 section.value_or("server_no_context_takeover", false);
338 port.pmd_options.compLevel = section.value_or("compress_level", 8);
339 port.pmd_options.memLevel = section.value_or("memory_level", 4);
340}
341
342} // namespace ripple
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Holds a collection of configuration values.
Definition BasicConfig.h:45
std::string const & name() const
Returns the name of this section.
Definition BasicConfig.h:61
T value_or(std::string const &name, T const &other) const
Returns a value if present, else another value.
std::optional< T > get(std::string const &name) const
T getline(T... args)
T insert(T... args)
Result split_commas(FwdIt first, FwdIt last)
Definition rfc2616.h:199
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
static void populate(Section const &section, std::string const &field, std::ostream &log, std::vector< boost::asio::ip::network_v4 > &nets4, std::vector< boost::asio::ip::network_v6 > &nets6)
Definition Port.cpp:103
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
void parse_Port(ParsedPort &port, Section const &section, std::ostream &log)
Definition Port.cpp:214
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:647
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
void Rethrow()
Rethrow the exception currently being handled.
Definition contract.h:48
T push_back(T... args)
T size(T... args)
std::string ssl_ciphers
Definition Port.h:110
boost::beast::websocket::permessage_deflate pmd_options
Definition Port.h:111
std::optional< std::uint16_t > port
Definition Port.h:116
std::vector< boost::asio::ip::network_v4 > admin_nets_v4
Definition Port.h:117
std::string user
Definition Port.h:103
std::string ssl_key
Definition Port.h:107
std::uint16_t ws_queue_limit
Definition Port.h:113
std::vector< boost::asio::ip::network_v6 > secure_gateway_nets_v6
Definition Port.h:120
std::set< std::string, boost::beast::iless > protocol
Definition Port.h:102
std::string admin_password
Definition Port.h:106
std::string name
Definition Port.h:101
std::string ssl_chain
Definition Port.h:109
std::string password
Definition Port.h:104
std::vector< boost::asio::ip::network_v6 > admin_nets_v6
Definition Port.h:118
std::string ssl_cert
Definition Port.h:108
std::string admin_user
Definition Port.h:105
std::optional< boost::asio::ip::address > ip
Definition Port.h:115
std::vector< boost::asio::ip::network_v4 > secure_gateway_nets_v4
Definition Port.h:119
Configuration information for a Server listening port.
Definition Port.h:50
std::uint16_t port
Definition Port.h:55
bool secure() const
Definition Port.cpp:46
std::vector< boost::asio::ip::network_v6 > admin_nets_v6
Definition Port.h:58
std::string protocols() const
Definition Port.cpp:53
std::vector< boost::asio::ip::network_v6 > secure_gateway_nets_v6
Definition Port.h:60
std::vector< boost::asio::ip::network_v4 > secure_gateway_nets_v4
Definition Port.h:59
boost::asio::ip::address ip
Definition Port.h:54
std::string name
Definition Port.h:53
std::vector< boost::asio::ip::network_v4 > admin_nets_v4
Definition Port.h:57