Giter VIP home page Giter VIP logo

rust-packet's Introduction

packet Crates.io packet WTFPL Build Status

This crate allows the parsing and creation of various network packets with an ergonomic API.

Usage

First, add the following to your Cargo.toml:

[dependencies]
packet = "0.1"

Next, add this to your crate root:

extern crate packet;

Packet

Packets take any type implementing AsRef<[u8]>, this means they can borrow an &[u8] or own a Vec<u8> or your own buffer type without needing different types or annoying lifetime parameters.

If the type also implements AsMut<[u8]> some fields are modifiable in place instead of going through a builder, not all fields are settable this way, for instance any fields that have a dynamic size.

Fields in any packet are parsed lazily directly from the buffer, the only exception are fields that are required to verify the packet is correct.

The correctness check doesn't do any checksum validation, this is because some protocols require additional information to calculate the checksum, for instance TCP and UDP require the IP packet to validate.

Buffer

Buffers are abstractions over growable or static slices, they implement a layered setup where each builder creates its own layer and any accesses to the buffer start from where the layer starts.

The buffer can be grown, but the operation may fail if the underlying buffer is not growable, static buffers will only fail if they can't accomodate the requested size.

Builder

Builders are structures that take a Buffer (or create one internally) and incrementally define a new packet.

Builders of upper layer protocols usually provide a way to create a specific sub-protocol, for example ip::v4::Builder allows creating an udp::Builder or tcp::Builder and deal with checksuming and length delimiting as needed.

Examples

Creating an ICMP packet echo request packet.

extern crate packet;
use packet::builder::Builder;
use packet::icmp;

fn main() {
	let packet = icmp::Builder::default()
	  .echo().unwrap().request().unwrap()
	  .identifier(42).unwrap()
			.sequence(2).unwrap()
			.payload(b"test").unwrap()
			.build().unwrap();
}

rust-packet's People

Contributors

fdubois1 avatar gdetal avatar kurikomoe avatar meh avatar noirotm 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  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

rust-packet's Issues

When Flags are 0x000, packet parsing causes panic

In my application I'm seeing panics on certain IPV4 packets:

called `Option::unwrap()` on a `None` value
stack backtrace:

I believe this is caused by calling Unwrap on the Flags::from_bits when no bitflags are set. This is the wireshark capture from the packet that caused the panic:

Screenshot 2024-03-07 at 9 19 22 AM

Unknown value in protocol()

I have tried to do some experiments with rust-packet crate in order to parse inbound data from a tun interface (using tokio_tun crate), as seen in the code below:

  #[tokio::main]
  async fn main() -> Result<()> {
      let tun = TunBuilder::new()
          .name("")            // if name is empty, then it is set by kernel.
          .tap(false)          // false (default): TUN, true: TAP.
          .packet_info(false)  // false: IFF_NO_PI, default is true.
          .up()                // or set it up manually using `sudo ip link set <tun-name> up`.
          .try_build()?;       // or `.try_build_mq(queues)` for multi-queue support.

      println!("tun created, name: {}, fd: {}", tun.name(), tun.as_raw_fd());

      let (mut reader, mut _writer) = tokio::io::split(tun);

      let mut buf = [0u8; 1024];
      loop {
          let n = reader.read(&mut buf).await?;
  //        println!("reading {} bytes: {:?}", n, &buf[..n]);

          let ether = ether::Packet::new(&mut buf[..]).unwrap();
          println!("ETHER SRC: {} DST: {}  PROTOCOL: {:?}", ether.source(), ether.destination(), ether.protocol());

          if(ether.protocol() == Protocol::Ipv4) {
              let ip    = ip::v4::Packet::new(ether.payload()).unwrap();
              println!("IP SRC: {} DST: {}", ip.source(), ip.destination());
          }

      }
  }

The above code seems not working as expected, since while performing a simple PING command on that tun interface, I got the following output:

ETHER SRC: 40:00:40:01:ED:5D DST: 45:00:00:54:C9:F6  PROTOCOL: Unknown(49320)
ETHER SRC: 40:00:40:01:EC:89 DST: 45:00:00:54:CA:CA  PROTOCOL: Unknown(49320)
ETHER SRC: 40:00:40:01:EB:D8 DST: 45:00:00:54:CB:7B  PROTOCOL: Unknown(49320)
ETHER SRC: 40:00:40:01:EB:1F DST: 45:00:00:54:CC:34  PROTOCOL: Unknown(49320)
ETHER SRC: 40:00:40:01:EA:7E DST: 45:00:00:54:CC:D5  PROTOCOL: Unknown(49320)
ETHER SRC: 40:00:40:01:EA:47 DST: 45:00:00:54:CD:0C  PROTOCOL: Unknown(49320)

Possibly I did something wrong and that is not an issue at all, but I would appreciate it if anybody can help me on this.

Thank you in advance!

Wrong data_offset in a tcp packet with a payload

With tcp::Builder, if you build a packet with a payload (calling payload() function on the builder), when you build the packet, the data offset will be wrong (byte 12).

We have this code:
let length = self.buffer.length();
let offset = (length / 4) as u8;
tcp[12] = offset << 4 | flags;

The length include the payload. But the data_offset should not be built with that length. If we don't have any option in the header, the header size is 20 bytes, so we should get 5 (20/4). But we will get a different value, depending on the payload size.

I'm not sure the best way to fix it. We could keep the payload size in the struct and calculate the length of the header itself.

Add setters for packets.

Need to add setters to impl<B: AsMut<[u8]>> Packet<B>, it might be a good idea to make builders use setters too.

Orthogonally an AsPacketMut should be added too, just in case.

Protocol wish list.

If anyone wants a protocol that's not been implemented yet to be added, just ask here.

Protocols

  • Ethernet II
  • IPv4
  • ICMPv4
  • TCP
  • UDP
  • ARP
  • DNS
  • IPv6
  • ICMPv6

Setting flag on ipv4 header gives invalid result

When trying to set the Don't Fragment flag on an Ipv4 packet, using .flags(Flags::DONT_FRAGMENT), the resulting packet is incorrect

| 45 | 00 | 00 28 | 00 00 | 00 02 | 40 | 06 | F7 14 | C0 A8 01 36 | C0 A8 01 33 |
                            ^^^^^

I underlined the flag+fragment offset fields. It should be 0x4000 (0b0100_0000_0000_0000).

It seems when modifying flags, the full 2 bytes are overwritten, without any bitshift

pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> {
Cursor::new(&mut self.header_mut()[6 ..])
.write_u16::<BigEndian>(value.bits())?;
Ok(self)
}

Panic creating TCP packet

Hello, I'm trying to create TCP packets using this library, but the internal library is panicking. Here is my code:

let pkt = packet::tcp::Builder::default()
            .acknowledgment(0)
            .unwrap()
            .sequence(0)
            .unwrap()
            .destination(12345)
            .unwrap()
            .source(12345)
            .unwrap()
            .flags(Flags::empty())
            .unwrap()
            .pointer(0)
            .unwrap()
            .window(0xffff)
            .unwrap()
            .payload::<Vec<&u8>>(vec![&0x00])
            .unwrap()
            .build()
            .unwrap();

        println!("{:02X?}", pkt);

and the error message

thread 'tests::packet' panicked at 'range start index 18 out of range for slice of length 0', library/core/src/slice/index.rs:52:5
stack backtrace:
   0: rust_begin_unwind
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/panicking.rs:142:14
   2: core::slice::index::slice_start_index_len_fail_rt
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/slice/index.rs:52:5
   3: core::ops::function::FnOnce::call_once
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/ops/function.rs:248:5
   4: core::intrinsics::const_eval_select
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/intrinsics.rs:2372:5
   5: core::slice::index::slice_start_index_len_fail
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/slice/index.rs:42:9
   6: <core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index_mut
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/slice/index.rs:399:13
   7: core::slice::index::<impl core::ops::index::IndexMut<I> for [T]>::index_mut
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/slice/index.rs:30:9
   8: packet::tcp::packet::Packet<B>::set_pointer
             at /Users/jacksoncoxson/.cargo/registry/src/github.com-1ecc6299db9ec823/packet-0.1.4/src/tcp/packet.rs:253:20
   9: packet::tcp::builder::Builder<B>::pointer
             at /Users/jacksoncoxson/.cargo/registry/src/github.com-1ecc6299db9ec823/packet-0.1.4/src/tcp/builder.rs:133:3
  10: secret_tunnel::tests::packet
             at ./src/lib.rs:82:19
  11: secret_tunnel::tests::packet::{{closure}}
             at ./src/lib.rs:81:5
  12: core::ops::function::FnOnce::call_once
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/ops/function.rs:248:5
  13: core::ops::function::FnOnce::call_once
             at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/ops/function.rs:248:5

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.