//! An example on how to create Async RADIUS Client from generic RADIUS Client which is provided in //! this crate //! //! ```bash //! cargo run --example async_radius_client --all-features //! ``` use radius_rust::client::{ client::Client, AsyncClientTrait }; use radius_rust::protocol::dictionary::Dictionary; use radius_rust::protocol::error::RadiusError; use radius_rust::protocol::radius_packet::{ RadiusPacket, RadiusMsgType }; use radius_rust::tools::{ encrypt_data, ipv4_string_to_bytes, integer_to_bytes }; use async_std::net::UdpSocket; use async_std::task; use async_trait::async_trait; use log::{ debug, LevelFilter }; use simple_logger::SimpleLogger; use std::io::{Error, ErrorKind}; struct ClientWrapper { base_client: Client, socket: UdpSocket } impl ClientWrapper { async fn initialise_client(auth_port: u16, dictionary: Dictionary, server: String, secret: String, retries: u16, timeout: u16) -> Result { // Bind socket let socket = UdpSocket::bind("0.0.0.0:0").await.map_err(|error| RadiusError::SocketConnectionError(error))?; // -------------------- let client = Client::with_dictionary(dictionary) .set_server(server) .set_secret(secret) .set_retries(retries) .set_timeout(timeout) .set_port(RadiusMsgType::AUTH, auth_port); Ok(ClientWrapper { base_client: client, socket: socket }) } } #[async_trait] impl AsyncClientTrait for ClientWrapper { async fn send_packet(&self, packet: &mut RadiusPacket) -> Result<(), RadiusError> { let remote_port = self.base_client.port(packet.code()).ok_or_else(|| RadiusError::MalformedPacketError { error: String::from("There is no port match for packet code") })?; let remote = format!("{}:{}", &self.base_client.server(), remote_port); let mut retry = 0; loop { if retry >= self.base_client.retries() { break; } debug!("Sending: {:?}", &packet.to_bytes()); self.socket.send_to(&packet.to_bytes(), &remote).await.map_err(|error| RadiusError::SocketConnectionError(error))?; let mut response = [0; 4096]; let (amount, _) = self.socket.recv_from(&mut response).await.map_err(|error| RadiusError::SocketConnectionError(error))?; if amount > 0 { debug!("Received reply: {:?}", &response[0..amount]); return Ok(()) } retry += 1; } Err( RadiusError::SocketConnectionError(Error::new(ErrorKind::TimedOut, "")) ) } } fn main() -> Result<(), RadiusError> { SimpleLogger::new().with_level(LevelFilter::Debug).init().expect("Failed to create new logger"); debug!("Async RADIUS Client started"); task::block_on(async { let dictionary = Dictionary::from_file("./dict_examples/integration_dict")?; let client = ClientWrapper::initialise_client(1812, dictionary, String::from("127.0.0.1"), String::from("secret"), 1, 2).await?; let user_name = String::from("testing").into_bytes(); let user_pass = b"very secure password, that noone is able to guess"; let nas_ip_addr_bytes = ipv4_string_to_bytes("192.168.1.10")?; let framed_ip_addr_bytes = ipv4_string_to_bytes("10.0.0.100")?; let nas_id = String::from("trillian").into_bytes(); let called_station_id = String::from("00-04-5F-00-0F-D1").into_bytes(); let calling_station_id = String::from("00-01-24-80-B3-9C").into_bytes(); let mut auth_packet = client.base_client.create_auth_packet(); let attributes = vec![ client.base_client.create_attribute_by_name("User-Name", user_name)?, client.base_client.create_attribute_by_name("Password", encrypt_data(user_pass, auth_packet.authenticator(), client.base_client.secret().as_bytes()))?, client.base_client.create_attribute_by_name("NAS-IP-Address", nas_ip_addr_bytes)?, client.base_client.create_attribute_by_name("NAS-Port-Id", integer_to_bytes(0))?, client.base_client.create_attribute_by_name("Service-Type", integer_to_bytes(2))?, client.base_client.create_attribute_by_name("NAS-Identifier", nas_id)?, client.base_client.create_attribute_by_name("Called-Station-Id", called_station_id)?, client.base_client.create_attribute_by_name("Calling-Station-Id", calling_station_id)?, client.base_client.create_attribute_by_name("Framed-IP-Address", framed_ip_addr_bytes)? ]; auth_packet.set_attributes(attributes); match client.send_packet(&mut auth_packet).await { Err(error) => { println!("{:?}", error); }, Ok(()) => { println!("{:?}", &auth_packet); } } debug!("Async RADIUS Client finished"); Ok(()) }) }