1#![warn(rust_2018_idioms)]
29#![deny(missing_docs)]
30
31use anyhow::Result;
32use packed_struct::prelude::*;
33use tokio::net::UdpSocket;
34
35#[derive(PackedStruct, Debug, Clone)]
36#[packed_struct(endian = "msb")]
37pub struct MessageHeader {
39 pub magic_number: u16,
41 pub packet_length: u16,
43 pub unknown: u32,
45 pub device_id: u32,
47 pub stamp: u32,
49 pub checksum: [u8; 16],
51}
52
53pub struct Device {
55 socket: std::sync::Arc<UdpSocket>,
57 device_id: u32,
59 token: [u8; 16],
61}
62
63impl Device {
64 pub async fn new(address: &str, device_id: u32, token: [u8; 16]) -> Result<Self> {
72 let socket = UdpSocket::bind("0.0.0.0:0").await?;
73 socket.connect(address).await?;
74
75 let r = Self {
76 socket: std::sync::Arc::new(socket),
77 device_id,
78 token,
79 };
80 Ok(r)
81 }
82
83 fn encode_payload(token: &[u8; 16], payload: &str) -> Vec<u8> {
84 let key = md5::compute(token).to_vec();
85 let mut iv_src = key.to_vec();
86 iv_src.extend(token);
87 let iv = md5::compute(iv_src).to_vec();
88
89 use aes::Aes128;
90 use block_modes::block_padding::Pkcs7;
91 use block_modes::{BlockMode, Cbc};
92
93 let cipher = Cbc::<Aes128, Pkcs7>::new_from_slices(&key, &iv).unwrap();
94
95 cipher.encrypt_vec(payload.as_bytes())
96 }
97
98 fn decode_payload(token: &[u8; 16], payload: &[u8]) -> Vec<u8> {
99 let key = md5::compute(token).to_vec();
100 let mut iv_src = key.to_vec();
101 iv_src.extend(token);
102 let iv = md5::compute(iv_src).to_vec();
103
104 use aes::Aes128;
105 use block_modes::block_padding::Pkcs7;
106 use block_modes::{BlockMode, Cbc};
107
108 let cipher = Cbc::<Aes128, Pkcs7>::new_from_slices(&key, &iv).unwrap();
109
110 let mut buf = payload.to_vec();
111 cipher.decrypt(&mut buf).unwrap().to_vec()
112 }
113
114 async fn send_raw(
115 socket: std::sync::Arc<UdpSocket>,
116 unknown: u32,
117 device_id: u32,
118 stamp: u32,
119 token: &[u8; 16],
120 payload: &str,
121 ) -> Result<()> {
122 let payload = if payload.is_empty() {
123 Vec::new()
124 } else {
125 log::trace!("Plain payload: {:?}", payload);
126 let payload = Self::encode_payload(token, payload);
127 log::trace!("Encoded payload len={}: {:?}", payload.len(), payload);
128 payload
129 };
130
131 let message = MessageHeader {
132 magic_number: 0x2131,
133 packet_length: (payload.len() + 32) as u16,
134 unknown,
135 device_id,
136 stamp,
137 checksum: *token,
138 };
139
140 let mut packet = message.pack_to_vec()?.pack_to_vec()?;
141 packet.extend(&payload);
142 let checksum = md5::compute(packet);
143
144 let message = MessageHeader {
145 checksum: *checksum,
146 ..message
147 };
148
149 let mut packet = message.pack()?.pack_to_vec()?;
150 packet.extend(&payload);
151 log::trace!(
152 "Sending packet. Total length {} bytes, payload length {}. Raw packet: {:?}",
153 packet.len(),
154 payload.len(),
155 packet
156 );
157 let sent = socket.send(&packet).await?;
158 log::debug!("Sent {} bytes", sent);
159
160 Ok(())
161 }
162
163 pub async fn recv(&self) -> Result<(MessageHeader, String)> {
168 let mut buf = [0_u8; 65535];
169 self.socket.recv(&mut buf).await?;
170 let mut hdr: [u8; 32] = Default::default();
171 hdr.copy_from_slice(&buf[..32]);
172 let resp = MessageHeader::unpack(&hdr)?;
173 log::trace!("Got header: {:?}", resp);
174 let payload = &buf[32..resp.packet_length as usize];
175 log::trace!("Got payload len={}: {:?}", payload.len(), payload);
176 let payload = Self::decode_payload(&self.token, payload);
177 let payload = std::str::from_utf8(&payload)?;
178 if !payload.is_empty() {
179 log::trace!("Decoded payload: {}", payload);
180 }
181
182 Ok((resp, payload.to_string()))
183 }
184
185 pub async fn send_handshake(&self) -> Result<()> {
187 Self::send_raw(
188 self.socket.clone(),
189 0xffffffff,
190 0xffffffff,
191 0xffffffff,
192 &[
193 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
194 0xff, 0xff,
195 ],
196 "",
197 )
198 .await
199 }
200
201 pub async fn send(&self, stamp: u32, payload: &str) -> Result<()> {
208 Self::send_raw(
209 self.socket.clone(),
210 0,
211 self.device_id,
212 stamp,
213 &self.token,
214 payload,
215 )
216 .await
217 }
218}