Skip to content

Commit d3e583b

Browse files
committed
check session IDs in all UDP response packets
1 parent 2bdf979 commit d3e583b

File tree

4 files changed

+48
-3
lines changed

4 files changed

+48
-3
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "craftping",
33
"type": "module",
4-
"version": "2.0.0",
4+
"version": "2.0.1",
55
"main": "index.js",
66
"repository": "github:aternosorg/craftping",
77
"scripts": {

src/BedrockPing/BedrockPing.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,37 @@
11
import UDPClient from "../UDPSocket/UDPClient.js";
22
import UnconnectedPing from "../Packet/BedrockPing/UnconnectedPing.js";
33
import UnconnectedPong from "../Packet/BedrockPing/UnconnectedPong.js";
4+
import * as crypto from "node:crypto";
45

56
export default class BedrockPing extends UDPClient {
7+
/** @type {BigInt} */ sessionId;
8+
69
/**
710
* @return {Promise<UnconnectedPong>}
811
*/
912
async ping() {
13+
// Normally, the time field is used for the current ms timestamp, but we're using it as a session ID
14+
// to identify which reply belongs to which request.
15+
this.sessionId = crypto.randomBytes(8).readBigInt64BE();
1016
let startTime = BigInt(Date.now());
11-
await this.sendPacket(new UnconnectedPing().setTime(startTime).generateClientGUID());
17+
await this.sendPacket(new UnconnectedPing().setTime(this.sessionId).generateClientGUID());
1218
this.signal?.throwIfAborted();
1319

14-
return new UnconnectedPong().read(await this.readData());
20+
// The time field in the response contains the session ID, but we replace it with the start time
21+
// in case anyone relies on the time field containing an actual timestamp.
22+
return new UnconnectedPong().read(await this.readData()).setTime(startTime);
23+
}
24+
25+
/**
26+
* @inheritDoc
27+
*/
28+
shouldAcceptPacket(packet) {
29+
let data = packet.getData();
30+
if (data.byteLength < 9) {
31+
return false;
32+
}
33+
34+
let timestamp = data.readBigInt64BE(1);
35+
return timestamp === this.sessionId;
1536
}
1637
}

src/Query/Query.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,17 @@ export default class Query extends UDPClient {
5252
this.signal?.throwIfAborted();
5353
return new FullStatResponse().read(await this.readData());
5454
}
55+
56+
/**
57+
* @inheritDoc
58+
*/
59+
shouldAcceptPacket(packet) {
60+
let data = packet.getData();
61+
if (data.byteLength < 5) {
62+
return false;
63+
}
64+
65+
let session = data.readUInt32BE(1);
66+
return session === this.sessionId;
67+
}
5568
}

src/UDPSocket/UDPSocket.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ export default class UDPSocket extends EventEmitter {
115115

116116
handleMessage(data, info) {
117117
let message = new UDPMessage(data, info);
118+
if (!this.shouldAcceptPacket(message)) {
119+
return this;
120+
}
118121

119122
if (this.readQueue.length > 0) {
120123
this.readQueue.shift().resolve(message);
@@ -166,4 +169,12 @@ export default class UDPSocket extends EventEmitter {
166169
});
167170
});
168171
}
172+
173+
/**
174+
* @param {UDPMessage} packet
175+
* @return {boolean}
176+
*/
177+
shouldAcceptPacket(packet) {
178+
return true
179+
}
169180
}

0 commit comments

Comments
 (0)