diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 86ac54b7f..a0001ef85 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1,9 +1,14 @@ # The socket bind address for all net.psforever.services except admin. 127.0.0.1 is the -# default for local testing, for public servers use 0.0.0.0 instead. +# default for local testing, for LAN or public servers use 0.0.0.0 instead. bind = 127.0.0.1 -# The public host name or IP address. Used to forward clients from the login -# server to the world server. The default value will only allow local connections. +# The private host name or IP address. Used to forward clients on the local network +# from the login server to the world server. The default value will only allow connections from the host machine, +# set this to the host machines private address on the local network to allow connections from other machines on it. +local = 127.0.0.1 + +# The public host name or IP address. Used to forward external clients from outside the local network +# from the login server to the world server. The default value will not allow external connections. public = 127.0.0.1 # Login server configuration diff --git a/src/main/scala/net/psforever/actors/net/LoginActor.scala b/src/main/scala/net/psforever/actors/net/LoginActor.scala index abfc9c900..bc82119bc 100644 --- a/src/main/scala/net/psforever/actors/net/LoginActor.scala +++ b/src/main/scala/net/psforever/actors/net/LoginActor.scala @@ -33,6 +33,10 @@ object LoginActor { final case class ReceptionistListing(listing: Receptionist.Listing) extends Command + private val gameTestServerAddressLocal = new InetSocketAddress(InetAddress.getByName(Config.app.local), Config.app.world.port) + private val gameTestServerAddressPublic = new InetSocketAddress(InetAddress.getByName(Config.app.public), Config.app.world.port) + private val localHostAddress = new InetSocketAddress("127.0.0.1", Config.app.world.port) + /** * What does a token do? * No one knows. @@ -78,6 +82,26 @@ object LoginActor { //remove color codes from the server name - look for '\\#' followed by six characters or numbers name.replaceAll("\\\\#[\\da-fA-F]{6}","") } + + /** + * Selects the appropriate host address for transfer to world server. + * This is a workaround for cases of local connections not working + * properly when using a router that lacks Hairpin NAT support. + * @param ipAddress the IP address of the connecting client in string form + * @return the appropriate host address + */ + private def selectHostAddress(ipAddress: String): InetSocketAddress = { + val address = InetAddress.getByName(ipAddress) + if (address.isLoopbackAddress()) { + localHostAddress + } + else if (address.isSiteLocalAddress()) { + gameTestServerAddressLocal + } + else { + gameTestServerAddressPublic + } + } } class LoginActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], connectionId: String, sessionId: Long) @@ -96,7 +120,6 @@ class LoginActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], conne private var port: Int = 0 private val serverName: String = Config.app.world.serverName - private val gameTestServerAddress = new InetSocketAddress(InetAddress.getByName(Config.app.public), Config.app.world.port) private val bcryptRounds = 12 @@ -152,7 +175,7 @@ class LoginActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], conne updateServerList() case SocketPane.NextPort(_, _, portNum) => - val address = gameTestServerAddress.getAddress.getHostAddress + val address = LoginActor.selectHostAddress(ipAddress).getAddress.getHostAddress log.info(s"Connecting to ${address.toLowerCase}: $portNum ...") val response = ConnectToWorldMessage(serverName, address, portNum) context.become(idlingBehavior) @@ -165,7 +188,7 @@ class LoginActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], conne private def waitingForServerTransferBehavior: Receive = persistentSetupMixinBehavior.orElse { case SocketPane.NextPort(_, _, portNum) => - val address = gameTestServerAddress.getAddress.getHostAddress + val address = LoginActor.selectHostAddress(ipAddress).getAddress.getHostAddress log.info(s"Connecting to ${address.toLowerCase}: $portNum ...") val response = ConnectToWorldMessage(serverName, address, portNum) context.become(idlingBehavior) @@ -498,7 +521,7 @@ class LoginActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], conne serverName, WorldStatus.Up, Config.app.world.serverType, - Vector(WorldConnectionInfo(gameTestServerAddress)), //todo ideally, ask for info from SocketPane + Vector(WorldConnectionInfo(LoginActor.selectHostAddress(ipAddress))), //todo ideally, ask for info from SocketPane PlanetSideEmpire.VS ) ) diff --git a/src/main/scala/net/psforever/util/Config.scala b/src/main/scala/net/psforever/util/Config.scala index c814904b6..d11958ab8 100644 --- a/src/main/scala/net/psforever/util/Config.scala +++ b/src/main/scala/net/psforever/util/Config.scala @@ -84,6 +84,7 @@ object Config { case class AppConfig( bind: String, + local: String, public: String, login: LoginConfig, world: WorldConfig,