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

'sculpting' as an opt-in feature #70

Merged
merged 2 commits into from
May 6, 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
5 changes: 5 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ jobs:
- name: install maturin
run: |
python -m pip install maturin==0.13.6

- name: install rustup
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
sh rustup-init.sh -y --default-toolchain none
rustup target add ${{ matrix.target }}
rustup default ${{ matrix.cfg_release_channel }}

- name: Build with Python Bindings
run: |
maturin build --verbose --features python-bindings,logging --release --out dist
Expand All @@ -62,3 +64,6 @@ jobs:

- name: Run wasm-pack tests in node
run: wasm-pack test --node --features wasm

- name: Build and test with sculpting feature enabled
run: cargo build --features sculpting && cargo test --features sculpting
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,6 @@ walkdir = "2"
[features]
python-bindings = ['pyo3']
logging = ["log"]
sculpting = []

wasm = ['wasm-bindgen']
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

`scalpel` is a crate for Packet Dissection and Sculpting in Rust.

Scalpel can be used for dissecting packets on the wire and or generating packets from some specifications that can be sent on wire (This functionality is not being implemented at present). Goal of 'scalpel' is to be able to be able to make packet dissection API friendly so that it's easier to use it in any application. See Examples in the `examples/` directory to get an idea of what kind of 'applications' it can be used in.
Scalpel can be used for dissecting packets on the wire and or generating packets from some specifications that can be sent on wire (This functionality is very early in development and a proof of concept implementation is available). Goal of 'scalpel' is to be able to be able to make packet dissection API friendly so that it's easier to use it in any application. See Examples in the `examples/` directory to get an idea of what kind of 'applications' it can be used in.

This is still early, actively being developed, the APIs are not stable and are likely to change substantially.

Expand All @@ -16,4 +16,17 @@ Right now the supported API allows one to dissect packets on wire and display as
1. `packet_json` - An example that demonstrates how any `buffer` can be read as a `scalpel::Packet` structure.
1. `pcap` - An example that demonstrates how to display packets in Json format those captured on the wire. (this should be run as `sudo`).

By default, python bindings are disabled. If you want python bindings, use `--features="python-bindings"` command line argument while building or running the code. Refer to [`using-python-bindings.md`](https://github.com/gabhijit/scalpel/blob/master/using-python-bindings.md) to get started with using Python bindings. Currently, only we provide a basic dissection and displaying a packet as json functionality from the Python bindings. This support is a WIP.
# Features

## Python Bindings

An experimental Python API is available to demonstrate how scalpel can be used for packet dissection from Python. By default, python bindings are disabled. Python bindings can be enabled using `--features="python-bindings"` command line argument while building or running the code. Refer to ['Using Python Bindings'](https://github.com/gabhijit/scalpel/blob/master/using-python-bindings.md) to get started with using Python bindings. Currently, only we provide a basic dissection and displaying a packet as json functionality from the Python bindings. This support is a WIP.


## Wasm support

An experimental 'wasm' support is available. This support can be enabled using `--features=wasm`. Please note `python-bindings` and `wasm` are mutually exclusive features. [This repository](https://github.com/ystero-dev/scalpel-examples) contains an example using 'actix' based web server for running packet dissection inside the browser.

## Packet Generation (or Sculpting)

This is a WIP and a very early support. An initial implementation of creating a simple Ethernet and IP based packet and then serializing to wire is currently implemented. The goal of this feature is it should be possible to have an API friendly Packet Generator using `scalpel` crate.
17 changes: 11 additions & 6 deletions examples/packet_sculpting.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#![allow(unused)]
use std::error::Error;

use scalpel::{layers, ENCAP_TYPE_ETH};

#[cfg(feature = "sculpting")]
fn main() -> Result<(), Box<dyn Error>> {
let _ = scalpel::register_defaults()?;

Expand All @@ -18,16 +20,19 @@ fn main() -> Result<(), Box<dyn Error>> {

let res_string = result[0]
.iter()
.fold(String::new(), |acc, num| {
acc + "0x" + &num.to_string() + " "
})
.trim_end()
.to_string();
.map(|num| format!("{:02x}", num))
.collect::<Vec<_>>()
.join("");

println!("res: {:#?}", res_string);
println!("Packet Data: {:#?}", res_string);

let p = scalpel::Packet::from_bytes(&result[0], ENCAP_TYPE_ETH);
println!("{}", serde_json::to_string_pretty(&p.unwrap()).unwrap());

Ok(())
}

#[cfg(not(feature = "sculpting"))]
fn main() {
eprintln!("Feature 'sculpting' is required for this example!.");
}
2 changes: 2 additions & 0 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(feature = "sculpting")]

use crate::{errors::Error, Layer, Packet};

#[derive(Debug, Default)]
Expand Down
1 change: 1 addition & 0 deletions src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub trait Layer: Send + Debug + erased_serde::Serialize {
bytes: &[u8],
) -> Result<(Option<Box<dyn Layer + Send>>, usize), Error>;

#[cfg(feature = "sculpting")]
/// Main 'encoder' function.
///
/// The return value is a `Vec<u8>` on success. This indicates the encoded packet of the
Expand Down
6 changes: 4 additions & 2 deletions src/layers/ethernet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::convert::TryInto;

// FIXME: Should work with no_std
use std::collections::HashMap;
use std::sync::{RwLock,OnceLock};
use std::sync::{OnceLock, RwLock};

use serde::Serialize;

Expand All @@ -19,7 +19,8 @@ pub fn get_ethertypes_map() -> &'static RwLock<HashMap<EtherType, LayerCreatorFn
///
/// The creator function simply creates a `default` L3 struct that implements the dissector
/// for the Layer.
pub(crate) static ETHERTYPES_MAP: OnceLock<RwLock<HashMap<EtherType, LayerCreatorFn>>> = OnceLock::new();
pub(crate) static ETHERTYPES_MAP: OnceLock<RwLock<HashMap<EtherType, LayerCreatorFn>>> =
OnceLock::new();
ETHERTYPES_MAP.get_or_init(|| RwLock::new(HashMap::new()))
}

Expand Down Expand Up @@ -91,6 +92,7 @@ impl Layer for Ethernet {
}
}

#[cfg(feature = "sculpting")]
fn stack_and_encode(
&mut self,
next_layer: Option<&[u8]>,
Expand Down
2 changes: 2 additions & 0 deletions src/layers/ipv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ impl IPv4 {
Ok(((len as u8, data), i))
}

#[cfg(feature = "sculpting")]
fn calculate_checksum(_bytes: &[u8]) -> u16 {
0
}
Expand Down Expand Up @@ -322,6 +323,7 @@ impl Layer for IPv4 {
"ip"
}

#[cfg(feature = "sculpting")]
fn stack_and_encode(
&mut self,
next_layer: Option<&[u8]>,
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
//! feature is enabled.
//! - `wasm`: Build WASM capability in the scalpel. Currently `dissect_packet` API is provided,
//! dissects the packet and a JSON is generated for the packet.
//! - `sculpting`: Experimental, allows one to generate packet from layers using metadata. For
//! example this will be useful to develop packet generators.
//!
//! Note: `wasm` and `python-bindings` features cannot be enabled at the same time.

Expand Down
Loading