Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add packet capture for multiplayer traffic #2146

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/frontend/qt_sdl/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ LegacyEntry LegacyFile[] =
{"GdbARM7BreakOnStartup", 1, "Gdb.ARM7.BreakOnStartup", true},
{"GdbARM9BreakOnStartup", 1, "Gdb.ARM9.BreakOnStartup", true},
#endif
{"PcapEnabled", 1, "Pcap.Enabled", false},
{"PcapPath", 2, "Pcap.Path", false},

{"Camera0_InputType", 0, "DSi.Camera0.InputType", false},
{"Camera0_ImagePath", 2, "DSi.Camera0.ImagePath", false},
Expand Down
66 changes: 65 additions & 1 deletion src/frontend/qt_sdl/EmuInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "Config.h"
#include "Platform.h"
#include "Net.h"
#include "Net_PCap.h"
#include "MPInterface.h"

#include "NDS.h"
Expand All @@ -63,12 +64,14 @@

const string kWifiSettingsPath = "wfcsettings.bin";
extern Net net;
extern std::optional<melonDS::LibPCap> pcap;


EmuInstance::EmuInstance(int inst) : deleting(false),
instanceID(inst),
globalCfg(Config::GetGlobalTable()),
localCfg(Config::GetLocalTable(inst))
localCfg(Config::GetLocalTable(inst)),
packetCapture(nullptr), packetCaptureDumper(nullptr)
{
consoleType = globalCfg.GetInt("Emu.ConsoleType");

Expand Down Expand Up @@ -130,6 +133,7 @@

audioDeInit();
inputDeInit();
stopPacketCapture();
}


Expand Down Expand Up @@ -1336,6 +1340,7 @@
nds->Reset();
setBatteryLevels();
setDateTime();
startPacketCapture();
return true;
}

Expand Down Expand Up @@ -1805,6 +1810,7 @@
cartType = 0;
ndsSave = std::make_unique<SaveManager>(savname);
loadCheats();
startPacketCapture();

return true; // success
}
Expand All @@ -1821,6 +1827,8 @@
baseROMDir = "";
baseROMName = "";
baseAssetName = "";

stopPacketCapture();
}

bool EmuInstance::cartInserted()
Expand Down Expand Up @@ -2045,3 +2053,59 @@
animatedSequenceRef.push_back(i);
}
}

void EmuInstance::startPacketCapture()
{
if (packetCapture != nullptr || packetCaptureDumper != nullptr)
stopPacketCapture();

if (!globalCfg.GetBool("Pcap.Enabled"))
return;

if (!pcap)
pcap = melonDS::LibPCap::New();

std::string pcapPath = getAssetPath(false, globalCfg.GetString("Pcap.Path"), instanceFileSuffix() + ".pcap");
Log(LogLevel::Debug, "Starting packet capture: %s\n", pcapPath.c_str());

packetCapture = pcap->open_dead(DLT_IEEE802_11, 1024);
packetCaptureDumper = pcap->dump_open(packetCapture, pcapPath.c_str());
if (packetCaptureDumper == nullptr)
{
Log(LogLevel::Error, "Failed to open pcap file: %s\n", pcap->geterr(packetCapture));
return stopPacketCapture();
}
}

void EmuInstance::stopPacketCapture()
{
if (!pcap)
pcap = melonDS::LibPCap::New();

if (packetCaptureDumper != nullptr)
{
pcap->dump_flush(packetCaptureDumper);
pcap->dump_close(packetCaptureDumper);
packetCaptureDumper = nullptr;
}

if (packetCapture != nullptr)
{
pcap->close(packetCapture);
packetCapture = nullptr;
}
}

void EmuInstance::capturePacket(u8* data, int len)
{
if (!pcap || packetCaptureDumper == nullptr || len < 12)
return;

// data contains a 12-byte hardware header, and a trailing 4-byte checksum.
// https://problemkaputt.de/gbatek.htm#dswifihardwareheaders
pcap_pkthdr hdr = {};
gettimeofday(&hdr.ts, NULL);

Check failure on line 2107 in src/frontend/qt_sdl/EmuInstance.cpp

View workflow job for this annotation

GitHub Actions / build

'gettimeofday' was not declared in this scope; did you mean 'mingw_gettimeofday'?
hdr.caplen = len - 12 - 4;
hdr.len = len - 12 - 4;
pcap->dump((unsigned char*)packetCaptureDumper, &hdr, data + 12);
}
9 changes: 9 additions & 0 deletions src/frontend/qt_sdl/EmuInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
#define EMUINSTANCE_H

#include <SDL2/SDL.h>
#include <pcap/pcap.h>

#include "types.h"
#include "NDS.h"
#include "EmuThread.h"
#include "Window.h"
Expand Down Expand Up @@ -136,6 +138,8 @@ class EmuInstance
int getJoystickID() { return joystickID; }
SDL_Joystick* getJoystick() { return joystick; }

void capturePacket(melonDS::u8* data, int len);

private:
static int lastSep(const std::string& path);
std::string getAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file);
Expand Down Expand Up @@ -219,6 +223,11 @@ class EmuInstance
bool hotkeyPressed(int id) { return hotkeyPress & (1<<id); }
bool hotkeyReleased(int id) { return hotkeyRelease & (1<<id); }

void startPacketCapture();
void stopPacketCapture();
pcap_t* packetCapture;
pcap_dumper_t* packetCaptureDumper;

bool deleting;

int instanceID;
Expand Down
30 changes: 30 additions & 0 deletions src/frontend/qt_sdl/EmuSettingsDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <QFileDialog>
#include <QMessageBox>
#include <QTemporaryFile>

#include "types.h"
#include "Platform.h"
Expand Down Expand Up @@ -107,9 +108,12 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
ui->cbGdbBOSA7->setDisabled(true);
ui->cbGdbBOSA9->setDisabled(true);
#endif
ui->cbPcapEnabled->setChecked(cfg.GetBool("Pcap.Enabled"));
ui->txtPcapPath->setText(cfg.GetQString("Pcap.Path"));

on_chkEnableJIT_toggled();
on_cbGdbEnabled_toggled();
on_cbPcapEnabled_toggled();
on_chkExternalBIOS_toggled();

const int imgsizes[] = {256, 512, 1024, 2048, 4096, 0};
Expand Down Expand Up @@ -292,6 +296,8 @@ void EmuSettingsDialog::done(int r)
instcfg.SetBool("Gdb.ARM7.BreakOnStartup", ui->cbGdbBOSA7->isChecked());
instcfg.SetBool("Gdb.ARM9.BreakOnStartup", ui->cbGdbBOSA9->isChecked());
#endif
cfg.SetBool("Pcap.Enabled", ui->cbPcapEnabled->isChecked());
cfg.SetQString("Pcap.Path", ui->txtPcapPath->text());

cfg.SetInt("Emu.ConsoleType", ui->cbxConsoleType->currentIndex());
cfg.SetBool("Emu.DirectBoot", ui->chkDirectBoot->isChecked());
Expand Down Expand Up @@ -565,6 +571,30 @@ void EmuSettingsDialog::on_cbGdbEnabled_toggled()
ui->cbGdbBOSA9->setDisabled(disabled);
}

void EmuSettingsDialog::on_cbPcapEnabled_toggled()
{
bool disabled = !ui->cbPcapEnabled->isChecked();
ui->txtPcapPath->setDisabled(disabled);
ui->btnPcapBrowse->setDisabled(disabled);
}

void EmuSettingsDialog::on_btnPcapBrowse_clicked()
{
QString dir = QFileDialog::getExistingDirectory(this,
"Select packet captures path...",
lastBIOSFolder);

if (dir.isEmpty()) return;

if (!QTemporaryFile(dir).open())
{
QMessageBox::critical(this, "melonDS", "Unable to write to packet captures directory.\nPlease check file/folder write permissions.");
return;
}

ui->txtPcapPath->setText(dir);
}

void EmuSettingsDialog::on_chkExternalBIOS_toggled()
{
bool disabled = !ui->chkExternalBIOS->isChecked();
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/qt_sdl/EmuSettingsDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ private slots:
void on_chkExternalBIOS_toggled();

void on_cbGdbEnabled_toggled();
void on_cbPcapEnabled_toggled();
void on_btnPcapBrowse_clicked();

private:
void verifyFirmware();
Expand Down
Loading
Loading