use radius_rust::protocol::dictionary::Dictionary;
use radius_rust::protocol::error::RadiusError;
use radius_rust::protocol::radius_packet::{ RadiusMsgType, TypeCode };
use radius_rust::tools::{ ipv6_string_to_bytes, ipv4_string_to_bytes, integer_to_bytes };
use radius_rust::server::{ server::Server, AsyncServerTrait };
use async_std::task;
use async_std::net::UdpSocket;
use async_trait::async_trait;
use futures::{
future::FutureExt,
pin_mut,
select,
};
use log::{ debug, LevelFilter };
use simple_logger::SimpleLogger;
struct CustomServer {
base_server: Server,
auth_socket: UdpSocket,
acct_socket: UdpSocket,
coa_socket: UdpSocket
}
impl CustomServer {
async fn initialise_server(auth_port: u16, acct_port: u16, coa_port: u16, dictionary: Dictionary, server: String, secret: String, retries: u16, timeout: u16, allowed_hosts: Vec<String>) -> Result<CustomServer, RadiusError> {
let auth_socket = UdpSocket::bind(format!("{}:{}", &server, auth_port)).await?;
let acct_socket = UdpSocket::bind(format!("{}:{}", &server, acct_port)).await?;
let coa_socket = UdpSocket::bind(format!("{}:{}", &server, coa_port)).await?;
debug!("Authentication Server is started on {}", &auth_socket.local_addr()?);
debug!("Acconting Server is started on {}", &acct_socket.local_addr()?);
debug!("CoA Server is started on {}", &coa_socket.local_addr()?);
let server = Server::with_dictionary(dictionary)
.set_server(server)
.set_secret(secret)
.set_port(RadiusMsgType::AUTH, auth_port)
.set_port(RadiusMsgType::ACCT, acct_port)
.set_port(RadiusMsgType::COA, coa_port)
.set_allowed_hosts(allowed_hosts)
.set_retries(retries)
.set_timeout(timeout);
Ok(
CustomServer {
base_server: server,
auth_socket: auth_socket,
acct_socket: acct_socket,
coa_socket: coa_socket,
}
)
}
}
#[async_trait]
impl AsyncServerTrait for CustomServer {
async fn run(&mut self) -> Result<(), RadiusError> {
let auth_task = self.handle_auth_request().fuse();
let acct_task = self.handle_acct_request().fuse();
let coa_task = self.handle_coa_request().fuse();
pin_mut!(auth_task, acct_task, coa_task);
select! {
_ = auth_task => {
Ok(())
},
_ = acct_task => {
Ok(())
},
_ = coa_task => {
Ok(())
}
}
}
async fn handle_auth_request(&self) -> Result<(), RadiusError> {
loop {
debug!("Handling AUTH request");
let mut request = [0u8; 4096];
let (_, source_addr) = self.auth_socket.recv_from(&mut request).await.unwrap();
let ipv6_bytes = ipv6_string_to_bytes("fc66::1/64")?;
let ipv4_bytes = ipv4_string_to_bytes("192.168.0.1")?;
let attributes = vec![
self.base_server.create_attribute_by_name("Service-Type", integer_to_bytes(2))?,
self.base_server.create_attribute_by_name("Framed-IP-Address", ipv4_bytes)?,
self.base_server.create_attribute_by_name("Framed-IPv6-Prefix", ipv6_bytes)?
];
let mut reply_packet = self.base_server.create_reply_packet(TypeCode::AccessAccept, attributes, &mut request);
self.auth_socket.send_to(&reply_packet.to_bytes(), &source_addr).await.map_err(|error| RadiusError::SocketConnectionError(error))?;
}
}
async fn handle_acct_request(&self) -> Result<(), RadiusError> {
loop {
debug!("Handling ACCT request");
let mut request = [0u8; 4096];
let (_, source_addr) = self.acct_socket.recv_from(&mut request).await.unwrap();
let ipv6_bytes = ipv6_string_to_bytes("fc66::1/64")?;
let ipv4_bytes = ipv4_string_to_bytes("192.168.0.1")?;
let nas_ip_addr_bytes = ipv4_string_to_bytes("192.168.1.10")?;
let attributes = vec![
self.base_server.create_attribute_by_name("Service-Type", integer_to_bytes(2))?,
self.base_server.create_attribute_by_name("Framed-IP-Address", ipv4_bytes)?,
self.base_server.create_attribute_by_name("Framed-IPv6-Prefix", ipv6_bytes)?,
self.base_server.create_attribute_by_name("NAS-IP-Address", nas_ip_addr_bytes)?
];
let mut reply_packet = self.base_server.create_reply_packet(TypeCode::AccountingResponse, attributes, &mut request);
self.acct_socket.send_to(&reply_packet.to_bytes(), &source_addr).await.map_err(|error| RadiusError::SocketConnectionError(error))?;
}
}
async fn handle_coa_request(&self) -> Result<(), RadiusError> {
loop {
debug!("Handling CoA request");
let mut request = [0u8; 4096];
let (_, source_addr) = self.coa_socket.recv_from(&mut request).await.unwrap();
let state = String::from("testing").into_bytes();
let attributes = vec![
self.base_server.create_attribute_by_name("State", state)?
];
let mut reply_packet = self.base_server.create_reply_packet(TypeCode::CoAACK, attributes, &mut request);
self.coa_socket.send_to(&reply_packet.to_bytes(), &source_addr).await.map_err(|error| RadiusError::SocketConnectionError(error))?;
}
}
}
fn main() -> Result<(), RadiusError> {
SimpleLogger::new().with_level(LevelFilter::Debug).init().expect("Failed to create new logger");
debug!("Async RADIUS Server started");
task::block_on(async {
let dictionary = Dictionary::from_file("./dict_examples/integration_dict").expect("Failed to load or parse file");
let allowed_hosts = vec![String::from("127.0.0.1")];
let mut server = CustomServer::initialise_server(1812, 1813, 3799, dictionary, String::from("127.0.0.1"), String::from("secret"), 1, 2, allowed_hosts).await.expect("Failed to create RADIUS Server");
server.run().await
})
}