fix up local/external address handling

This commit is contained in:
Martin Michelsen
2024-11-10 16:20:11 -08:00
parent 8cb7b465da
commit a59a2d7cd3
6 changed files with 129 additions and 46 deletions
+44 -25
View File
@@ -10,6 +10,7 @@
#include <phosg/JSON.hh>
#include <phosg/Math.hh>
#include <phosg/Network.hh>
#include <phosg/Platform.hh>
#include <phosg/Strings.hh>
#include <phosg/Tools.hh>
#include <set>
@@ -53,6 +54,12 @@
using namespace std;
#ifdef PHOSG_WINDOWS
static constexpr bool IS_WINDOWS = true;
#else
static constexpr bool IS_WINDOWS = false;
#endif
bool use_terminal_colors = false;
void print_version_info();
@@ -3167,9 +3174,21 @@ Action a_run_server_replay_log(
state->ip_stack_simulator->listen(
spec, netloc.first, netloc.second, IPStackSimulator::Protocol::HDLC_RAW);
if (netloc.second) {
if (state->local_address == state->external_address) {
if (state->local_address == 0 && state->external_address == 0) {
config_log.info(
"Note: The Devolution phone number for %s is %" PRIu64,
"Cannot generate Devolution phone numbers for %s because LocalAddress and ExternalAddress are not specified in the configuration",
spec.c_str());
} else if (state->local_address == 0) {
config_log.info(
"Note: The Devolution phone number for %s is %" PRIu64 " (external)",
spec.c_str(), devolution_phone_number_for_netloc(state->external_address, netloc.second));
} else if (state->external_address == 0) {
config_log.info(
"Note: The Devolution phone number for %s is %" PRIu64 " (local)",
spec.c_str(), devolution_phone_number_for_netloc(state->local_address, netloc.second));
} else if (state->local_address == state->external_address) {
config_log.info(
"Note: The Devolution phone number for %s is %" PRIu64 " (local+external)",
spec.c_str(), devolution_phone_number_for_netloc(state->local_address, netloc.second));
} else {
config_log.info(
@@ -3328,30 +3347,30 @@ int main(int argc, char** argv) {
phosg::log_error("Unknown or invalid action; try --help");
return 1;
}
#ifdef PHOSG_WINDOWS
// Cygwin just gives a stackdump when an exception falls out of main(), so
// unlike Linux and macOS, we have to manually catch exceptions here just to
// see what the exception message was.
try {
if (IS_WINDOWS) {
// Cygwin just gives a stackdump when an exception falls out of main(), so
// unlike Linux and macOS, we have to manually catch exceptions here just to
// see what the exception message was.
try {
a->run(args);
} catch (const phosg::cannot_open_file& e) {
phosg::log_error("Top-level exception (cannot_open_file): %s", e.what());
throw;
} catch (const invalid_argument& e) {
phosg::log_error("Top-level exception (invalid_argument): %s", e.what());
throw;
} catch (const out_of_range& e) {
phosg::log_error("Top-level exception (out_of_range): %s", e.what());
throw;
} catch (const runtime_error& e) {
phosg::log_error("Top-level exception (runtime_error): %s", e.what());
throw;
} catch (const exception& e) {
phosg::log_error("Top-level exception: %s", e.what());
throw;
}
} else {
a->run(args);
} catch (const phosg::cannot_open_file& e) {
phosg::log_error("Top-level exception (cannot_open_file): %s", e.what());
throw;
} catch (const invalid_argument& e) {
phosg::log_error("Top-level exception (invalid_argument): %s", e.what());
throw;
} catch (const out_of_range& e) {
phosg::log_error("Top-level exception (out_of_range): %s", e.what());
throw;
} catch (const runtime_error& e) {
phosg::log_error("Top-level exception (runtime_error): %s", e.what());
throw;
} catch (const exception& e) {
phosg::log_error("Top-level exception: %s", e.what());
throw;
}
#else
a->run(args);
#endif
return 0;
}
+9 -2
View File
@@ -66,9 +66,16 @@ map<string, uint32_t> get_local_addresses() {
return ret;
}
bool is_loopback_address(uint32_t addr) {
return ((addr & 0xFF000000) == 0x7F000000); // 127.0.0.0/8
}
bool is_local_address(uint32_t addr) {
uint8_t net = (addr >> 24) & 0xFF;
return ((net == 127) || (net == 172) || (net == 10) || (net == 192));
return is_loopback_address(addr) || // 127.0.0.0/8
((addr & 0xFF000000) == 0x0A000000) || // 10.0.0.0/8
((addr & 0xFFF00000) == 0xAC100000) || // 172.16.0.0/12
((addr & 0xFFFF0000) == 0xC0A80000) || // 192.168.0.0/16
((addr & 0xFFFF0000) == 0xA9FE0000); // 169.254.0.0/16
}
bool is_local_address(const sockaddr_storage& daddr) {
+1
View File
@@ -12,6 +12,7 @@
uint32_t resolve_address(const char* address);
std::map<std::string, uint32_t> get_local_addresses();
uint32_t get_connected_address(int fd);
bool is_loopback_address(uint32_t addr);
bool is_local_address(uint32_t daddr);
bool is_local_address(const sockaddr_storage& daddr);
+44 -6
View File
@@ -5,6 +5,7 @@
#include <memory>
#include <phosg/Image.hh>
#include <phosg/Network.hh>
#include <phosg/Platform.hh>
#include "Compression.hh"
#include "EventUtils.hh"
@@ -19,6 +20,12 @@
using namespace std;
#ifdef PHOSG_WINDOWS
static constexpr bool IS_WINDOWS = true;
#else
static constexpr bool IS_WINDOWS = false;
#endif
CheatFlags::CheatFlags(const phosg::JSON& json) : CheatFlags() {
unordered_set<std::string> enabled_keys;
for (const auto& it : json.as_list()) {
@@ -673,8 +680,10 @@ void ServerState::load_config_early() {
for (const auto& item : this->config_json->at("IPStackListen").as_list()) {
if (item->is_int()) {
this->ip_stack_addresses.emplace_back(phosg::string_printf("0.0.0.0:%" PRId64, item->as_int()));
} else {
} else if (!IS_WINDOWS) {
this->ip_stack_addresses.emplace_back(item->as_string());
} else {
config_log.warning("Unix sockets are not supported on Windows; skipping address %s", item->as_string().c_str());
}
}
} catch (const out_of_range&) {
@@ -683,8 +692,10 @@ void ServerState::load_config_early() {
for (const auto& item : this->config_json->at("PPPStackListen").as_list()) {
if (item->is_int()) {
this->ppp_stack_addresses.emplace_back(phosg::string_printf("0.0.0.0:%" PRId64, item->as_int()));
} else {
} else if (!IS_WINDOWS) {
this->ppp_stack_addresses.emplace_back(item->as_string());
} else {
config_log.warning("Unix sockets are not supported on Windows; skipping address %s", item->as_string().c_str());
}
}
} catch (const out_of_range&) {
@@ -693,8 +704,10 @@ void ServerState::load_config_early() {
for (const auto& item : this->config_json->at("PPPRawListen").as_list()) {
if (item->is_int()) {
this->ppp_raw_addresses.emplace_back(phosg::string_printf("0.0.0.0:%" PRId64, item->as_int()));
} else {
} else if (!IS_WINDOWS) {
this->ppp_raw_addresses.emplace_back(item->as_string());
} else {
config_log.warning("Unix sockets are not supported on Windows; skipping address %s", item->as_string().c_str());
}
}
} catch (const out_of_range&) {
@@ -703,8 +716,10 @@ void ServerState::load_config_early() {
for (const auto& item : this->config_json->at("HTTPListen").as_list()) {
if (item->is_int()) {
this->http_addresses.emplace_back(phosg::string_printf("0.0.0.0:%" PRId64, item->as_int()));
} else {
} else if (!IS_WINDOWS) {
this->http_addresses.emplace_back(item->as_string());
} else {
config_log.warning("Unix sockets are not supported on Windows; skipping address %s", item->as_string().c_str());
}
}
} catch (const out_of_range&) {
@@ -727,7 +742,18 @@ void ServerState::load_config_early() {
this->all_addresses.erase("<local>");
this->all_addresses.emplace("<local>", this->local_address);
} catch (const out_of_range&) {
config_log.warning("Local address not specified; interface defaults will be used");
for (const auto& it : this->all_addresses) {
// Choose any local interface except the loopback interface
if (!is_loopback_address(it.second) && is_local_address(it.second)) {
this->local_address = it.second;
}
}
if (this->local_address) {
string addr_str = string_for_address(this->local_address);
config_log.warning("Local address not specified; using %s as default", addr_str.c_str());
} else {
config_log.warning("Local address not specified and no default is available");
}
}
try {
@@ -744,7 +770,19 @@ void ServerState::load_config_early() {
this->all_addresses.erase("<external>");
this->all_addresses.emplace("<external>", this->external_address);
} catch (const out_of_range&) {
config_log.warning("External address not specified; only local clients will be able to connect");
for (const auto& it : this->all_addresses) {
// Choose any non-local address, if any exist
if (!is_local_address(it.second)) {
this->external_address = it.second;
break;
}
}
if (this->external_address) {
string addr_str = string_for_address(this->external_address);
config_log.warning("External address not specified; using %s as default", addr_str.c_str());
} else {
config_log.warning("External address not specified and no default is available; only local clients will be able to connect");
}
}
try {