1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
//! Provides functionality for interacting with the data link layer, support for sending and receiving packets.
#![deny(warnings)]
use std::io;
use std::option::Option;
use std::time::Duration;
mod bindings;
#[cfg(windows)]
#[path = "wpcap.rs"]
mod backend;
#[cfg(windows)]
pub mod wpcap;
#[cfg(all(any(target_os = "linux", target_os = "android")))]
#[path = "linux.rs"]
mod backend;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod linux;
#[cfg(all(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "illumos",
target_os = "solaris",
target_os = "macos",
target_os = "ios"
)))]
#[path = "bpf.rs"]
mod backend;
#[cfg(any(
target_os = "freebsd",
target_os = "netbsd",
target_os = "illumos",
target_os = "solaris",
target_os = "macos",
target_os = "ios"
))]
pub mod bpf;
#[cfg(feature = "pcap")]
pub mod pcap;
/// Type alias for an `EtherType`.
pub type EtherType = u16;
/// Type of data link channel to present (Linux only).
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum ChannelType {
/// Send and receive layer 2 packets directly, including headers.
Layer2,
/// Send and receive IP packets - send and receive network layer packets.
Layer3(EtherType),
}
/// A channel for sending and receiving at the data link layer.
#[non_exhaustive]
pub enum Channel {
/// A datalink channel which sends and receives Ethernet packets.
Ethernet(Box<dyn RawSender>, Box<dyn RawReceiver>),
}
/// Socket fanout type (Linux only).
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum FanoutType {
HASH,
LB,
CPU,
ROLLOVER,
RND,
QM,
CBPF,
EBPF,
}
/// Fanout settings (Linux only).
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct FanoutOption {
pub group_id: u16,
pub fanout_type: FanoutType,
pub defrag: bool,
pub rollover: bool,
}
/// A generic configuration type, encapsulating all options supported by each backend.
///
/// Each option should be treated as a hint - each backend is free to ignore any and all
/// options which don't apply to it.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
/// The size of buffer to use when writing packets. Defaults to 4096.
pub write_buffer_size: usize,
/// The size of buffer to use when reading packets. Defaults to 4096.
pub read_buffer_size: usize,
/// Linux/BPF/Netmap only: The read timeout. Defaults to None.
pub read_timeout: Option<Duration>,
/// Linux/BPF/Netmap only: The write timeout. Defaults to None.
pub write_timeout: Option<Duration>,
/// Linux only: Specifies whether to read packets at the datalink layer or network layer.
/// Defaults to Layer2
pub channel_type: ChannelType,
/// BPF/macOS only: The number of /dev/bpf* file descriptors to attempt before failing. Defaults
/// to: 1000.
pub bpf_fd_attempts: usize,
pub linux_fanout: Option<FanoutOption>,
pub promiscuous: bool,
}
impl Default for Config {
fn default() -> Config {
Config {
write_buffer_size: 4096,
read_buffer_size: 4096,
read_timeout: None,
write_timeout: None,
channel_type: ChannelType::Layer2,
bpf_fd_attempts: 1000,
linux_fanout: None,
promiscuous: true,
}
}
}
/// Creates a new datalink channel for sending and receiving raw packets.
///
/// This function sets up a channel to send and receive raw packets directly from a data link layer
/// such as Ethernet. It uses the provided network interface and configuration settings to
/// establish the channel. Note that the actual usage of the configuration may vary based on the
/// underlying backend; some settings may be ignored or treated differently depending on the system
/// and library capabilities.
///
/// The function returns a `Channel` object encapsulating the transmission and reception capabilities.
#[inline]
pub fn channel(
network_interface: &nex_core::interface::Interface,
configuration: Config,
) -> io::Result<Channel> {
backend::channel(network_interface, (&configuration).into())
}
/// Trait to enable sending `$packet` packets.
pub trait RawSender: Send {
/// Create and send a number of packets.
///
/// This will call `func` `num_packets` times. The function will be provided with a
/// mutable packet to manipulate, which will then be sent. This allows packets to be
/// built in-place, avoiding the copy required for `send`. If there is not sufficient
/// capacity in the buffer, None will be returned.
fn build_and_send(
&mut self,
num_packets: usize,
packet_size: usize,
func: &mut dyn FnMut(&mut [u8]),
) -> Option<io::Result<()>>;
/// Send a packet.
///
/// This may require an additional copy compared to `build_and_send`, depending on the
/// operating system being used.
fn send(&mut self, packet: &[u8]) -> Option<io::Result<()>>;
}
/// Structure for receiving packets at the data link layer. Should be constructed using
/// `channel()`.
pub trait RawReceiver: Send {
/// Get the next ethernet frame in the channel.
fn next(&mut self) -> io::Result<&[u8]>;
}