#![cfg(all(feature = "async-radius"))] 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::{ integer_to_bytes, ipv4_string_to_bytes}; use async_std::net::UdpSocket; use async_std::task; use async_trait::async_trait; use log::debug; use std::io::{Error, ErrorKind}; struct ClientWrapper { base_client: Client, socket: UdpSocket } impl ClientWrapper { async fn initialise_client(auth_port: u16, acct_port: u16, coa_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) .set_port(RadiusMsgType::ACCT, acct_port) .set_port(RadiusMsgType::COA, coa_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, "")) ) } async fn send_and_receive_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; } 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(response[0..amount].to_vec()); } retry += 1; } Err( RadiusError::SocketConnectionError(Error::new(ErrorKind::TimedOut, "")) ) } } // Test Async RADIUS Client #[test] fn test_async_client_auth_request() { task::block_on(async { let dictionary = Dictionary::from_file("./dict_examples/integration_dict").unwrap(); let client = ClientWrapper::initialise_client(1812, 1813, 3799, dictionary, String::from("127.0.0.1"), String::from("secret"), 1, 2).await.expect("Failed to create Client Wrapper"); let nas_ip_addr_bytes = ipv4_string_to_bytes("192.168.1.10").unwrap(); let framed_ip_addr_bytes = ipv4_string_to_bytes("10.0.0.100").unwrap(); let attributes = vec![ client.base_client.create_attribute_by_name("User-Name", String::from("testing").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("NAS-IP-Address", nas_ip_addr_bytes).unwrap(), client.base_client.create_attribute_by_name("NAS-Port-Id", integer_to_bytes(0)).unwrap(), client.base_client.create_attribute_by_name("Service-Type", integer_to_bytes(2)).unwrap(), client.base_client.create_attribute_by_name("NAS-Identifier", String::from("trillian").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("Called-Station-Id", String::from("00-04-5F-00-0F-D1").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("Calling-Station-Id", String::from("00-01-24-80-B3-9C").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("Framed-IP-Address", framed_ip_addr_bytes).unwrap() ]; let mut auth_packet = client.base_client.create_auth_packet(); auth_packet.set_attributes(attributes); match client.send_packet(&mut auth_packet).await { Err(error) => { println!("{:?}", error); assert!(false) }, _ => { assert!(true) } } match client.send_and_receive_packet(&mut auth_packet).await { Err(error) => { println!("{:?}", error); assert!(false) }, Ok(packet) => { println!("{:?}", &auth_packet); println!("{:?}", &packet); assert!(true) } } }) } #[test] fn test_async_client_acct_request() { task::block_on(async { let dictionary = Dictionary::from_file("./dict_examples/integration_dict").unwrap(); let client = ClientWrapper::initialise_client(1812, 1813, 3799, dictionary, String::from("127.0.0.1"), String::from("secret"), 1, 2).await.expect("Failed to create Client Wrapper"); let nas_ip_addr_bytes = ipv4_string_to_bytes("192.168.1.10").unwrap(); let framed_ip_addr_bytes = ipv4_string_to_bytes("10.0.0.100").unwrap(); let attributes = vec![ client.base_client.create_attribute_by_name("User-Name", String::from("testing").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("NAS-IP-Address", nas_ip_addr_bytes).unwrap(), client.base_client.create_attribute_by_name("NAS-Port-Id", integer_to_bytes(0)).unwrap(), client.base_client.create_attribute_by_name("NAS-Identifier", String::from("trillian").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("Called-Station-Id", String::from("00-04-5F-00-0F-D1").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("Calling-Station-Id", String::from("00-01-24-80-B3-9C").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("Framed-IP-Address", framed_ip_addr_bytes).unwrap() ]; let mut acct_packet = client.base_client.create_acct_packet(); acct_packet.set_attributes(attributes); match client.send_packet(&mut acct_packet).await { Err(error) => { println!("{:?}", error); assert!(false) }, _ => { assert!(true) } } match client.send_and_receive_packet(&mut acct_packet).await { Err(error) => { println!("{:?}", error); assert!(false) }, Ok(packet) => { println!("{:?}", &acct_packet); println!("{:?}", &packet); assert!(true) } } }) } #[test] fn test_async_client_coa_request() { task::block_on(async { let dictionary = Dictionary::from_file("./dict_examples/integration_dict").unwrap(); let client = ClientWrapper::initialise_client(1812, 1813, 3799, dictionary, String::from("127.0.0.1"), String::from("secret"), 1, 2).await.expect("Failed to create Client Wrapper"); let attributes = vec![ client.base_client.create_attribute_by_name("User-Name", String::from("testing").into_bytes()).unwrap(), client.base_client.create_attribute_by_name("Calling-Station-Id", String::from("00-01-24-80-B3-9C").into_bytes()).unwrap(), ]; let mut coa_packet = client.base_client.create_coa_packet(); coa_packet.set_attributes(attributes); match client.send_packet(&mut coa_packet).await { Err(error) => { println!("{:?}", error); assert!(false) }, _ => { assert!(true) } } match client.send_and_receive_packet(&mut coa_packet).await { Err(error) => { println!("{:?}", error); assert!(false) }, Ok(packet) => { println!("{:?}", &coa_packet); println!("{:?}", &packet); assert!(true) } } }) } // ------------------------