diff --git a/Cargo.lock b/Cargo.lock index 5d9afd4..d59ee31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,7 @@ dependencies = [ "tracing", "tracing-error", "tracing-subscriber", + "zerocopy", ] [[package]] @@ -1338,3 +1339,24 @@ name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "zerocopy" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/Cargo.toml b/Cargo.toml index 0368cf6..52d71e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ once_cell = "1.17.1" eyre = "0.6.8" color-eyre = "0.6.2" tracing-error = "0.2.0" +zerocopy = "0.6.1" [features] default = ["debug_server", "tokio_console"] diff --git a/src/auth.rs b/src/auth.rs index 6df0281..6d70bd2 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -2,9 +2,21 @@ use std::net::SocketAddr; use eyre::eyre; use tracing::{debug, instrument}; +use zerocopy::{AsBytes, FromBytes, LittleEndian, Unaligned}; use crate::packets::{Header, Packet, PacketKind}; +type U16 = zerocopy::U16; +type U32 = zerocopy::U32; + +#[derive(AsBytes)] +#[repr(C)] +struct DynIpUpdate { + number: U32, + pin: U16, + port: U16, +} + /// # Errors /// - the dyn ip server returns a malformed response or is unreachable /// - the authentication fails @@ -25,18 +37,21 @@ pub async fn dyn_ip_update( data: Vec::new(), }; - packet.data.clear(); - packet.data.reserve(packet.header.length as usize); - packet.data.extend_from_slice(&number.to_le_bytes()); - packet.data.extend_from_slice(&pin.to_le_bytes()); - packet.data.extend_from_slice(&port.to_le_bytes()); + packet.data.resize(packet.header.length as usize, 0); + + DynIpUpdate { + number: number.into(), + pin: pin.into(), + port: port.into(), + } + .write_to(packet.data.as_mut_slice()) + .unwrap(); let mut socket = tokio::net::TcpStream::connect(server).await?; let (mut reader, mut writer) = socket.split(); packet.send(&mut writer).await?; - packet.recv_into(&mut reader).await?; let result = match packet.kind() { diff --git a/src/client.rs b/src/client.rs index e145102..18dc2bb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -15,6 +15,7 @@ use tracing::{info, instrument, trace}; use crate::{ auth::dyn_ip_update, constants::{AUTH_TIMEOUT, CALL_ACK_TIMEOUT, CALL_TIMEOUT, PING_TIMEOUT, SEND_PING_INTERVAL}, + debug_server::peer_query, packets::{Header, Packet, PacketKind, RemConnect, REJECT_OOP, REJECT_TIMEOUT}, ports::{PortHandler, PortStatus}, Config, HandlerMetadata, @@ -328,6 +329,10 @@ pub async fn handler( info!(%addr, number, port, "authenticated"); + let res = peer_query(&config.dyn_ip_server, number).await; + + dbg!(&res); + let Some(listener) = handler_metadata.listener.as_mut() else { unreachable!("client sucessfully authenticated but did not set handler_metadata.listener"); }; diff --git a/src/debug_server.rs b/src/debug_server.rs index e6a5cc2..d12e799 100644 --- a/src/debug_server.rs +++ b/src/debug_server.rs @@ -7,6 +7,12 @@ use std::net::SocketAddr; use std::sync::Arc; use tokio::sync::Mutex; use tracing::error; +use zerocopy::{AsBytes, FromBytes, LittleEndian, Unaligned}; + +use eyre::eyre; +use tracing::{debug, instrument}; + +use crate::packets::{Header, Packet, PacketKind}; use crate::ports::PortHandler; use crate::spawn; @@ -41,3 +47,77 @@ pub async fn debug_server(addr: SocketAddr, port_handler: Arc error!(%error, "debug server error"); } } + +type U16 = zerocopy::U16; +type U32 = zerocopy::U32; + +#[derive(AsBytes)] +#[repr(transparent)] +struct PeerQuery { + number: U32, +} + +#[derive(FromBytes, Unaligned, Debug)] +#[repr(packed)] +struct PeerReply { + number: U32, + name: [u8; 40], + flags: U16, + kind: u8, + hostname: [u8; 40], + ipaddress: [u8; 4], + port: U16, + extension: u8, + pin: U16, + timestamp: U32, +} + +#[instrument] +pub async fn peer_query(server: &SocketAddr, number: u32) -> eyre::Result> { + debug!(%number, "looking up"); + + let mut packet = Packet { + header: Header { + kind: 3, // Peer Query + length: 4, + }, + data: Vec::new(), + }; + + packet.data.clear(); + packet.data.resize(packet.header.length as usize, 0); + + PeerQuery { + number: number.into(), + } + .write_to(packet.data.as_mut_slice()) + .unwrap(); + + let mut socket = tokio::net::TcpStream::connect(server).await?; + + let (mut reader, mut writer) = socket.split(); + + packet.send(&mut writer).await?; + + packet.recv_into(&mut reader).await?; + + dbg!(&packet); + + if packet.kind().raw() == 5 { + // PeerReply + let reply = PeerReply::read_from(packet.data.as_slice()); + dbg!(&reply); + Ok(reply.and_then(|x| { + let i = x + .name + .iter() + .enumerate() + .find_map(|(i, c)| (*c == 0).then_some(i)) + .unwrap_or(x.name.len()); + + std::str::from_utf8(&x.name[..i]).ok().map(|x| x.to_owned()) + })) + } else { + Ok(None) + } +} diff --git a/src/ports.rs b/src/ports.rs index eedda49..a3a4583 100644 --- a/src/ports.rs +++ b/src/ports.rs @@ -465,7 +465,7 @@ impl PortHandler { }; if let Some(port) = port { - info!(port, "allocated port"); + info!(port, "allocated"); } port