ruipmi

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", "admin",
"password",
None, None, None, ).await?;
client.connect().await?;
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);
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?;
let mut sol = client.activate_sol().await?;
client.sol_send(&mut sol, b"ls\r\n").await?;
let data = client.sol_recv(&mut sol).await?;
println!("{}", String::from_utf8_lossy(&data));
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
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