netconf-rust 0.2.0

An async NETCONF client library implementing RFC 6241 (NETCONF), RFC 6242 (chunked framing), and RFC 4742 (EOM framing) with pipelining and zero-copy parsing
Documentation
# netconf-rust

> **Warning:** This library is EXTREMELY experimental and under active development. The API is subject to change without notice. Use in production at your own risk.

An async Rust NETCONF client implementing RFC 6241, RFC 6242, and RFC 4742 with pipelining and zero-copy XML parsing.

## Features

- **Async** -- Built on tokio with split read/write architecture
- **Pipelining** -- Send multiple RPCs without waiting for replies, correlated by message-id
- **Zero-copy parsing** -- `DataPayload` references the codec buffer directly, avoiding copies for large responses
- **RFC 6242 chunked framing** -- Automatically negotiated during the hello exchange
- **RFC 4742 EOM framing** -- Fallback for NETCONF 1.0-only devices
- **Keyboard-interactive auth** -- Fallback for devices (Cisco, Nokia) that require it

## Usage

```rust
use netconf_rust::{Session, Datastore};

#[tokio::main]
async fn main() -> netconf_rust::Result<()> {
    let mut session = Session::connect("192.168.1.1", 830, "admin", "admin").await?;

    let config = session.get_config(Datastore::Running, None).await?;
    println!("{config}");

    session.close_session().await?;
    Ok(())
}
```

### Subtree filtering

```rust
let interfaces = session.get_config(
    Datastore::Running,
    Some(r#"<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"/>"#),
).await?;
```

### Edit config with candidate commit

```rust
session.lock(Datastore::Candidate).await?;
session.edit_config(Datastore::Candidate, r#"
    <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
            <name>eth0</name>
            <description>Uplink</description>
        </interface>
    </interfaces>
"#).await?;
session.commit().await?;
session.unlock(Datastore::Candidate).await?;
```

### Pipelining

```rust
let fut1 = session.rpc_send("<get-config><source><running/></source></get-config>").await?;
let fut2 = session.rpc_send("<get-config><source><running/></source></get-config>").await?;
let fut3 = session.rpc_send("<get-config><source><running/></source></get-config>").await?;

let reply1 = fut1.response().await?;
let reply2 = fut2.response().await?;
let reply3 = fut3.response().await?;
```

### Zero-copy DataPayload

```rust
let payload = session.get_config_payload(Datastore::Running, None).await?;
println!("Config size: {} bytes", payload.len());

// Zero-copy &str view
let s: &str = payload.as_str();

// Stream XML events directly from the payload's bytes
let mut reader = payload.reader();
```

### Raw RPC

```rust
let reply = session.rpc_raw(
    "<get-schema><identifier>ietf-interfaces</identifier></get-schema>"
).await?;
```

## Built with

- [russh]https://github.com/Eugeny/russh -- Async SSH implementation used for the transport layer
- [quick-xml]https://github.com/tafia/quick-xml -- Fast, zero-allocation XML parser powering our event-based parsing and span extraction
- [bytes]https://github.com/tokio-rs/bytes -- Reference-counted byte buffers enabling zero-copy message handling

## RFCs

- [RFC 6241]https://datatracker.ietf.org/doc/html/rfc6241 -- NETCONF Configuration Protocol
- [RFC 6242]https://datatracker.ietf.org/doc/html/rfc6242 -- Using NETCONF over SSH (chunked framing)
- [RFC 4742]https://datatracker.ietf.org/doc/html/rfc4742 -- Using NETCONF over SSH (EOM framing)

## License

Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT License](LICENSE-MIT) at your option.