├── src ├── lib.rs └── xdp │ ├── mod.rs │ ├── bpf │ ├── mod.rs │ ├── xdp.bpf.c │ └── xdp_loader.c │ └── capture.rs ├── .gitignore ├── Cargo.toml ├── examples └── 01 │ ├── capturing_frames.rs │ └── README.md └── README.md /src/lib.rs: -------------------------------------------------------------------------------- 1 | // src/lib.rs 2 | pub mod xdp; 3 | -------------------------------------------------------------------------------- /src/xdp/mod.rs: -------------------------------------------------------------------------------- 1 | // src/xdp/mod.rs 2 | mod bpf; 3 | mod capture; 4 | pub use capture::XdpCapture; 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /run_main.zsh 3 | /publish.zsh 4 | /src/bin 5 | /src/net 6 | /src/net/ctrl 7 | /src/net/proto 8 | /src/parser 9 | /tests 10 | /tests/integration_tests.rs 11 | 12 | Cargo.lock 13 | -------------------------------------------------------------------------------- /src/xdp/bpf/mod.rs: -------------------------------------------------------------------------------- 1 | // src/xdp/bpf/mod.rs 2 | use std::os::raw::{c_uchar, c_ulong}; 3 | 4 | // Embed the xdp.bpf.o file as a byte array 5 | const XDP_BPF_O_BYTES: &[u8] = include_bytes!(env!("XDP_BPF_O")); 6 | 7 | // Expose the byte array and its length to C via FFI 8 | #[no_mangle] 9 | pub extern "C" fn get_xdp_bpf_o_data() -> *const c_uchar { 10 | XDP_BPF_O_BYTES.as_ptr() 11 | } 12 | 13 | #[no_mangle] 14 | pub extern "C" fn get_xdp_bpf_o_len() -> c_ulong { 15 | XDP_BPF_O_BYTES.len() as c_ulong 16 | } 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty_tcp" 3 | version = "0.1.0" 4 | authors = ["Franco Kurte"] 5 | description = "A Rust library network packet capture using eBPF and XDP." 6 | license = "MIT" 7 | repository = "https://github.com/FrancoKurte/rusty-tcp" 8 | edition = "2021" 9 | readme = "README.md" 10 | 11 | [dependencies] 12 | anyhow = "1.0.97" 13 | libc = "0.2.170" 14 | nix = { version = "0.29.0", features = ["net"] } 15 | 16 | [build-dependencies] 17 | cc = "1.2.16" 18 | 19 | [lib] 20 | name = "rusty_tcp" 21 | path = "src/lib.rs" 22 | -------------------------------------------------------------------------------- /src/xdp/bpf/xdp.bpf.c: -------------------------------------------------------------------------------- 1 | // src/xdp/bpf/xdp.bpf.c 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_FRAME_SIZE 9000 // Maximum Ethernet frame size (jumbo frames) 7 | 8 | // Define the ring buffer map to send frames to user space 9 | struct { 10 | __uint(type, BPF_MAP_TYPE_RINGBUF); 11 | __uint(max_entries, 256 * 1024); // 256 KB ring buffer 12 | } frame_ringbuf SEC(".maps"); 13 | 14 | // Define a constant size 15 | #define RINGBUF_FRAME_SIZE 2048 // Choose a reasonable fixed size for your needs 16 | 17 | SEC("xdp") 18 | int xdp_frame_capture(struct xdp_md *ctx) { 19 | void *data_end = (void *)(long)ctx->data_end; 20 | void *data = (void *)(long)ctx->data; 21 | __u32 frame_size = data_end - data; 22 | 23 | if (frame_size > MAX_FRAME_SIZE) { 24 | bpf_printk("XDP: Dropping oversized frame (%u bytes)", frame_size); 25 | return XDP_DROP; 26 | } 27 | 28 | // Use a constant size for ringbuf reservation 29 | // https://elixir.bootlin.com/linux/v6.14-rc6/source/kernel/bpf/ringbuf.c#L477 30 | void *ringbuf_data = bpf_ringbuf_reserve(&frame_ringbuf, RINGBUF_FRAME_SIZE, 0); 31 | if (!ringbuf_data) { 32 | bpf_printk("XDP: Failed to reserve ring buffer space"); 33 | return XDP_PASS; 34 | } 35 | 36 | // Fix it with this: 37 | __u32 read_size = frame_size; 38 | if (read_size > RINGBUF_FRAME_SIZE) 39 | read_size = RINGBUF_FRAME_SIZE; 40 | 41 | // Ensure verifier can prove read_size is bounded and non-negative 42 | read_size &= 0x7FF; // Equivalent to min(read_size, 2047) - matches your RINGBUF_FRAME_SIZE 43 | 44 | if (bpf_probe_read_kernel(ringbuf_data, read_size, data) < 0) { 45 | bpf_printk("XDP: Failed to read frame data into ring buffer"); 46 | bpf_ringbuf_discard(ringbuf_data, 0); 47 | return XDP_PASS; 48 | } 49 | 50 | // You'll need to store the actual frame size for userspace to know 51 | // Store it at the beginning or end of the buffer, or use a header struct 52 | // For example, store it as the first 4 bytes 53 | *(__u32 *)ringbuf_data = frame_size; 54 | 55 | bpf_printk("XDP: Captured frame of size %u bytes", frame_size); 56 | bpf_ringbuf_submit(ringbuf_data, 0); 57 | return XDP_PASS; 58 | } 59 | 60 | char _license[] SEC("license") = "GPL"; 61 | -------------------------------------------------------------------------------- /examples/01/capturing_frames.rs: -------------------------------------------------------------------------------- 1 | // rusty_tcp/examples/01/capturing_frames.rs 2 | use rusty_tcp::xdp::XdpCapture; 3 | use anyhow::Result; 4 | use std::io::Write; 5 | use std::str; 6 | 7 | fn main() -> Result<()> { 8 | // Parse command line arguments for interface name 9 | let args: Vec = std::env::args().collect(); 10 | let interface = args.get(1).map(|s| s.as_str()).unwrap_or("wlan0"); 11 | 12 | // Initialize XDP capture on the specified interface 13 | let capture = XdpCapture::new(interface)?; 14 | println!("XDP capture initialized on interface {}, ringbuf_fd: {}", 15 | interface, capture.ringbuf_fd()); 16 | println!("Waiting for packets... Press Ctrl+C to exit"); 17 | 18 | // Main loop to read and process frames 19 | let mut frame_count = 0; 20 | loop { 21 | // Poll for frames with a 100ms timeout 22 | match capture.poll_frame(100) { 23 | Ok(Some(frame)) => { 24 | frame_count += 1; 25 | println!("\n--- Frame #{} ({} bytes) ---", frame_count, frame.len()); 26 | 27 | // Print the frame in a hexdump-like format 28 | print_hexdump(&frame); 29 | 30 | // Try to decode printable ASCII 31 | print_ascii(&frame); 32 | 33 | // Flush stdout to ensure output is visible immediately 34 | std::io::stdout().flush()?; 35 | } 36 | Ok(None) => { 37 | // No frame received, just continue polling 38 | } 39 | Err(e) => { 40 | eprintln!("Error polling for frames: {}", e); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | Ok(()) 47 | } 48 | 49 | /// Prints a hexdump of the binary data 50 | fn print_hexdump(data: &[u8]) { 51 | const BYTES_PER_LINE: usize = 16; 52 | 53 | for chunk in data.chunks(BYTES_PER_LINE) { 54 | // Print offset 55 | print!("{:08x} ", (chunk.as_ptr() as usize) - (data.as_ptr() as usize)); 56 | 57 | // Print hex values 58 | for (i, byte) in chunk.iter().enumerate() { 59 | print!("{:02x} ", byte); 60 | if i == 7 { 61 | print!(" "); // Extra space in the middle 62 | } 63 | } 64 | 65 | // Padding if the last line is incomplete 66 | if chunk.len() < BYTES_PER_LINE { 67 | let padding = BYTES_PER_LINE - chunk.len(); 68 | for _ in 0..padding { 69 | print!(" "); 70 | } 71 | if chunk.len() <= 8 { 72 | print!(" "); // Extra space for middle alignment 73 | } 74 | } 75 | 76 | // Print ASCII representation 77 | print!(" |"); 78 | for byte in chunk { 79 | if *byte >= 32 && *byte <= 126 { 80 | print!("{}", *byte as char); 81 | } else { 82 | print!("."); 83 | } 84 | } 85 | println!("|"); 86 | } 87 | } 88 | 89 | /// Attempts to print ASCII representation if the data appears to be text 90 | fn print_ascii(data: &[u8]) { 91 | let printable_chars = data.iter().filter(|&&b| b >= 32 && b <= 126).count(); 92 | let ratio = printable_chars as f32 / data.len() as f32; 93 | 94 | // If more than 70% of the bytes are printable ASCII, try to show as text 95 | if ratio > 0.7 { 96 | if let Ok(text) = str::from_utf8(data) { 97 | println!("\nPossible ASCII text:\n{}", text); 98 | } 99 | } 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/xdp/bpf/xdp_loader.c: -------------------------------------------------------------------------------- 1 | // src/xdp/bpf/xdp_loader.c 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Declare the Rust FFI functions to access the embedded xdp.bpf.o data 14 | extern unsigned char *get_xdp_bpf_o_data(void); 15 | extern unsigned long get_xdp_bpf_o_len(void); 16 | 17 | struct xdp_loader { 18 | struct bpf_object *obj; 19 | struct bpf_program *prog; 20 | struct bpf_map *ringbuf_map; 21 | int prog_fd; 22 | int ringbuf_fd; 23 | }; 24 | 25 | struct xdp_loader *xdp_loader_init(const char *ifname) { 26 | struct xdp_loader *loader = calloc(1, sizeof(struct xdp_loader)); 27 | if (!loader) { 28 | fprintf(stderr, "Failed to allocate loader: %s\n", strerror(errno)); 29 | return NULL; 30 | } 31 | 32 | // Get the embedded xdp.bpf.o data and length 33 | unsigned char *xdp_bpf_o_data = get_xdp_bpf_o_data(); 34 | unsigned long xdp_bpf_o_len = get_xdp_bpf_o_len(); 35 | 36 | // Open the eBPF object from memory 37 | loader->obj = bpf_object__open_mem(xdp_bpf_o_data, xdp_bpf_o_len, NULL); 38 | if (libbpf_get_error(loader->obj)) { 39 | fprintf(stderr, "Failed to open eBPF object from memory: %s\n", strerror(errno)); 40 | free(loader); 41 | return NULL; 42 | } 43 | 44 | loader->prog = bpf_object__find_program_by_name(loader->obj, "xdp_frame_capture"); 45 | if (!loader->prog) { 46 | fprintf(stderr, "Failed to find eBPF program 'xdp_frame_capture'\n"); 47 | bpf_object__close(loader->obj); 48 | free(loader); 49 | return NULL; 50 | } 51 | 52 | if (bpf_object__load(loader->obj)) { 53 | fprintf(stderr, "Failed to load eBPF object: %s\n", strerror(errno)); 54 | bpf_object__close(loader->obj); 55 | free(loader); 56 | return NULL; 57 | } 58 | 59 | // Find the ring buffer map 60 | loader->ringbuf_map = bpf_object__find_map_by_name(loader->obj, "frame_ringbuf"); 61 | if (!loader->ringbuf_map) { 62 | fprintf(stderr, "Failed to find ring buffer map 'frame_ringbuf'\n"); 63 | bpf_object__close(loader->obj); 64 | free(loader); 65 | return NULL; 66 | } 67 | 68 | loader->prog_fd = bpf_program__fd(loader->prog); 69 | loader->ringbuf_fd = bpf_map__fd(loader->ringbuf_map); 70 | 71 | // Attach the XDP program to the interface 72 | int ifindex = if_nametoindex(ifname); 73 | if (!ifindex) { 74 | fprintf(stderr, "Failed to get ifindex for %s: %s\n", ifname, strerror(errno)); 75 | bpf_object__close(loader->obj); 76 | free(loader); 77 | return NULL; 78 | } 79 | 80 | if (bpf_xdp_attach(ifindex, loader->prog_fd, XDP_FLAGS_SKB_MODE, NULL) < 0) { 81 | fprintf(stderr, "Failed to attach XDP program to %s: %s\n", ifname, strerror(errno)); 82 | bpf_object__close(loader->obj); 83 | free(loader); 84 | return NULL; 85 | } 86 | 87 | printf("XDP program attached to %s\n", ifname); 88 | return loader; 89 | } 90 | 91 | void xdp_loader_cleanup(struct xdp_loader *loader) { 92 | if (loader) { 93 | // Note: Hardcoded "eth0" should be replaced with the actual interface name in a real application 94 | bpf_xdp_detach(if_nametoindex("eth0"), XDP_FLAGS_SKB_MODE, NULL); 95 | bpf_object__close(loader->obj); 96 | free(loader); 97 | } 98 | } 99 | 100 | int xdp_loader_get_ringbuf_fd(struct xdp_loader *loader) { 101 | return loader ? loader->ringbuf_fd : -1; 102 | } 103 | -------------------------------------------------------------------------------- /examples/01/README.md: -------------------------------------------------------------------------------- 1 | # Example 01: Capturing Network Frames with Rusty TCP 2 | 3 | This example demonstrates basic network frame capture using the Rusty TCP library. It initializes XDP capture on a specified network interface and continuously polls for incoming frames. Captured frames are then displayed in a hexdump format on the console, along with an attempt to decode and display any printable ASCII text found within the frame. 4 | 5 | ## What it does 6 | 7 | The `capturing_frames.rs` example performs the following actions: 8 | 9 | 1. **Initializes XDP Capture:** It uses the `XdpCapture` struct from the `rusty_tcp` library to attach an eBPF program to a network interface. This program is designed to capture all network frames received by the interface. 10 | 2. **Polls for Frames:** In a loop, it polls the ring buffer associated with the XDP program for newly captured frames. The polling is done with a timeout to avoid excessive CPU usage when no frames are available. 11 | 3. **Displays Frame Information:** When a frame is received, the example prints: 12 | * A frame counter. 13 | * The size of the captured frame in bytes. 14 | * A hexdump representation of the frame data, showing the raw byte values in hexadecimal format alongside a potential ASCII representation. 15 | * If a significant portion of the frame data appears to be printable ASCII characters (above a 70% threshold), it will also attempt to decode and display the data as ASCII text. 16 | 17 | ## How to Run 18 | 19 | 1. **Navigate to the Example Directory:** 20 | ```bash 21 | cd examples/01 22 | ``` 23 | 24 | 2. **Run the Example:** 25 | You need to specify the network interface you want to capture traffic from as a command-line argument. For example, to capture traffic on the `wlan0` interface, use: 26 | ```bash 27 | cargo run -- capturing_frames wlan0 28 | ``` 29 | Replace `wlan0` with the actual name of your network interface (e.g., `eth0`, `enp0s3`, etc.). You can usually find your interface names using the `ip link` or `ifconfig` commands. 30 | 31 | **Note:** Running this example requires root privileges or capabilities that allow attaching XDP programs to network interfaces. You might need to run it using `sudo`: 32 | ```bash 33 | sudo cargo run -- capturing_frames wlan0 34 | ``` 35 | 36 | 3. **Observe the Output:** 37 | Once the example is running and XDP capture is initialized successfully, you will see messages indicating the interface and ring buffer FD. The program will then wait for network packets. As packets are received on the specified interface, you will see output similar to the following for each captured frame: 38 | 39 | ``` 40 | XDP capture initialized on interface wlan0, ringbuf_fd: 3 41 | Waiting for packets... Press Ctrl+C to exit 42 | 43 | --- Frame #1 (60 bytes) --- 44 | 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 45 | 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 46 | 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 47 | 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 48 | 49 | --- Frame #2 (1514 bytes) --- 50 | 00000000 ff ff ff ff ff ff 00 00 00 00 00 00 08 00 45 00 |..............E.| 51 | 00000010 05 dc 00 00 40 00 ff 11 ff ff 00 00 00 00 00 00 |....@...........| 52 | ... (rest of hexdump) ... 53 | 54 | Possible ASCII text: 55 | ... (if applicable, decoded ASCII text from the frame) ... 56 | ``` 57 | 58 | 4. **Stop the Example:** 59 | Press `Ctrl+C` to terminate the program. This will gracefully detach the XDP program from the interface and clean up resources. 60 | 61 | 62 | ## Prerequisites 63 | 64 | * Ensure you have followed the installation instructions in the main project `README.md` to set up the Rust toolchain, Clang, libbpf, and have a Linux kernel with XDP support. 65 | * You need to have built the `rusty_tcp` library using `cargo build` in the project's root directory before running this example. This ensures that the core library components are compiled and available. 66 | * **Example-Specific Dependencies:** This example, `capturing_frames.rs`, utilizes additional Rust crates for functionality specific to the example, such as error handling and hexadecimal output formatting. The extra dependency is: 67 | * [hex](https://crates.io/crates/hex) : For generating hexdump output. 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/xdp/capture.rs: -------------------------------------------------------------------------------- 1 | // src/xdp/capture.rs 2 | use std::ffi::{CString, c_void}; 3 | use std::os::unix::io::RawFd; 4 | use std::ptr; 5 | use std::slice; 6 | use libc::{c_char, c_int}; 7 | use libc::c_uint; 8 | 9 | /// Handle to the XDP loader (defined in C) 10 | #[repr(C)] 11 | struct XdpLoader { 12 | // Actual fields are in C 13 | _private: [u8; 0], 14 | } 15 | 16 | extern "C" { 17 | fn xdp_loader_init(ifname: *const c_char) -> *mut XdpLoader; 18 | fn xdp_loader_cleanup(loader: *mut XdpLoader); 19 | fn xdp_loader_get_ringbuf_fd(loader: *mut XdpLoader) -> c_int; 20 | } 21 | 22 | // Constants matching those in the BPF program 23 | const RINGBUF_FRAME_SIZE: usize = 2048; 24 | 25 | // Struct for libbpf ring buffer callback 26 | #[allow(non_camel_case_types)] 27 | type ring_buffer_sample_fn = extern "C" fn(ctx: *mut c_void, data: *mut c_void, size: c_uint) -> c_int; 28 | 29 | // Binding to libbpf ring buffer functions 30 | extern "C" { 31 | fn ring_buffer__new(fd: c_int, sample_cb: ring_buffer_sample_fn, ctx: *mut c_void, opts: *const c_void) -> *mut c_void; 32 | fn ring_buffer__free(rb: *mut c_void); 33 | fn ring_buffer__poll(rb: *mut c_void, timeout_ms: c_int) -> c_int; 34 | } 35 | 36 | // Global buffer to store the current frame (used in the callback) 37 | thread_local! { 38 | static CURRENT_FRAME: std::cell::RefCell>> = std::cell::RefCell::new(None); 39 | } 40 | 41 | // Callback function for ring buffer 42 | extern "C" fn process_sample(_ctx: *mut c_void, data: *mut c_void, _size: c_uint) -> c_int { 43 | // The first 4 bytes contain the actual frame size 44 | unsafe { 45 | let size_ptr = data as *const u32; 46 | let frame_size = *size_ptr as usize; 47 | 48 | // Ensure we don't read beyond the buffer 49 | let read_size = std::cmp::min(frame_size, RINGBUF_FRAME_SIZE - 4); 50 | 51 | // Create a vector from the data (skip the first 4 bytes which contain the size) 52 | let frame_data = slice::from_raw_parts((data as *const u8).add(4), read_size); 53 | let frame = frame_data.to_vec(); 54 | 55 | // Store the frame in thread-local storage 56 | CURRENT_FRAME.with(|f| { 57 | *f.borrow_mut() = Some(frame); 58 | }); 59 | } 60 | 61 | 0 62 | } 63 | 64 | /// Manages the XDP frame capture functionality. 65 | pub struct XdpCapture { 66 | loader: *mut XdpLoader, 67 | ringbuf_fd: RawFd, 68 | ring_buffer: *mut c_void, 69 | } 70 | 71 | impl XdpCapture { 72 | /// Initializes XDP frame capture on the specified network interface. 73 | pub fn new(ifname: &str) -> Result { 74 | let ifname_c = CString::new(ifname)?; 75 | let loader = unsafe { xdp_loader_init(ifname_c.as_ptr()) }; 76 | if loader.is_null() { 77 | return Err(anyhow::anyhow!("Failed to initialize XDP loader")); 78 | } 79 | 80 | let ringbuf_fd = unsafe { xdp_loader_get_ringbuf_fd(loader) }; 81 | if ringbuf_fd < 0 { 82 | unsafe { xdp_loader_cleanup(loader) }; 83 | return Err(anyhow::anyhow!("Failed to get ring buffer FD")); 84 | } 85 | 86 | // Initialize the ring buffer 87 | let ring_buffer = unsafe { 88 | ring_buffer__new(ringbuf_fd, process_sample, ptr::null_mut(), ptr::null()) 89 | }; 90 | 91 | if ring_buffer.is_null() { 92 | unsafe { xdp_loader_cleanup(loader) }; 93 | return Err(anyhow::anyhow!("Failed to create ring buffer")); 94 | } 95 | 96 | Ok(XdpCapture { 97 | loader, 98 | ringbuf_fd, 99 | ring_buffer, 100 | }) 101 | } 102 | 103 | /// Returns the ring buffer file descriptor for polling or mapping. 104 | pub fn ringbuf_fd(&self) -> RawFd { 105 | self.ringbuf_fd 106 | } 107 | 108 | /// Polls the ring buffer for new frames with a timeout in milliseconds. 109 | /// Returns the captured frame if available. 110 | pub fn poll_frame(&self, timeout_ms: i32) -> Result>, anyhow::Error> { 111 | // Clear any previous frame 112 | CURRENT_FRAME.with(|f| { 113 | *f.borrow_mut() = None; 114 | }); 115 | 116 | // Poll the ring buffer 117 | let ret = unsafe { ring_buffer__poll(self.ring_buffer, timeout_ms) }; 118 | if ret < 0 { 119 | return Err(anyhow::anyhow!("Error polling ring buffer: {}", ret)); 120 | } 121 | 122 | // Get the frame from thread-local storage if available 123 | let frame = CURRENT_FRAME.with(|f| { 124 | f.borrow_mut().take() 125 | }); 126 | 127 | Ok(frame) 128 | } 129 | } 130 | 131 | impl Drop for XdpCapture { 132 | fn drop(&mut self) { 133 | unsafe { 134 | if !self.ring_buffer.is_null() { 135 | ring_buffer__free(self.ring_buffer); 136 | } 137 | xdp_loader_cleanup(self.loader) 138 | }; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rusty TCP: eBPF-Powered Network Capture Library in Rust 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | 5 | Rusty TCP is a Rust library developed for network packet capture, leveraging the efficiency of eBPF (Extended Berkeley Packet Filter) and XDP (eXpress Data Path). Currently under active development in its early stages, this library aims to provide a streamlined and robust method for capturing network traffic directly at the kernel level, thereby minimizing overhead and maximizing throughput. 6 | 7 | ## Overview 8 | 9 | This project centers around creating a user-friendly Rust interface to eBPF programs within the Linux kernel, specifically for network packet capture. By employing XDP, Rusty TCP enables packet processing at the earliest possible point in the network stack, directly within the network driver itself. Captured packets are then efficiently transferred to user space via a ring buffer, ready for immediate analysis or processing within your Rust applications. 10 | 11 | Key features of Rusty TCP include: 12 | 13 | * **High-Performance Capture:** Achieves near-line-rate packet capture with minimal kernel overhead thanks to XDP. 14 | * **Kernel Bypass Architecture:** Operates at the XDP layer, bypassing significant portions of the traditional kernel network stack for enhanced speed. 15 | * **Efficient Ring Buffer Delivery:** Utilizes a ring buffer mechanism for asynchronous and high-throughput transfer of network frames from kernel to user space. 16 | * **Rust and C Synergy:** Combines the memory safety and expressiveness of Rust with the low-level system capabilities of C and eBPF for optimal performance and reliability. 17 | * **Modern eBPF Management:** Integrated with the libbpf library for efficient, up-to-date eBPF program loading and lifecycle management. 18 | 19 | 20 | 21 | ## Installation 22 | 23 | To utilize Rusty TCP, ensure the following prerequisites are installed on your system: 24 | 25 | * **Rust Toolchain:** A stable Rust installation is required. Installation instructions are available at [https://www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install). 26 | * **Clang Compiler:** Clang is necessary for compiling the eBPF program. Ensure it is installed and accessible in your system's PATH. 27 | * **libbpf Library:** The libbpf library and its development headers are essential for compiling and running the eBPF loader component. On Arch Linux systems, install with: `sudo pacman -S libbpf zlib`. For other distributions, use your system's package manager (eg. `apt`) to install the libbpf development packages. 28 | * **XDP-Enabled Linux Kernel:** Your Linux kernel must have XDP functionality enabled. Most modern Linux distributions include this support by default. 29 | 30 | Once these prerequisites are met, you can incorporate Rusty TCP into your Rust project by adding it as a dependency in your `Cargo.toml` file: 31 | 32 | 33 | ```toml 34 | [dependencies] 35 | rusty_tcp = { git = "https://github.com/FrancoKurte/rusty-tcp" } 36 | ``` 37 | 38 | Alternatively, you can clone the repository and build the library locally: 39 | 40 | ```sh 41 | git clone https://github.com/FrancoKurte/rusty-tcp 42 | cd rusty-tcp 43 | cargo build 44 | ``` 45 | 46 | ## Usage 47 | 48 | To quickly experience Rusty TCP's capabilities, explore the example provided in [examples/01/capturing_frames.rs](https://github.com/FrancoKurte/rusty-tcp/examples/01/). This example showcases basic packet capture and displays captured data in a hexdump format. For detailed instructions on running this example and understanding its output, please refer to the examples/01/README.md file within the example directory. More usage examples and comprehensive API documentation are planned for upcoming releases. Currently, the most detailed reference for library usage is the source code itself, particularly the src/xdp/capture.rs module. 49 | 50 | ## Future Prospects 51 | 52 | Rusty TCP is envisioned to evolve into more than just a packet capture utility. A significant long-term goal for this project is the development of a complete, from-scratch TCP/IP stack implemented entirely in Rust. Motivated by the desire to explore Rust's potential in building high-performance, secure, and highly customizable networking solutions. Also, this project aims to serve as a valuable platform for education in network protocol design and implementation. 53 | 54 | The current packet capture functionality is a foundational step towards this broader vision. By mastering eBPF and XDP for efficient data acquisition, the project is establishing the necessary groundwork to progress towards more complex network stack components. Future development will explore areas such as: 55 | 56 | * **Integrated IP Layer**: Building an IP layer to manage network addressing, routing, and packet forwarding. 57 | 58 | * **Rust-Native TCP Protocol Implementation**: Developing a robust and feature-complete TCP protocol implementation in Rust. 59 | 60 | 61 | * **User-Space Networking library**: Creating a user-space networking library that leverages the custom TCP/IP stack, enabling the development of network applications directly in user space. 62 | 63 | 64 | ## Documentation 65 | 66 | For now, please refer to the inline comments within the code for API details and usage information. As the project progresses, comprehensive documentation will be provided, including API references, usage guides, and design documents outlining the architecture of the Rust-based TCP/IP stack as it evolves. 67 | 68 | ## Contributing 69 | 70 | Contributions to Rusty TCP are highly welcome! If you have ideas for improvements, bug fixes, or new features, especially in the areas of networking protocols, eBPF, or Rust systems programming, please contributeby reporting issues (bugs or feature requests) please open a detailed issue on the GitHub repository or submitting pull request with a clear description of your changes :) 71 | 72 | ## License 73 | 74 | Rusty TCP is distributed under the MIT License. See the LICENSE file in the repository for the full license text. 75 | 76 | ## Contact 77 | 78 | For any questions, suggestions, collaboration inquiries, or discussions related to Rusty TCP, please feel free to reach out: 79 | 80 | Email: franco.kurte@gmail.com 81 | 82 | LinkedIn: https://www.linkedin.com/in/franco-kurte-a4975b220/ 83 | 84 | Thank you! 85 | --------------------------------------------------------------------------------