From ab735cf980a9e4bc2a7ddf647d7447615870540a Mon Sep 17 00:00:00 2001 From: Alex Janka Date: Thu, 22 Feb 2024 12:50:46 +1100 Subject: [PATCH] yessss --- Cargo.lock | 2 +- homekit-controller/Cargo.toml | 2 +- homekit-controller/src/homekit_http.rs | 201 +++++++++++++------------ homekit-controller/src/lib.rs | 28 ++-- homekit-controller/src/tlv8/mod.rs | 2 +- 5 files changed, 119 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cefaa70..1fee322 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -442,8 +442,8 @@ dependencies = [ "serde", "serde_json", "sha2", - "socket2", "thiserror", + "tokio", "x25519-dalek", ] diff --git a/homekit-controller/Cargo.toml b/homekit-controller/Cargo.toml index 781d9cd..b565034 100644 --- a/homekit-controller/Cargo.toml +++ b/homekit-controller/Cargo.toml @@ -18,4 +18,4 @@ sha2 = "0.10" hex = { version = "0.4", features = ["serde"] } http = "1.0" httparse = "1.8" -socket2 = "0.5" +tokio = { version = "1.36", features = ["net"] } diff --git a/homekit-controller/src/homekit_http.rs b/homekit-controller/src/homekit_http.rs index 8a8e732..013b80b 100644 --- a/homekit-controller/src/homekit_http.rs +++ b/homekit-controller/src/homekit_http.rs @@ -1,20 +1,16 @@ -use std::{ - io::{Read, Write}, - net::SocketAddr, - time::Duration, -}; - use chacha20poly1305::{ aead::generic_array::GenericArray, AeadInPlace, ChaCha20Poly1305, KeyInit, Nonce, }; use http::{Method, Request}; -use socket2::Socket; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpStream, +}; use crate::{tlv8::TlvEncode, HomekitError}; pub(super) struct AccessorySocket { - socket: Socket, - address: SocketAddr, + socket: TcpStream, ip: String, port: usize, socket_encryption: Option, @@ -40,21 +36,10 @@ impl SocketEncryption { impl AccessorySocket { pub async fn new(ip: &str, port: usize) -> Result { - let socket = Socket::new( - socket2::Domain::IPV4, - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; - socket.set_reuse_port(true)?; - socket.set_keepalive(true)?; - socket.set_linger(Some(Duration::from_secs(10)))?; - - let address: SocketAddr = format!("{ip}:{port}").parse()?; - socket.connect(&address.into())?; + let socket = TcpStream::connect(format!("{ip}:{port}")).await?; Ok(Self { socket, - address, ip: ip.into(), port, socket_encryption: None, @@ -92,10 +77,10 @@ impl AccessorySocket { .await } - pub async fn get_accessories(&mut self) -> Result<(), HomekitError> { + pub async fn get_accessories(&mut self) -> Result { let response = self.req("/accessories", Method::GET, None, &[]).await?; - log::info!("response: {response:?}"); - Ok(()) + + Ok(String::from_utf8(response)?) } pub async fn get_characteristics( @@ -142,11 +127,7 @@ impl AccessorySocket { .to_vec(); for (name, value) in parts.headers { if let Some(name) = name { - if name == "host" { - send_data.extend_from_slice("Host: ".to_string().as_bytes()); - } else { - send_data.extend_from_slice(format!("{name}: ").as_bytes()); - } + send_data.extend_from_slice(format!("{name}: ").as_bytes()); send_data.extend_from_slice(value.as_bytes()); send_data.extend_from_slice("\r\n".as_bytes()); } else { @@ -192,82 +173,102 @@ impl AccessorySocket { log::info!("encrypted {i} chunks!"); } - self.socket.write_all(&send_data)?; - - let mut buf = [0; 1024]; - - let mut read_num = self.socket.read(&mut buf)?; - - while read_num == 0 { - log::info!("read 0 bytes - about to reconnect"); - std::thread::sleep(std::time::Duration::from_millis(200)); - self.socket.flush()?; - - log::warn!("reconnecting..."); - self.socket = Socket::new( - socket2::Domain::IPV4, - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; - self.socket.set_reuse_port(true)?; - self.socket.set_keepalive(true)?; - self.socket.set_linger(Some(Duration::from_secs(10)))?; - self.socket.connect(&self.address.into())?; - - self.socket.write_all(&send_data)?; - self.socket.flush()?; - - read_num = self.socket.read(&mut buf)?; - } + self.socket.write_all(&send_data).await?; let mut headers = [httparse::EMPTY_HEADER; 4]; - let mut resp = httparse::Response::new(&mut headers); + let mut response = httparse::Response::new(&mut headers); - // if let Some(encryption) = self.socket_encryption.as_mut() { - // log::info!("read num: {read_num}"); - // log::info!("got {buf:?}"); - // let length = u16::from_le_bytes(buf[..2].try_into()?); - // log::info!("alleged length: {length}"); - // let associated_data: [u8; 16] = length - // .to_le_bytes() - // .iter() - // .chain([0; 14].iter()) - // .copied() - // .collect::>() - // .try_into()?; - // let authtag: [u8; 16] = buf[2..(2 + 16)].try_into()?; - // let mut data = buf[(2/*+ 16*/)..].to_vec(); - // let counter_bytes = encryption.accessory_to_controller_counter.to_le_bytes(); - // encryption.accessory_to_controller_counter += 1; - // log::info!("pebis number 1"); - // let nonce: [u8; 12] = [0; 4] - // .iter() - // .chain(counter_bytes.iter()) - // .copied() - // .collect::>() - // .try_into()?; - // encryption.chacha.decrypt_in_place_detached( - // GenericArray::from_slice(&nonce), - // &associated_data, - // &mut data, - // GenericArray::from_slice(&authtag), - // )?; + let packet = self.get_next().await?; - // log::info!("pebios 2"); - // let res = resp.parse(&data)?; - // match res { - // httparse::Status::Complete(header_size) => { - // Ok(data[header_size..(read_num - (2 + 16))].to_vec()) - // } - // httparse::Status::Partial => panic!("LOL"), - // } - // } else { - let res = resp.parse(&buf)?; - log::info!("response:\n{resp:#?}"); - match res { - httparse::Status::Complete(header_size) => Ok(buf[header_size..read_num].to_vec()), + let result = response.parse(&packet)?; + log::info!("response:\n{response:#?}"); + + let header_size = match result { + httparse::Status::Complete(header_size) => header_size, httparse::Status::Partial => panic!("LOL"), + }; + let mut packet = packet[header_size..].to_vec(); + + if let Some(transfer_encoding) = response + .headers + .iter() + .find(|v| v.name.to_lowercase() == "Transfer-Encoding".to_lowercase()) + { + if transfer_encoding.value == b"chunked" { + loop { + packet.append(&mut self.get_next().await?); + + let utf8_decoded = String::from_utf8(packet.clone())?; + + let split = utf8_decoded + .split_terminator("\r\n") + .map(String::from) + .collect::>(); + if let Some(last) = split.chunks(2).last() { + if last.len() == 2 && last[0] == "0" { + break; + } + } + } + + let utf8_decoded = String::from_utf8(std::mem::take(&mut packet))?; + + let split = utf8_decoded + .split_terminator("\r\n") + .map(String::from) + .collect::>(); + + for chunk in split.chunks_exact(2) { + packet.extend_from_slice(chunk[1].as_bytes()) + } + } + } + + Ok(packet) + } + + async fn get_next(&mut self) -> Result, HomekitError> { + // max packet size + authtag size + associated data size + let mut buf = [0; 1024 + 16 + 2]; + // let mut buf = [0; 1536]; + + let mut read_num = self.socket.read(&mut buf).await?; + let mut tries = 0; + + while read_num == 0 { + if tries > 20 { + log::error!("unsuccessfully tried to reconnect"); + return Err(HomekitError::Http); + } + tries += 1; + log::info!("read 0 bytes - about to reconnect"); + std::thread::sleep(std::time::Duration::from_millis(200)); + self.socket.flush().await?; + + log::warn!("reconnecting..."); + self.socket = TcpStream::connect(format!("{}:{}", self.ip, self.port)).await?; + + read_num = self.socket.read(&mut buf).await?; + } + if let Some(encryption) = self.socket_encryption.as_mut() { + let associated_data: [u8; 2] = buf[..2].try_into()?; + let length = u16::from_le_bytes(associated_data); + + let mut buffer = buf[2..(length as usize + 18)].to_vec(); + + let mut nonce = [0; 12]; + nonce[4..].copy_from_slice(&encryption.accessory_to_controller_counter.to_le_bytes()); + encryption.accessory_to_controller_counter += 1; + + let chacha = ChaCha20Poly1305::new(GenericArray::from_slice( + &encryption.accessory_to_controller_key, + )); + + chacha.decrypt_in_place(Nonce::from_slice(&nonce), &associated_data, &mut buffer)?; + + Ok(buffer) + } else { + Ok(buf[..read_num].to_vec()) } - // } } } diff --git a/homekit-controller/src/lib.rs b/homekit-controller/src/lib.rs index 0521abd..2fbe54a 100644 --- a/homekit-controller/src/lib.rs +++ b/homekit-controller/src/lib.rs @@ -247,19 +247,19 @@ impl DevicePairingData { socket.get_accessories().await?; // now get characteristics - socket - .get_characteristics( - &self - .accessories - .as_ref() - .map(|a| { - a.iter() - .flat_map(|v| v.get_service_ids()) - .collect::>() - }) - .unwrap_or_default(), - ) - .await?; + // socket + // .get_characteristics( + // &self + // .accessories + // .as_ref() + // .map(|a| { + // a.iter() + // .flat_map(|v| v.get_service_ids()) + // .collect::>() + // }) + // .unwrap_or_default(), + // ) + // .await?; Ok(()) } @@ -307,6 +307,8 @@ pub enum HomekitError { AddrParse(#[from] std::net::AddrParseError), #[error("tlv error from device")] TlvDeviceError(TlvError), + #[error("parsing utf-8")] + Utf8(#[from] std::string::FromUtf8Error), } impl From for HomekitError { diff --git a/homekit-controller/src/tlv8/mod.rs b/homekit-controller/src/tlv8/mod.rs index add2e49..a48f6c4 100644 --- a/homekit-controller/src/tlv8/mod.rs +++ b/homekit-controller/src/tlv8/mod.rs @@ -101,7 +101,7 @@ pub fn decode(data: &[u8]) -> Result>, TlvCodecError> { }; tlvs.insert(tlv_type, tlv_data); } - log::info!("Decoded TLV: {}\n", tlvs.as_tlv_string()); + log::info!("Decoded TLV: {}", tlvs.as_tlv_string()); Ok(tlvs) }