Crate pnet

source ·
Expand description

libpnet

libpnet provides a cross-platform API for low level networking using Rust.

There are four key components:

  • The packet module, allowing safe construction and manipulation of packets;
  • The pnet_packet crate, providing infrastructure for the packet module;
  • The transport module, which allows implementation of transport protocols;
  • The datalink module, which allows sending and receiving data link packets directly.

Terminology

The documentation uses the following terms interchangeably:

  • Layer 2, datalink layer;
  • Layer 3, network layer;
  • Layer 4, transport layer.

Unless otherwise stated, all interactions with libpnet are in host-byte order - any platform specific variations are handled internally.

Examples

More examples, including a packet logger, and a version of the echo server written at the transport layer, can be found in the examples/ directory.

Ethernet echo server

This (fairly useless) code implements an Ethernet echo server. Whenever a packet is received on an interface, it echoes the packet back; reversing the source and destination addresses.

extern crate pnet;

use pnet::datalink::{self, NetworkInterface};
use pnet::datalink::Channel::Ethernet;
use pnet::packet::{Packet, MutablePacket};
use pnet::packet::ethernet::{EthernetPacket, MutableEthernetPacket};

use std::env;

// Invoke as echo <interface name>
fn main() {
    let interface_name = env::args().nth(1).unwrap();
    let interface_names_match =
        |iface: &NetworkInterface| iface.name == interface_name;

    // Find the network interface with the provided name
    let interfaces = datalink::interfaces();
    let interface = interfaces.into_iter()
                              .filter(interface_names_match)
                              .next()
                              .unwrap();

    // Create a new channel, dealing with layer 2 packets
    let (mut tx, mut rx) = match datalink::channel(&interface, Default::default()) {
        Ok(Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("Unhandled channel type"),
        Err(e) => panic!("An error occurred when creating the datalink channel: {}", e)
    };

    loop {
        match rx.next() {
            Ok(packet) => {
                let packet = EthernetPacket::new(packet).unwrap();

                // Constructs a single packet, the same length as the the one received,
                // using the provided closure. This allows the packet to be constructed
                // directly in the write buffer, without copying. If copying is not a
                // problem, you could also use send_to.
                //
                // The packet is sent once the closure has finished executing.
                tx.build_and_send(1, packet.packet().len(),
                    &mut |mut new_packet| {
                        let mut new_packet = MutableEthernetPacket::new(new_packet).unwrap();

                        // Create a clone of the original packet
                        new_packet.clone_from(&packet);

                        // Switch the source and destination
                        new_packet.set_source(packet.get_destination());
                        new_packet.set_destination(packet.get_source());
                });
            },
            Err(e) => {
                // If an error occurs, we can handle it here
                panic!("An error occurred while reading: {}", e);
            }
        }
    }
}

Re-exports

Modules

  • Support for sending and receiving data link layer packets.
  • Support for packet parsing and manipulation.
  • Support for sending and receiving transport layer packets.
  • Miscellaneous utilities for low-level networking.