ruipmi 0.4.0

An asynchronous IPMI client library implemented in Rust using Tokio.
Documentation

ruipmi

Crates.io Docs.rs License

ruipmi is a minimal asynchronous RMCP+ IPMI client written in Rust. It implements the IPMI v2.0 LAN+ session handshake (Open Session + RAKP1–4) with full cryptographic verification, and provides encrypted message transmission over UDP.


Features

  • Asynchronous UDP networking (tokio::net::UdpSocket)
  • Full RMCP+ session with RAKP2/RAKP4 verification (BMC identity + SIK integrity)
  • Cipher suite support:
    • Authentication: HMAC-SHA1, HMAC-MD5, HMAC-SHA256
    • Integrity: HMAC-SHA1-96, HMAC-SHA256-128, HMAC-MD5-128
    • Confidentiality: AES-CBC-128 or None
  • Automatic SIK / K1 / K2 derivation
  • Session sequence number validation (sliding window replay protection)
  • Automatic retry on UDP packet loss (up to 3 attempts)
  • Session reconnect with DNS re-resolution
  • Hostname DNS resolution (not just IP)
  • IPMB encapsulation support (bridging to other BMCs)
  • High-level API for common operations

Quick Start

use ruipmi::IpmiClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = IpmiClient::new(
        "10.0.0.5",  // BMC hostname or IP
        "admin",
        "password",
        None,  // default cipher suite (ID 17)
        None,  // IPMB channel
        None,  // IPMB target
    ).await?;

    client.connect().await?;

    // High-level API
    let device_id = client.get_device_id().await?;
    println!("Device ID: {:02X?}", device_id);

    let status = client.get_chassis_status().await?;
    println!("Chassis status: {:02X?}", status);

    // Raw command: [netfn, cmd, data...]
    let resp = client.request(&[0x06, 0x01]).await?;
    println!("Response: {:02X?}", resp);

    client.close().await?;
    Ok(())
}

API

Session Management

Method Description
new(host, user, pass, cipher, ch, tgt) Create client (supports hostname & IP)
connect() RMCP+ handshake with RAKP2/4 verification
request(&[u8]) Send raw IPMI command with auto-retry (up to 3x)
close() Gracefully close session (waits for BMC response)
reconnect() Close + re-resolve DNS + re-establish session

High-Level Commands

Method Description
get_device_id() Get Device ID
get_chassis_status() Get Chassis Status
chassis_control(u8) Chassis Control (0=off, 1=on, 2=cycle, 3=reset, 5=shutdown)
power_on() Power on
power_off() Power off
power_cycle() Power cycle
hard_reset() Hard reset
soft_shutdown() ACPI soft shutdown
get_sensor_reading(n) Get sensor reading by number
get_sdr_repo_info() Get SDR Repository Info
get_sel_info() Get System Event Log Info
get_fru_info(id) Get FRU Inventory Area Info
set_boot_pxe() Set next boot to PXE

SOL (Serial over LAN)

Method Description
activate_sol() Activate SOL, returns SolSession
deactivate_sol() Deactivate SOL
sol_send(&mut sol, data) Send bytes to serial console
sol_recv(&mut sol) Receive bytes from serial console

SOL (Serial over LAN)

use ruipmi::IpmiClient;

let mut client = IpmiClient::new("host", "user", "pass", None, None, None).await?;
client.connect().await?;

// Activate SOL
let mut sol = client.activate_sol().await?;

// Send data to serial console
client.sol_send(&mut sol, b"ls\r\n").await?;

// Receive serial output
let data = client.sol_recv(&mut sol).await?;
println!("{}", String::from_utf8_lossy(&data));

// Deactivate SOL
client.deactivate_sol().await?;
client.close().await?;

Custom Cipher Suite

use ruipmi::{CipherSuite, AuthAlg, IntegrityAlg, CryptAlg};

let cipher = CipherSuite {
    authentication: AuthAlg::HmacSha1,
    integrity: IntegrityAlg::HmacSha1_96,
    confidentiality: CryptAlg::None,
};
let mut client = IpmiClient::new("host", "user", "pass", Some(cipher), None, None).await?;

IPMB Bridging

// Bridge commands through channel 7 to target 0x72
let mut client = IpmiClient::new("host", "user", "pass", None, Some(7), Some(0x72)).await?;

Security

  • RAKP2 verification — validates BMC knows the password (prevents MITM)
  • RAKP4 verification — confirms SIK derivation integrity
  • Sequence number tracking — sliding window (32) prevents replay attacks
  • HMAC integrity — every encrypted message is authenticated

Performance

Tested against a real BMC on local network:

Metric Result
Session establish ~4ms
Command latency ~2ms
Throughput ~500 cmd/s
Reconnect ~5ms

Project Structure

src/
├── lib.rs          # Public exports
├── client.rs       # IpmiClient (session, retry, reconnect, high-level API)
├── codec.rs        # Packet build/parse (RAKP, encrypted msg, IPMB)
├── crypto.rs       # HMAC & AES-CBC encryption
├── cipher.rs       # CipherSuite type definitions
├── constants.rs    # IPMI/RMCP constants
└── error.rs        # IpmiError

Dependencies

[dependencies]
tokio = { version = "1", features = ["net", "time", "macros", "rt-multi-thread"] }
rand = "0.8"
hmac = "0.12"
sha1 = "0.10"
sha2 = "0.10"
md-5 = "0.10"
aes = "0.8"
cbc = { version = "0.1", features = ["alloc"] }
thiserror = "1"
log = "0.4"

License

MIT OR Apache-2.0