yessss
This commit is contained in:
parent
009aeabd45
commit
ab735cf980
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -442,8 +442,8 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"socket2",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -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"] }
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue