Skip to content

Commit c486fb8

Browse files
authored
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
1 parent f3942a6 commit c486fb8

File tree

4 files changed

+21
-1
lines changed

4 files changed

+21
-1
lines changed

packages/voice/src/networking/Networking.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { VoiceReceivePayload, VoiceSpeakingFlags } from 'discord-api-types/
88
import { VoiceEncryptionMode, VoiceOpcodes } from 'discord-api-types/voice/v8';
99
import type { CloseEvent } from 'ws';
1010
import * as secretbox from '../util/Secretbox';
11+
import { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';
1112
import { noop } from '../util/util';
1213
import { DAVESession, getMaxProtocolVersion } from './DAVESession';
1314
import { VoiceUDPSocket } from './VoiceUDPSocket';
@@ -745,7 +746,7 @@ export class Networking extends EventEmitter {
745746
private createAudioPacket(opusPacket: Buffer, connectionData: ConnectionData, daveSession?: DAVESession) {
746747
const rtpHeader = Buffer.alloc(12);
747748
rtpHeader[0] = 0x80;
748-
rtpHeader[1] = 0x78;
749+
rtpHeader[1] = RTP_OPUS_PAYLOAD_TYPE;
749750

750751
const { sequence, timestamp, ssrc } = connectionData;
751752

packages/voice/src/receive/VoiceReceiver.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { VoiceOpcodes } from 'discord-api-types/voice/v8';
77
import { VoiceConnectionStatus, type VoiceConnection } from '../VoiceConnection';
88
import { NetworkingStatusCode, type ConnectionData } from '../networking/Networking';
99
import { methods } from '../util/Secretbox';
10+
import { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';
1011
import {
1112
AudioReceiveStream,
1213
createDefaultAudioReceiveStreamOptions,
@@ -137,6 +138,15 @@ export class VoiceReceiver {
137138
let packet: Buffer = this.decrypt(buffer, mode, nonce, secretKey);
138139
if (!packet) throw new Error('Failed to parse packet');
139140

141+
// Strip padding (RFC3550 5.1)
142+
const hasPadding = buffer[0] && Boolean(buffer[0] & 0b100000);
143+
if (hasPadding) {
144+
const paddingAmount = packet[packet.length - 1]!;
145+
if (paddingAmount < packet.length) {
146+
packet = packet.subarray(0, packet.length - paddingAmount);
147+
}
148+
}
149+
140150
// Strip decrypted RTP Header Extension if present
141151
// The header is only indicated in the original data, so compare with buffer first
142152
if (buffer.subarray(12, 14).compare(HEADER_EXTENSION_BYTE) === 0) {
@@ -176,6 +186,13 @@ export class VoiceReceiver {
176186
if (!stream) return;
177187

178188
if (this.connectionData.encryptionMode && this.connectionData.nonceBuffer && this.connectionData.secretKey) {
189+
// As a guard, we shouldn't parse packets that (1) aren't voice packets and (2) are not in the right RTP version
190+
if ((msg[1]! & 0x7f) !== RTP_OPUS_PAYLOAD_TYPE) return;
191+
192+
// Ignore packets not in RTP version 2
193+
const rtpVersion = msg[0]! >> 6;
194+
if (rtpVersion !== 2) return;
195+
179196
try {
180197
const packet = this.parsePacket(
181198
msg,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const RTP_OPUS_PAYLOAD_TYPE = 0x78;

packages/voice/src/util/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './constants';
12
export * from './generateDependencyReport';
23
export * from './entersState';
34
export type * from './adapter';

0 commit comments

Comments
 (0)