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 {
202 auto const optResult = section.get("ip");
203 if (optResult)
204 {
205 try
206 {
207 port.ip = boost::asio::ip::address::from_string(*optResult);
208 }
209 catch (std::exception const&)
210 {
211 log << "Invalid value '" << *optResult << "' for key 'ip' in ["
212 << section.name() << "]";
213 Rethrow();
214 }
215 }
216 }
217
218 {
219 auto const optResult = section.get("port");
220 if (optResult)
221 {
222 try
223 {
224 port.port = beast::lexicalCastThrow<std::uint16_t>(*optResult);
225
226 // Port 0 is not supported
227 if (*port.port == 0)
228 Throw<std::exception>();
229 }
230 catch (std::exception const&)
231 {
232 log << "Invalid value '" << *optResult << "' for key "
233 << "'port' in [" << section.name() << "]";
234 Rethrow();
235 }
236 }
237 }
238
239 {
240 auto const optResult = section.get("protocol");
241 if (optResult)
242 {
243 for (auto const& s : beast::rfc2616::split_commas(
244 optResult->begin(), optResult->end()))
245 port.protocol.insert(s);
246 }
247 }
248
249 {
250 auto const lim = get(section, "limit", "unlimited");
251
252 if (!boost::iequals(lim, "unlimited"))
253 {
254 try
255 {
256 port.limit =
257 safe_cast<int>(beast::lexicalCastThrow<std::uint16_t>(lim));
258 }
259 catch (std::exception const&)
260 {
261 log << "Invalid value '" << lim << "' for key "
262 << "'limit' in [" << section.name() << "]";
263 Rethrow();
264 }
265 }
266 }
267
268 {
269 auto const optResult = section.get("send_queue_limit");
270 if (optResult)
271 {
272 try
273 {
274 port.ws_queue_limit =
275 beast::lexicalCastThrow<std::uint16_t>(*optResult);
276
277 // Queue must be greater than 0
278 if (port.ws_queue_limit == 0)
279 Throw<std::exception>();
280 }
281 catch (std::exception const&)
282 {
283 log << "Invalid value '" << *optResult << "' for key "
284 << "'send_queue_limit' in [" << section.name() << "]";
285 Rethrow();
286 }
287 }
288 else
289 {
290 // Default Websocket send queue size limit
291 port.ws_queue_limit = 100;
292 }
293 }
294
295 populate(section, "admin", log, port.admin_nets_v4, port.admin_nets_v6);
296 populate(
297 section,
298 "secure_gateway",
299 log,
302
303 set(port.user, "user", section);
304 set(port.password, "password", section);
305 set(port.admin_user, "admin_user", section);
306 set(port.admin_password, "admin_password", section);
307 set(port.ssl_key, "ssl_key", section);
308 set(port.ssl_cert, "ssl_cert", section);
309 set(port.ssl_chain, "ssl_chain", section);
310 set(port.ssl_ciphers, "ssl_ciphers", section);
311
312 port.pmd_options.server_enable =
313 section.value_or("permessage_deflate", true);
314 port.pmd_options.client_max_window_bits =
315 section.value_or("client_max_window_bits", 15);
316 port.pmd_options.server_max_window_bits =
317 section.value_or("server_max_window_bits", 15);
318 port.pmd_options.client_no_context_takeover =
319 section.value_or("client_no_context_takeover", false);
320 port.pmd_options.server_no_context_takeover =
321 section.value_or("server_no_context_takeover", false);
322 port.pmd_options.compLevel = section.value_or("compress_level", 8);
323 port.pmd_options.memLevel = section.value_or("memory_level", 4);
324}
325
326} // 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:43
std::string const & name() const
Returns the name of this section.
Definition: BasicConfig.h:59
T value_or(std::string const &name, T const &other) const
Returns a value if present, else another value.
Definition: BasicConfig.h:149
std::optional< T > get(std::string const &name) const
Definition: BasicConfig.h:138
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:313
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:353
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 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