/// Complete, offline examples used by the README and the test suite.
///
/// These functions deliberately return packets rather than opening sockets.
/// Applications can connect the result to UDP, a simulator, or a gateway.
///|
/// Enterprise Wi-Fi Access-Request with PAP.
pub fn example_wifi_request() -> Packet {
let request_authenticator = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
let encrypted = encrypt_user_password(
b"correct horse battery staple", b"wifi-shared-secret", request_authenticator,
) catch {
_ => b""
}
Packet::new(AccessRequest, 42, request_authenticator)
.with_attribute(Attribute::text(User_Name, "alice@example.com"))
.with_attribute(Attribute::new(User_Password, encrypted))
.with_attribute(Attribute::text(NAS_Identifier, "ap-east-01"))
.with_attribute(Attribute::integer(NAS_Port, 17))
.with_attribute(Attribute::integer(Service_Type, Framed))
}
///|
/// VPN Access-Challenge flow with a CHAP challenge.
pub fn example_vpn_challenge() -> Packet {
let challenge = b"vpn-challenge-2026"
Packet::new(
AccessRequest,
7,
b"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F",
)
.with_attribute(Attribute::text(User_Name, "vpn-user"))
.with_attribute(
Attribute::new(
CHAP_Password,
make_chap_password(7, b"vpn-password", challenge),
),
)
.with_attribute(Attribute::new(State, challenge))
.with_attribute(Attribute::text(NAS_Identifier, "vpn-gateway"))
}
///|
/// NAS Accounting Start record.
pub fn example_accounting_start() -> Packet {
Packet::new(
AccountingRequest,
12,
b"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F",
)
.with_attribute(Attribute::integer(Acct_Status_Type, Acct_Start))
.with_attribute(Attribute::text(Acct_Session_Id, "sess-20260923-0001"))
.with_attribute(Attribute::text(User_Name, "alice@example.com"))
.with_attribute(Attribute::text(NAS_Identifier, "nas-01"))
.with_attribute(Attribute::integer(NAS_Port, 17))
}
///|
/// Build an Access-Accept for the Wi-Fi example.
pub fn example_wifi_accept() -> Packet raise RadiusError {
let request = example_wifi_request()
let policy = AccessPolicy::new()
.allow(
Credential::new("alice@example.com", b"correct horse battery staple"),
)
.with_reply("authenticated by MoonRADIUS")
let decision = decide_access(request, policy, b"wifi-shared-secret")
access_response(request, decision, b"wifi-shared-secret")
}
///|
/// Build an Accounting-Response for the start example.
pub fn example_accounting_response() -> Packet raise RadiusError {
accounting_response(example_accounting_start(), b"accounting-secret")
}
///|
/// Run all three examples through encode/decode and return wire lengths.
pub fn run_examples() -> Array[Int] raise RadiusError {
let wifi = decode(encode(example_wifi_request()))
let vpn = decode(encode(example_vpn_challenge()))
let accounting = decode(encode(example_accounting_start()))
[encode(wifi).length(), encode(vpn).length(), encode(accounting).length()]
}
///|
/// A short textual description suitable for CLI help output.
pub fn example_catalog() -> Array[String] {
[
"wifi-pap: enterprise Wi-Fi Access-Request with encrypted User-Password", "vpn-chap: VPN Access-Request with CHAP response and state",
"nas-accounting: Accounting-Start record with session counters",
]
}