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/safe_cast.h>
21#include <xrpl/beast/core/LexicalCast.h>
22#include <xrpl/beast/rfc2616.h>
23#include <xrpl/server/Port.h>
24#include <boost/algorithm/string/predicate.hpp>
25#include <boost/algorithm/string/trim.hpp>
26#include <sstream>
27
28namespace ripple {
29
30bool
32{
33 return protocol.count("peer") > 0 || protocol.count("https") > 0 ||
34 protocol.count("wss") > 0 || protocol.count("wss2") > 0;
35}
36
39{
41 for (auto iter = protocol.cbegin(); iter != protocol.cend(); ++iter)
42 s += (iter != protocol.cbegin() ? "," : "") + *iter;
43 return s;
44}
45
47operator<<(std::ostream& os, Port const& p)
48{
49 os << "'" << p.name << "' (ip=" << p.ip << ":" << p.port << ", ";
50
51 if (p.admin_nets_v4.size() || p.admin_nets_v6.size())
52 {
53 os << "admin nets:";
54 for (auto const& net : p.admin_nets_v4)
55 {
56 os << net.to_string();
57 os << ", ";
58 }
59 for (auto const& net : p.admin_nets_v6)
60 {
61 os << net.to_string();
62 os << ", ";
63 }
64 }
65
67 {
68 os << "secure_gateway nets:";
69 for (auto const& net : p.secure_gateway_nets_v4)
70 {
71 os << net.to_string();
72 os << ", ";
73 }
74 for (auto const& net : p.secure_gateway_nets_v6)
75 {
76 os << net.to_string();
77 os << ", ";
78 }
79 }
80
81 os << p.protocols() << ")";
82 return os;
83}
84
85//------------------------------------------------------------------------------
86
87static void
89 Section const& section,
90 std::string const& field,
91 std::ostream& log,
94{
95 auto const optResult = section.get(field);
96 if (!optResult)
97 return;
98
99 std::stringstream ss(*optResult);
100 std::string ip;
101
102 while (std::getline(ss, ip, ','))
103 {
104 boost::algorithm::trim(ip);
105 bool v4;
106 boost::asio::ip::network_v4 v4Net;
107 boost::asio::ip::network_v6 v6Net;
108
109 try
110 {
111 // First, check to see if 0.0.0.0 or ipv6 equivalent was configured,
112 // which means all IP addresses.
113 auto const addr = beast::IP::Endpoint::from_string_checked(ip);
114 if (addr)
115 {
116 if (is_unspecified(*addr))
117 {
118 nets4.push_back(
119 boost::asio::ip::make_network_v4("0.0.0.0/0"));
120 nets6.push_back(boost::asio::ip::make_network_v6("::/0"));
121 // No reason to allow more IPs--it would be redundant.
122 break;
123 }
124
125 // The configured address is a single IP (or else addr would
126 // be unset). We need this to be a subnet, so append
127 // the number of network bits to make a subnet of 1,
128 // depending on type.
129 v4 = addr->is_v4();
130 std::string addressString = addr->to_string();
131 if (v4)
132 {
133 addressString += "/32";
134 v4Net = boost::asio::ip::make_network_v4(addressString);
135 }
136 else
137 {
138 addressString += "/128";
139 v6Net = boost::asio::ip::make_network_v6(addressString);
140 }
141 }
142 else
143 {
144 // Since addr is empty, assume that the entry is
145 // for a subnet which includes trailing /0-32 or /0-128
146 // depending on ip type.
147 // First, see if it's an ipv4 subnet. If not, try ipv6.
148 // If that throws, then there's nothing we can do with
149 // the entry.
150 try
151 {
152 v4Net = boost::asio::ip::make_network_v4(ip);
153 v4 = true;
154 }
155 catch (boost::system::system_error const&)
156 {
157 v6Net = boost::asio::ip::make_network_v6(ip);
158 v4 = false;
159 }
160 }
161
162 // Confirm that the address entry is the same as the subnet's
163 // underlying network address.
164 // 10.1.2.3/24 makes no sense. The underlying network address
165 // is 10.1.2.0/24.
166 if (v4)
167 {
168 if (v4Net != v4Net.canonical())
169 {
170 log << "The configured subnet " << v4Net.to_string()
171 << " is not the same as the network address, which is "
172 << v4Net.canonical().to_string();
173 Throw<std::exception>();
174 }
175 nets4.push_back(v4Net);
176 }
177 else
178 {
179 if (v6Net != v6Net.canonical())
180 {
181 log << "The configured subnet " << v6Net.to_string()
182 << " is not the same as the network address, which is "
183 << v6Net.canonical().to_string();
184 Throw<std::exception>();
185 }
186 nets6.push_back(v6Net);
187 }
188 }
189 catch (boost::system::system_error const& e)
190 {
191 log << "Invalid value '" << ip << "' for key '" << field << "' in ["
192 << section.name() << "]: " << e.what();
193 Throw<std::exception>();
194 }
195 }
196}
197
198void
199parse_Port(ParsedPort& port, Section const& section, std::ostream& log)
200{
201 port.name = section.name();
202 {
203 auto const optResult = section.get("ip");
204 if (optResult)
205 {
206 try
207 {
208 port.ip = boost::asio::ip::address::from_string(*optResult);
209 }
210 catch (std::exception const&)
211 {
212 log << "Invalid value '" << *optResult << "' for key 'ip' in ["
213 << section.name() << "]";
214 Rethrow();
215 }
216 }
217 }
218
219 {
220 auto const optResult = section.get("port");
221 if (optResult)
222 {
223 try
224 {
225 port.port = beast::lexicalCastThrow<std::uint16_t>(*optResult);
226
227 // Port 0 is not supported for [server]
228 if ((*port.port == 0) && (port.name == "server"))
229 Throw<std::exception>();
230 }
231 catch (std::exception const&)
232 {
233 log << "Invalid value '" << *optResult << "' for key "
234 << "'port' in [" << section.name() << "]";
235 Rethrow();
236 }
237 }
238 }
239
240 {
241 auto const optResult = section.get("protocol");
242 if (optResult)
243 {
244 for (auto const& s : beast::rfc2616::split_commas(
245 optResult->begin(), optResult->end()))
246 port.protocol.insert(s);
247 }
248 }
249
250 {
251 auto const lim = get(section, "limit", "unlimited");
252
253 if (!boost::iequals(lim, "unlimited"))
254 {
255 try
256 {
257 port.limit =
258 safe_cast<int>(beast::lexicalCastThrow<std::uint16_t>(lim));
259 }
260 catch (std::exception const&)
261 {
262 log << "Invalid value '" << lim << "' for key "
263 << "'limit' in [" << section.name() << "]";
264 Rethrow();
265 }
266 }
267 }
268
269 {
270 auto const optResult = section.get("send_queue_limit");
271 if (optResult)
272 {
273 try
274 {
275 port.ws_queue_limit =
276 beast::lexicalCastThrow<std::uint16_t>(*optResult);
277
278 // Queue must be greater than 0
279 if (port.ws_queue_limit == 0)
280 Throw<std::exception>();
281 }
282 catch (std::exception const&)
283 {
284 log << "Invalid value '" << *optResult << "' for key "
285 << "'send_queue_limit' in [" << section.name() << "]";
286 Rethrow();
287 }
288 }
289 else
290 {
291 // Default Websocket send queue size limit
292 port.ws_queue_limit = 100;
293 }
294 }
295
296 populate(section, "admin", log, port.admin_nets_v4, port.admin_nets_v6);
297 populate(
298 section,
299 "secure_gateway",
300 log,
303
304 set(port.user, "user", section);
305 set(port.password, "password", section);
306 set(port.admin_user, "admin_user", section);
307 set(port.admin_password, "admin_password", section);
308 set(port.ssl_key, "ssl_key", section);
309 set(port.ssl_cert, "ssl_cert", section);
310 set(port.ssl_chain, "ssl_chain", section);
311 set(port.ssl_ciphers, "ssl_ciphers", section);
312
313 port.pmd_options.server_enable =
314 section.value_or("permessage_deflate", true);
315 port.pmd_options.client_max_window_bits =
316 section.value_or("client_max_window_bits", 15);
317 port.pmd_options.server_max_window_bits =
318 section.value_or("server_max_window_bits", 15);
319 port.pmd_options.client_no_context_takeover =
320 section.value_or("client_no_context_takeover", false);
321 port.pmd_options.server_no_context_takeover =
322 section.value_or("server_no_context_takeover", false);
323 port.pmd_options.compLevel = section.value_or("compress_level", 8);
324 port.pmd_options.memLevel = section.value_or("memory_level", 4);
325}
326
327} // namespace ripple
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Definition: IPEndpoint.cpp:35
Holds a collection of configuration values.
Definition: BasicConfig.h:46
std::string const & name() const
Returns the name of this section.
Definition: BasicConfig.h:62
T value_or(std::string const &name, T const &other) const
Returns a value if present, else another value.
Definition: BasicConfig.h:152
std::optional< T > get(std::string const &name) const
Definition: BasicConfig.h:141
T getline(T... args)
T insert(T... args)
Result split_commas(FwdIt first, FwdIt last)
Definition: rfc2616.h:204
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
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:88
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,...
Definition: BasicConfig.h:316
void parse_Port(ParsedPort &port, Section const &section, std::ostream &log)
Definition: Port.cpp:199
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition: base_uint.h:636
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
Definition: BasicConfig.h:356
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:109
boost::beast::websocket::permessage_deflate pmd_options
Definition: Port.h:110
std::optional< std::uint16_t > port
Definition: Port.h:115
std::vector< boost::asio::ip::network_v4 > admin_nets_v4
Definition: Port.h:116
std::string user
Definition: Port.h:102
std::string ssl_key
Definition: Port.h:106
std::uint16_t ws_queue_limit
Definition: Port.h:112
std::vector< boost::asio::ip::network_v6 > secure_gateway_nets_v6
Definition: Port.h:119
std::set< std::string, boost::beast::iless > protocol
Definition: Port.h:101
std::string admin_password
Definition: Port.h:105
std::string name
Definition: Port.h:100
std::string ssl_chain
Definition: Port.h:108
std::string password
Definition: Port.h:103
std::vector< boost::asio::ip::network_v6 > admin_nets_v6
Definition: Port.h:117
std::string ssl_cert
Definition: Port.h:107
std::string admin_user
Definition: Port.h:104
std::optional< boost::asio::ip::address > ip
Definition: Port.h:114
std::vector< boost::asio::ip::network_v4 > secure_gateway_nets_v4
Definition: Port.h:118
Configuration information for a Server listening port.
Definition: Port.h:49
std::uint16_t port
Definition: Port.h:54
bool secure() const
Definition: Port.cpp:31
std::vector< boost::asio::ip::network_v6 > admin_nets_v6
Definition: Port.h:57
std::string protocols() const
Definition: Port.cpp:38
std::vector< boost::asio::ip::network_v6 > secure_gateway_nets_v6
Definition: Port.h:59
std::vector< boost::asio::ip::network_v4 > secure_gateway_nets_v4
Definition: Port.h:58
boost::asio::ip::address ip
Definition: Port.h:53
std::string name
Definition: Port.h:52
std::vector< boost::asio::ip::network_v4 > admin_nets_v4
Definition: Port.h:56