Giter Site home page Giter Site logo

wireshark-dissector-rs's Introduction

Writing a Wireshark dissector in Rust

What this repo contains

  • Basic TCP server written in Rust, listening on port 8888 for a made-up binary protocol called dummy
  • Basic TCP client which sends dummy protocol messages to the server on port 8888
  • Wireshark dissector which, when compiled, allows Wireshark to understand the dummy protocol

The dummy protocol

16-byte payload - first 8 bytes is an 8-char string representing the "version", the second 8 bytes is an 8-char string representing the "body".

The catch is that these are encoded (with transform). The encode/decode is just add/subtract 1 from the chars. Yep, not safe, overflow, underflow - it's just for demonstration.

We "encode" (i.e. increment each char) the data before sending it on the wire in client/src/main.rs:

let version = encode(&CString::new("testver3").unwrap().into_bytes());
let body = encode(&CString::new("hifriend").unwrap().into_bytes());

I use CStrings here to use into_bytes to drop the implicit NUL termination of Rust.

let mut payload = [&version[..], &body[..]].concat();

let nsent = unsafe { send(fd, payload.as_mut_ptr() as *mut c_void, MSGLEN, 0) };

if nsent < 0 {
    bail!("recv failed: {}", Errno::last());
} else {
    println!("Sent: {} bytes...\n", nsent);
}

These are decoded server-side:

let vers = decode(&payload[..8]);
let body = decode(&payload[8..16]);

println!(
    "\tversion: {:?}\n\tbody: {:?}",
    String::from_utf8_lossy(&vers),
    String::from_utf8_lossy(&body)
);

tcpdump - why can't I understand it?

From the client we saw that we're sending a Dummy packet with:

version: "testver3"
body: "hifriend'

However, since it's encoded in this protocol, you can't understand the plain-text from tcpdump.

Client:

sevagh:wireshark-dissector-rs $ ./target/debug/client
Sent: 16 bytes...

sevagh:wireshark-dissector-rs $

Server:

sevagh:wireshark-dissector-rs $ ./target/debug/server
Read 16 bytes...

        version: "testver3"
        body: "hifriend"

Sometimes in prod we want to check the packets with tcpdump - debugging in case the server isn't receiving, or any other reason:

sevagh:wireshark-dissector-rs $ sudo tcpdump -i any dst port 8888 -A
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:04:38.803566 IP localhost.41104 > localhost.ddi-tcp-1: Flags [P.], seq 0:16, ack 1, win 342, options [nop,nop,TS val 2431784080 ecr 2431784080], length 16
E..D..@.@............."..Y.........V.8.....
........uftuwfs4ijgsjfoe

Here we see the body: uftuwfs4 ijgsjfoe. This is testver3 hifriend with all the chars incremented, but pretend that this is a more complicated protocol with more fields and more rigorous encoding.

Rust FFI in the Wireshark dissector

I'll skip the repetition and give a link-dump of some posts I perused to understand how to write a Wireshark dissector in C:

All of this code can be found in ./dissector/plugins.

Importantly, these are the additions I made for Rust FFI inside the dissector.

In dummy/Makefile.rust, the rule to create libdummy_dissector.a:

libdummy_dissector:
        @cargo build
        @cp ../../../target/debug/libdummy_dissector.a ./

This places the compiled Rust/FFI .a file into the dummy plugin directory.

dummy/Cargo.toml:

[lib]
name = "dummy_dissector"
crate-type = ["staticlib"]

[dependencies]
transform = { path = "../../../transform" }
common = { path = "../../../common" }
libc = "0.2.29"

The function signature inside dummy/src/lib.rs:

#![crate_type = "staticlib"]

#[no_mangle]
pub extern "C" fn dissect_dummy_rs(data: &mut [u8]) -> i32 {

In dummy/Makefile.am:

dummy_la_LDFLAGS = $(PLUGIN_LDFLAGS) libdummy_dissector.a

In dummy/packet-dummy.c:

extern int32_t
dissect_dummy_rs(const void *data);

After this, copying the dummy plugin folder to your Wireshark sources (more here) should allow you to compile Wireshark with the FFI. There's a Make rule:

wireshark_plugin:
        @if test -z "$$WIRESHARK_SRC_DIR"; then echo "Please define WIRESHARK_SRC_DIR" && exit -1; fi;
        @cd $(WIRESHARK_PLUGIN_DIR)/dummy && make -f ./Makefile.rust
        @cp -r $(WIRESHARK_PLUGIN_DIR) $$WIRESHARK_SRC_DIR
        @cd $$WIRESHARK_SRC_DIR && ./autogen.sh && make -C plugins && make && sudo make install && cd -

The result

When you launch Wireshark with dummy.pcap file, you're greeted with a parsed protocol:

screenie

We taught Wireshark how to understand dummy!

How?

In the body of the dissector method in packet-dummy.c, we delegate decoding the packet to Rust:

static int
dissect_dummy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
        // this is our rust function!
        // it modifies the packet in place to decode it
        dissect_dummy_rs(tvb->real_data);

        gint offset = 0;

        // here we print the decoded data (once rust is done decoding it)
        if (tree) {
                proto_item *ti;
                ti = proto_tree_add_item(tree, proto_dummy, tvb, 0, -1, FALSE);
                tree = proto_item_add_subtree(ti, ett_dummy);
                proto_tree_add_item(tree, hf_dummy_version, tvb, offset, 8, FT_STRING);
                offset += 8;
                proto_tree_add_item(tree, hf_dummy_body, tvb, offset, 8, FT_STRING);
        }

The Rust code looks like this:

use transform::decode;

pub extern "C" fn dissect_dummy_rs(data: &mut [u8]) -> i32 {
    if data.len() > 2*MSGLEN {
        return -1;
    }

    let mut decoded_version = decode(&data[..8]);
    let mut decoded_body = decode(&data[8..]);

    // some unsafe memcpies 
}

The beauty of this is that we used the same transform crate that the client and server use.

What does this imply? You can re-use protocol decoding logic from your Rust application code inside the Wireshark dissector instead of needing to rewrite it in C or Lua.

wireshark-dissector-rs's People

Contributors

kumassy avatar sevagh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

wireshark-dissector-rs's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.