# ruipmi
[](https://crates.io/crates/ruipmi)
[](https://docs.rs/ruipmi)
[](https://github.com/dalof41014/ruipmi/blob/main/LICENSE-MIT)
**`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
```rust
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
| `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
| `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)
| `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)
```rust
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
```rust
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
```rust
// 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:
| 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
```toml
[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