From a41cb7965e8545557189f50caee75cdb27aec028 Mon Sep 17 00:00:00 2001 From: iceBear67 Date: Wed, 15 Jul 2026 16:05:34 +0000 Subject: [PATCH] remove username sniffer --- PROTOCOL.md | 6 ++-- client/client.go | 7 ++-- docs/architecture.md | 4 +-- .../io/icybear/redapricot/ControlSession.java | 5 ++- .../io/icybear/redapricot/HubConnection.java | 32 +++---------------- 5 files changed, 14 insertions(+), 40 deletions(-) diff --git a/PROTOCOL.md b/PROTOCOL.md index e4a9da4..50d24c2 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -195,7 +195,7 @@ Type : u8 | `0x01` | Register | C → S | `Pattern: String` | | `0x02` | Unregister | C → S | `Pattern: String` | | `0x03` | RegisterAck | S → C | `Pattern: String`, `Status: u8` (0 = ok, 1 = invalid pattern) | -| `0x04` | ControlRequest | S → C | `CID: Bytes[16]`, `Pattern: String`, `PlayerIP: String`, `PlayerPort: U16`, `Username: String` | +| `0x04` | ControlRequest | S → C | `CID: Bytes[16]`, `Pattern: String`, `PlayerIP: String`, `PlayerPort: U16` | | `0x05` | Ping | C → S | `Nonce: I64` | | `0x06` | Pong | S → C | `Nonce: I64` | @@ -214,9 +214,7 @@ Type : u8 can look the pattern up in its own route table. `CID` is 16 cryptographically-random bytes generated by the hub, unique to that pending player. `PlayerIP`/`PlayerPort` are the player's source address (used for - HAProxy v2). `Username` is the player's name, read best-effort from the Login - Start packet — present when the client pipelined it with the Handshake (the - usual case), otherwise an empty string. It is informational (logging) only. + HAProxy v2). * **Ping/Pong**: optional keepalive so idle control sessions survive NAT timeouts. The client pings periodically; the hub echoes the nonce. diff --git a/client/client.go b/client/client.go index 42ebbe3..2165e0f 100644 --- a/client/client.go +++ b/client/client.go @@ -221,8 +221,7 @@ func (c *Client) dispatchControl(payload []byte) { pattern, _ := r.String() ip, _ := r.String() port, _ := r.U16() - username, _ := r.String() - go c.handleControlRequest(cid, pattern, ip, int(port), username) + go c.handleControlRequest(cid, pattern, ip, int(port)) case CtlPong: // ignore default: @@ -248,13 +247,13 @@ func (c *Client) pingLoop(ctx context.Context, fc *wire.FramedConn) { // handleControlRequest reacts to a matched player: allocate a worker stream, // SYN it, and bridge it to the mapped destination. -func (c *Client) handleControlRequest(cid []byte, pattern, ip string, port int, username string) { +func (c *Client) handleControlRequest(cid []byte, pattern, ip string, port int) { mapping, ok := c.mappings[NormalizeAddress(pattern)] if !ok { log.Printf("control-request for unmapped pattern %q; ignoring", pattern) return } - log.Printf("player %s:%d joined as %q via pattern %q -> %s", ip, port, username, pattern, mapping.Destination) + log.Printf("player %s:%d joined via pattern %q -> %s", ip, port, pattern, mapping.Destination) wc, sid, err := c.pool.Allocate() if err != nil { log.Printf("worker allocate failed: %v", err) diff --git a/docs/architecture.md b/docs/architecture.md index 41da6d6..6ab96a9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -65,9 +65,9 @@ share a keystream beyond that first frame. ``` Player Hub Client Destination │─ Handshake(addr="mc.example.com", Intent=2)─▶ normalize + regex-match - │ (+ maybe pipelined Login Start) │ pause player socket, + │ │ pause player socket, │ │ buffer bytes, mint CID - │ │─ ControlRequest(CID, pattern, ip:port, user) ─▶ + │ │─ ControlRequest(CID, pattern, ip:port) ─▶ │ │ allocate worker+stream │ │◀──────── SYN(streamId, CID) ────────────│ │ │ takePending(CID) → bind dial destination, diff --git a/server/src/main/java/io/icybear/redapricot/ControlSession.java b/server/src/main/java/io/icybear/redapricot/ControlSession.java index 913c07e..e1859b6 100644 --- a/server/src/main/java/io/icybear/redapricot/ControlSession.java +++ b/server/src/main/java/io/icybear/redapricot/ControlSession.java @@ -43,17 +43,16 @@ public final class ControlSession { } } - public void sendControlRequest(byte[] cid, String pattern, String playerIp, int playerPort, String username) { + public void sendControlRequest(byte[] cid, String pattern, String playerIp, int playerPort) { byte[] msg = new ProtoWriter() .u8(Protocol.CTL_CONTROL_REQUEST) .bytes(cid) .string(pattern) .string(playerIp) .u16(playerPort) - .string(username) .toBytes(); frames.send(msg); - LOG.info("control-request pattern={} player={}:{} user={}", pattern, playerIp, playerPort, username); + LOG.info("control-request pattern={} player={}:{}", pattern, playerIp, playerPort); } private void sendRegisterAck(String pattern, int status) { diff --git a/server/src/main/java/io/icybear/redapricot/HubConnection.java b/server/src/main/java/io/icybear/redapricot/HubConnection.java index abe71d2..145c6b1 100644 --- a/server/src/main/java/io/icybear/redapricot/HubConnection.java +++ b/server/src/main/java/io/icybear/redapricot/HubConnection.java @@ -106,7 +106,7 @@ public final class HubConnection { LOG.info("{} reserved intent 18; closing", id); socket.close(); } else { - handlePlayer(address, intent, afterHandshake); + handlePlayer(address); } } @@ -203,7 +203,7 @@ public final class HubConnection { // ---- player connection ---- - private void handlePlayer(String address, int intent, Buffer afterHandshake) { + private void handlePlayer(String address) { String host = Hub.normalizeAddress(address); Hub.Match matched = hub.match(address); if (matched == null) { @@ -219,9 +219,6 @@ public final class HubConnection { String cidHex = Hex.encode(cid); String ip = socket.remoteAddress() != null ? socket.remoteAddress().host() : "0.0.0.0"; int port = socket.remoteAddress() != null ? socket.remoteAddress().port() : 0; - // Best-effort username: only login/transfer intents carry a Login Start, and only - // if the client pipelined it into this same buffer (the usual case). - String username = (intent == 2 || intent == 3) ? parseLoginName(afterHandshake) : ""; socket.pause(); Buffer buffered = hs.copy(); // handshake + any pipelined bytes, forwarded verbatim @@ -230,27 +227,8 @@ public final class HubConnection { hub.addPending(p); closeCleanup = () -> hub.removePending(cidHex); - session.sendControlRequest(cid, pattern, ip, port, username); - LOG.info("{} player {}:{} host '{}' user '{}' matched pattern '{}' cid={}", - id, ip, port, host, username, pattern, cidHex); - } - - /** - * Best-effort read of the player's username from a pipelined Login Start packet - * (Login state, packet id 0x00, first field {@code Name: String}). Returns "" if - * the packet is not (yet) fully present or does not parse as a Login Start; the hub - * never blocks waiting for it. - */ - private static String parseLoginName(Buffer afterHandshake) { - if (afterHandshake == null || afterHandshake.length() == 0) return ""; - try { - ProtoReader r = new ProtoReader(afterHandshake); - int pktLen = r.readVarInt(); - if (pktLen <= 0 || pktLen > r.remaining()) return ""; // not fully buffered - if (r.readVarInt() != 0x00) return ""; // not a Login Start - return r.readString(); - } catch (RuntimeException e) { - return ""; - } + session.sendControlRequest(cid, pattern, ip, port); + LOG.info("{} player {}:{} host '{}' matched pattern '{}' cid={}", + id, ip, port, host, pattern, cidHex); } }