changes...

This commit is contained in:
DJMrTV 2025-01-26 12:09:56 +01:00
commit 40ca10651f
18 changed files with 998 additions and 112 deletions

25
Cargo.lock generated
View file

@ -163,6 +163,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]]
name = "cc"
version = "1.2.10"
@ -303,6 +309,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "generic-array"
version = "0.14.7"
@ -840,6 +852,7 @@ dependencies = [
"simplelog",
"thiserror",
"tokio",
"tokio-stream",
"v_byte_macros",
]
@ -940,6 +953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"pin-project-lite",
@ -959,6 +973,17 @@ dependencies = [
"syn 2.0.96",
]
[[package]]
name = "tokio-stream"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "typenum"
version = "1.17.0"

View file

@ -19,3 +19,4 @@ rustls = "^0.23.21"
hmac = "0.12.1"
md-5 = "^0.10.6"
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync"] }
tokio-stream = { version = "0.1.17", features = ["io-util"] }

View file

@ -3,6 +3,7 @@ use std::io::Read;
use std::marker::PhantomData;
use std::pin::Pin;
use bytemuck::Pod;
use tokio::io::{AsyncRead, AsyncReadExt};
#[cfg(target_endian = "little")]
pub const IS_LITTLE_ENDIAN: bool = true;
@ -130,6 +131,8 @@ impl<T: Read> ReadExtensions for T{
}
pub trait SwapEndian: Clone + Copy{
fn swap_endian(self) -> Self;
}

View file

@ -1,17 +1,26 @@
use std::env::current_dir;
use std::{env, fs};
use std::fs::File;
use std::io::Cursor;
use std::net::{Ipv4Addr, SocketAddrV4};
use chrono::Local;
use log::{info, trace};
use log::{error, info, trace};
use once_cell::sync::Lazy;
use rc4::{KeyInit, Rc4, StreamCipher};
use rc4::consts::U5;
use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger};
use crate::prudp::socket::{Socket, SocketImpl};
use crate::prudp::packet::VirtualPort;
use crate::prudp::socket::{Socket, SocketData};
use crate::prudp::packet::{PRUDPPacket, VirtualPort};
use crate::prudp::router::Router;
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{RMCResponse, RMCResponseResult, send_response};
use crate::rmc::response::ErrorCode::Core_InvalidIndex;
mod endianness;
mod prudp;
pub mod rmc;
mod protocols;
static AUTH_SERVER_PORT: Lazy<u16> = Lazy::new(||{
env::var("AUTH_SERVER_PORT")
@ -44,23 +53,122 @@ async fn main() {
start_servers().await;
}
async fn auth_server_handle_rmc(packet: PRUDPPacket, rmc_message: RMCMessage){
}
async fn start_servers(){
info!("starting auth server on {}:{}", *OWN_IP, *AUTH_SERVER_PORT);
let auth_server_router =
let (auth_server_router, auth_router_join) =
Router::new(SocketAddrV4::new(*OWN_IP, *AUTH_SERVER_PORT)).await
.expect("unable to startauth server");
info!("setting up endpoints");
let mut socket =
// dont assign it to the name _ as that will make it drop right here and now
let mut _socket =
Socket::new(
auth_server_router.clone(),
VirtualPort::new(1,10),
"6f599f81"
).await.expect("unable to create socket");
"6f599f81",
Box::new(|_|{
Box::pin(
async move {
let rc4: Rc4<U5> = Rc4::new_from_slice( "CD&ML".as_bytes()).unwrap();
let cypher = Box::new(rc4);
let server_cypher: Box<dyn StreamCipher + Send + Sync> = cypher;
let Some(connection) = socket.accept().await else {
let rc4: Rc4<U5> = Rc4::new_from_slice( "CD&ML".as_bytes()).unwrap();
let cypher = Box::new(rc4);
let client_cypher: Box<dyn StreamCipher + Send + Sync> = cypher;
(true, (server_cypher, client_cypher))
}
)
}),
Box::new(|p, socket, connection|{
Box::pin(
async move {
println!("{:?}",p);
let Ok(rmc) = RMCMessage::new(&mut Cursor::new(&p.payload)) else {
error!("error reading rmc message");
return;
};
println!("recieved rmc message: {{ protocol: {}, method: {}}}", rmc.protocol_id, rmc.method_id);
if let Some(response) = protocols::auth::try_process_via_protocol(&rmc){
send_response(&p, &socket, connection, response).await;
}
send_response(&p, &socket, connection, RMCResponse{
protocol_id: rmc.protocol_id as u8,
response_result: RMCResponseResult::Error {
call_id: rmc.call_id,
error_code: Core_InvalidIndex
}
}).await;
}
)
})
).await.expect("unable to create socket");
auth_router_join.await.expect("auth server crashed")
}
#[cfg(test)]
mod test{
use std::io::Cursor;
use std::num::ParseIntError;
use std::str::from_utf8;
use hmac::digest::consts::U5;
use rc4::{KeyInit, Rc4, StreamCipher};
use crate::prudp::packet::PRUDPPacket;
use crate::rmc;
fn from_hex_stream(val: &str) -> Result<Vec<u8>, ParseIntError> {
let res: Result<Vec<u8>, _> = val.as_bytes()
.chunks_exact(2)
.map(|c| from_utf8(c).expect("unable to convert back to string"))
.map(|s| u8::from_str_radix(s, 16))
.collect();
res
}
#[tokio::test]
async fn simulate_packets(){
let val = from_hex_stream("ead001037d00afa1e200a5000200d9e4a4050368c18c6de4e2fb1cc40f0c020100768744db99f92c5005a061fd2a1df280cd64d5c1a565952c6befa607cbaf34661312b16db0fa6fccfb81e28b5a3a9bed02b49152bbc99cc112b7e29b9e45ec3d4b89df0fe71390883d9a927c264d07ada0de9cd28499e3ccdf3fd079e4a9848d4d783778c42da2af06106a7326634dc5bec5c3438ef18e30109839ffcc").expect("uuuuh");
let mut packet = PRUDPPacket::new(&mut Cursor::new(&val)).expect("invalid packet");
let mut rc4: Rc4<U5> =
Rc4::new_from_slice("CD&ML".as_bytes().into()).expect("invalid key");
rc4.apply_keystream(&mut packet.payload);
println!("packet: {:?}", packet);
let rmc_packet = rmc::message::RMCMessage::new(&mut Cursor::new(&packet.payload)).expect("unable to read message");
let mut a = Cursor::new(&rmc_packet.rest_of_data);
let pid = rmc::structures::string::read(&mut a).expect("unable to read pid");
}
#[tokio::test]
async fn simulate_packets_response(){
let val = from_hex_stream("ead001032501a1af6200a500010013ffcdbc3a2ebc44efc6e38ea32a72b40201002e8644db19fe2a5005a2637d2a16f3b1fe5633037c1ed61c5aefad8afebdf2ff8600e9350fba1298b570c70f6dd647eac2d3faf0ab74ef761e2ee43dc10e249e5f91aed6813dcc04b3c707d9442b6e353b9b0b654e98f860fe5379c41d3c2a1874b7dd37ebf499e03bd2fd3e9a9203c0959feb760c38f504dcd0c9e99b17fd410657da4efa3e01c8a68ab3042d6d489788d5580778d32249cdf1fba8bf68cf4019d116ea7c580622ea1e3635139d91b44635d5e95b6c35b33898fdc0117fa6fc7162840d07a49f1e7089aa0ea65409a8ddeb2334449ba73a0ff7de462cf4a706a696de0f0521b84ae5a3f8587f3585d202d3cc0fb0451519c1b830b5e3cdd6de52e9add7325cbbf08a7c2f8b875934942b226703a22b4bc8931932dab055049051e4144b02").expect("uuuuh");
let mut packet = PRUDPPacket::new(&mut Cursor::new(&val)).expect("invalid packet");
let mut rc4: Rc4<U5> =
Rc4::new_from_slice("CD&ML".as_bytes().into()).expect("invalid key");
rc4.apply_keystream(&mut packet.payload);
println!("packet: {:?}", packet);
}
}

View file

@ -0,0 +1,39 @@
use std::io::Cursor;
use log::{error, info};
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
use crate::rmc::structures::{string, any};
pub fn login_ex(name: &str) -> RMCResponseResult{
// todo: figure out how the AuthenticationInfo struct works, parse it and validate login info
//return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
unreachable!()
}
pub fn login_ex_raw_params(rmcmessage: &RMCMessage) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(str) = string::read(&mut reader) else {
error!("error reading packet");
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
let Ok(any) = any::read(&mut reader) else {
error!("error reading packet");
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
match any.name.as_ref(){
"AuthenticationInfo" => {
}
v => {
error!("error reading packet: invalid structure type: {}", v);
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
}
}
//login_ex(&str)
rmcmessage.error_result_with_code(ErrorCode::Core_AccessDenied)
}

25
src/protocols/auth/mod.rs Normal file
View file

@ -0,0 +1,25 @@
mod method_login_ex;
use log::{error, info};
use crate::protocols::auth::method_login_ex::{login_ex, login_ex_raw_params};
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
pub fn try_process_via_protocol(rmcmessage: &RMCMessage) -> Option<RMCResponse>{
if rmcmessage.protocol_id != 10{
return None;
}
let response_result = match rmcmessage.method_id{
0x02 => login_ex_raw_params(rmcmessage),
_ => {
error!("invalid method id sent to ticket-granting protocol: {:?}", rmcmessage.method_id);
rmcmessage.error_result_with_code(ErrorCode::Core_Exception)
}
};
Some(RMCResponse{
protocol_id: 10,
response_result
})
}

1
src/protocols/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod auth;

View file

@ -1,7 +0,0 @@
use tokio::sync::mpsc::Receiver;
//struct Connection(Arc<ConnectionImpl>, Receiver<>);
struct ConnectionImpl{
}

View file

@ -3,4 +3,3 @@ pub mod router;
pub mod socket;
mod auth_module;
mod sockaddr;
mod connection;

View file

@ -36,7 +36,7 @@ pub enum Error {
pub type Result<T> = std::result::Result<T, Error>;
#[repr(transparent)]
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian)]
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default)]
pub struct TypesFlags(u16);
impl TypesFlags {
@ -77,6 +77,10 @@ pub mod types {
pub const SYN: u8 = 0x0;
pub const CONNECT: u8 = 0x1;
pub const DATA: u8 = 0x2;
pub const DISCONNECT: u8 = 0x3;
pub const PING: u8 = 0x4;
/// no idea what user is supposed to mean
pub const USER: u8 = 0x5;
}
impl Debug for TypesFlags {
@ -135,8 +139,8 @@ impl Debug for VirtualPort {
#[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian)]
pub struct PRUDPHeader {
magic: [u8; 2],
version: u8,
pub magic: [u8; 2],
pub version: u8,
pub packet_specific_size: u8,
pub payload_size: u16,
pub source_port: VirtualPort,
@ -146,6 +150,24 @@ pub struct PRUDPHeader {
pub substream_id: u8,
pub sequence_id: u16,
}
impl Default for PRUDPHeader{
fn default() -> Self {
Self{
magic: [0xEA, 0xD0],
version: 1,
session_id: 0,
source_port: VirtualPort(0),
sequence_id: 0,
payload_size: 0,
destination_port: VirtualPort(0),
types_and_flags: TypesFlags(0),
packet_specific_size: 0,
substream_id: 0
}
}
}
#[repr(u16)]
#[derive(EnumTryInto)]
enum PacketSpecificData {

View file

@ -12,9 +12,10 @@ use tokio::task::JoinHandle;
use once_cell::sync::Lazy;
use log::{error, info, trace, warn};
use thiserror::Error;
use tokio::io::Join;
use tokio::sync::RwLock;
use crate::prudp::auth_module::AuthModule;
use crate::prudp::socket::{Socket, SocketImpl};
use crate::prudp::socket::{Socket, SocketData};
use crate::prudp::packet::{PRUDPPacket, VirtualPort};
use crate::prudp::router::Error::VirtualPortTaken;
use crate::prudp::sockaddr::PRUDPSockAddr;
@ -26,7 +27,7 @@ static SERVER_DATAGRAMS: Lazy<u8> = Lazy::new(||{
});
pub struct Router {
endpoints: RwLock<[Option<Arc<SocketImpl>>; 16]>,
endpoints: RwLock<[Option<Arc<SocketData>>; 16]>,
running: AtomicBool,
socket: Arc<UdpSocket>,
//pub auth_module: Arc<dyn AuthModule>
@ -43,8 +44,8 @@ impl Router {
fn process_prudp_packet(&self, packet: &PRUDPPacket){
}
async fn process_prudp_packets<'a>(&self, socket: &'a UdpSocket, addr: SocketAddrV4, udp_message: &[u8]){
let mut stream = Cursor::new(udp_message);
async fn process_prudp_packets<'a>(self: Arc<Self>, socket: Arc<UdpSocket>, addr: SocketAddrV4, udp_message: Vec<u8>){
let mut stream = Cursor::new(&udp_message);
while stream.position() as usize != udp_message.len() {
let packet = match PRUDPPacket::new(&mut stream){
@ -93,13 +94,12 @@ impl Router {
};
let current_msg = &msg_buffer[0..len];
info!("attempting to process message");
self.process_prudp_packets(&socket, addr, current_msg).await;
tokio::spawn(self.clone().process_prudp_packets(socket.clone(), addr, current_msg.to_vec()));
}
}
pub async fn new(addr: SocketAddrV4) -> io::Result<Arc<Self>>{
pub async fn new(addr: SocketAddrV4) -> io::Result<(Arc<Self>, JoinHandle<()>)>{
trace!("starting router on {}", addr);
let socket = Arc::new(UdpSocket::bind(addr).await?);
@ -114,14 +114,14 @@ impl Router {
let arc = Arc::new(own_impl);
{
let task = {
let socket = socket.clone();
let server= arc.clone();
tokio::spawn(async {
server.server_thread_send_entry(socket).await;
});
}
})
};
{
let socket = socket.clone();
@ -135,7 +135,7 @@ impl Router {
}
Ok(arc)
Ok((arc, task))
}
pub fn get_udp_socket(&self) -> Arc<UdpSocket>{
@ -149,7 +149,7 @@ impl Router {
}
// returns Some(()) i
pub(crate) async fn add_socket(&self, socket: Arc<SocketImpl>) -> Result<(), Error>{
pub(crate) async fn add_socket(&self, socket: Arc<SocketData>) -> Result<(), Error>{
let mut endpoints = self.endpoints.write().await;
let idx = socket.get_virual_port().get_port_number() as usize;

View file

@ -1,74 +1,101 @@
use std::array;
use std::collections::{HashMap, VecDeque};
use std::future::Future;
use std::io::Write;
use std::ops::Deref;
use std::pin::Pin;
use tokio::net::UdpSocket;
use std::sync::{Arc};
use tokio::sync::{Mutex, RwLock};
use tokio::sync::{Mutex, MutexGuard, RwLock};
use hmac::{Hmac, Mac};
use log::{error, info, trace, warn};
use rand::random;
use rc4::consts::U256;
use rc4::consts::{U256, U5};
use rc4::{Rc4, Rc4Core, StreamCipher};
use rc4::cipher::{KeySizeUser, StreamCipherCoreWrapper};
use rustls::internal::msgs::handshake::SessionId;
use tokio::io::AsyncWriteExt;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::task::JoinHandle;
use tokio_stream::wrappers::ReceiverStream;
use crate::prudp::packet::{flags, PacketOption, PRUDPPacket, types, VirtualPort};
use crate::prudp::packet::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE};
use crate::prudp::packet::PacketOption::{ConnectionSignature, MaximumSubstreamId, SupportedFunctions};
use crate::prudp::packet::types::{CONNECT, DATA, SYN};
use crate::prudp::packet::types::{CONNECT, DATA, PING, SYN};
use crate::prudp::router::{Error, Router};
use crate::prudp::sockaddr::PRUDPSockAddr;
use rc4::KeyInit;
// due to the way this is designed crashing the router thread causes deadlock, sorry ;-;
// (maybe i will fix that some day)
/// PRUDP Socket for accepting connections to then send and recieve data from those clients
pub struct Socket(Arc<SocketImpl>, Arc<Router>, Receiver<Connection>);
#[derive(Debug)]
pub struct SocketImpl {
virtual_port: VirtualPort,
socket: Arc<UdpSocket>,
access_key: &'static str,
connections: RwLock<HashMap<PRUDPSockAddr, Arc<Mutex<Connection>>>>,
connection_creation_sender: Sender<Connection>,
pub struct Socket {
socket_data: Arc<SocketData>,
router: Arc<Router>,
}
type OnConnectHandlerFn = Box<dyn Fn(PRUDPPacket) -> Pin<Box<dyn Future<Output=(bool, (Box<dyn StreamCipher + Send + Sync>, Box<dyn StreamCipher + Send + Sync>))> + Send + Sync>> + Send + Sync>;
type OnDataHandlerFn = Box<dyn for<'a> Fn(PRUDPPacket, Arc<SocketData>, &'a mut MutexGuard<'_, ConnectionData>) -> Pin<Box<dyn Future<Output=()> + 'a + Send + Sync>> + Send + Sync>;
#[derive(Debug)]
pub struct Connection {
sock_addr: PRUDPSockAddr,
id: u64,
signature: [u8; 16],
server_signature: [u8; 16],
session_id: u8,
reliable_client_counter: u16,
reliable_server_counter: u16,
reliable_client_queue: VecDeque<PRUDPPacket>,
pub struct SocketData {
virtual_port: VirtualPort,
pub socket: Arc<UdpSocket>,
pub access_key: &'static str,
connections: RwLock<HashMap<PRUDPSockAddr, Arc<Mutex<ConnectionData>>>>,
on_connect_handler: OnConnectHandlerFn,
on_data_handler: OnDataHandlerFn,
}
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>>,
pub server_encryption: Box<dyn StreamCipher + Send + Sync>,
pub client_decryption: Box<dyn StreamCipher + Send + Sync>,
pub server_session_id: u8,
}
pub struct ConnectionData {
pub sock_addr: PRUDPSockAddr,
pub id: u64,
pub signature: [u8; 16],
pub server_signature: [u8; 16],
pub active_connection_data: Option<ActiveConnectionData>,
}
impl Socket {
pub async fn new(router: Arc<Router>, port: VirtualPort, access_key: &'static str) -> Result<Self, Error> {
pub async fn new(
router: Arc<Router>,
port: VirtualPort,
access_key: &'static str,
on_connection_handler: OnConnectHandlerFn,
on_data_handler: OnDataHandlerFn,
) -> Result<Self, Error> {
trace!("creating socket on router at {} on virtual port {:?}", router.get_own_address(), port);
let (send, recv) = channel(20);
let socket = Arc::new(
SocketImpl::new(&router, send, port, access_key)
let socket_data = Arc::new(
SocketData::new_unbound(&router, port, access_key, on_connection_handler, on_data_handler)
);
router.add_socket(socket.clone()).await?;
router.add_socket(socket_data.clone()).await?;
Ok(Self(socket, router, recv))
}
pub async fn accept(&mut self) -> Option<Connection> {
self.2.recv().await
Ok(Self {
socket_data,
router,
})
}
}
impl Drop for Socket {
fn drop(&mut self) {
{
let router = self.1.clone();
let router = self.router.clone();
let virtual_port = self.virtual_port;
trace!("socket dropped socket will be removed from router soon");
@ -82,21 +109,27 @@ impl Drop for Socket {
}
impl Deref for Socket {
type Target = SocketImpl;
type Target = SocketData;
fn deref(&self) -> &Self::Target {
&self.0
&self.socket_data
}
}
impl SocketImpl {
fn new(router: &Router, connection_creation_sender: Sender<Connection>, port: VirtualPort, access_key: &'static str) -> Self {
SocketImpl {
impl SocketData {
fn new_unbound(router: &Router,
port: VirtualPort,
access_key: &'static str,
on_connect_handler: OnConnectHandlerFn,
on_data_handler: OnDataHandlerFn,
) -> Self {
SocketData {
socket: router.get_udp_socket(),
virtual_port: port,
connections: Default::default(),
access_key,
connection_creation_sender,
on_connect_handler,
on_data_handler,
}
}
@ -104,26 +137,22 @@ impl SocketImpl {
self.virtual_port
}
pub async fn process_packet(&self, connection: PRUDPSockAddr, packet: &PRUDPPacket) {
info!("recieved packet on endpoint");
pub async fn process_packet(self: &Arc<Self>, client_address: PRUDPSockAddr, packet: &PRUDPPacket) {
let conn = self.connections.read().await;
if !conn.contains_key(&connection) {
if !conn.contains_key(&client_address) {
drop(conn);
let mut conn = self.connections.write().await;
//only insert if we STILL dont have the connection preventing double insertion
if !conn.contains_key(&connection) {
conn.insert(connection, Arc::new(Mutex::new(Connection {
sock_addr: connection,
if !conn.contains_key(&client_address) {
conn.insert(client_address, Arc::new(Mutex::new(ConnectionData {
sock_addr: client_address,
id: random(),
signature: [0; 16],
server_signature: [0; 16],
session_id: 0,
reliable_client_queue: VecDeque::new(),
reliable_client_counter: 0,
reliable_server_counter: 0,
active_connection_data: None,
})));
}
drop(conn);
@ -133,7 +162,7 @@ impl SocketImpl {
let connections = self.connections.read().await;
let Some(conn) = connections.get(&connection) else {
let Some(conn) = connections.get(&client_address) else {
error!("connection is still not present after making sure connection is present, giving up.");
return;
};
@ -143,7 +172,7 @@ impl SocketImpl {
// dont keep holding the connections list unnescesarily
drop(connections);
let mut conn = conn.lock().await;
let mut connection = conn.lock().await;
if (packet.header.types_and_flags.get_flags() & ACK) != 0 {
info!("acknowledgement recieved");
@ -152,7 +181,7 @@ impl SocketImpl {
if (packet.header.types_and_flags.get_flags() & MULTI_ACK) != 0 {
info!("acknowledgement recieved");
unimplemented!()
return;
}
@ -166,9 +195,9 @@ impl SocketImpl {
response_packet.header.types_and_flags.set_flag(ACK);
response_packet.header.types_and_flags.set_flag(HAS_SIZE);
conn.signature = connection.calculate_connection_signature();
connection.signature = client_address.calculate_connection_signature();
response_packet.options.push(ConnectionSignature(conn.signature));
response_packet.options.push(ConnectionSignature(connection.signature));
for options in &packet.options {
match options {
@ -190,7 +219,7 @@ impl SocketImpl {
response_packet.write_to(&mut vec).expect("somehow failed to convert backet to bytes");
self.socket.send_to(&vec, connection.regular_socket_addr).await.expect("failed to send data back");
self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back");
}
CONNECT => {
info!("got connect");
@ -202,18 +231,23 @@ impl SocketImpl {
response_packet.header.types_and_flags.set_flag(HAS_SIZE);
// todo: (or not) sliding windows and stuff
conn.session_id = packet.header.session_id;
response_packet.header.session_id = conn.session_id;
response_packet.header.session_id = packet.header.session_id;
response_packet.header.sequence_id = 1;
response_packet.options.push(ConnectionSignature(Default::default()));
let mut init_seq_id = 0;
for option in &packet.options {
match option {
MaximumSubstreamId(max_substream) => response_packet.options.push(MaximumSubstreamId(*max_substream)),
SupportedFunctions(funcs) => response_packet.options.push(SupportedFunctions(*funcs)),
ConnectionSignature(sig) => {
conn.server_signature = *sig
connection.server_signature = *sig
}
PacketOption::InitialSequenceId(id) => {
init_seq_id = *id;
}
_ => { /* ? */ }
}
@ -225,53 +259,125 @@ impl SocketImpl {
// todo: implement something to do secure servers
if conn.server_signature == <[u8; 16] as Default>::default() {
if connection.server_signature == <[u8; 16] as Default>::default() {
error!("didn't get connection signature from client")
}
response_packet.set_sizes();
response_packet.calculate_and_assign_signature(self.access_key, None, Some(conn.server_signature));
response_packet.calculate_and_assign_signature(self.access_key, None, Some(connection.server_signature));
let mut vec = Vec::new();
response_packet.write_to(&mut vec).expect("somehow failed to convert backet to bytes");
self.socket.send_to(&vec, connection.regular_socket_addr).await.expect("failed to send data back");
self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back");
let (send, recv) = channel(100);
let (accepted, (client_decryption, server_encryption))
= (self.on_connect_handler)(packet.clone()).await;
if !accepted {
// rejected
return;
}
connection.active_connection_data = Some(ActiveConnectionData {
connection_data_channel: send,
client_decryption,
server_encryption,
reliable_client_queue: VecDeque::new(),
reliable_client_counter: 2,
reliable_server_counter: 1,
server_session_id: packet.header.session_id,
});
}
DATA => {
if (packet.header.types_and_flags.get_flags() & RELIABLE) != 0 {
match conn.reliable_client_queue.binary_search_by_key(&conn.reliable_client_counter, |p| p.header.sequence_id) {
let Some(active_connection) = connection.active_connection_data.as_mut() else {
error!("got data packet on non active connection!");
return;
};
info!("ctr: {}, packet seq: {}", active_connection.reliable_client_counter, packet.header.sequence_id);
match active_connection.reliable_client_queue.binary_search_by_key(&packet.header.sequence_id, |p| p.header.sequence_id) {
Ok(_) => warn!("recieved packet twice"),
Err(position) => conn.reliable_client_queue.insert(position, packet.clone()),
Err(position) => active_connection.reliable_client_queue.insert(position, packet.clone()),
}
if (packet.header.types_and_flags.get_flags() & NEED_ACK) != 0{
if (packet.header.types_and_flags.get_flags() & NEED_ACK) != 0 {
let mut ack = packet.base_acknowledgement_packet();
ack.header.session_id = active_connection.server_session_id;
ack.set_sizes();
ack.calculate_and_assign_signature(self.access_key, None, Some(conn.server_signature));
ack.calculate_and_assign_signature(self.access_key, None, Some(connection.server_signature));
let mut vec = Vec::new();
ack.write_to(&mut vec).expect("somehow failed to convert backet to bytes");
self.socket.send_to(&vec, connection.regular_socket_addr).await.expect("failed to send data back");
self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back");
}
while let Some(packet) =
conn.reliable_client_queue
while let Some(mut packet) = {
connection.active_connection_data.as_mut().map(|a|
a.reliable_client_queue
.front()
.is_some_and(|v| v.header.sequence_id == conn.reliable_client_counter)
.then(|| conn.reliable_client_queue.pop_front())
.flatten(){
conn.reliable_client_counter = conn.reliable_client_counter.overflowing_add(1).0;
.is_some_and(|v| v.header.sequence_id == a.reliable_client_counter)
.then(|| a.reliable_client_queue.pop_front())).flatten().flatten()
} {
if packet.options.iter().any(|v| match v{
PacketOption::FragmentId(f) => (*f != 0),
_ => false,
}){
error!("fragmented packets are unsupported right now")
}
// ignored
let active_connection = connection.active_connection_data.as_mut()
.expect("we litterally just recieved a packet which requires the connection to be active, failing this should be impossible");
active_connection.reliable_client_counter = active_connection.reliable_client_counter.overflowing_add(1).0;
active_connection.client_decryption.apply_keystream(&mut packet.payload);
// we cant divert this off to another thread we HAVE to process it now to keep order
(self.on_data_handler)(packet, self.clone(), &mut connection).await;
// ignored for now
}
} else {
error!("unreliable packets are unimplemented");
unimplemented!()
}
info!("{:?}", packet);
//info!("{:?}", packet);
}
PING => {
let ConnectionData {
active_connection_data,
server_signature,
..
} = &mut *connection;
if (packet.header.types_and_flags.get_flags() & NEED_ACK) != 0 {
let Some(active_connection) = active_connection_data.as_mut() else {
error!("got data packet on non active connection!");
return;
};
let mut ack = packet.base_acknowledgement_packet();
ack.header.session_id = active_connection.server_session_id;
ack.set_sizes();
ack.calculate_and_assign_signature(self.access_key, None, Some(*server_signature));
let mut vec = Vec::new();
ack.write_to(&mut vec).expect("somehow failed to convert backet to bytes");
self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back");
}
}
_ => unimplemented!("unimplemented packet type: {}", packet.header.types_and_flags.get_types())
}
}
@ -286,9 +392,9 @@ mod test {
use tokio::sync::mpsc::channel;
use crate::prudp::packet::{PRUDPPacket, VirtualPort};
use crate::prudp::sockaddr::PRUDPSockAddr;
use crate::prudp::socket::SocketImpl;
use crate::prudp::socket::SocketData;
#[tokio::test]
/*#[tokio::test]
async fn test_connect() {
let packet_1 = [234, 208, 1, 27, 0, 0, 175, 161, 192, 0, 0, 0, 0, 0, 36, 21, 233, 179, 203, 154, 57, 222, 219, 9, 21, 2, 29, 172, 56, 92, 0, 4, 4, 1, 0, 0, 1, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0];
let packet_2 = [234, 208, 1, 31, 0, 0, 175, 161, 225, 0, 249, 0, 1, 0, 40, 168, 31, 138, 58, 193, 30, 134, 3, 232, 205, 245, 28, 155, 193, 198, 0, 4, 0, 0, 0, 0, 1, 16, 211, 240, 113, 188, 227, 114, 114, 30, 157, 179, 246, 55, 233, 240, 44, 197, 3, 2, 247, 244, 4, 1, 0];
@ -299,13 +405,13 @@ mod test {
let (send, recv) = channel(100);
let sock = SocketImpl {
let sock = Arc::new(SocketData {
connections: Default::default(),
access_key: "6f599f81",
virtual_port: VirtualPort(0),
socket: Arc::new(UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 10000)).await.unwrap()),
connection_creation_sender: send,
};
});
println!("sent: {:?}", packet_1);
sock.process_packet(PRUDPSockAddr {
virtual_port: VirtualPort(0),
@ -316,5 +422,5 @@ mod test {
virtual_port: VirtualPort(0),
regular_socket_addr: SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2469),
}, &packet_2).await;
}
}*/
}

61
src/rmc/message.rs Normal file
View file

@ -0,0 +1,61 @@
use std::io;
use std::io::{Read, Seek};
use log::error;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use crate::rmc::response::{ErrorCode, RMCResponseResult};
#[derive(Debug)]
pub struct RMCMessage{
pub protocol_id: u16,
pub call_id: u32,
pub method_id: u32,
pub rest_of_data: Vec<u8>
}
impl RMCMessage{
pub fn new(stream: &mut (impl Seek + Read)) -> io::Result<Self>{
let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
let mut header_size = 1 + 4 + 4;
let protocol_id: u8 = stream.read_struct(IS_BIG_ENDIAN)?;
let protocol_id= protocol_id & (!0x80);
let protocol_id: u16 = match protocol_id{
0x7F => {
header_size += 2;
stream.read_struct(IS_BIG_ENDIAN)?
},
_ => protocol_id as u16
};
let call_id = stream.read_struct(IS_BIG_ENDIAN)?;
let method_id = stream.read_struct(IS_BIG_ENDIAN)?;
let mut rest_of_data = Vec::new();
stream.read_to_end(&mut rest_of_data)?;
if header_size + rest_of_data.len() != size as usize {
error!("received incorrect rmc packet: expected size {} but found {}", size, header_size + rest_of_data.len());
}
//stream.
Ok(Self{
protocol_id,
method_id,
call_id,
rest_of_data
})
}
pub fn error_result_with_code(&self, error_code: ErrorCode) -> RMCResponseResult{
RMCResponseResult::Error {
call_id: self.call_id,
error_code
}
}
}

6
src/rmc/mod.rs Normal file
View file

@ -0,0 +1,6 @@
pub mod message;
pub mod structures;
pub mod response;

432
src/rmc/response.rs Normal file
View file

@ -0,0 +1,432 @@
use std::io;
use std::io::{Cursor, Write};
use std::mem::transmute;
use tokio::sync::Mutex;
use bytemuck::bytes_of;
use hmac::digest::consts::U5;
use hmac::digest::KeyInit;
use rc4::{Rc4, StreamCipher};
use crate::prudp::packet::{PRUDPHeader, PRUDPPacket, TypesFlags};
use crate::prudp::packet::flags::{HAS_SIZE, NEED_ACK, RELIABLE};
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,
method_id: u32,
data: Vec<u8>,
},
Error{
error_code: ErrorCode,
call_id: u32,
}
}
pub struct RMCResponse {
pub protocol_id: u8,
pub response_result: RMCResponseResult
}
impl RMCResponse {
pub fn to_data(self) -> Vec<u8>{
generate_response(self.protocol_id, self.response_result).expect("failed to generate response")
}
}
pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result<Vec<u8>>{
let size = 1 + 1 + match &response{
RMCResponseResult::Success {
data,
..
} => 4 + 4 + data.len(),
RMCResponseResult::Error{..} => 4 + 4,
};
let mut data_out = Vec::with_capacity(size + 4);
let u32_size: u32 = size as _;
data_out.write_all(bytes_of(&u32_size))?;
data_out.push(protocol_id | 0x80);
match response{
RMCResponseResult::Success {
call_id,
method_id,
data
} => {
data_out.push(1);
data_out.write_all(bytes_of(&call_id))?;
data_out.write_all(bytes_of(&method_id))?;
data_out.write_all(&data)?;
},
RMCResponseResult::Error {
call_id,
error_code
} => {
data_out.push(0);
let error_code_val: u32 = error_code.into();
data_out.write_all(bytes_of(&error_code_val))?;
data_out.write_all(bytes_of(&call_id))?;
}
}
assert_eq!(data_out.len(), size + 4);
Ok(data_out)
}
pub async fn send_response(original_packet: &PRUDPPacket, socket: &SocketData, connection: &mut ConnectionData, rmcresponse: RMCResponse){
let ConnectionData{
active_connection_data,
sock_addr,
server_signature,
..
} = connection;
let Some(active_connection) = active_connection_data else {
return;
};
let mut packet = original_packet.base_response_packet();
packet.header.types_and_flags.set_types(DATA);
packet.header.types_and_flags.set_flag(RELIABLE | HAS_SIZE | NEED_ACK);
packet.header.sequence_id = active_connection.reliable_server_counter;
active_connection.reliable_server_counter += 1;
packet.header.session_id = active_connection.server_session_id;
packet.header.substream_id = 0;
packet.options.push(FragmentId(0));
packet.payload = rmcresponse.to_data();
active_connection.server_encryption.apply_keystream(&mut packet.payload);
packet.set_sizes();
packet.calculate_and_assign_signature(socket.access_key, None, Some(*server_signature));
let mut vec = Vec::new();
packet.write_to(&mut vec).expect("somehow failed to convert backet to bytes");
socket.socket.send_to(&vec, sock_addr.regular_socket_addr).await.expect("failed to send data back");
}
//taken from kinnays error list directly
#[allow(nonstandard_style)]
#[repr(u32)]
pub enum ErrorCode {
Core_Unknown = 0x00010001,
Core_NotImplemented = 0x00010002,
Core_InvalidPointer = 0x00010003,
Core_OperationAborted = 0x00010004,
Core_Exception = 0x00010005,
Core_AccessDenied = 0x00010006,
Core_InvalidHandle = 0x00010007,
Core_InvalidIndex = 0x00010008,
Core_OutOfMemory = 0x00010009,
Core_InvalidArgument = 0x0001000A,
Core_Timeout = 0x0001000B,
Core_InitializationFailure = 0x0001000C,
Core_CallInitiationFailure = 0x0001000D,
Core_RegistrationError = 0x0001000E,
Core_BufferOverflow = 0x0001000F,
Core_InvalidLockState = 0x00010010,
Core_InvalidSequence = 0x00010011,
Core_SystemError = 0x00010012,
Core_Cancelled = 0x00010013,
DDL_InvalidSignature = 0x00020001,
DDL_IncorrectVersion = 0x00020002,
RendezVous_ConnectionFailure = 0x00030001,
RendezVous_NotAuthenticated = 0x00030002,
RendezVous_InvalidUsername = 0x00030064,
RendezVous_InvalidPassword = 0x00030065,
RendezVous_UsernameAlreadyExists = 0x00030066,
RendezVous_AccountDisabled = 0x00030067,
RendezVous_AccountExpired = 0x00030068,
RendezVous_ConcurrentLoginDenied = 0x00030069,
RendezVous_EncryptionFailure = 0x0003006A,
RendezVous_InvalidPID = 0x0003006B,
RendezVous_MaxConnectionsReached = 0x0003006C,
RendezVous_InvalidGID = 0x0003006D,
RendezVous_InvalidControlScriptID = 0x0003006E,
RendezVous_InvalidOperationInLiveEnvironment = 0x0003006F,
RendezVous_DuplicateEntry = 0x00030070,
RendezVous_ControlScriptFailure = 0x00030071,
RendezVous_ClassNotFound = 0x00030072,
RendezVous_SessionVoid = 0x00030073,
RendezVous_DDLMismatch = 0x00030075,
RendezVous_InvalidConfiguration = 0x00030076,
RendezVous_SessionFull = 0x000300C8,
RendezVous_InvalidGatheringPassword = 0x000300C9,
RendezVous_WithoutParticipationPeriod = 0x000300CA,
RendezVous_PersistentGatheringCreationMax = 0x000300CB,
RendezVous_PersistentGatheringParticipationMax = 0x000300CC,
RendezVous_DeniedByParticipants = 0x000300CD,
RendezVous_ParticipantInBlackList = 0x000300CE,
RendezVous_GameServerMaintenance = 0x000300CF,
RendezVous_OperationPostpone = 0x000300D0,
RendezVous_OutOfRatingRange = 0x000300D1,
RendezVous_ConnectionDisconnected = 0x000300D2,
RendezVous_InvalidOperation = 0x000300D3,
RendezVous_NotParticipatedGathering = 0x000300D4,
RendezVous_MatchmakeSessionUserPasswordUnmatch = 0x000300D5,
RendezVous_MatchmakeSessionSystemPasswordUnmatch = 0x000300D6,
RendezVous_UserIsOffline = 0x000300D7,
RendezVous_AlreadyParticipatedGathering = 0x000300D8,
RendezVous_PermissionDenied = 0x000300D9,
RendezVous_NotFriend = 0x000300DA,
RendezVous_SessionClosed = 0x000300DB,
RendezVous_DatabaseTemporarilyUnavailable = 0x000300DC,
RendezVous_InvalidUniqueId = 0x000300DD,
RendezVous_MatchmakingWithdrawn = 0x000300DE,
RendezVous_LimitExceeded = 0x000300DF,
RendezVous_AccountTemporarilyDisabled = 0x000300E0,
RendezVous_PartiallyServiceClosed = 0x000300E1,
RendezVous_ConnectionDisconnectedForConcurrentLogin = 0x000300E2,
PythonCore_Exception = 0x00040001,
PythonCore_TypeError = 0x00040002,
PythonCore_IndexError = 0x00040003,
PythonCore_InvalidReference = 0x00040004,
PythonCore_CallFailure = 0x00040005,
PythonCore_MemoryError = 0x00040006,
PythonCore_KeyError = 0x00040007,
PythonCore_OperationError = 0x00040008,
PythonCore_ConversionError = 0x00040009,
PythonCore_ValidationError = 0x0004000A,
Transport_Unknown = 0x00050001,
Transport_ConnectionFailure = 0x00050002,
Transport_InvalidUrl = 0x00050003,
Transport_InvalidKey = 0x00050004,
Transport_InvalidURLType = 0x00050005,
Transport_DuplicateEndpoint = 0x00050006,
Transport_IOError = 0x00050007,
Transport_Timeout = 0x00050008,
Transport_ConnectionReset = 0x00050009,
Transport_IncorrectRemoteAuthentication = 0x0005000A,
Transport_ServerRequestError = 0x0005000B,
Transport_DecompressionFailure = 0x0005000C,
Transport_ReliableSendBufferFullFatal = 0x0005000D,
Transport_UPnPCannotInit = 0x0005000E,
Transport_UPnPCannotAddMapping = 0x0005000F,
Transport_NatPMPCannotInit = 0x00050010,
Transport_NatPMPCannotAddMapping = 0x00050011,
Transport_UnsupportedNAT = 0x00050013,
Transport_DnsError = 0x00050014,
Transport_ProxyError = 0x00050015,
Transport_DataRemaining = 0x00050016,
Transport_NoBuffer = 0x00050017,
Transport_NotFound = 0x00050018,
Transport_TemporaryServerError = 0x00050019,
Transport_PermanentServerError = 0x0005001A,
Transport_ServiceUnavailable = 0x0005001B,
Transport_ReliableSendBufferFull = 0x0005001C,
Transport_InvalidStation = 0x0005001D,
Transport_InvalidSubStreamID = 0x0005001E,
Transport_PacketBufferFull = 0x0005001F,
Transport_NatTraversalError = 0x00050020,
Transport_NatCheckError = 0x00050021,
DOCore_StationNotReached = 0x00060001,
DOCore_TargetStationDisconnect = 0x00060002,
DOCore_LocalStationLeaving = 0x00060003,
DOCore_ObjectNotFound = 0x00060004,
DOCore_InvalidRole = 0x00060005,
DOCore_CallTimeout = 0x00060006,
DOCore_RMCDispatchFailed = 0x00060007,
DOCore_MigrationInProgress = 0x00060008,
DOCore_NoAuthority = 0x00060009,
DOCore_NoTargetStationSpecified = 0x0006000A,
DOCore_JoinFailed = 0x0006000B,
DOCore_JoinDenied = 0x0006000C,
DOCore_ConnectivityTestFailed = 0x0006000D,
DOCore_Unknown = 0x0006000E,
DOCore_UnfreedReferences = 0x0006000F,
DOCore_JobTerminationFailed = 0x00060010,
DOCore_InvalidState = 0x00060011,
DOCore_FaultRecoveryFatal = 0x00060012,
DOCore_FaultRecoveryJobProcessFailed = 0x00060013,
DOCore_StationInconsitency = 0x00060014,
DOCore_AbnormalMasterState = 0x00060015,
DOCore_VersionMismatch = 0x00060016,
FPD_NotInitialized = 0x00650000,
FPD_AlreadyInitialized = 0x00650001,
FPD_NotConnected = 0x00650002,
FPD_Connected = 0x00650003,
FPD_InitializationFailure = 0x00650004,
FPD_OutOfMemory = 0x00650005,
FPD_RmcFailed = 0x00650006,
FPD_InvalidArgument = 0x00650007,
FPD_InvalidLocalAccountID = 0x00650008,
FPD_InvalidPrincipalID = 0x00650009,
FPD_InvalidLocalFriendCode = 0x0065000A,
FPD_LocalAccountNotExists = 0x0065000B,
FPD_LocalAccountNotLoaded = 0x0065000C,
FPD_LocalAccountAlreadyLoaded = 0x0065000D,
FPD_FriendAlreadyExists = 0x0065000E,
FPD_FriendNotExists = 0x0065000F,
FPD_FriendNumMax = 0x00650010,
FPD_NotFriend = 0x00650011,
FPD_FileIO = 0x00650012,
FPD_P2PInternetProhibited = 0x00650013,
FPD_Unknown = 0x00650014,
FPD_InvalidState = 0x00650015,
FPD_AddFriendProhibited = 0x00650017,
FPD_InvalidAccount = 0x00650019,
FPD_BlacklistedByMe = 0x0065001A,
FPD_FriendAlreadyAdded = 0x0065001C,
FPD_MyFriendListLimitExceed = 0x0065001D,
FPD_RequestLimitExceed = 0x0065001E,
FPD_InvalidMessageID = 0x0065001F,
FPD_MessageIsNotMine = 0x00650020,
FPD_MessageIsNotForMe = 0x00650021,
FPD_FriendRequestBlocked = 0x00650022,
FPD_NotInMyFriendList = 0x00650023,
FPD_FriendListedByMe = 0x00650024,
FPD_NotInMyBlacklist = 0x00650025,
FPD_IncompatibleAccount = 0x00650026,
FPD_BlockSettingChangeNotAllowed = 0x00650027,
FPD_SizeLimitExceeded = 0x00650028,
FPD_OperationNotAllowed = 0x00650029,
FPD_NotNetworkAccount = 0x0065002A,
FPD_NotificationNotFound = 0x0065002B,
FPD_PreferenceNotInitialized = 0x0065002C,
FPD_FriendRequestNotAllowed = 0x0065002D,
Ranking_NotInitialized = 0x00670001,
Ranking_InvalidArgument = 0x00670002,
Ranking_RegistrationError = 0x00670003,
Ranking_NotFound = 0x00670005,
Ranking_InvalidScore = 0x00670006,
Ranking_InvalidDataSize = 0x00670007,
Ranking_PermissionDenied = 0x00670009,
Ranking_Unknown = 0x0067000A,
Ranking_NotImplemented = 0x0067000B,
Authentication_NASAuthenticateError = 0x00680001,
Authentication_TokenParseError = 0x00680002,
Authentication_HttpConnectionError = 0x00680003,
Authentication_HttpDNSError = 0x00680004,
Authentication_HttpGetProxySetting = 0x00680005,
Authentication_TokenExpired = 0x00680006,
Authentication_ValidationFailed = 0x00680007,
Authentication_InvalidParam = 0x00680008,
Authentication_PrincipalIdUnmatched = 0x00680009,
Authentication_MoveCountUnmatch = 0x0068000A,
Authentication_UnderMaintenance = 0x0068000B,
Authentication_UnsupportedVersion = 0x0068000C,
Authentication_ServerVersionIsOld = 0x0068000D,
Authentication_Unknown = 0x0068000E,
Authentication_ClientVersionIsOld = 0x0068000F,
Authentication_AccountLibraryError = 0x00680010,
Authentication_ServiceNoLongerAvailable = 0x00680011,
Authentication_UnknownApplication = 0x00680012,
Authentication_ApplicationVersionIsOld = 0x00680013,
Authentication_OutOfService = 0x00680014,
Authentication_NetworkServiceLicenseRequired = 0x00680015,
Authentication_NetworkServiceLicenseSystemError = 0x00680016,
Authentication_NetworkServiceLicenseError3 = 0x00680017,
Authentication_NetworkServiceLicenseError4 = 0x00680018,
DataStore_Unknown = 0x00690001,
DataStore_InvalidArgument = 0x00690002,
DataStore_PermissionDenied = 0x00690003,
DataStore_NotFound = 0x00690004,
DataStore_AlreadyLocked = 0x00690005,
DataStore_UnderReviewing = 0x00690006,
DataStore_Expired = 0x00690007,
DataStore_InvalidCheckToken = 0x00690008,
DataStore_SystemFileError = 0x00690009,
DataStore_OverCapacity = 0x0069000A,
DataStore_OperationNotAllowed = 0x0069000B,
DataStore_InvalidPassword = 0x0069000C,
DataStore_ValueNotEqual = 0x0069000D,
ServiceItem_Unknown = 0x006C0001,
ServiceItem_InvalidArgument = 0x006C0002,
ServiceItem_EShopUnknownHttpError = 0x006C0003,
ServiceItem_EShopResponseParseError = 0x006C0004,
ServiceItem_NotOwned = 0x006C0005,
ServiceItem_InvalidLimitationType = 0x006C0006,
ServiceItem_ConsumptionRightShortage = 0x006C0007,
MatchmakeReferee_Unknown = 0x006F0001,
MatchmakeReferee_InvalidArgument = 0x006F0002,
MatchmakeReferee_AlreadyExists = 0x006F0003,
MatchmakeReferee_NotParticipatedGathering = 0x006F0004,
MatchmakeReferee_NotParticipatedRound = 0x006F0005,
MatchmakeReferee_StatsNotFound = 0x006F0006,
MatchmakeReferee_RoundNotFound = 0x006F0007,
MatchmakeReferee_RoundArbitrated = 0x006F0008,
MatchmakeReferee_RoundNotArbitrated = 0x006F0009,
Subscriber_Unknown = 0x00700001,
Subscriber_InvalidArgument = 0x00700002,
Subscriber_OverLimit = 0x00700003,
Subscriber_PermissionDenied = 0x00700004,
Ranking2_Unknown = 0x00710001,
Ranking2_InvalidArgument = 0x00710002,
Ranking2_InvalidScore = 0x00710003,
SmartDeviceVoiceChat_Unknown = 0x00720001,
SmartDeviceVoiceChat_InvalidArgument = 0x00720002,
SmartDeviceVoiceChat_InvalidResponse = 0x00720003,
SmartDeviceVoiceChat_InvalidAccessToken = 0x00720004,
SmartDeviceVoiceChat_Unauthorized = 0x00720005,
SmartDeviceVoiceChat_AccessError = 0x00720006,
SmartDeviceVoiceChat_UserNotFound = 0x00720007,
SmartDeviceVoiceChat_RoomNotFound = 0x00720008,
SmartDeviceVoiceChat_RoomNotActivated = 0x00720009,
SmartDeviceVoiceChat_ApplicationNotSupported = 0x0072000A,
SmartDeviceVoiceChat_InternalServerError = 0x0072000B,
SmartDeviceVoiceChat_ServiceUnavailable = 0x0072000C,
SmartDeviceVoiceChat_UnexpectedError = 0x0072000D,
SmartDeviceVoiceChat_UnderMaintenance = 0x0072000E,
SmartDeviceVoiceChat_ServiceNoLongerAvailable = 0x0072000F,
SmartDeviceVoiceChat_AccountTemporarilyDisabled = 0x00720010,
SmartDeviceVoiceChat_PermissionDenied = 0x00720011,
SmartDeviceVoiceChat_NetworkServiceLicenseRequired = 0x00720012,
SmartDeviceVoiceChat_AccountLibraryError = 0x00720013,
SmartDeviceVoiceChat_GameModeNotFound = 0x00720014,
Screening_Unknown = 0x00730001,
Screening_InvalidArgument = 0x00730002,
Screening_NotFound = 0x00730003,
Custom_Unknown = 0x00740001,
Ess_Unknown = 0x00750001,
Ess_GameSessionError = 0x00750002,
Ess_GameSessionMaintenance = 0x00750003
}
impl Into<u32> for ErrorCode {
fn into(self) -> u32 {
unsafe{ transmute(self) }
}
}
#[cfg(test)]
mod test{
use hmac::digest::consts::U5;
use hmac::digest::KeyInit;
use rc4::{Rc4, StreamCipher};
#[test]
fn test(){
let mut data_orig = [0,1,2,3,4,5,6,7,8,9,69,4,20];
let mut data = data_orig;
let mut rc4: Rc4<U5> =
Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
rc4.apply_keystream(&mut data);
assert_ne!(data_orig, data);
let mut rc4: Rc4<U5> =
Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
rc4.apply_keystream(&mut data);
assert_eq!(data_orig, data);
}
}

28
src/rmc/structures/any.rs Normal file
View file

@ -0,0 +1,28 @@
use std::io::{Read, Seek};
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use super::{string, Result};
#[derive(Debug)]
pub struct Any{
pub name: String,
pub data: Vec<u8>
}
pub fn read(reader: &mut (impl Read + Seek)) -> Result<Any>{
let name = string::read(reader)?;
// also length ?
let len2: u32 = reader.read_struct(IS_BIG_ENDIAN)?;
let length: u32 = reader.read_struct(IS_BIG_ENDIAN)?;
let mut data = vec![0; length as usize];
reader.read_exact(&mut data)?;
Ok(
Any{
name,
data
}
)
}

19
src/rmc/structures/mod.rs Normal file
View file

@ -0,0 +1,19 @@
use std::io;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use thiserror::Error;
//ideas for the future: make a proc macro library which allows generation of struct reads
#[derive(Error, Debug)]
pub enum Error{
#[error("Io Error: {0}")]
Io(#[from] io::Error),
#[error("UTF8 conversion Error: {0}")]
Utf8(#[from] FromUtf8Error)
}
type Result<T> = std::result::Result<T, Error>;
pub mod string;
pub mod any;

View file

@ -0,0 +1,18 @@
use std::ffi::CString;
use std::io::{Read, Seek};
use log::error;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use super::Result;
pub fn read(reader: &mut (impl Read + Seek)) -> Result<String>{
let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?;
let mut data = vec![0; len as usize - 1];
reader.read_exact(&mut data)?;
let null: u8 = reader.read_struct(IS_BIG_ENDIAN)?;
if null != 0{
error!("unable to find null terminator... continuing anyways");
}
Ok(String::from_utf8(data)?)
}