Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

### Bug Fixes

- Fixed telnet server failing to accept connections on Windows when loopback interface is intercepted by third-party software (e.g. Npcap/Wireshark) (#3171)
- Fixed numeric formatting patters (thanks @sisve) [commit](https://github.com/KSP-KOS/KOS/commit/5780b75ff90e238c441ab71d366391b051e8bd14)
- Fixed many documentation issues (thanks @sisve) [commit1](https://github.com/KSP-KOS/KOS/commit/727d345679fe992077fa5604c27b43c34a80fbe7) [commit2](https://github.com/KSP-KOS/KOS/commit/afabb19e860adc67ad63f939a3d624e9344ad7b8) [commit3](https://github.com/KSP-KOS/KOS/commit/110b209ad89225bf447caa079334c434df0e9746)
- Fixed `GetSignalDelayToSatellite` for RemoteTech (thanks @KerbalOne) [commit](https://github.com/KSP-KOS/KOS/commit/b76759f24ba43e7cb2d82437c2251caf7d3a582f)
Expand Down
29 changes: 25 additions & 4 deletions src/kOS/UserIO/TelnetMainServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,16 @@ public void StartListening()
// refresh the port information, don't need to refresh address because it's refreshed every Update
port = SafeHouse.Config.TelnetPort;

server = new TcpListener(bindAddr, port);
// Bind to IPAddress.Any instead of the specific bindAddr when using loopback.
// On Windows, Npcap (installed by Wireshark/Nmap) installs a "Npcap Loopback Adapter"
// that intercepts traffic bound specifically to the loopback interface (127.0.0.1),
// causing TCP connections to time out with no SYN-ACK. Binding to IPAddress.Any
// routes through the normal network stack and avoids this issue.
// Non-loopback addresses are used as-is since users explicitly chose them.
var listenAddr = IPAddress.IsLoopback(bindAddr) ? IPAddress.Any : bindAddr;
server = new TcpListener(listenAddr, port);
server.Start();
SafeHouse.Logger.Log(string.Format("{2} TelnetMainServer started listening on {0} {1}", bindAddr, port, KSPLogger.LOGGER_PREFIX));
SafeHouse.Logger.Log(string.Format("{2} TelnetMainServer started listening on {0} (requested {1}) port {3}", listenAddr, bindAddr, KSPLogger.LOGGER_PREFIX, port));
isListening = true;
}

Expand Down Expand Up @@ -333,10 +340,24 @@ public void Update()
return;

TcpClient incomingClient = server.AcceptTcpClient();

string remoteIdent = ((IPEndPoint)(incomingClient.Client.RemoteEndPoint)).Address.ToString();
SafeHouse.Logger.Log(string.Format("{0} telnet server got an incoming connection from {1}", KSPLogger.LOGGER_PREFIX, remoteIdent));


// When the user configured loopback mode, reject connections from non-loopback addresses.
// We bind to IPAddress.Any to work around Npcap intercepting the loopback interface,
// but we still enforce the user's intent to only allow local connections.
if (IPAddress.IsLoopback(bindAddr))
{
var remoteAddr = ((IPEndPoint)(incomingClient.Client.RemoteEndPoint)).Address;
if (!IPAddress.IsLoopback(remoteAddr))
{
SafeHouse.Logger.Log(string.Format("{0} Rejected non-loopback connection from {1} (server is in loopback mode)", KSPLogger.LOGGER_PREFIX, remoteIdent));
incomingClient.Close();
return;
}
}

TelnetSingletonServer newServer = new TelnetSingletonServer(this, incomingClient, ++howManySpawned);
telnets.Add(newServer);
newServer.StartListening();
Expand Down