Web relay websocket ping/pong forwarding, #4172
Ylian Saint-Hilaire committed
Jun 28, 2022 at 15:42 UTC
a383bd1cb3f794c59dbc88c5243aa54d15e8651d
1 file changed
+43
-59
apprelays.js
+43
-59
@@ -260,42 +260,48 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
260
// Setup opcode and payload
261
var op = 2, payload = data;
262
if (typeof data == 'string') { op = 1; payload = Buffer.from(data, 'binary'); } // Text frame
263
-
264
- // Select a random mask
265
- const mask = parent.parent.crypto.randomBytes(4)
266
-
267
- // Setup header and mask
268
- var header = null;
269
- if (data.length < 126) {
270
- header = Buffer.alloc(6); // Header (2) + Mask (4)
271
- header[0] = 0x80 + op; // FIN + OP
272
- header[1] = 0x80 + data.length; // Mask + Length
273
- mask.copy(header, 2, 0, 4); // Copy the mask
274
- } else if (data.length <= 0xFFFF) {
275
- header = Buffer.alloc(8); // Header (2) + Length (2) + Mask (4)
276
- header[0] = 0x80 + op; // FIN + OP
277
- header[1] = 0x80 + 126; // Mask + 126
278
- header.writeInt16BE(data.length, 2); // Payload size
279
- mask.copy(header, 4, 0, 4); // Copy the mask
280
- } else {
281
- header = Buffer.alloc(14); // Header (2) + Length (8) + Mask (4)
282
- header[0] = 0x80 + op; // FIN + OP
283
- header[1] = 0x80 + 127; // Mask + 127
284
- header.writeInt32BE(data.length, 6); // Payload size
285
- mask.copy(header, 10, 0, 4); // Copy the mask
286
- }
287
-
288
- // Mask the payload
289
- for (var i = 0; i < payload.length; i++) { payload[i] = (payload[i] ^ mask[i % 4]); }
290
-
291
- // Send the frame
292
- //console.log(obj.tunnelId, '-->', op, payload.length);
293
- send(Buffer.concat([header, payload]));
263
+ sendWebSocketFrameToDevice(op, payload);
264
});
265
+
266
+ obj.ws.on('ping', function (data) { sendWebSocketFrameToDevice(9, data); }); // Forward ping frame
267
+ obj.ws.on('pong', function (data) { sendWebSocketFrameToDevice(10, data); }); // Forward pong frame
268
obj.ws.on('close', function () { obj.close(); });
269
obj.ws.on('error', function (err) { obj.close(); });
270
}
271
272
+ function sendWebSocketFrameToDevice(op, payload) {
273
+ // Select a random mask
274
+ const mask = parent.parent.crypto.randomBytes(4)
275
+
276
+ // Setup header and mask
277
+ var header = null;
278
+ if (payload.length < 126) {
279
+ header = Buffer.alloc(6); // Header (2) + Mask (4)
280
+ header[0] = 0x80 + op; // FIN + OP
281
+ header[1] = 0x80 + payload.length; // Mask + Length
282
+ mask.copy(header, 2, 0, 4); // Copy the mask
283
+ } else if (payload.length <= 0xFFFF) {
284
+ header = Buffer.alloc(8); // Header (2) + Length (2) + Mask (4)
285
+ header[0] = 0x80 + op; // FIN + OP
286
+ header[1] = 0x80 + 126; // Mask + 126
287
+ header.writeInt16BE(payload.length, 2); // Payload size
288
+ mask.copy(header, 4, 0, 4); // Copy the mask
289
+ } else {
290
+ header = Buffer.alloc(14); // Header (2) + Length (8) + Mask (4)
291
+ header[0] = 0x80 + op; // FIN + OP
292
+ header[1] = 0x80 + 127; // Mask + 127
293
+ header.writeInt32BE(payload.length, 6); // Payload size
294
+ mask.copy(header, 10, 0, 4); // Copy the mask
295
+ }
296
+
297
+ // Mask the payload
298
+ for (var i = 0; i < payload.length; i++) { payload[i] = (payload[i] ^ mask[i % 4]); }
299
+
300
+ // Send the frame
301
+ //console.log(obj.tunnelId, '-->', op, payload.length);
302
+ send(Buffer.concat([header, payload]));
303
+ }
304
+
305
// Disconnect
306
obj.close = function (arg) {
307
if (obj.closed == true) return;
@@ -541,34 +547,12 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
547
548
// Perform operation
549
switch (op) {
544
- case 0: { // Continue frame
545
- //console.log('continue', payload.length);
546
- break;
547
- }
548
- case 1: { // Text frame
549
- //console.log('text', payload.length);
550
- try { obj.ws.send(payload.toString('binary')); } catch (ex) { }
551
- break;
552
- }
553
- case 2: { // Binary frame
554
- //console.log('binary', payload.length);
555
- try { obj.ws.send(payload); } catch (ex) { }
556
- break;
557
- }
558
- case 8: { // Connection close
559
- obj.close();
560
- return;
561
- }
562
- case 9: { // Ping frame
563
- //console.log('ping', payload.length);
564
- // TODO
565
- break;
566
- }
567
- case 10: { // Pong frame
568
- //console.log('pong', payload.length);
569
- // TODO
570
- break;
571
- }
550
+ case 0: { break; } // Continue frame (TODO)
551
+ case 1: { try { obj.ws.send(payload.toString('binary')); } catch (ex) { } break; } // Text frame
552
+ case 2: { try { obj.ws.send(payload); } catch (ex) { } break; } // Binary frame
553
+ case 8: { obj.close(); return; } // Connection close
554
+ case 9: { try { obj.ws.ping(payload); } catch (ex) { } break; } // Ping frame
555
+ case 10: { try { obj.ws.pong(payload); } catch (ex) { } break; } // Pong frame
556
}
557
}
558
}