radius_server/
handler.rs

1use std::sync::Arc;
2use crate::{
3    dictionary::Dictionary,
4    packet::{RadiusAttribute, RadiusPacket},
5};
6use md5;
7
8/// Builds a RADIUS response packet with the proper Response Authenticator.
9pub fn build_response_with_auth(
10    mut packet: RadiusPacket,
11    request_authenticator: [u8; 16],
12    secret: &str,
13) -> RadiusPacket {
14    let mut buf = Vec::new();
15    buf.push(packet.code);
16    buf.push(packet.identifier);
17    buf.extend_from_slice(&[0x00, 0x00]); // placeholder for length
18    buf.extend_from_slice(&request_authenticator);
19
20    for attr in &packet.attributes {
21        buf.push(attr.typ);
22        buf.push(attr.len);
23        buf.extend_from_slice(&attr.value);
24    }
25
26    let length = buf.len() as u16;
27    buf[2] = (length >> 8) as u8;
28    buf[3] = (length & 0xFF) as u8;
29
30    buf.extend_from_slice(secret.as_bytes());
31
32    let hash = md5::compute(&buf);
33    let mut authenticator = [0u8; 16];
34    authenticator.copy_from_slice(&hash.0);
35
36    packet.length = length;
37    packet.authenticator = authenticator;
38
39    packet
40}
41
42/// Handles an incoming RADIUS packet and returns a response packet.
43pub fn handle(packet: RadiusPacket, dict: Arc<Dictionary>) -> Result<RadiusPacket, String> {
44    println!("🔍 Handling RADIUS packet ID: {}", packet.identifier);
45
46    for attr in &packet.attributes {
47        let attr_code = attr.typ as u32;
48        match dict.attributes.get(&attr_code) {
49            Some(def) => {
50                let name = &def.name;
51                match std::str::from_utf8(&attr.value) {
52                    Ok(s) => println!("→ {}: {}", name, s.trim()),
53                    Err(_) => println!("→ {}: {:?}", name, attr.value),
54                }
55            }
56            None => println!("→ Unknown Attribute Type {}: {:?}", attr.typ, attr.value),
57        }
58    }
59
60    let mut attributes = vec![
61        RadiusAttribute::reply_message("Access granted via Rust RADIUS server."),
62        RadiusAttribute::session_timeout(3600),
63        RadiusAttribute::idle_timeout(300),
64        RadiusAttribute::wispr_bandwidth_max_up(512_000),
65        RadiusAttribute::wispr_bandwidth_max_down(1_000_000),
66    ];
67
68    // Optional: Echo back username if present
69    if let Some(user_attr) = packet.attributes.iter().find(|a| a.typ == 1) {
70        if let Ok(username) = std::str::from_utf8(&user_attr.value) {
71            attributes.push(RadiusAttribute::user_name(username));
72        }
73    }
74
75    let accept = RadiusPacket::access_accept(packet.identifier, attributes);
76    let response = build_response_with_auth(accept, packet.authenticator, "test123");
77    Ok(response)
78}