Skip to content

SimoHypers/discord-voice-patch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

drover-go

Bypass DPI blocking of Discord voice chat.

Drover intercepts the 74-byte UDP STUN Binding Request that Discord sends to voice servers, injects two tiny 1-byte probe packets (0x00, 0x01) before it, waits 50ms, then releases the original packet. This corrupts the DPI's flow signature and lets voice traffic through.

Disclaimer: This project is experimental and for educational/research purposes only. It is a personal tool developed to study network filtering techniques. Use at your own risk. Not affiliated with Discord or any ISP.

Getting Started

git clone https://github.com/SimoHypers/discord-voice-patch.git
cd discord-voice-patch

Prerequisites

  • Linux (kernel with NFQUEUE and nftables support)
  • Go 1.25+
  • Root privileges (or CAP_NET_ADMIN + CAP_NET_RAW) for daemon mode
  • gcc for LD_PRELOAD fallback mode

Build

go build -o drover ./cmd/drover

No CGo required. The binary is pure Go.

To embed version/commit data:

go build -ldflags "-X main.version=$(git describe --tags --always --dirty) \
                    -X main.commit=$(git rev-parse --short HEAD) \
                    -X main.buildDate=$(date -u +%Y-%m-%d)" \
          -o drover ./cmd/drover

Install

sudo cp drover /usr/local/bin/

Or run ./drover directly from the project directory.

Quick Start

One-command install (recommended)

sudo drover install

Installs the systemd service, starts the daemon immediately, and configures it to auto-start on boot. After this, Discord voice works β€” no terminal needed.

Manual Daemon Mode

sudo drover daemon

Sets up nftables rules, opens an NFQUEUE, and processes packets. Press Ctrl+C to stop. Rules are automatically removed on exit unless disabled in config.

LD_PRELOAD Mode (fallback β€” native Discord installs only)

drover launch

This compiles an embedded C shim and launches Discord with LD_PRELOAD. No root required. Only works with native (RPM/deb/tar.gz) Discord installations.

Commands

drover daemon    Start the NFQUEUE packet processing daemon
drover setup     Install nftables rules (one-time)
drover teardown  Remove nftables rules
drover status    Check if nftables rules are active
drover launch    Launch Discord with LD_PRELOAD shim
drover install   Install systemd service (auto-starts on boot)
drover uninstall Remove systemd service
drover version   Show version information

Configuration

Drover reads a TOML config file searched in this order:

  1. ./drover.toml
  2. ~/.config/drover/drover.toml
  3. /etc/drover/drover.toml

All values are optional β€” sensible defaults are used when absent.

[probe]
size = 74          # UDP payload size to match (STUN Binding Request)
bytes = [0, 1]     # Probe packet payloads
delay_ms = 50      # Delay after probes in milliseconds

[filter]
ports = [
  { lo = 1024, hi = 65535 },
]

[daemon]
nfqueue_num = 1       # NFQUEUE number
auto_teardown = true  # Remove nftables rules on exit
pid_file = "/run/drover.pid"
mark = 212             # 0xD4 β€” fwmark to bypass nftables

[log]
level = "info"       # debug, info, warn, error
file = ""             # Empty = stderr, or path to log file

Environment variables override TOML values:

DROVER_PROBE_SIZE=100
DROVER_PROBE_DELAY_MS=75
DROVER_PROBE_BYTES="0,1"
DROVER_DAEMON_NFQUEUE_NUM=2
DROVER_LOG_LEVEL=debug

Systemd

The drover install command handles everything automatically. To remove:

sudo drover uninstall

The service uses AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW so it runs without full root, and logs to the systemd journal (journalctl -u drover).

Architecture

Daemon Mode (NFQUEUE)

Discord sends 74-byte UDP STUN packet
  -> nftables rule matches (udp dport 1024-65535, mark != 0xD4)
  -> packet sent to NFQUEUE
  -> Go daemon receives packet
  -> payload == 74 bytes AND destination not yet probed?
      YES: NF_DROP, send probes via raw socket, wait, reinject original
      NO:  NF_ACCEPT immediately

Probe packets and reinjected originals carry SO_MARK=0xD4. The nftables rule excludes marked packets, preventing infinite re-queueing loops.

LD_PRELOAD Mode

An adapted C shim (based on the original linux/drover.c) hooks socket(), sendto(), and sendmsg() inside the Discord process. When a 74-byte UDP send is detected on a socket that hasn't sent before, it injects probes via the real sendto(), sleeps, then lets the real call proceed.

Supported Discord Clients

Client Daemon Mode LD_PRELOAD Mode
Native (RPM/deb/tar.gz) Works Works
Flatpak Works Fails (sandbox)
AppImage Works Fails (FUSE/re-exec)
Vencord / BetterDiscord Works Depends on host install

Limitations

  • Daemon mode requires root or appropriate capabilities
  • LD_PRELOAD mode does not work with Flatpak, AppImage, or sandboxed Discord
  • The 74-byte probe size assumption matches current Discord WebRTC; if Discord updates their STUN packet size, the filter will need adjustment
  • Designed for Linux only

Testing

# Unit tests (no root required)
go test ./...

# Integration tests (requires root)
go test -tags integration ./test/integration/

License

MIT

About

Bypass DPI blocking of Discord voice chat 🎀

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages