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

fix(dc): support updated wireshark definitions #2346

Merged
merged 1 commit into from
Oct 9, 2024
Merged
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
12 changes: 10 additions & 2 deletions dc/wireshark/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

fn main() {
let plugin_name = option_env("PLUGIN_NAME").unwrap_or_else(|| "dcQUIC".to_string());
println!("cargo:rustc-env=PLUGIN_NAME={plugin_name}");
let plugin_name = fwd("PLUGIN_NAME", "dcQUIC");
let _ = fwd("PLUGIN_MAJOR_VERSION", "4");
let _ = fwd("PLUGIN_MINOR_VERSION", "2");
println!(
"cargo:rustc-env=PLUGIN_NAME_LOWER={}",
plugin_name.to_lowercase()
Expand All @@ -18,6 +19,13 @@ fn main() {
}
}

fn fwd<N: AsRef<str>, D: AsRef<str>>(name: N, default: D) -> String {
let name = name.as_ref();
let value = option_env(name).unwrap_or_else(|| default.as_ref().to_string());
println!("cargo:rustc-env={name}={value}");
value
}

fn env<N: AsRef<str>>(name: N) -> String {
let name = name.as_ref();
option_env(name).unwrap_or_else(|| panic!("missing env {name}"))
Expand Down
34 changes: 24 additions & 10 deletions dc/wireshark/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,29 @@ use std::{ffi::CStr, sync::OnceLock};
#[used]
static plugin_version: [std::ffi::c_char; 4] = [b'0' as _, b'.' as _, b'1' as _, b'\0' as _];

macro_rules! env_version {
($name:literal) => {{
let v = env!($name);
if v.len() != 1 {
panic!("unexpected version");
}
let v = v.as_bytes()[0] as char;
match v.to_digit(10) {
Some(v) => v as _,
None => panic!("unexpected version"),
}
}};
}

// When bumping, make sure that the bindgen bindings are updated to the new version.
#[no_mangle]
#[used]
static plugin_want_major: std::ffi::c_int = 4;
static plugin_want_major: std::ffi::c_int = env_version!("PLUGIN_MAJOR_VERSION");

// When bumping, make sure that the bindgen bindings are updated to the new version.
#[no_mangle]
#[used]
static plugin_want_minor: std::ffi::c_int = 2;
static plugin_want_minor: std::ffi::c_int = env_version!("PLUGIN_MINOR_VERSION");

#[no_mangle]
pub extern "C" fn plugin_register() {
Expand Down Expand Up @@ -80,12 +94,12 @@ pub fn copy_to_rust(tvb: *mut wireshark_sys::tvbuff_t) -> Vec<u8> {
buffer
}

unsafe extern "C" fn dissect_heur_udp(
unsafe extern "C" fn dissect_heur_udp<Ret: From<bool>>(
tvb: *mut wireshark_sys::tvbuff_t,
mut pinfo: *mut wireshark_sys::_packet_info,
proto: *mut wireshark_sys::_proto_node,
_: *mut std::ffi::c_void,
) -> i32 {
) -> Ret {
let fields = field::get();

let packet = copy_to_rust(tvb);
Expand Down Expand Up @@ -116,7 +130,7 @@ unsafe extern "C" fn dissect_heur_udp(

// Didn't look like a dcQUIC packet.
if accepted_offset == 0 {
return 0;
return false.into();
}

if !info.is_empty() {
Expand All @@ -128,15 +142,15 @@ unsafe extern "C" fn dissect_heur_udp(

set_protocol(pinfo, c"dcQUIC");

accepted_offset as _
(accepted_offset != 0).into()
}

unsafe extern "C" fn dissect_heur_tcp(
unsafe extern "C" fn dissect_heur_tcp<Ret: From<bool>>(
tvb: *mut wireshark_sys::tvbuff_t,
mut pinfo: *mut wireshark_sys::_packet_info,
proto: *mut wireshark_sys::_proto_node,
_: *mut std::ffi::c_void,
) -> i32 {
) -> Ret {
let fields = field::get();

let packet = copy_to_rust(tvb);
Expand Down Expand Up @@ -179,7 +193,7 @@ unsafe extern "C" fn dissect_heur_tcp(

// Didn't look like a dcQUIC segment.
if accepted_offset == 0 {
return 0;
return false.into();
}

if !info.is_empty() {
Expand All @@ -191,7 +205,7 @@ unsafe extern "C" fn dissect_heur_tcp(

set_protocol(pinfo, c"TCP/dcQUIC");

accepted_offset as _
(accepted_offset != 0).into()
}

unsafe fn register_root_node(
Expand Down
8 changes: 4 additions & 4 deletions dc/wireshark/src/wireshark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ mod wireshark_sys_impl {
buffer.tvb,
parsed.offset as _,
parsed.len as _,
parsed.value as u32,
parsed.value as _,
)
}
}
Expand All @@ -186,7 +186,7 @@ mod wireshark_sys_impl {
buffer.tvb,
parsed.offset as _,
parsed.len as _,
parsed.value.into() as u32,
parsed.value.into() as _,
)
}
}
Expand Down Expand Up @@ -237,8 +237,8 @@ mod wireshark_sys_impl {
parsed: Parsed<Duration>,
) -> Self::AddedItem {
let time = wireshark_sys::nstime_t {
secs: parsed.value.as_secs() as i64,
nsecs: parsed.value.subsec_nanos() as i32,
secs: parsed.value.as_secs() as _,
nsecs: parsed.value.subsec_nanos() as _,
};
unsafe {
wireshark_sys::proto_tree_add_time(
Expand Down
114 changes: 98 additions & 16 deletions dc/wireshark/xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,46 @@ struct Build {
profile: Option<String>,
#[arg(long)]
target: Option<String>,
#[command(flatten)]
wireshark_version: WiresharkVersion,
}

impl Build {
fn run(self, sh: &Shell) -> Result {
fn run(mut self, sh: &Shell) -> Result {
self.wireshark_version.load(sh);

let target = if let Some(target) = self.target.as_ref() {
let _ = cmd!(sh, "rustup target add {target}").run();
vec!["--target", target]
} else {
vec![]
};
let profile = self.profile.as_deref().unwrap_or("release");

let _env = sh.push_env(
"PLUGIN_MAJOR_VERSION",
self.wireshark_version.major_version(),
);
let _env = sh.push_env(
"PLUGIN_MINOR_VERSION",
self.wireshark_version.minor_version(),
);

cmd!(sh, "cargo build --profile {profile} {target...}").run()?;
Ok(())
}
}

#[derive(Debug, Parser)]
struct Test {}
struct Test {
#[command(flatten)]
wireshark_version: WiresharkVersion,
}

impl Test {
fn run(self, sh: &Shell) -> Result {
fn run(mut self, sh: &Shell) -> Result {
cmd!(sh, "cargo test").run()?;
let plugin_dir = plugin_dir();
let plugin_dir = self.wireshark_version.plugin_dir(sh);

sh.create_dir(format!("target/wireshark/{plugin_dir}"))?;
sh.create_dir("target/pcaps")?;
Expand All @@ -76,6 +93,14 @@ impl Test {
let plugin_name = "dcQUIC__DEV";
let plugin_name_lower = &plugin_name.to_lowercase();
let _env = sh.push_env("PLUGIN_NAME", plugin_name);
let _env = sh.push_env(
"PLUGIN_MAJOR_VERSION",
self.wireshark_version.major_version(),
);
let _env = sh.push_env(
"PLUGIN_MINOR_VERSION",
self.wireshark_version.minor_version(),
);

let profile = "release-test";

Expand Down Expand Up @@ -176,26 +201,27 @@ fn so() -> &'static str {
}
}

fn plugin_dir() -> &'static str {
if cfg!(target_os = "macos") {
"plugins/4-2/epan"
} else {
"plugins/4.2/epan"
}
}

#[derive(Debug, Parser)]
struct Install {}
struct Install {
#[command(flatten)]
wireshark_version: WiresharkVersion,
}

impl Install {
fn run(self, sh: &Shell) -> Result {
Build::default().run(sh)?;
fn run(mut self, sh: &Shell) -> Result {
let plugin_dir = self.wireshark_version.plugin_dir(sh);

Build {
wireshark_version: self.wireshark_version.clone(),
..Default::default()
}
.run(sh)?;

let dir = if cfg!(unix) {
homedir::get_my_home()?
.expect("missing home dir")
.join(".local/lib/wireshark")
.join(plugin_dir())
.join(plugin_dir)
} else {
todo!("OS is currently unsupported")
};
Expand All @@ -212,6 +238,62 @@ impl Install {
}
}

#[derive(Clone, Debug, Default, Parser)]
struct WiresharkVersion {
#[arg(long, default_value = "DYNAMIC")]
wireshark_version: String,
}

impl WiresharkVersion {
fn plugin_dir(&mut self, sh: &Shell) -> String {
self.load(sh);

let value = &self.wireshark_version;
if cfg!(target_os = "macos") {
format!("plugins/{}/epan", value.replace('.', "-"))
} else {
format!("plugins/{value}/epan")
}
}

fn load(&mut self, sh: &Shell) {
if !(self.wireshark_version.is_empty() || self.wireshark_version == "DYNAMIC") {
return;
}

let tshark = tshark(sh).unwrap();
let output = cmd!(sh, "{tshark} --version").read().unwrap();
let version = output.lines().next().unwrap();
let version = version.trim_start_matches(|v: char| !v.is_digit(10));
let (version, _) = version
.split_once(char::is_whitespace)
.unwrap_or((version, ""));

let version = version.trim_end_matches('.');

match version.split('.').count() {
2 => {
self.wireshark_version = version.to_string();
}
3 => {
let (version, _) = version.rsplit_once('.').unwrap();
self.wireshark_version = version.to_string();
}
_ => panic!("invalid tshark version: {version}"),
}
}

fn major_version(&self) -> &str {
let (version, _) = self.wireshark_version.split_once('.').unwrap();
version
}

fn minor_version(&self) -> &str {
let (_, version) = self.wireshark_version.split_once('.').unwrap();
version
}
}

fn main() {
Args::parse().run();
}
Loading