Crate netsim

Source
Expand description

netsim is a library for testing networking code. It allows you to run tests in network-isolated threads, on virtual network interfaces, in parallel, without tests interfering with each other or with your actual network. You can also connect these isolated environments to each other to create simulated networks on which you can capture and inject packets.

§Example 1: Isolating tests.

Suppose you have multiple tests that need to bind to the same port for some reason. By using #[netsim::isolate] you can run your test suite without having to use --test-threads=1 and without having to stop any daemons running on your dev machine.

#[test]
#[netsim::isolate]
fn a_test() {
    let _listener = std::net::TcpListener::bind("0.0.0.0:80").unwrap();
}

#[test]
#[netsim::isolate]
fn another_test_that_runs_in_parallel() {
    let _listener = std::net::TcpListener::bind("0.0.0.0:80").unwrap();
}

§Example 2: Capturing a packet.

The #[netsim::isolate] attribute showcased above is just a convenient way to setup a Machine and spawn a task onto it. To capture a packet you’ll need to do these steps yourself. You’ll also need to give the machine a network interface to send the packet on.

In this example we create a UDP socket and use it to send the message “hello” towards an arbitary address. The packet then arrives on our IpIface, hoping to be routed somewhere, and we can check that it still contains the correct message.

let local_addr: SocketAddrV4 = "10.1.2.3:5555".parse().unwrap();
let remote_addr: SocketAddrV4 = "1.1.1.1:53".parse().unwrap();
let machine = Machine::new().unwrap();
let mut iface = {
    machine
    .add_ip_iface()
    .ipv4_addr(*local_addr.ip())
    .ipv4_default_route()
    .build()
    .unwrap()
};
machine.spawn(async move {
    let socket = UdpSocket::bind(local_addr).await.unwrap();
    socket.send_to(b"hello", remote_addr).await.unwrap();
}).await.unwrap();

let packet = loop {
    let packet = iface.next().await.unwrap().unwrap();
    let IpPacketVersion::V4(packet) = packet.version_box() else { continue };
    let Ipv4PacketProtocol::Udp(packet) = packet.protocol_box() else { continue };
    break packet;
};
assert_eq!(packet.data(), b"hello");

§More, longer examples.

Check out the examples directory in the repo.

Re-exports§

pub use tokio;

Modules§

adapter
Sink/Stream adapters.
device
IP devices for creating networks with.
packet
Types for representing IP packets.

Macros§

ipv4_network
Creates a Ipv4Network given an address range in CIDR notation.
ipv6_network
Creates a Ipv6Network given an address range in CIDR notation.

Structs§

IpIface
A handle to a network interface of a Machine.
IpIfaceBuilder
Builder for adding an IP interface to a Machine.
Ipv4Network
An IPv4 address range, for example 192.168.0.0/16.
Ipv4NetworkIter
An iterator over the IPv4 addresses in an Ipv4Network.
Ipv6Network
An IPv6 address range, for example fc00::/7.
Ipv6NetworkIter
An iterator over the IPv6 addresses in an Ipv6Network.
JoinHandle
A handle to a future executing on a Machine.
Machine
The entry point for this library.
NetworkParseError
Error that can be returned when parsing an Ipv4Network or Ipv6Network.

Traits§

IpSinkStream
Helper trait for types which are both Sinks and Streams of Box<IpPacket>.
SinkStreamExt
Extension trait for types which are both Sinks and Streams.

Functions§

connect
Convenience method for connecting two IpSinkStreams to each other.

Attribute Macros§

isolate
Makes a function run in an isolated network environment.