feat(auth): finish protocol 10 method 2 and 3
This commit is contained in:
parent
8a3f443d85
commit
d18ba43aed
24 changed files with 490 additions and 43 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -549,6 +549,12 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
|
|
@ -1304,6 +1310,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"chrono",
|
||||
"dotenv",
|
||||
"hex",
|
||||
"hmac",
|
||||
"log",
|
||||
"md-5",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "s
|
|||
tokio-stream = { version = "0.1.17", features = ["io-util"] }
|
||||
tonic = "0.12.3"
|
||||
prost = "0.13.4"
|
||||
hex = "0.4.3"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12.3"
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
use std::{env, result};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::array::TryFromSliceError;
|
||||
use std::net::{Ipv4Addr};
|
||||
use once_cell::sync::Lazy;
|
||||
use thiserror::Error;
|
||||
use tonic::codegen::http::uri::InvalidUri;
|
||||
use tonic::metadata::{Ascii, MetadataValue};
|
||||
use tonic::{Request, Status, transport};
|
||||
use tonic::{Request, transport};
|
||||
use tonic::codegen::InterceptedService;
|
||||
use tonic::service::Interceptor;
|
||||
use tonic::transport::Channel;
|
||||
use crate::grpc::{InterceptorFunc, protobufs};
|
||||
use crate::grpc::InterceptorFunc;
|
||||
use crate::grpc::protobufs::account::account_client::AccountClient;
|
||||
use crate::grpc::protobufs::account::GetNexPasswordRequest;
|
||||
|
||||
|
|
@ -42,7 +41,9 @@ pub enum Error{
|
|||
#[error(transparent)]
|
||||
Transport(#[from] transport::Error),
|
||||
#[error(transparent)]
|
||||
Status(#[from] tonic::Status)
|
||||
Status(#[from] tonic::Status),
|
||||
#[error("invalid password size: {0}")]
|
||||
PasswordConversion(#[from] TryFromSliceError)
|
||||
}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
|
@ -64,14 +65,14 @@ impl Client{
|
|||
Ok(Self(client))
|
||||
}
|
||||
|
||||
pub async fn get_nex_password(&mut self , pid: u32) -> Result<Box<str>>{
|
||||
pub async fn get_nex_password(&mut self , pid: u32) -> Result<[u8; 16]>{
|
||||
let req = Request::new(GetNexPasswordRequest{
|
||||
pid
|
||||
});
|
||||
|
||||
let response = self.0.get_nex_password(req).await?.into_inner();
|
||||
|
||||
Ok(response.password.into_boxed_str())
|
||||
Ok(response.password.as_bytes().try_into()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
use std::env;
|
||||
use std::net::Ipv4Addr;
|
||||
use once_cell::sync::Lazy;
|
||||
use tonic::{Request, Status};
|
||||
|
||||
type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result<Request<()>, Status> + Send)>;
|
||||
|
|
|
|||
111
src/kerberos/mod.rs
Normal file
111
src/kerberos/mod.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use std::io::{Read, Write};
|
||||
use bytemuck::{bytes_of, Pod, Zeroable};
|
||||
use chrono::{Datelike, Timelike};
|
||||
use hmac::Hmac;
|
||||
use md5::{Digest, Md5};
|
||||
use rc4::{Rc4, Rc4Core, StreamCipher};
|
||||
use rc4::cipher::StreamCipherCoreWrapper;
|
||||
use rc4::consts::U16;
|
||||
use hmac::Mac;
|
||||
use rc4::KeyInit;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
|
||||
type Md5Hmac = Hmac<md5::Md5>;
|
||||
|
||||
pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{
|
||||
let iteration_count = 65000 + pid%1024;
|
||||
|
||||
let mut key = password;
|
||||
|
||||
for _ in 0..iteration_count {
|
||||
let mut md5 = Md5::new();
|
||||
md5.update(key);
|
||||
key = md5.finalize().try_into().unwrap();
|
||||
}
|
||||
|
||||
key
|
||||
}
|
||||
#[derive(Pod, Zeroable, Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct KerberosDateTime(u64);
|
||||
|
||||
impl KerberosDateTime{
|
||||
pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year:u64 ) -> Self {
|
||||
Self(second | (minute << 6) | (hour << 12) | (day << 17) | (month << 22) | (year << 26))
|
||||
}
|
||||
|
||||
pub fn now() -> Self{
|
||||
let now = chrono::Utc::now();
|
||||
Self::new(
|
||||
now.second() as u64,
|
||||
now.minute() as u64,
|
||||
now.hour() as u64,
|
||||
now.day() as u64,
|
||||
now.month() as u64,
|
||||
now.year() as u64,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Pod, Zeroable, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct TicketInternalData{
|
||||
issued_time: KerberosDateTime,
|
||||
pub pid: u32,
|
||||
pub session_key: [u8; 32],
|
||||
}
|
||||
|
||||
impl TicketInternalData{
|
||||
pub(crate) fn new(pid: u32) -> Self{
|
||||
Self{
|
||||
issued_time: KerberosDateTime::now(),
|
||||
pid,
|
||||
session_key: rand::random()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]>{
|
||||
let mut data = bytes_of(self).to_vec();
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U16>> = Rc4::new_from_slice(&key).unwrap();
|
||||
rc4.apply_keystream(&mut data);
|
||||
|
||||
let mut hmac = <Md5Hmac as KeyInit>::new_from_slice(&key).unwrap();
|
||||
|
||||
hmac.write_all(&data[..]).expect("failed to write data to hmac");
|
||||
|
||||
let hmac_result = &hmac.finalize().into_bytes()[..];
|
||||
|
||||
data.write_all(&hmac_result).expect("failed to write data to vec");
|
||||
|
||||
data.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Pod, Zeroable, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct Ticket{
|
||||
pub session_key: [u8; 32],
|
||||
pub pid: u32,
|
||||
}
|
||||
|
||||
impl Ticket{
|
||||
pub(crate) fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]>{
|
||||
let mut data = bytes_of(self).to_vec();
|
||||
|
||||
internal_data.serialize(&mut data).expect("unable to write to vec");
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U16>> = Rc4::new_from_slice(&key).unwrap();
|
||||
rc4.apply_keystream(&mut data);
|
||||
|
||||
let mut hmac = <Md5Hmac as KeyInit>::new_from_slice(&key).unwrap();
|
||||
|
||||
hmac.write_all(&data[..]).expect("failed to write data to hmac");
|
||||
|
||||
let hmac_result = &hmac.finalize().into_bytes()[..];
|
||||
|
||||
data.write_all(&hmac_result).expect("failed to write data to vec");
|
||||
|
||||
data.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
13
src/main.rs
13
src/main.rs
|
|
@ -11,6 +11,7 @@ use rc4::consts::U5;
|
|||
use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger};
|
||||
use crate::nex::account::Account;
|
||||
use crate::protocols::auth;
|
||||
use crate::protocols::auth::AuthProtocolConfig;
|
||||
use crate::protocols::server::RMCProtocolServer;
|
||||
use crate::prudp::socket::Socket;
|
||||
use crate::prudp::packet::{PRUDPPacket, VirtualPort};
|
||||
|
|
@ -24,9 +25,10 @@ mod protocols;
|
|||
|
||||
mod nex;
|
||||
mod grpc;
|
||||
mod kerberos;
|
||||
|
||||
static KERBEROS_SERVER_PASSWORD: Lazy<String> = Lazy::new(||{
|
||||
env::var("AUTH_SERVER_PORT")
|
||||
env::var("AUTH_SERVER_PASSWORD")
|
||||
.ok()
|
||||
.unwrap_or("password".to_owned())
|
||||
});
|
||||
|
|
@ -80,8 +82,15 @@ async fn start_servers(){
|
|||
info!("setting up endpoints");
|
||||
|
||||
// dont assign it to the name _ as that will make it drop right here and now
|
||||
|
||||
let auth_protocol_config = AuthProtocolConfig{
|
||||
secure_server_account: &SECURE_SERVER_ACCOUNT,
|
||||
build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0",
|
||||
station_url: "prudps:/PID=2;sid=1;stream=10;type=2;address=31.220.75.208;port=10001;CID=1"
|
||||
};
|
||||
|
||||
let rmcserver = RMCProtocolServer::new(Box::new([
|
||||
Box::new(auth::bound_protocol(&SECURE_SERVER_ACCOUNT))
|
||||
Box::new(auth::bound_protocol(auth_protocol_config))
|
||||
]));
|
||||
|
||||
let mut _socket =
|
||||
|
|
|
|||
|
|
@ -1,18 +1,38 @@
|
|||
|
||||
|
||||
pub struct Account{
|
||||
pid: u32,
|
||||
username: Box<str>,
|
||||
kerbros_password: Box<str>,
|
||||
pub pid: u32,
|
||||
pub username: Box<str>,
|
||||
pub kerbros_password: [u8; 16],
|
||||
|
||||
}
|
||||
|
||||
impl Account{
|
||||
pub fn new(pid: u32, username: &str, passwd: &str) -> Self{
|
||||
let passwd_data = passwd.as_bytes();
|
||||
|
||||
let mut passwd = [0u8; 16];
|
||||
|
||||
for (idx, byte) in passwd_data.iter().enumerate(){
|
||||
passwd[idx] = *byte;
|
||||
}
|
||||
|
||||
Self{
|
||||
kerbros_password: passwd.into(),
|
||||
kerbros_password: passwd,
|
||||
username: username.into(),
|
||||
pid
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self{
|
||||
Self{
|
||||
kerbros_password: passwd,
|
||||
username: username.into(),
|
||||
pid
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_login_data(&self) -> (u32, [u8; 16]){
|
||||
(self.pid, self.kerbros_password)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
use std::io::Cursor;
|
||||
use log::error;
|
||||
use crate::nex::account::Account;
|
||||
use crate::protocols::auth::method_login_ex::login_ex;
|
||||
use crate::protocols::auth::AuthProtocolConfig;
|
||||
use crate::rmc::message::RMCMessage;
|
||||
use crate::rmc::response::{ErrorCode, RMCResponseResult};
|
||||
use crate::rmc::structures::any::Any;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
|
||||
pub async fn login(rmcmessage: &RMCMessage, name: &str) -> RMCResponseResult{
|
||||
pub async fn login(rmcmessage: &RMCMessage, _name: &str) -> RMCResponseResult{
|
||||
|
||||
|
||||
rmcmessage.error_result_with_code(ErrorCode::Core_NotImplemented)
|
||||
}
|
||||
|
||||
pub async fn login_raw_params(rmcmessage: &RMCMessage, data: (&Account)) -> RMCResponseResult{
|
||||
pub async fn login_raw_params(rmcmessage: &RMCMessage, data: AuthProtocolConfig) -> RMCResponseResult{
|
||||
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
|
||||
|
||||
let Ok(str) = String::deserialize(&mut reader) else {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
use std::io::Cursor;
|
||||
use log::{error, info};
|
||||
use std::io::{Cursor, Write};
|
||||
use bytemuck::bytes_of;
|
||||
use hex::encode;
|
||||
use log::{error};
|
||||
use crate::grpc::account;
|
||||
use crate::kerberos::KerberosDateTime;
|
||||
use crate::nex::account::Account;
|
||||
use crate::protocols::auth::AuthProtocolConfig;
|
||||
use crate::protocols::auth::ticket_generation::generate_ticket;
|
||||
use crate::rmc::message::RMCMessage;
|
||||
use crate::rmc::response::{ErrorCode, RMCResponseResult};
|
||||
use crate::rmc::structures::{RmcSerialize};
|
||||
use crate::rmc::structures::any::Any;
|
||||
use crate::rmc::structures::connection_data::ConnectionData;
|
||||
use crate::rmc::structures::qresult::QResult;
|
||||
|
||||
pub async fn login_ex(rmcmessage: &RMCMessage, secure_server_account: &Account , pid: u32) -> RMCResponseResult{
|
||||
pub async fn login_ex(rmcmessage: &RMCMessage, proto_data: AuthProtocolConfig, pid: u32) -> RMCResponseResult{
|
||||
// todo: figure out how the AuthenticationInfo struct works, parse it and validate login info
|
||||
|
||||
let Ok(mut client) = account::Client::new().await else {
|
||||
|
|
@ -18,15 +25,35 @@ pub async fn login_ex(rmcmessage: &RMCMessage, secure_server_account: &Account ,
|
|||
return rmcmessage.error_result_with_code(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let source_login_data = (pid, passwd);
|
||||
let destination_login_data = proto_data.secure_server_account.get_login_data();
|
||||
|
||||
let ticket = generate_ticket(source_login_data, destination_login_data);
|
||||
|
||||
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
|
||||
let result = QResult::success(ErrorCode::Core_Unknown);
|
||||
|
||||
let connection_data = ConnectionData{
|
||||
station_url: proto_data.station_url,
|
||||
special_station_url: "",
|
||||
date_time: KerberosDateTime::now(),
|
||||
special_protocols: Vec::new()
|
||||
};
|
||||
|
||||
let mut response: Vec<u8> = Vec::new();
|
||||
|
||||
result.serialize(&mut response).expect("failed serializing result");
|
||||
response.write_all(bytes_of(&source_login_data.0)).expect("failed writing pid");
|
||||
ticket.serialize(&mut response).expect("failed serializing ticket");
|
||||
connection_data.serialize(&mut response).expect("failed writing connection data");
|
||||
proto_data.build_name.serialize(&mut response).expect("failed writing build name");
|
||||
|
||||
return rmcmessage.success_with_data(response);
|
||||
}
|
||||
|
||||
pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, (secure_server_account): (&Account)) -> RMCResponseResult{
|
||||
pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, data: AuthProtocolConfig) -> RMCResponseResult{
|
||||
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
|
||||
|
||||
let Ok(_str) = String::deserialize(&mut reader) else {
|
||||
let Ok(str) = String::deserialize(&mut reader) else {
|
||||
error!("error reading packet");
|
||||
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
|
@ -50,5 +77,5 @@ pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, (secure_server_account
|
|||
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
||||
login_ex(rmcmessage, secure_server_account, pid).await
|
||||
login_ex(rmcmessage, data, pid).await
|
||||
}
|
||||
53
src/protocols/auth/method_request_ticket.rs
Normal file
53
src/protocols/auth/method_request_ticket.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
use std::io::Cursor;
|
||||
use log::error;
|
||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
use crate::grpc::account;
|
||||
use crate::protocols::auth::{AuthProtocolConfig, get_login_data_by_pid};
|
||||
use crate::protocols::auth::method_login_ex::login_ex;
|
||||
use crate::protocols::auth::ticket_generation::generate_ticket;
|
||||
use crate::rmc::message::RMCMessage;
|
||||
use crate::rmc::response::{ErrorCode, RMCResponseResult};
|
||||
use crate::rmc::response::ErrorCode::Core_Unknown;
|
||||
use crate::rmc::structures::any::Any;
|
||||
use crate::rmc::structures::qresult::QResult;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
|
||||
pub async fn request_ticket(rmcmessage: &RMCMessage, data: AuthProtocolConfig, source_pid: u32, destination_pid: u32) -> RMCResponseResult{
|
||||
let Some(source_login_data) = get_login_data_by_pid(source_pid).await else {
|
||||
return rmcmessage.error_result_with_code(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let desgination_login_data = if destination_pid == data.secure_server_account.pid{
|
||||
data.secure_server_account.get_login_data()
|
||||
} else {
|
||||
let Some(login) = get_login_data_by_pid(destination_pid).await else {
|
||||
return rmcmessage.error_result_with_code(ErrorCode::Core_Exception);
|
||||
};
|
||||
login
|
||||
};
|
||||
|
||||
let result = QResult::success(Core_Unknown);
|
||||
|
||||
let ticket = generate_ticket(source_login_data, desgination_login_data);
|
||||
|
||||
let mut response: Vec<u8> = Vec::new();
|
||||
|
||||
result.serialize(&mut response).expect("failed serializing result");
|
||||
ticket.serialize(&mut response).expect("failed serializing ticket");
|
||||
|
||||
rmcmessage.success_with_data(response)
|
||||
}
|
||||
|
||||
pub async fn request_ticket_raw_params(rmcmessage: &RMCMessage, data: AuthProtocolConfig) -> RMCResponseResult{
|
||||
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
|
||||
|
||||
let Ok(source_pid) = reader.read_struct(IS_BIG_ENDIAN) else {
|
||||
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
||||
let Ok(destination_pid) = reader.read_struct(IS_BIG_ENDIAN) else {
|
||||
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
||||
request_ticket(rmcmessage, data, source_pid, destination_pid).await
|
||||
}
|
||||
|
|
@ -1,18 +1,42 @@
|
|||
mod method_login_ex;
|
||||
mod method_login;
|
||||
mod ticket_generation;
|
||||
mod method_request_ticket;
|
||||
|
||||
use std::sync::Arc;
|
||||
use log::{error};
|
||||
use crate::define_protocol;
|
||||
use crate::grpc::account;
|
||||
use crate::nex::account::Account;
|
||||
use crate::protocols::auth::method_login::login_raw_params;
|
||||
use crate::protocols::auth::method_login_ex::{login_ex, login_ex_raw_params};
|
||||
use crate::protocols::auth::method_login_ex::login_ex_raw_params;
|
||||
use crate::protocols::auth::method_request_ticket::request_ticket_raw_params;
|
||||
use crate::rmc::message::RMCMessage;
|
||||
use crate::rmc::response::{ErrorCode, RMCResponse};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AuthProtocolConfig {
|
||||
pub secure_server_account: &'static Account,
|
||||
pub build_name: &'static str,
|
||||
pub station_url: &'static str
|
||||
}
|
||||
|
||||
define_protocol!{
|
||||
10(secure_server_account: &'static Account) => {
|
||||
10(proto_data: AuthProtocolConfig) => {
|
||||
0x01 => login_raw_params,
|
||||
0x02 => login_ex_raw_params
|
||||
0x02 => login_ex_raw_params,
|
||||
0x03 => request_ticket_raw_params
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> {
|
||||
let Ok(mut client) = account::Client::new().await else {
|
||||
return None
|
||||
};
|
||||
|
||||
let Ok(passwd) = client.get_nex_password(pid).await else{
|
||||
return None
|
||||
};
|
||||
|
||||
Some((pid, passwd))
|
||||
}
|
||||
19
src/protocols/auth/ticket_generation.rs
Normal file
19
src/protocols/auth/ticket_generation.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use crate::kerberos;
|
||||
use crate::kerberos::{derive_key, Ticket};
|
||||
|
||||
|
||||
pub fn generate_ticket(source_act_login_data: (u32, [u8;16]), dest_act_login_data: (u32, [u8;16])) -> Box<[u8]>{
|
||||
let source_key = derive_key(source_act_login_data.0, source_act_login_data.1);
|
||||
let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1);
|
||||
|
||||
let internal_data = kerberos::TicketInternalData::new(source_act_login_data.0);
|
||||
|
||||
let encrypted_inner = internal_data.encrypt(dest_key);
|
||||
let encrypted_session_ticket = Ticket{
|
||||
pid: dest_act_login_data.0,
|
||||
session_key: internal_data.session_key,
|
||||
}.encrypt(source_key, &encrypted_inner);
|
||||
|
||||
|
||||
encrypted_session_ticket
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ pub mod server;
|
|||
#[macro_export]
|
||||
macro_rules! define_protocol {
|
||||
($id:literal ($($varname:ident : $ty:ty),*) => {$($func_id:literal => $func:path),*} ) => {
|
||||
#[allow(unused_parens)]
|
||||
async fn protocol (rmcmessage: &RMCMessage, $($varname : $ty),*) -> Option<RMCResponse>{
|
||||
if rmcmessage.protocol_id != $id{
|
||||
return None;
|
||||
|
|
@ -30,7 +31,7 @@ macro_rules! define_protocol {
|
|||
response_result
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_parens)]
|
||||
pub fn bound_protocol($($varname : $ty,)*) -> Box<dyn for<'message_lifetime> Fn(&'message_lifetime RMCMessage) -> ::std::pin::Pin<Box<dyn ::std::future::Future<Output = Option<RMCResponse>> + Send + 'message_lifetime>> + Send + Sync>{
|
||||
Box::new(
|
||||
move |v| {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use hmac::{Hmac, Mac};
|
|||
use log::{error, trace, warn};
|
||||
use md5::{Md5, Digest};
|
||||
use thiserror::Error;
|
||||
use v_byte_macros::{EnumTryInto, SwapEndian};
|
||||
use v_byte_macros::{SwapEndian};
|
||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
use crate::prudp::packet::flags::ACK;
|
||||
use crate::prudp::packet::PacketOption::{ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions};
|
||||
|
|
@ -173,13 +173,6 @@ impl Default for PRUDPHeader{
|
|||
}
|
||||
|
||||
|
||||
#[derive(EnumTryInto)]
|
||||
|
||||
#[repr(u16)]
|
||||
enum PacketSpecificData {
|
||||
E = 0x10
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PacketOption{
|
||||
SupportedFunctions(u32),
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ pub struct ActiveConnectionData {
|
|||
pub reliable_client_counter: u16,
|
||||
pub reliable_server_counter: u16,
|
||||
pub reliable_client_queue: VecDeque<PRUDPPacket>,
|
||||
pub connection_data_channel: Sender<Vec<u8>>,
|
||||
server_encryption: Box<dyn StreamCipher + Send>,
|
||||
client_decryption: Box<dyn StreamCipher + Send>,
|
||||
pub server_session_id: u8,
|
||||
|
|
@ -363,7 +362,7 @@ impl SocketData {
|
|||
self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back");
|
||||
}
|
||||
}
|
||||
|
||||
3 => {}
|
||||
_ => unimplemented!("unimplemented packet type: {}", packet.header.types_and_flags.get_types())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,4 +58,12 @@ impl RMCMessage{
|
|||
error_code
|
||||
}
|
||||
}
|
||||
|
||||
pub fn success_with_data(&self, data: Vec<u8>) -> RMCResponseResult{
|
||||
RMCResponseResult::Success {
|
||||
call_id: self.call_id,
|
||||
method_id: self.method_id,
|
||||
data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@ use crate::prudp::packet::PacketOption::FragmentId;
|
|||
use crate::prudp::packet::types::DATA;
|
||||
use crate::prudp::socket::{ConnectionData, SocketData};
|
||||
|
||||
|
||||
|
||||
pub enum RMCResponseResult {
|
||||
Success{
|
||||
call_id: u32,
|
||||
|
|
@ -389,6 +391,7 @@ mod test{
|
|||
use hmac::digest::consts::U5;
|
||||
use hmac::digest::KeyInit;
|
||||
use rc4::{Rc4, StreamCipher};
|
||||
use crate::rmc::response::ErrorCode;
|
||||
|
||||
#[test]
|
||||
fn test(){
|
||||
|
|
@ -410,4 +413,10 @@ mod test{
|
|||
assert_eq!(data_orig, data);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum_equivilance(){
|
||||
let val: u32 = ErrorCode::Core_Unknown.into();
|
||||
assert_eq!(val, 0x00010001)
|
||||
}
|
||||
}
|
||||
44
src/rmc/structures/buffer.rs
Normal file
44
src/rmc/structures/buffer.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
use std::io::{Read, Write};
|
||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
|
||||
impl<'a> RmcSerialize for &'a [u8]{
|
||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||
let u32_size = self.len() as u32;
|
||||
writer.write(bytemuck::bytes_of(&u32_size))?;
|
||||
writer.write(self)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// DO NOT USE (also maybe split off the serialize and deserialize functions at some point)
|
||||
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||
panic!("cannot deserialize to a u8 slice reference (use this ONLY for writing)")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RmcSerialize for Vec<u8>{
|
||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||
(&self[..]).serialize(writer)
|
||||
}
|
||||
|
||||
fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||
let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?;
|
||||
|
||||
let mut data = vec![0; len as usize];
|
||||
|
||||
reader.read_exact(&mut data)?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RmcSerialize for Box<[u8]>{
|
||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||
(&self[..]).serialize(writer)
|
||||
}
|
||||
|
||||
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||
Vec::deserialize(reader).map(|v| v.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
27
src/rmc/structures/connection_data.rs
Normal file
27
src/rmc/structures/connection_data.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use std::io::{Read, Write};
|
||||
use bytemuck::bytes_of;
|
||||
use crate::kerberos::KerberosDateTime;
|
||||
use crate::rmc::structures::{rmc_struct, RmcSerialize};
|
||||
|
||||
pub struct ConnectionData<'a>{
|
||||
pub station_url: &'a str,
|
||||
pub special_protocols: Vec<u8>,
|
||||
pub special_station_url: &'a str,
|
||||
pub date_time: KerberosDateTime
|
||||
}
|
||||
|
||||
impl<'a> RmcSerialize for ConnectionData<'a>{
|
||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||
rmc_struct::write_struct(writer, 1, |mut v|{
|
||||
self.station_url.serialize(v).expect("unable to write station url");
|
||||
self.special_protocols.serialize(v).expect("unable to write special protocols");
|
||||
self.special_station_url.serialize(v).expect("unable to write special station url");
|
||||
v.write_all(bytes_of(&self.date_time)).expect("unable to write date time");
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
21
src/rmc/structures/list.rs
Normal file
21
src/rmc/structures/list.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use std::io::{Read, Write};
|
||||
use bytemuck::bytes_of;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
|
||||
|
||||
impl<T: RmcSerialize> RmcSerialize for Vec<T>{
|
||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||
let u32_len = self.len();
|
||||
|
||||
writer.write_all(bytes_of(&u32_len))?;
|
||||
for e in self{
|
||||
e.serialize(writer)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,11 @@ type Result<T> = std::result::Result<T, Error>;
|
|||
|
||||
pub mod string;
|
||||
pub mod any;
|
||||
pub mod qresult;
|
||||
pub mod buffer;
|
||||
pub mod connection_data;
|
||||
pub mod rmc_struct;
|
||||
pub mod list;
|
||||
|
||||
pub trait RmcSerialize: Sized{
|
||||
fn serialize(&self, writer: &mut dyn Write) -> Result<()>;
|
||||
|
|
|
|||
37
src/rmc/structures/qresult.rs
Normal file
37
src/rmc/structures/qresult.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
use std::io::{Read, Write};
|
||||
use bytemuck::{bytes_of, Pod, Zeroable};
|
||||
use v_byte_macros::SwapEndian;
|
||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
use crate::rmc::response::ErrorCode;
|
||||
use crate::rmc::structures::{RmcSerialize, Result};
|
||||
|
||||
const ERROR_MASK: u32 = 1 << 31;
|
||||
|
||||
#[derive(Pod, Zeroable, Copy, Clone, SwapEndian)]
|
||||
#[repr(transparent)]
|
||||
pub struct QResult(u32);
|
||||
|
||||
impl QResult{
|
||||
pub fn success(error_code: ErrorCode) -> Self{
|
||||
let val: u32 = error_code.into();
|
||||
|
||||
Self(val & (!ERROR_MASK))
|
||||
}
|
||||
|
||||
pub fn error(error_code: ErrorCode) -> Self{
|
||||
let val: u32 = error_code.into();
|
||||
|
||||
Self(val | ERROR_MASK)
|
||||
}
|
||||
}
|
||||
|
||||
impl RmcSerialize for QResult{
|
||||
fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
writer.write(bytes_of(self))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn deserialize(mut reader: &mut dyn Read) -> Result<Self> {
|
||||
Ok(reader.read_struct(IS_BIG_ENDIAN)?)
|
||||
}
|
||||
}
|
||||
24
src/rmc/structures/rmc_struct.rs
Normal file
24
src/rmc/structures/rmc_struct.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use std::io::Write;
|
||||
use bytemuck::bytes_of;
|
||||
use crate::rmc::structures::Result;
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct StructureHeader{
|
||||
version: u8,
|
||||
length: u32
|
||||
}
|
||||
|
||||
pub fn write_struct(mut writer: &mut dyn Write, version: u8, pred: impl Fn(&mut Vec<u8>)) -> Result<()> {
|
||||
writer.write_all(&[version])?;
|
||||
|
||||
let mut scratch_space: Vec<u8> = Vec::new();
|
||||
|
||||
(pred)(&mut scratch_space);
|
||||
|
||||
let u32_size= scratch_space.len() as u32;
|
||||
|
||||
writer.write_all(bytes_of(&u32_size))?;
|
||||
writer.write_all(&scratch_space)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -17,6 +17,15 @@ impl RmcSerialize for String{
|
|||
|
||||
Ok(String::from_utf8(data)?)
|
||||
}
|
||||
fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
(&self[..]).serialize(writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl RmcSerialize for &str{
|
||||
fn deserialize(mut reader: &mut dyn Read) -> Result<Self> {
|
||||
panic!("cannot serialize to &str")
|
||||
}
|
||||
fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
let u16_len: u16 = self.len() as u16;
|
||||
writer.write(bytes_of(&u16_len))?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue