Add server

This commit is contained in:
moznion
2020-11-22 21:15:21 +09:00
parent 3ffb8b75be
commit 6164f7b597
10 changed files with 457 additions and 5 deletions
Generated
+257 -1
View File
@@ -6,12 +6,30 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bytes"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
@@ -25,6 +43,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "cloudabi"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
dependencies = [
"bitflags",
]
[[package]]
name = "derivative"
version = "2.1.1"
@@ -36,29 +63,115 @@ dependencies = [
"syn",
]
[[package]]
name = "futures-core"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748"
[[package]]
name = "getrandom"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "hermit-abi"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
dependencies = [
"libc",
]
[[package]]
name = "instant"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "lock_api"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
[[package]]
name = "memchr"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "mio"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f33bc887064ef1fd66020c9adfc45bb9f33d75a42096c81e7c56c65b75dd1a8b"
dependencies = [
"libc",
"log",
"miow",
"ntapi",
"winapi",
]
[[package]]
name = "miow"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
dependencies = [
"socket2",
"winapi",
]
[[package]]
name = "ntapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [
"winapi",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@@ -78,6 +191,16 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "num_enum"
version = "0.5.1"
@@ -100,6 +223,38 @@ dependencies = [
"syn",
]
[[package]]
name = "parking_lot"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
dependencies = [
"cfg-if 0.1.10",
"cloudabi",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "pin-project-lite"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
@@ -138,9 +293,12 @@ name = "radius-rs"
version = "0.1.0"
dependencies = [
"chrono",
"log",
"md5",
"num_enum",
"rand",
"thiserror",
"tokio",
]
[[package]]
@@ -184,12 +342,57 @@ dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
[[package]]
name = "signal-hook-registry"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab"
dependencies = [
"libc",
]
[[package]]
name = "slab"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "smallvec"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85"
[[package]]
name = "socket2"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "syn"
version = "1.0.48"
@@ -201,6 +404,26 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "thiserror"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.1.44"
@@ -212,6 +435,39 @@ dependencies = [
"winapi",
]
[[package]]
name = "tokio"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dfe2523e6fa84ddf5e688151d4e5fddc51678de9752c6512a24714c23818d61"
dependencies = [
"autocfg",
"bytes",
"futures-core",
"lazy_static",
"libc",
"memchr",
"mio",
"num_cpus",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"slab",
"tokio-macros",
"winapi",
]
[[package]]
name = "tokio-macros"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21d30fdbb5dc2d8f91049691aa1a9d4d4ae422a21c334ce8936e5886d30c5c45"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.5.7"
+3
View File
@@ -11,3 +11,6 @@ md5 = "0.7.0"
chrono = "0.4"
rand = "0.7.3"
num_enum = "0.5.1"
tokio = { version = "0.3.4", features = ["full"] }
log = "0.4.11"
thiserror = "1.0"
+1 -1
View File
@@ -14,7 +14,7 @@ pub struct AVP {
pub struct Attributes(pub(crate) Vec<AVP>);
impl Attributes {
pub fn parse_attributes(bs: &Vec<u8>) -> Result<Attributes, String> {
pub(crate) fn parse_attributes(bs: &Vec<u8>) -> Result<Attributes, String> {
let mut i = 0;
let mut attrs = Vec::new();
+1 -1
View File
@@ -2,7 +2,7 @@ use std::convert::TryFrom;
use num_enum::TryFromPrimitive;
#[derive(Debug, Clone, PartialEq, TryFromPrimitive)]
#[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum Code {
AccessRequest = 1,
+7
View File
@@ -1,4 +1,11 @@
#[macro_use]
extern crate log;
pub mod code;
pub mod attribute;
pub mod attributes;
pub mod packet;
pub mod server;
pub mod secret_provider;
pub mod request_handler;
pub mod request;
+5 -2
View File
@@ -1,5 +1,4 @@
use std::convert::TryInto;
use std::io::Write;
use rand::Rng;
@@ -30,6 +29,10 @@ impl Packet {
}
}
pub(crate) fn get_identifier(&self) -> u8 {
self.identifier
}
pub fn parse(bs: &Vec<u8>, secret: &Vec<u8>) -> Result<Self, String> {
if bs.len() < 20 {
return Err("radius packet doesn't have enough length of bytes; that has to be at least 20 bytes".to_owned());
@@ -129,7 +132,7 @@ impl Packet {
].concat()).to_vec().eq(&response[4..20].to_vec())
}
pub fn is_authentic_request(request: Vec<u8>, secret: Vec<u8>) -> bool {
pub fn is_authentic_request(request: &Vec<u8>, secret: &Vec<u8>) -> bool {
if request.len() < 20 || secret.len() == 0 {
return false;
}
+31
View File
@@ -0,0 +1,31 @@
use std::net::SocketAddr;
use crate::packet::Packet;
pub struct Request {
local_addr: SocketAddr,
remote_addr: SocketAddr,
packet: Packet,
}
impl Request {
pub(crate) fn new(local_addr: SocketAddr, remote_addr: SocketAddr, packet: Packet) -> Self {
Self {
local_addr,
remote_addr,
packet,
}
}
pub fn get_local_addr(&self) -> SocketAddr {
self.local_addr
}
pub fn get_remote_addr(&self) -> SocketAddr {
self.remote_addr
}
pub fn get_packet(&self) -> &Packet {
&self.packet
}
}
+7
View File
@@ -0,0 +1,7 @@
use tokio::net::UdpSocket;
use crate::request::Request;
pub trait RequestHandler: Sync {
fn handle_radius_request(&self, conn: &UdpSocket, request: &Request);
}
+13
View File
@@ -0,0 +1,13 @@
use std::net::SocketAddr;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum SecretProviderError {
#[error("failed to fetch a secret value => `{0}`")]
FailedFetching(String)
}
pub trait SecretProvider: Sync {
fn fetch_secret(&self, remote_addr: SocketAddr) -> Result<Vec<u8>, SecretProviderError>;
}
+132
View File
@@ -0,0 +1,132 @@
use std::borrow::Borrow;
use std::collections::HashSet;
use std::io;
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use tokio::net::UdpSocket;
use crate::packet::Packet;
use crate::request::Request;
use crate::request_handler::RequestHandler;
use crate::secret_provider::SecretProvider;
pub struct Server<T: 'static + RequestHandler, U: 'static + SecretProvider> {
address: String,
buf_size: u8,
skip_authenticity_validation: bool,
request_handler: &'static T,
secret_provider: &'static U,
}
impl<T: RequestHandler, U: SecretProvider> Server<T, U> {
pub fn new(host: &str, port: u16, buf_size: u8, skip_authenticity_validation: bool, request_handler: &'static T, secret_provider: &'static U) -> Self {
Self {
address: format!("{}:{}", host, port),
buf_size,
skip_authenticity_validation,
request_handler,
secret_provider,
}
}
pub async fn run(&'static self) -> Result<(), io::Error> {
let mut buf = vec![0, self.buf_size];
let conn_arc = Arc::new(UdpSocket::bind(&self.address).await?);
let undergoing_requests_lock_arc = Arc::new(RwLock::new(HashSet::new()));
loop {
let conn = conn_arc.clone();
let (size, remote_addr) = conn.recv_from(&mut buf).await?;
let request_data = buf[..size].to_vec();
let local_addr = match conn.local_addr() {
Ok(addr) => addr,
Err(e) => {
error!("failed to get a local address from from a connection; {}", e);
continue;
}
};
let undergoing_requests_lock = undergoing_requests_lock_arc.clone();
tokio::spawn(async move {
Self::process_request(
conn,
&request_data,
local_addr,
remote_addr,
undergoing_requests_lock,
self.request_handler,
self.secret_provider,
self.skip_authenticity_validation,
).await;
});
}
}
async fn process_request(
conn: Arc<UdpSocket>,
request_data: &Vec<u8>,
local_addr: SocketAddr,
remote_addr: SocketAddr,
undergoing_requests_lock: Arc<RwLock<HashSet<RequestKey>>>,
request_handler: &T,
secret_provider: &U,
skip_authenticity_validation: bool,
) {
let secret: Vec<u8> = match secret_provider.fetch_secret(remote_addr) {
Ok(secret) => secret,
Err(e) => {
error!("failed to fetch secret binary vector from the secret provider; {}", e);
return;
}
};
if secret.len() <= 0 {
error!("empty secret returned from secret source; empty secret is prohibited");
return;
}
if !skip_authenticity_validation && !Packet::is_authentic_request(request_data, &secret) {
info!("packet validation failed; bad secret");
return;
}
let packet = match Packet::parse(request_data, &secret) {
Ok(packet) => packet,
Err(e) => {
error!("failed to parse given request data to pack into the RADIUS packet; {}", e);
debug!("failed request data => {:?}", request_data);
return;
}
};
let key = RequestKey {
ip: remote_addr.to_string(),
identifier: packet.get_identifier(),
};
let key_for_remove = key.clone();
{
let mut undergoing_requests = undergoing_requests_lock.write().unwrap();
if undergoing_requests.contains(&key) {
return;
}
undergoing_requests.insert(key);
}
request_handler.handle_radius_request(conn.borrow(), &Request::new(local_addr, remote_addr, packet));
let mut undergoing_requests = undergoing_requests_lock.write().unwrap();
undergoing_requests.remove(&key_for_remove);
}
}
#[derive(PartialEq, Eq, Hash, Clone)]
struct RequestKey {
ip: String,
identifier: u8,
}