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:
Snazzah
2026-03-13 04:36:01 -04:00
committed by GitHub
parent f3942a6319
commit c486fb8127
4 changed files with 21 additions and 1 deletions

View File

@@ -8,6 +8,7 @@ import type { VoiceReceivePayload, VoiceSpeakingFlags } from 'discord-api-types/
import { VoiceEncryptionMode, VoiceOpcodes } from 'discord-api-types/voice/v8';
import type { CloseEvent } from 'ws';
import * as secretbox from '../util/Secretbox';
import { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';
import { noop } from '../util/util';
import { DAVESession, getMaxProtocolVersion } from './DAVESession';
import { VoiceUDPSocket } from './VoiceUDPSocket';
@@ -745,7 +746,7 @@ export class Networking extends EventEmitter {
private createAudioPacket(opusPacket: Buffer, connectionData: ConnectionData, daveSession?: DAVESession) {
const rtpHeader = Buffer.alloc(12);
rtpHeader[0] = 0x80;
rtpHeader[1] = 0x78;
rtpHeader[1] = RTP_OPUS_PAYLOAD_TYPE;
const { sequence, timestamp, ssrc } = connectionData;

View File

@@ -7,6 +7,7 @@ import { VoiceOpcodes } from 'discord-api-types/voice/v8';
import { VoiceConnectionStatus, type VoiceConnection } from '../VoiceConnection';
import { NetworkingStatusCode, type ConnectionData } from '../networking/Networking';
import { methods } from '../util/Secretbox';
import { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';
import {
AudioReceiveStream,
createDefaultAudioReceiveStreamOptions,
@@ -137,6 +138,15 @@ export class VoiceReceiver {
let packet: Buffer = this.decrypt(buffer, mode, nonce, secretKey);
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
// The header is only indicated in the original data, so compare with buffer first
if (buffer.subarray(12, 14).compare(HEADER_EXTENSION_BYTE) === 0) {
@@ -176,6 +186,13 @@ export class VoiceReceiver {
if (!stream) return;
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 {
const packet = this.parsePacket(
msg,

View File

@@ -0,0 +1 @@
export const RTP_OPUS_PAYLOAD_TYPE = 0x78;

View File

@@ -1,3 +1,4 @@
export * from './constants';
export * from './generateDependencyReport';
export * from './entersState';
export type * from './adapter';