diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index a09bb5c9da..1e27924dfd 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -109,10 +109,11 @@ int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint) #endif -static bool ParseArgs(ArgsManager& args, int argc, char* argv[]) +static bool ParseArgs(NodeContext& node, int argc, char* argv[]) { + ArgsManager& args{*Assert(node.args)}; // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main() - SetupServerArgs(args); + SetupServerArgs(args, node.init->canListenIpc()); std::string error; if (!args.ParseParameters(argc, argv, error)) { return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error))); @@ -268,7 +269,7 @@ MAIN_FUNCTION // Interpret command line arguments ArgsManager& args = *Assert(node.args); - if (!ParseArgs(args, argc, argv)) return EXIT_FAILURE; + if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE; // Process early info return commands such as -help or -version if (ProcessInitCommands(args)) return EXIT_SUCCESS; diff --git a/src/common/args.cpp b/src/common/args.cpp index 9b3ad38296..f59d2b8f0f 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -635,6 +635,9 @@ std::string ArgsManager::GetHelpMessage() const case OptionsCategory::RPC: usage += HelpMessageGroup("RPC server options:"); break; + case OptionsCategory::IPC: + usage += HelpMessageGroup("IPC interprocess connection options:"); + break; case OptionsCategory::WALLET: usage += HelpMessageGroup("Wallet options:"); break; diff --git a/src/common/args.h b/src/common/args.h index 3f4cbbfab4..8d9daf5f65 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -64,6 +64,7 @@ enum class OptionsCategory { COMMANDS, REGISTER_COMMANDS, CLI_COMMANDS, + IPC, HIDDEN // Always the last option to avoid printing these in the help }; diff --git a/src/init.cpp b/src/init.cpp index e60feecf10..3123266e4b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -441,7 +442,7 @@ static void OnRPCStopped() LogDebug(BCLog::RPC, "RPC stopped.\n"); } -void SetupServerArgs(ArgsManager& argsman) +void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) { SetupHelpOptions(argsman); argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now @@ -676,6 +677,9 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcworkqueue=", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC); argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); + if (can_listen_ipc) { + argsman.AddArg("-ipcbind=
", "Bind to Unix socket address and listen for incoming connections. Valid address values are \"unix\" to listen on the default path, /node.sock, or \"unix:/custom/path\" to specify a custom path. Can be specified multiple times to listen on multiple paths. Default behavior is not to listen on any path. If relative paths are specified, they are interpreted relative to the network data directory. If paths include any parent directory components and the parent directories do not exist, they will be created.", ArgsManager::ALLOW_ANY, OptionsCategory::IPC); + } #if HAVE_DECL_FORK argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -1200,6 +1204,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) g_wallet_init_interface.Construct(node); uiInterface.InitWallet(); + if (interfaces::Ipc* ipc = node.init->ipc()) { + for (std::string address : gArgs.GetArgs("-ipcbind")) { + try { + ipc->listenAddress(address); + } catch (const std::exception& e) { + return InitError(strprintf(Untranslated("Unable to bind to IPC address '%s'. %s"), address, e.what())); + } + LogPrintf("Listening for IPC requests on address %s\n", address); + } + } + /* Register RPC commands regardless of -server setting so they will be * available in the GUI RPC console even if external calls are disabled. */ diff --git a/src/init.h b/src/init.h index 40a5da3c0b..6d8a35d80e 100644 --- a/src/init.h +++ b/src/init.h @@ -74,7 +74,7 @@ bool AppInitMain(node::NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip /** * Register all arguments with the ArgsManager */ -void SetupServerArgs(ArgsManager& argsman); +void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc=false); /** Validates requirements to run the indexes and spawns each index initial sync thread */ bool StartIndexBackgroundSync(node::NodeContext& node); diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp index aceff1e40f..eae30bc995 100644 --- a/src/init/bitcoin-gui.cpp +++ b/src/init/bitcoin-gui.cpp @@ -34,6 +34,11 @@ public: } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } + // bitcoin-gui accepts -ipcbind option even though it does not use it + // directly. It just returns true here to accept the option because + // bitcoin-node accepts the option, and bitcoin-gui accepts all bitcoin-node + // options and will start the node with those options. + bool canListenIpc() override { return true; } node::NodeContext m_node; std::unique_ptr m_ipc; }; diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 00a3822791..3f8c50b8d6 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -37,6 +37,7 @@ public: } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } + bool canListenIpc() override { return true; } node::NodeContext& m_node; std::unique_ptr m_ipc; }; diff --git a/src/interfaces/init.h b/src/interfaces/init.h index 094ead399d..b496ada05f 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -37,6 +37,7 @@ public: virtual std::unique_ptr makeWalletLoader(Chain& chain) { return nullptr; } virtual std::unique_ptr makeEcho() { return nullptr; } virtual Ipc* ipc() { return nullptr; } + virtual bool canListenIpc() { return false; } }; //! Return implementation of Init interface for the node process. If the argv diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 7a0979056e..ec415f0bac 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -525,7 +525,7 @@ int GuiMain(int argc, char* argv[]) /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these // Command-line options take precedence: - SetupServerArgs(gArgs); + SetupServerArgs(gArgs, init->canListenIpc()); SetupUIArgs(gArgs); std::string error; if (!gArgs.ParseParameters(argc, argv, error)) { diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp index 3a404c0b48..2ab5b7ed39 100644 --- a/src/test/fuzz/system.cpp +++ b/src/test/fuzz/system.cpp @@ -59,7 +59,7 @@ FUZZ_TARGET(system, .init = initialize_system) args_manager.SoftSetBoolArg(str_arg, f_value); }, [&] { - const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::CLI_COMMANDS, OptionsCategory::HIDDEN}); + const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::CLI_COMMANDS, OptionsCategory::IPC, OptionsCategory::HIDDEN}); // Avoid hitting: // common/args.cpp:563: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));