#port-scanner #network-scanner #arp #syn #packet

r-lanlib

A library crate for performing network scanning operations on any local area network (LAN)

10 releases (5 breaking)

Uses new Rust 2024

new 0.7.1 Feb 15, 2026
0.7.0 Feb 11, 2026
0.6.0 Feb 1, 2026
0.5.0 Jan 29, 2026
0.1.5 Aug 14, 2025

#1409 in Network programming


Used in 2 crates

MIT/Apache

130KB
3K SLoC

r-lanlib

A Rust library crate for performing network scanning operations on any local area network (LAN). This is the Rust version of the go-lanscan package.

Features

  • ARP Scanning: Discover devices on your network using Address Resolution Protocol
  • SYN Scanning: Detect open ports on discovered devices using TCP SYN packets
  • Full Scanning: Combined ARP and SYN scanning in a single operation
  • Vendor Detection: Identify device manufacturers using MAC address lookup
  • Hostname Resolution: Resolve hostnames for discovered devices
  • Async Communication: Channel-based communication for real-time scan results
  • Flexible Targeting: Support for CIDR blocks, IP ranges, and port ranges

Requirements

  • Root privileges required: This library performs raw packet operations that require elevated permissions
  • Rust 1.89.0+ with 2024 edition support

Installation

cargo add r-lanlib

Quick Start

Basic ARP Scanning

use std::{sync::mpsc, time::Duration};
use r_lanlib::{
    network, packet,
    scanners::{arp_scanner::ARPScanner, Device, ScanMessage, Scanner},
    targets::ips::IPTargets,
};

// Get default network interface
let interface = network::get_default_interface()
    .expect("Cannot find network interface");

// Create packet wire (reader/sender)
let wire = packet::wire::default(&interface)
    .expect("Failed to create packet wire");

// Define IP targets (scan entire subnet)
let ip_targets = IPTargets::new(vec![interface.cidr.clone()])
    .expect("Failed to parse IP targets");

// Create communication channel
let (tx, rx) = mpsc::channel::<ScanMessage>();

// Configure scanner using builder pattern
let scanner = ARPScanner::builder()
    .interface(&interface)
    .packet_reader(wire.0)
    .packet_sender(wire.1)
    .targets(ip_targets)
    .source_port(54321u16)
    .include_vendor(true)
    .include_host_names(true)
    .idle_timeout(Duration::from_millis(10000))
    .notifier(tx)
    .build()
    .expect("Failed to build scanner");

// Start scanning (runs in background thread)
let handle = scanner.scan().expect("Failed to start scan");

// Process results in real-time
let mut devices = Vec::new();
loop {
    match rx.recv().expect("Failed to receive message") {
        ScanMessage::Done => break,
        ScanMessage::ARPScanDevice(device) => {
            println!("Found device: {} ({})", device.ip, device.hostname);
            devices.push(device);
        }
        ScanMessage::Info(scanning) => {
            println!("Scanning: {}", scanning.ip);
        }
        _ => {}
    }
}

handle.join().expect("Scanner thread failed");
println!("Discovered {} devices", devices.len());

SYN Port Scanning

use r_lanlib::{
    scanners::{syn_scanner::SYNScanner, Device, PortSet, Scanner},
    targets::ports::PortTargets,
};

// Define target devices (from previous ARP scan or manual)
let devices = vec![
    Device {
        hostname: "router".to_string(),
        ip: Ipv4Addr::new(192, 168, 1, 1),
        mac: MacAddr::new(0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff),
        vendor: "".to_string(),
        is_current_host: false,
        open_ports: PortSet::new(),
    }
];

// Define port targets
let port_targets = PortTargets::new(vec![
    "22".to_string(),      // SSH
    "80".to_string(),      // HTTP
    "443".to_string(),     // HTTPS
    "8000-9000".to_string(), // Port range
])
.expect("Failed to parse port targets");

let scanner = SYNScanner::builder()
    .interface(&interface)
    .packet_reader(wire.0)
    .packet_sender(wire.1)
    .targets(devices)
    .ports(port_targets)
    .source_port(54321u16)
    .idle_timeout(Duration::from_millis(10000))
    .notifier(tx)
    .build()
    .expect("Failed to build scanner");

// Process SYN scan results
let mut results = Vec::new();
let handle = scanner.scan().expect("Failed to start scan");

loop {
    match rx.recv().expect("Failed to receive message") {
        ScanMessage::Done => break,
        ScanMessage::SYNScanDevice(device) => {
            for port in device.open_ports.to_sorted_vec() {
                println!("Open port {} on {}", port.id, device.ip);
            }
            results.push(device);
        }
        _ => {}
    }
}

Full Scanning (ARP + SYN)

use r_lanlib::scanners::{full_scanner::FullScanner, Scanner};

let scanner = FullScanner::builder()
    .interface(&interface)
    .packet_reader(wire.0)
    .packet_sender(wire.1)
    .targets(ip_targets)
    .ports(port_targets)
    .vendor(true)
    .host(true)
    .idle_timeout(Duration::from_millis(10000))
    .notifier(tx)
    .source_port(54321u16)
    .build()
    .expect("Failed to build scanner");

// This will perform ARP discovery first, then SYN scan on found devices
let handle = scanner.scan().expect("Failed to start scan");

API Reference

Core Modules

network

Provides helpers for selecting network interfaces:

  • get_default_interface() - Get the default network interface
  • get_interface(name) - Get a specific interface by name
  • get_available_port() - Find an available port for scanning

packet

Low-level packet creation and transmission:

  • wire::default(interface) - Create default packet reader/sender pair
  • Various packet builders for ARP, SYN, RST packets

scanners

Main scanning implementations:

  • ARPScanner - Discover devices using ARP
  • SYNScanner - Scan ports on known devices
  • FullScanner - Combined ARP + SYN scanning

targets

Target specification utilities:

  • ips::IPTargets - Define IP ranges and CIDR blocks
  • ports::PortTargets - Define port ranges and individual ports

Data Structures

Device

Represents a discovered network device:

pub struct Device {
    pub hostname: String,
    pub ip: Ipv4Addr,
    pub mac: MacAddr,
    pub vendor: String,
    pub is_current_host: bool,
    pub open_ports: PortSet,
}

Port

Represents a network port:

pub struct Port {
    pub id: u16,
    pub service: String,
}

PortSet

Wrapper around HashSet<Port> with convenience methods:

pub struct PortSet(pub HashSet<Port>);

impl PortSet {
    pub fn new() -> Self;
    pub fn to_sorted_vec(&self) -> Vec<Port>;
}

ScanMessage

Messages sent over the notification channel:

pub enum ScanMessage {
    Done,                    // Scanning complete
    Info(Scanning),          // Status update
    ARPScanDevice(Device),   // ARP discovery result
    SYNScanDevice(Device),   // SYN scan result (Device with open_ports populated)
}

Target Specification

IP Targets

// CIDR blocks
IPTargets::new(vec!["192.168.1.0/24".to_string()]);

// IP ranges
IPTargets::new(vec!["192.168.1.1-192.168.1.100".to_string()]);

// Individual IPs
IPTargets::new(vec!["192.168.1.1".to_string(), "10.0.0.1".to_string()]);

Port Targets

// Port ranges
PortTargets::new(vec!["1-1000".to_string()]);

// Individual ports
PortTargets::new(vec!["22".to_string(), "80".to_string(), "443".to_string()]);

// Mixed specification
PortTargets::new(vec![
    "22".to_string(),
    "80".to_string(),
    "8000-9000".to_string()
]);

Examples

The library includes several complete examples in the examples/ directory:

  • arp-scanner.rs - Basic ARP device discovery
  • syn-scanner.rs - Port scanning on known devices
  • full-scanner.rs - Complete network reconnaissance

Run examples from the workspace root with:

sudo -E cargo run --example arp-scanner -p r-lanlib
sudo -E cargo run --example syn-scanner -p r-lanlib
sudo -E cargo run --example full-scanner -p r-lanlib

Configuration Options

Scanner Timeouts

  • idle_timeout - How long to wait for responses before concluding scan
  • Default: 10 seconds (10,000ms)
  • Recommended: 5-30 seconds depending on network size and latency

Scanner Features

  • include_vendor - Perform MAC address vendor lookup using IEEE OUI database
  • include_host_names - Resolve hostnames via reverse DNS lookup
  • source_port - Source port for scan packets (auto-selected if not specified)

Performance Tuning

  • Concurrent scanning: Multiple threads handle packet I/O for optimal throughput
  • Memory efficiency: Zero-copy packet processing where possible
  • Network-aware: Automatic rate limiting to prevent network congestion
  • Timeout optimization: Adaptive timeouts based on network response times

Security Considerations

  • Requires root privileges for raw socket access on Unix-like systems
  • Network scanning may be restricted by network policies and firewalls
  • Built-in rate limiting prevents network congestion and reduces detection risk
  • Minimal network footprint: Optimized packet sizes and timing
  • Memory safety: Rust's ownership system prevents buffer overflows and memory corruption
  • Use responsibly and only on networks you own or have permission to scan
  • Logging: All scan activities can be logged for audit purposes

Ethical Usage Guidelines

  • Always obtain proper authorization before scanning
  • Respect network resources and avoid aggressive scanning
  • Be aware that scanning activities may be logged by network security systems
  • Consider the impact on network performance during large-scale scans

Error Handling

The library uses RLanLibError for comprehensive error reporting:

License

This project is dual-licensed under either of

at your option.

  • go-lanscan - Original Go implementation
  • r-lancli - Command-line interface using this library
  • r-lanterm - Terminal UI application using this library

Dependencies

~8–23MB
~278K SLoC