Skip to content

Commit 02bde63

Browse files
committed
Add connection type tracking and secure telnet port support
Overview: Secure ports only listen to localhost like the LocalPort, and will display on the website as secure if added to config. Added: - ConnectionType field to OnlineInfo struct showing "Web", "Telnet", or "Secure" - GetLocalPort method to ConnectionDetails for port detection - GetConnectionPort helper function in connections package - SecureTelnetPort configuration field for localhost-only secure connections - Automatic listening on SecureTelnetPort (localhost-only, like LocalPort) - Connection type detection based on WebSocket status and port number - Connection type column to online users HTML table Changed: - GetOnlineInfo method to determine and include connection type - Online page to display how each user is connected - Config documentation to clarify SecureTelnetPort behavior
1 parent daa7057 commit 02bde63

File tree

8 files changed

+83
-13
lines changed

8 files changed

+83
-13
lines changed

_datafiles/config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,9 @@ Network:
384384
# ports by separating them with commas. For example, [33333, 33334, 33335]
385385
TelnetPort: [33333, 44444]
386386
# - SecureTelnetPort -
387-
# The port the server listens on for secure telnet connections. Listen on multiple
388-
# ports by separating them with commas. For example, [33334, 33335]
389-
# Set to [0] to disable secure telnet.
387+
# Localhost-only ports for secure telnet connections (e.g., TLS proxy forwarding).
388+
# Like LocalPort but shown on website. Multiple ports supported: [33334, 33335]
389+
# Set to [0] to disable.
390390
SecureTelnetPort: [0]
391391
# - LocalPort -
392392
# A port that can only be accessed via localhost, but will not limit based on connection count

_datafiles/html/public/online.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ <h3>Users Online: </h3>
1212
<th>Alignment</th>
1313
<th>Profession</th>
1414
<th>Time Online</th>
15+
<th>Connection</th>
1516
<th>Role</th>
1617
</tr>
1718
{{range $index, $uInfo := .STATS.OnlineUsers}}
@@ -22,6 +23,7 @@ <h3>Users Online: </h3>
2223
<td align="center">{{ $uInfo.Alignment }}</td>
2324
<td align="center">{{ $uInfo.Profession }}</td>
2425
<td align="center">{{ $uInfo.OnlineTimeStr }}{{ if $uInfo.IsAFK }} (AFK){{end}}</td>
26+
<td align="center">{{ $uInfo.ConnectionType }}</td>
2527
<td align="center">{{ $uInfo.Role }}</td>
2628
</tr>
2729
{{end}}

internal/connections/connectiondetails.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package connections
33
import (
44
"errors"
55
"net"
6+
"strconv"
67
"strings"
78
"sync"
89
"sync/atomic"
@@ -278,6 +279,32 @@ func (cd *ConnectionDetails) RemoteAddr() net.Addr {
278279
return cd.conn.RemoteAddr()
279280
}
280281

282+
// GetLocalPort returns the local port the connection came in on
283+
func (cd *ConnectionDetails) GetLocalPort() int {
284+
var localAddr net.Addr
285+
if cd.wsConn != nil {
286+
localAddr = cd.wsConn.LocalAddr()
287+
} else if cd.conn != nil {
288+
localAddr = cd.conn.LocalAddr()
289+
} else {
290+
return 0
291+
}
292+
293+
// Extract port from address
294+
if tcpAddr, ok := localAddr.(*net.TCPAddr); ok {
295+
return tcpAddr.Port
296+
}
297+
298+
// Try parsing as string
299+
_, portStr, err := net.SplitHostPort(localAddr.String())
300+
if err != nil {
301+
return 0
302+
}
303+
304+
port, _ := strconv.Atoi(portStr)
305+
return port
306+
}
307+
281308
// get for uniqueId
282309
func (cd *ConnectionDetails) ConnectionId() ConnectionId {
283310
return ConnectionId(atomic.LoadUint64((*uint64)(&cd.connectionId)))

internal/connections/connections.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ func IsWebsocket(id ConnectionId) bool {
8080
return false
8181
}
8282

83+
func GetConnectionPort(id ConnectionId) int {
84+
lock.Lock()
85+
defer lock.Unlock()
86+
87+
if cd, ok := netConnections[id]; ok {
88+
return cd.GetLocalPort()
89+
}
90+
91+
return 0
92+
}
93+
8394
func GetAllConnectionIds() []ConnectionId {
8495

8596
lock.Lock()

internal/users/onlineinfo.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package users
22

33
type OnlineInfo struct {
4-
Username string
5-
CharacterName string
6-
Level int
7-
Alignment string
8-
Profession string
9-
OnlineTime int64
10-
OnlineTimeStr string
11-
IsAFK bool
12-
Role string
4+
Username string
5+
CharacterName string
6+
Level int
7+
Alignment string
8+
Profession string
9+
OnlineTime int64
10+
OnlineTimeStr string
11+
IsAFK bool
12+
Role string
13+
ConnectionType string // "Web", "Telnet", or "Secure"
1314
}

internal/users/userrecord.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"math"
77
"math/big"
8+
"strconv"
89
"strings"
910
"time"
1011

@@ -619,6 +620,23 @@ func (u *UserRecord) GetOnlineInfo() OnlineInfo {
619620
isAfk = true
620621
}
621622

623+
// Determine connection type
624+
connectionType := "Telnet"
625+
if connections.IsWebsocket(u.connectionId) {
626+
connectionType = "Web"
627+
} else {
628+
// Check if connected through a secure telnet port
629+
port := connections.GetConnectionPort(u.connectionId)
630+
networkConfig := configs.GetNetworkConfig()
631+
for _, securePortStr := range networkConfig.SecureTelnetPort {
632+
securePort, _ := strconv.Atoi(securePortStr)
633+
if securePort > 0 && port == securePort {
634+
connectionType = "Secure"
635+
break
636+
}
637+
}
638+
}
639+
622640
return OnlineInfo{
623641
u.Username,
624642
u.Character.Name,
@@ -629,6 +647,7 @@ func (u *UserRecord) GetOnlineInfo() OnlineInfo {
629647
timeStr,
630648
isAfk,
631649
u.Role,
650+
connectionType,
632651
}
633652
}
634653

internal/web/web.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ func getClientIP(r *http.Request) string {
5858
}
5959

6060
// Only trust proxy headers if the connection is from localhost
61-
if host == "127.0.0.1" || host == "::1" || host == "localhost" {
61+
// Check for various localhost representations
62+
if host == "127.0.0.1" || host == "::1" || host == "localhost" || host == "0.0.0.0" {
6263
// Check X-Real-IP first (higher priority)
6364
if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
6465
return realIP

main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,15 @@ func main() {
271271
TelnetListenOnPort(`127.0.0.1`, int(c.Network.LocalPort), &wg, 0)
272272
}
273273

274+
// Secure telnet ports - same as LocalPort but tracked differently
275+
for _, port := range c.Network.SecureTelnetPort {
276+
if p, err := strconv.Atoi(port); err == nil && p > 0 {
277+
mudlog.Info("Telnet", "stage", "Listening on secure port (localhost only)", "port", p)
278+
// Same as LocalPort - localhost only, no connection limit
279+
TelnetListenOnPort(`127.0.0.1`, p, &wg, 0)
280+
}
281+
}
282+
274283
go worldManager.InputWorker(workerShutdownChan, &wg)
275284
go worldManager.MainWorker(workerShutdownChan, &wg)
276285

0 commit comments

Comments
 (0)