mod sniffer;
mod cryptography;
mod utils;
use std::fmt::{Debug, Display, Formatter};
use std::thread;
use serde::{Deserialize, Serialize};
use anyhow::Result;
use crossbeam_channel::Sender;
use log::{error, trace};
#[cfg(feature = "tokio")]
use tokio::sync::mpsc::UnboundedSender as AsyncSender;
#[cfg(feature = "tokio")]
use tokio::runtime::Handle;
struct CrossbeamSender {
sender: Sender<GamePacket>
}
impl PacketSender for CrossbeamSender {
fn send(&self, data: GamePacket) {
self.sender.send(data).unwrap()
}
}
#[cfg(feature = "tokio")]
struct TokioSender {
sender: AsyncSender<GamePacket>
}
#[cfg(feature = "tokio")]
impl PacketSender for TokioSender {
fn send(&self, data: GamePacket) {
let sender = self.sender.clone();
_ = Handle::current().spawn(async move {
sender.send(data)
});
}
}
pub fn sniff(
config: Config,
consumer: Sender<GamePacket>
) -> Result<Sender<()>> {
trace!("Configuration to be used: {:#?}", config);
let (tx, rx) = crossbeam_channel::bounded(1);
let consumer = CrossbeamSender { sender: consumer };
thread::spawn(|| {
if let Err(error) = sniffer::run(config, rx, consumer) {
error!("Failed to run the sniffer: {:#?}", error);
}
});
Ok(tx)
}
#[cfg(feature = "tokio")]
pub fn sniff_async(
config: Config,
consumer: AsyncSender<GamePacket>
) -> Result<Sender<()>> {
trace!("Configuration to be used: {:#?}", config);
let (tx, rx) = crossbeam_channel::bounded(1);
let consumer = TokioSender { sender: consumer };
tokio::spawn(async move {
if let Err(error) = sniffer::run(config, rx, consumer) {
error!("Failed to run the sniffer: {:#?}", error);
}
});
Ok(tx)
}
#[derive(Clone, Debug)]
pub struct GamePacket {
pub id: u16,
pub header: Vec<u8>,
pub data: Vec<u8>,
pub source: PacketSource
}
impl Default for GamePacket {
fn default() -> Self {
GamePacket {
id: 0,
header: vec![],
data: vec![],
source: PacketSource::Server
}
}
}
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq)]
pub enum PacketSource {
Client,
Server
}
impl PacketSource {
pub fn from(config: &Config, port: u16) -> PacketSource {
if config.server_port.contains(&port) {
PacketSource::Server
} else {
PacketSource::Client
}
}
pub fn to_string(&self) -> &'static str {
match self {
PacketSource::Client => "Client",
PacketSource::Server => "Server"
}
}
pub fn is_client(&self) -> bool {
self.eq(&PacketSource::Client)
}
pub fn is_server(&self) -> bool {
self.eq(&PacketSource::Server)
}
}
impl Display for PacketSource {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_string())
}
}
impl Debug for PacketSource {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_string())
}
}
impl Default for PacketSource {
fn default() -> Self {
PacketSource::Server
}
}
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct Config {
pub device_name: Option<String>,
pub filter: Option<String>,
pub server_port: Vec<u16>,
pub known_seeds: String
}
impl Default for Config {
fn default() -> Self {
Config {
device_name: None,
filter: Some("udp portrange 22101-22102".to_string()),
server_port: vec![22101, 22102],
known_seeds: "known_seeds.txt".to_string()
}
}
}
#[cfg(feature = "processor")]
pub use sniffer::Processor;
use crate::sniffer::PacketSender;