add ability to specify listening interfaces

This commit is contained in:
Martin Michelsen
2023-12-31 22:21:00 -08:00
parent cd4a8050d7
commit 4ff4c86047
6 changed files with 56 additions and 15 deletions
+10 -6
View File
@@ -1890,9 +1890,13 @@ Action a_run_server_replay_log(
shared_ptr<DNSServer> dns_server; shared_ptr<DNSServer> dns_server;
if (state->dns_server_port && !is_replay) { if (state->dns_server_port && !is_replay) {
config_log.info("Starting DNS server on port %hu", state->dns_server_port); if (!state->dns_server_addr.empty()) {
config_log.info("Starting DNS server on %s:%hu", state->dns_server_addr.c_str(), state->dns_server_port);
} else {
config_log.info("Starting DNS server on port %hu", state->dns_server_port);
}
dns_server = make_shared<DNSServer>(base, state->local_address, state->external_address); dns_server = make_shared<DNSServer>(base, state->local_address, state->external_address);
dns_server->listen("", state->dns_server_port); dns_server->listen(state->dns_server_addr, state->dns_server_port);
} else { } else {
config_log.info("DNS server is disabled"); config_log.info("DNS server is disabled");
} }
@@ -1934,14 +1938,14 @@ Action a_run_server_replay_log(
auto [ss, size] = make_sockaddr_storage( auto [ss, size] = make_sockaddr_storage(
state->proxy_destination_patch.first, state->proxy_destination_patch.first,
state->proxy_destination_patch.second); state->proxy_destination_patch.second);
state->proxy_server->listen(pc->port, pc->version, &ss); state->proxy_server->listen(pc->addr, pc->port, pc->version, &ss);
} else if (is_v4(pc->version)) { } else if (is_v4(pc->version)) {
auto [ss, size] = make_sockaddr_storage( auto [ss, size] = make_sockaddr_storage(
state->proxy_destination_bb.first, state->proxy_destination_bb.first,
state->proxy_destination_bb.second); state->proxy_destination_bb.second);
state->proxy_server->listen(pc->port, pc->version, &ss); state->proxy_server->listen(pc->addr, pc->port, pc->version, &ss);
} else { } else {
state->proxy_server->listen(pc->port, pc->version); state->proxy_server->listen(pc->addr, pc->port, pc->version);
} }
} }
} else { } else {
@@ -1950,7 +1954,7 @@ Action a_run_server_replay_log(
state->game_server = make_shared<Server>(base, state); state->game_server = make_shared<Server>(base, state);
} }
string spec = string_printf("T-%hu-%s-%s-%s", pc->port, name_for_enum(pc->version), pc->name.c_str(), name_for_enum(pc->behavior)); string spec = string_printf("T-%hu-%s-%s-%s", pc->port, name_for_enum(pc->version), pc->name.c_str(), name_for_enum(pc->behavior));
state->game_server->listen(spec, "", pc->port, pc->version, pc->behavior); state->game_server->listen(spec, pc->addr, pc->port, pc->version, pc->behavior);
} }
} }
+7 -4
View File
@@ -43,20 +43,23 @@ ProxyServer::ProxyServer(
state(state), state(state),
next_unlicensed_session_id(0xFF00000000000001) {} next_unlicensed_session_id(0xFF00000000000001) {}
void ProxyServer::listen(uint16_t port, Version version, const struct sockaddr_storage* default_destination) { void ProxyServer::listen(const std::string& addr, uint16_t port, Version version, const struct sockaddr_storage* default_destination) {
auto socket_obj = make_shared<ListeningSocket>(this, port, version, default_destination); auto socket_obj = make_shared<ListeningSocket>(this, addr, port, version, default_destination);
auto l = this->listeners.emplace(port, socket_obj).first->second; if (!this->listeners.emplace(port, socket_obj).second) {
throw runtime_error("duplicate port in proxy server configuration");
}
} }
ProxyServer::ListeningSocket::ListeningSocket( ProxyServer::ListeningSocket::ListeningSocket(
ProxyServer* server, ProxyServer* server,
const std::string& addr,
uint16_t port, uint16_t port,
Version version, Version version,
const struct sockaddr_storage* default_destination) const struct sockaddr_storage* default_destination)
: server(server), : server(server),
log(string_printf("[ProxyServer:ListeningSocket:%hu] ", port), proxy_server_log.min_level), log(string_printf("[ProxyServer:ListeningSocket:%hu] ", port), proxy_server_log.min_level),
port(port), port(port),
fd(::listen("", port, SOMAXCONN)), fd(::listen(addr, port, SOMAXCONN)),
listener(nullptr, evconnlistener_free), listener(nullptr, evconnlistener_free),
version(version) { version(version) {
if (!this->fd.is_open()) { if (!this->fd.is_open()) {
+2 -1
View File
@@ -26,7 +26,7 @@ public:
std::shared_ptr<ServerState> state); std::shared_ptr<ServerState> state);
virtual ~ProxyServer() = default; virtual ~ProxyServer() = default;
void listen(uint16_t port, Version version, const struct sockaddr_storage* default_destination = nullptr); void listen(const std::string& addr, uint16_t port, Version version, const struct sockaddr_storage* default_destination = nullptr);
void connect_client(struct bufferevent* bev, uint16_t server_port); void connect_client(struct bufferevent* bev, uint16_t server_port);
@@ -207,6 +207,7 @@ private:
ListeningSocket( ListeningSocket(
ProxyServer* server, ProxyServer* server,
const std::string& addr,
uint16_t port, uint16_t port,
Version version, Version version,
const struct sockaddr_storage* default_destination); const struct sockaddr_storage* default_destination);
+23 -3
View File
@@ -472,13 +472,28 @@ shared_ptr<const string> ServerState::load_bb_file(
} }
} }
static vector<PortConfiguration> parse_port_configuration(const JSON& json) { pair<string, uint16_t> ServerState::parse_port_spec(const JSON& json) const {
if (json.is_list()) {
string addr = json.at(0).as_string();
try {
addr = string_for_address(this->all_addresses.at(addr));
} catch (const out_of_range&) {
}
return make_pair(addr, json.at(1).as_int());
} else {
return make_pair("", json.as_int());
}
}
vector<PortConfiguration> ServerState::parse_port_configuration(const JSON& json) const {
vector<PortConfiguration> ret; vector<PortConfiguration> ret;
for (const auto& item_json_it : json.as_dict()) { for (const auto& item_json_it : json.as_dict()) {
const auto& item_list = item_json_it.second; const auto& item_list = item_json_it.second;
PortConfiguration& pc = ret.emplace_back(); PortConfiguration& pc = ret.emplace_back();
pc.name = item_json_it.first; pc.name = item_json_it.first;
pc.port = item_list->at(0).as_int(); auto spec = this->parse_port_spec(item_list->at(0));
pc.addr = std::move(spec.first);
pc.port = spec.second;
pc.version = enum_for_name<Version>(item_list->at(1).as_string().c_str()); pc.version = enum_for_name<Version>(item_list->at(1).as_string().c_str());
pc.behavior = enum_for_name<ServerBehavior>(item_list->at(2).as_string().c_str()); pc.behavior = enum_for_name<ServerBehavior>(item_list->at(2).as_string().c_str());
} }
@@ -537,7 +552,12 @@ void ServerState::load_config() {
} }
this->set_port_configuration(parse_port_configuration(json.at("PortConfiguration"))); this->set_port_configuration(parse_port_configuration(json.at("PortConfiguration")));
this->dns_server_port = json.get_int("DNSServerPort", this->dns_server_port); try {
auto spec = this->parse_port_spec(json.at("DNSServerPort"));
this->dns_server_addr = std::move(spec.first);
this->dns_server_port = spec.second;
} catch (const out_of_range&) {
}
try { try {
for (const auto& item : json.at("IPStackListen").as_list()) { for (const auto& item : json.at("IPStackListen").as_list()) {
if (item->is_int()) { if (item->is_int()) {
+5
View File
@@ -35,6 +35,7 @@ class Server;
struct PortConfiguration { struct PortConfiguration {
std::string name; std::string name;
std::string addr; // Blank = listen on all interfaces (default)
uint16_t port; uint16_t port;
Version version; Version version;
ServerBehavior behavior; ServerBehavior behavior;
@@ -74,6 +75,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::unordered_map<std::string, std::shared_ptr<PortConfiguration>> name_to_port_config; std::unordered_map<std::string, std::shared_ptr<PortConfiguration>> name_to_port_config;
std::unordered_map<uint16_t, std::shared_ptr<PortConfiguration>> number_to_port_config; std::unordered_map<uint16_t, std::shared_ptr<PortConfiguration>> number_to_port_config;
std::string username; std::string username;
std::string dns_server_addr;
uint16_t dns_server_port = 0; uint16_t dns_server_port = 0;
std::vector<std::string> ip_stack_addresses; std::vector<std::string> ip_stack_addresses;
std::vector<std::string> ppp_stack_addresses; std::vector<std::string> ppp_stack_addresses;
@@ -283,6 +285,9 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
const std::string& gsl_filename = "", const std::string& gsl_filename = "",
const std::string& bb_directory_filename = "") const; const std::string& bb_directory_filename = "") const;
std::pair<std::string, uint16_t> parse_port_spec(const JSON& json) const;
std::vector<PortConfiguration> parse_port_configuration(const JSON& json) const;
void create_load_step_graph(); void create_load_step_graph();
void create_default_lobbies(); void create_default_lobbies();
void collect_network_addresses(); void collect_network_addresses();
+9 -1
View File
@@ -37,7 +37,9 @@
"ExternalAddress": "10.0.1.5", "ExternalAddress": "10.0.1.5",
// Port to listen for DNS queries on. To disable the DNS server, comment this // Port to listen for DNS queries on. To disable the DNS server, comment this
// out or set it to zero. // out or set it to zero. By default, the DNS server listens on all
// interfaces, but you can specify an interface by replacing this with a list
// of [interface_addr_or_name, port].
"DNSServerPort": 53, "DNSServerPort": 53,
// Ports to listen for game connections on. // Ports to listen for game connections on.
@@ -45,6 +47,12 @@
// Format of entries in this dictionary: // Format of entries in this dictionary:
// name: [port, version, behavior] // name: [port, version, behavior]
// port is normally just an integer (which will cause the server to listen
// on that port on all interfaces), but you can also replace the integer
// with a 2-list of [address, port] to listen in a specific port. For
// example, that might look like:
// "xb-login": [["en0", 9500], "xb", "login_server"],
// Various versions of PSO hardcode these ports in the clients. Don't change // Various versions of PSO hardcode these ports in the clients. Don't change
// these unless you don't want to support certain versions of PSO. // these unless you don't want to support certain versions of PSO.
// Note: The pc_console_detect behavior is used for separating PSO PC and // Note: The pc_console_detect behavior is used for separating PSO PC and