mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-16 03:23:29 +01:00
fix(voice): strip padding from packets and add guards (#11449)
* fix(voice): strip padding from incoming packets * fix(voice): add additional guards to voice recieve * chore: apply comments * chore: fix formatting
This commit is contained in:
@@ -8,6 +8,7 @@ import type { VoiceReceivePayload, VoiceSpeakingFlags } from 'discord-api-types/
|
|||||||
import { VoiceEncryptionMode, VoiceOpcodes } from 'discord-api-types/voice/v8';
|
import { VoiceEncryptionMode, VoiceOpcodes } from 'discord-api-types/voice/v8';
|
||||||
import type { CloseEvent } from 'ws';
|
import type { CloseEvent } from 'ws';
|
||||||
import * as secretbox from '../util/Secretbox';
|
import * as secretbox from '../util/Secretbox';
|
||||||
|
import { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';
|
||||||
import { noop } from '../util/util';
|
import { noop } from '../util/util';
|
||||||
import { DAVESession, getMaxProtocolVersion } from './DAVESession';
|
import { DAVESession, getMaxProtocolVersion } from './DAVESession';
|
||||||
import { VoiceUDPSocket } from './VoiceUDPSocket';
|
import { VoiceUDPSocket } from './VoiceUDPSocket';
|
||||||
@@ -745,7 +746,7 @@ export class Networking extends EventEmitter {
|
|||||||
private createAudioPacket(opusPacket: Buffer, connectionData: ConnectionData, daveSession?: DAVESession) {
|
private createAudioPacket(opusPacket: Buffer, connectionData: ConnectionData, daveSession?: DAVESession) {
|
||||||
const rtpHeader = Buffer.alloc(12);
|
const rtpHeader = Buffer.alloc(12);
|
||||||
rtpHeader[0] = 0x80;
|
rtpHeader[0] = 0x80;
|
||||||
rtpHeader[1] = 0x78;
|
rtpHeader[1] = RTP_OPUS_PAYLOAD_TYPE;
|
||||||
|
|
||||||
const { sequence, timestamp, ssrc } = connectionData;
|
const { sequence, timestamp, ssrc } = connectionData;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { VoiceOpcodes } from 'discord-api-types/voice/v8';
|
|||||||
import { VoiceConnectionStatus, type VoiceConnection } from '../VoiceConnection';
|
import { VoiceConnectionStatus, type VoiceConnection } from '../VoiceConnection';
|
||||||
import { NetworkingStatusCode, type ConnectionData } from '../networking/Networking';
|
import { NetworkingStatusCode, type ConnectionData } from '../networking/Networking';
|
||||||
import { methods } from '../util/Secretbox';
|
import { methods } from '../util/Secretbox';
|
||||||
|
import { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';
|
||||||
import {
|
import {
|
||||||
AudioReceiveStream,
|
AudioReceiveStream,
|
||||||
createDefaultAudioReceiveStreamOptions,
|
createDefaultAudioReceiveStreamOptions,
|
||||||
@@ -137,6 +138,15 @@ export class VoiceReceiver {
|
|||||||
let packet: Buffer = this.decrypt(buffer, mode, nonce, secretKey);
|
let packet: Buffer = this.decrypt(buffer, mode, nonce, secretKey);
|
||||||
if (!packet) throw new Error('Failed to parse packet');
|
if (!packet) throw new Error('Failed to parse packet');
|
||||||
|
|
||||||
|
// Strip padding (RFC3550 5.1)
|
||||||
|
const hasPadding = buffer[0] && Boolean(buffer[0] & 0b100000);
|
||||||
|
if (hasPadding) {
|
||||||
|
const paddingAmount = packet[packet.length - 1]!;
|
||||||
|
if (paddingAmount < packet.length) {
|
||||||
|
packet = packet.subarray(0, packet.length - paddingAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Strip decrypted RTP Header Extension if present
|
// Strip decrypted RTP Header Extension if present
|
||||||
// The header is only indicated in the original data, so compare with buffer first
|
// The header is only indicated in the original data, so compare with buffer first
|
||||||
if (buffer.subarray(12, 14).compare(HEADER_EXTENSION_BYTE) === 0) {
|
if (buffer.subarray(12, 14).compare(HEADER_EXTENSION_BYTE) === 0) {
|
||||||
@@ -176,6 +186,13 @@ export class VoiceReceiver {
|
|||||||
if (!stream) return;
|
if (!stream) return;
|
||||||
|
|
||||||
if (this.connectionData.encryptionMode && this.connectionData.nonceBuffer && this.connectionData.secretKey) {
|
if (this.connectionData.encryptionMode && this.connectionData.nonceBuffer && this.connectionData.secretKey) {
|
||||||
|
// As a guard, we shouldn't parse packets that (1) aren't voice packets and (2) are not in the right RTP version
|
||||||
|
if ((msg[1]! & 0x7f) !== RTP_OPUS_PAYLOAD_TYPE) return;
|
||||||
|
|
||||||
|
// Ignore packets not in RTP version 2
|
||||||
|
const rtpVersion = msg[0]! >> 6;
|
||||||
|
if (rtpVersion !== 2) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const packet = this.parsePacket(
|
const packet = this.parsePacket(
|
||||||
msg,
|
msg,
|
||||||
|
|||||||
1
packages/voice/src/util/constants.ts
Normal file
1
packages/voice/src/util/constants.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const RTP_OPUS_PAYLOAD_TYPE = 0x78;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export * from './constants';
|
||||||
export * from './generateDependencyReport';
|
export * from './generateDependencyReport';
|
||||||
export * from './entersState';
|
export * from './entersState';
|
||||||
export type * from './adapter';
|
export type * from './adapter';
|
||||||
|
|||||||
Reference in New Issue
Block a user