Validate `port` options

Check `port` options for invalid values (ports are parsed as uint16, so
in practice values >65535 are invalid; port 0 is undefined and therefore
considered invalid too). This allows for an early rejection of faulty
values and an supplying an informative message to the user.

Splits tests in `feature_proxy.py` to cover both invalid `hostname`
and `port` values.

Adds a release-note as previously valid `-port` and `-rpcport` values
can now result in errors.
This commit is contained in:
amadeuszpawlik 2021-05-27 14:07:35 +02:00 committed by Amadeusz Pawlik
parent f8387c4234
commit 04526787b5
5 changed files with 80 additions and 9 deletions

View File

@ -0,0 +1,4 @@
Updated settings
----------------
- Ports specified in `-port` and `-rpcport` options are now validated at startup. Values that previously worked and were considered valid can now result in errors. (#22087)

View File

@ -1255,6 +1255,51 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// as they would never get updated.
if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args));
// Check port numbers
for (const std::string port_option : {
"-port",
"-rpcport",
}) {
if (args.IsArgSet(port_option)) {
const std::string port = args.GetArg(port_option, "");
uint16_t n;
if (!ParseUInt16(port, &n) || n == 0) {
return InitError(InvalidPortErrMsg(port_option, port));
}
}
}
for (const std::string port_option : {
"-i2psam",
"-onion",
"-proxy",
"-rpcbind",
"-torcontrol",
"-whitebind",
"-zmqpubhashblock",
"-zmqpubhashtx",
"-zmqpubrawblock",
"-zmqpubrawtx",
"-zmqpubsequence",
}) {
for (const std::string& socket_addr : args.GetArgs(port_option)) {
std::string host_out;
uint16_t port_out{0};
if (!SplitHostPort(socket_addr, port_out, host_out)) {
return InitError(InvalidPortErrMsg(port_option, socket_addr));
}
}
}
for (const std::string& socket_addr : args.GetArgs("-bind")) {
std::string host_out;
uint16_t port_out{0};
std::string bind_socket_addr = socket_addr.substr(0, socket_addr.rfind('='));
if (!SplitHostPort(bind_socket_addr, port_out, host_out)) {
return InitError(InvalidPortErrMsg("-bind", socket_addr));
}
}
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<std::string> uacomments;
for (const std::string& cmt : args.GetArgs("-uacomment")) {

View File

@ -49,6 +49,11 @@ bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBi
return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
}
bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& invalid_value)
{
return strprintf(_("Invalid port specified in %s: '%s'"), optname, invalid_value);
}
bilingual_str AmountHighWarn(const std::string& optname)
{
return strprintf(_("%s is set very high!"), optname);

View File

@ -39,6 +39,8 @@ bilingual_str TransactionErrorString(const TransactionError error);
bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind);
bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& strPort);
bilingual_str AmountHighWarn(const std::string& optname);
bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue);

View File

@ -317,19 +317,34 @@ class ProxyTest(BitcoinTestFramework):
self.stop_node(1)
self.log.info("Test passing invalid -proxy raises expected init error")
self.nodes[1].extra_args = ["-proxy=abc:def"]
msg = "Error: Invalid -proxy address or hostname: 'abc:def'"
self.log.info("Test passing invalid -proxy hostname raises expected init error")
self.nodes[1].extra_args = ["-proxy=abc..abc:23456"]
msg = "Error: Invalid -proxy address or hostname: 'abc..abc:23456'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
self.log.info("Test passing invalid -onion raises expected init error")
self.nodes[1].extra_args = ["-onion=xyz:abc"]
msg = "Error: Invalid -onion address or hostname: 'xyz:abc'"
self.log.info("Test passing invalid -proxy port raises expected init error")
self.nodes[1].extra_args = ["-proxy=192.0.0.1:def"]
msg = "Error: Invalid port specified in -proxy: '192.0.0.1:def'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
self.log.info("Test passing invalid -i2psam raises expected init error")
self.nodes[1].extra_args = ["-i2psam=def:xyz"]
msg = "Error: Invalid -i2psam address or hostname: 'def:xyz'"
self.log.info("Test passing invalid -onion hostname raises expected init error")
self.nodes[1].extra_args = ["-onion=xyz..xyz:23456"]
msg = "Error: Invalid -onion address or hostname: 'xyz..xyz:23456'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
self.log.info("Test passing invalid -onion port raises expected init error")
self.nodes[1].extra_args = ["-onion=192.0.0.1:def"]
msg = "Error: Invalid port specified in -onion: '192.0.0.1:def'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
self.log.info("Test passing invalid -i2psam hostname raises expected init error")
self.nodes[1].extra_args = ["-i2psam=def..def:23456"]
msg = "Error: Invalid -i2psam address or hostname: 'def..def:23456'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
self.log.info("Test passing invalid -i2psam port raises expected init error")
self.nodes[1].extra_args = ["-i2psam=192.0.0.1:def"]
msg = "Error: Invalid port specified in -i2psam: '192.0.0.1:def'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
self.log.info("Test passing invalid -onlynet=i2p without -i2psam raises expected init error")