This commit is contained in:
Alex Janka 2024-02-22 12:50:46 +11:00
parent 009aeabd45
commit ab735cf980
5 changed files with 119 additions and 116 deletions

2
Cargo.lock generated
View file

@ -442,8 +442,8 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"socket2",
"thiserror", "thiserror",
"tokio",
"x25519-dalek", "x25519-dalek",
] ]

View file

@ -18,4 +18,4 @@ sha2 = "0.10"
hex = { version = "0.4", features = ["serde"] } hex = { version = "0.4", features = ["serde"] }
http = "1.0" http = "1.0"
httparse = "1.8" httparse = "1.8"
socket2 = "0.5" tokio = { version = "1.36", features = ["net"] }

View file

@ -1,20 +1,16 @@
use std::{
io::{Read, Write},
net::SocketAddr,
time::Duration,
};
use chacha20poly1305::{ use chacha20poly1305::{
aead::generic_array::GenericArray, AeadInPlace, ChaCha20Poly1305, KeyInit, Nonce, aead::generic_array::GenericArray, AeadInPlace, ChaCha20Poly1305, KeyInit, Nonce,
}; };
use http::{Method, Request}; use http::{Method, Request};
use socket2::Socket; use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
use crate::{tlv8::TlvEncode, HomekitError}; use crate::{tlv8::TlvEncode, HomekitError};
pub(super) struct AccessorySocket { pub(super) struct AccessorySocket {
socket: Socket, socket: TcpStream,
address: SocketAddr,
ip: String, ip: String,
port: usize, port: usize,
socket_encryption: Option<SocketEncryption>, socket_encryption: Option<SocketEncryption>,
@ -40,21 +36,10 @@ impl SocketEncryption {
impl AccessorySocket { impl AccessorySocket {
pub async fn new(ip: &str, port: usize) -> Result<Self, HomekitError> { pub async fn new(ip: &str, port: usize) -> Result<Self, HomekitError> {
let socket = Socket::new( let socket = TcpStream::connect(format!("{ip}:{port}")).await?;
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())?;
Ok(Self { Ok(Self {
socket, socket,
address,
ip: ip.into(), ip: ip.into(),
port, port,
socket_encryption: None, socket_encryption: None,
@ -92,10 +77,10 @@ impl AccessorySocket {
.await .await
} }
pub async fn get_accessories(&mut self) -> Result<(), HomekitError> { pub async fn get_accessories(&mut self) -> Result<String, HomekitError> {
let response = self.req("/accessories", Method::GET, None, &[]).await?; let response = self.req("/accessories", Method::GET, None, &[]).await?;
log::info!("response: {response:?}");
Ok(()) Ok(String::from_utf8(response)?)
} }
pub async fn get_characteristics( pub async fn get_characteristics(
@ -142,11 +127,7 @@ impl AccessorySocket {
.to_vec(); .to_vec();
for (name, value) in parts.headers { for (name, value) in parts.headers {
if let Some(name) = name { if let Some(name) = name {
if name == "host" { send_data.extend_from_slice(format!("{name}: ").as_bytes());
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(value.as_bytes()); send_data.extend_from_slice(value.as_bytes());
send_data.extend_from_slice("\r\n".as_bytes()); send_data.extend_from_slice("\r\n".as_bytes());
} else { } else {
@ -192,82 +173,102 @@ impl AccessorySocket {
log::info!("encrypted {i} chunks!"); log::info!("encrypted {i} chunks!");
} }
self.socket.write_all(&send_data)?; self.socket.write_all(&send_data).await?;
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)?;
}
let mut headers = [httparse::EMPTY_HEADER; 4]; 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() { let packet = self.get_next().await?;
// 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::<Vec<_>>()
// .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::<Vec<_>>()
// .try_into()?;
// encryption.chacha.decrypt_in_place_detached(
// GenericArray::from_slice(&nonce),
// &associated_data,
// &mut data,
// GenericArray::from_slice(&authtag),
// )?;
// log::info!("pebios 2"); let result = response.parse(&packet)?;
// let res = resp.parse(&data)?; log::info!("response:\n{response:#?}");
// match res {
// httparse::Status::Complete(header_size) => { let header_size = match result {
// Ok(data[header_size..(read_num - (2 + 16))].to_vec()) httparse::Status::Complete(header_size) => header_size,
// }
// 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()),
httparse::Status::Partial => panic!("LOL"), 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::<Vec<_>>();
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::<Vec<_>>();
for chunk in split.chunks_exact(2) {
packet.extend_from_slice(chunk[1].as_bytes())
}
}
}
Ok(packet)
}
async fn get_next(&mut self) -> Result<Vec<u8>, 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())
} }
// }
} }
} }

View file

@ -247,19 +247,19 @@ impl DevicePairingData {
socket.get_accessories().await?; socket.get_accessories().await?;
// now get characteristics // now get characteristics
socket // socket
.get_characteristics( // .get_characteristics(
&self // &self
.accessories // .accessories
.as_ref() // .as_ref()
.map(|a| { // .map(|a| {
a.iter() // a.iter()
.flat_map(|v| v.get_service_ids()) // .flat_map(|v| v.get_service_ids())
.collect::<Vec<_>>() // .collect::<Vec<_>>()
}) // })
.unwrap_or_default(), // .unwrap_or_default(),
) // )
.await?; // .await?;
Ok(()) Ok(())
} }
@ -307,6 +307,8 @@ pub enum HomekitError {
AddrParse(#[from] std::net::AddrParseError), AddrParse(#[from] std::net::AddrParseError),
#[error("tlv error from device")] #[error("tlv error from device")]
TlvDeviceError(TlvError), TlvDeviceError(TlvError),
#[error("parsing utf-8")]
Utf8(#[from] std::string::FromUtf8Error),
} }
impl From<TlvError> for HomekitError { impl From<TlvError> for HomekitError {

View file

@ -101,7 +101,7 @@ pub fn decode(data: &[u8]) -> Result<HashMap<u8, Vec<u8>>, TlvCodecError> {
}; };
tlvs.insert(tlv_type, tlv_data); 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) Ok(tlvs)
} }