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;
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->listen("", state->dns_server_port);
dns_server->listen(state->dns_server_addr, state->dns_server_port);
} else {
config_log.info("DNS server is disabled");
}
@@ -1934,14 +1938,14 @@ Action a_run_server_replay_log(
auto [ss, size] = make_sockaddr_storage(
state->proxy_destination_patch.first,
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)) {
auto [ss, size] = make_sockaddr_storage(
state->proxy_destination_bb.first,
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 {
state->proxy_server->listen(pc->port, pc->version);
state->proxy_server->listen(pc->addr, pc->port, pc->version);
}
}
} else {
@@ -1950,7 +1954,7 @@ Action a_run_server_replay_log(
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));
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),
next_unlicensed_session_id(0xFF00000000000001) {}
void ProxyServer::listen(uint16_t port, Version version, const struct sockaddr_storage* default_destination) {
auto socket_obj = make_shared<ListeningSocket>(this, port, version, default_destination);
auto l = this->listeners.emplace(port, socket_obj).first->second;
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, addr, port, version, default_destination);
if (!this->listeners.emplace(port, socket_obj).second) {
throw runtime_error("duplicate port in proxy server configuration");
}
}
ProxyServer::ListeningSocket::ListeningSocket(
ProxyServer* server,
const std::string& addr,
uint16_t port,
Version version,
const struct sockaddr_storage* default_destination)
: server(server),
log(string_printf("[ProxyServer:ListeningSocket:%hu] ", port), proxy_server_log.min_level),
port(port),
fd(::listen("", port, SOMAXCONN)),
fd(::listen(addr, port, SOMAXCONN)),
listener(nullptr, evconnlistener_free),
version(version) {
if (!this->fd.is_open()) {
+2 -1
View File
@@ -26,7 +26,7 @@ public:
std::shared_ptr<ServerState> state);
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);
@@ -207,6 +207,7 @@ private:
ListeningSocket(
ProxyServer* server,
const std::string& addr,
uint16_t port,
Version version,
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;
for (const auto& item_json_it : json.as_dict()) {
const auto& item_list = item_json_it.second;
PortConfiguration& pc = ret.emplace_back();
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.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->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 {
for (const auto& item : json.at("IPStackListen").as_list()) {
if (item->is_int()) {
+5
View File
@@ -35,6 +35,7 @@ class Server;
struct PortConfiguration {
std::string name;
std::string addr; // Blank = listen on all interfaces (default)
uint16_t port;
Version version;
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<uint16_t, std::shared_ptr<PortConfiguration>> number_to_port_config;
std::string username;
std::string dns_server_addr;
uint16_t dns_server_port = 0;
std::vector<std::string> ip_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& 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_default_lobbies();
void collect_network_addresses();
+9 -1
View File
@@ -37,7 +37,9 @@
"ExternalAddress": "10.0.1.5",
// 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,
// Ports to listen for game connections on.
@@ -45,6 +47,12 @@
// Format of entries in this dictionary:
// 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
// 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