use crate::manager::net_types::WpaKey;
use crate::readwrite::BufferOverflow;
use crate::readwrite::Write;
use crate::socket::Socket;
use core::net::{Ipv4Addr, SocketAddrV4};
use super::constants::{AuthType, MAX_PSK_KEY_LEN, START_PROVISION_PACKET_SIZE};
use super::net_types::WepKey;
use super::{AccessPoint, Credentials, HostName};
pub fn write_connect_request(
auth: AuthType,
ssid: &str,
password: &str,
channel: u16,
dont_save_creds: bool,
) -> Result<[u8; 108], BufferOverflow> {
let mut result = [0xCCu8; 108];
let mut slice = result.as_mut_slice();
if password.len() > MAX_PSK_KEY_LEN {
return Err(BufferOverflow);
}
slice.write(password.as_bytes())?;
slice.write(&[0])?;
let mut slice = &mut result[65..];
slice.write(&[auth.into()])?;
slice.write(&[0xCC, 0xCC])?;
slice.write(&channel.to_le_bytes())?;
slice.write(ssid.as_bytes())?;
slice.write(&[0])?;
result[103] = dont_save_creds as u8;
Ok(result)
}
pub fn write_scan_req(channel: u8, scantime: u16) -> Result<[u8; 4], BufferOverflow> {
let mut result = [0u8; 4];
let mut slice = result.as_mut_slice();
slice.write(&channel.to_le_bytes())?;
slice.write(&[0u8])?; slice.write(&scantime.to_le_bytes())?;
Ok(result)
}
pub fn write_gethostbyname_req<'a, const N: usize>(
host: &str,
buffer: &'a mut [u8; N],
) -> Result<&'a [u8], BufferOverflow> {
let len = host.len();
if len + 1 > buffer.len() {
return Err(BufferOverflow);
}
buffer[0..len].copy_from_slice(host.as_bytes());
buffer[len] = 0;
Ok(&buffer[0..len + 1])
}
pub fn write_ping_req(
dest_ip: Ipv4Addr,
ttl: u8,
count: u16,
marker: u8,
) -> Result<[u8; 12], BufferOverflow> {
let mut result = [0x0u8; 12];
let mut slice = result.as_mut_slice();
let ip: u32 = dest_ip.into();
slice.write(&(ip).to_be_bytes())?;
slice.write(&[marker, 0xBE, 0xBE, 0xBE])?; slice.write(&count.to_le_bytes())?;
slice.write(&[ttl])?;
Ok(result)
}
pub fn write_bind_req(
socket: Socket,
address_family: u16,
address: SocketAddrV4,
) -> Result<[u8; 12], BufferOverflow> {
let mut result = [0x0u8; 12];
let mut slice = result.as_mut_slice();
let ip: u32 = (*address.ip()).into();
slice.write(&address_family.to_le_bytes())?;
slice.write(&address.port().to_be_bytes())?;
slice.write(&ip.to_be_bytes())?;
slice.write(&[socket.v, 0])?;
slice.write(&socket.s.to_le_bytes())?;
Ok(result)
}
pub fn write_connect_req(
socket: Socket,
address_family: u16,
address: SocketAddrV4,
ssl_flags: u8,
) -> Result<[u8; 12], BufferOverflow> {
let mut result = [0x0u8; 12];
let mut slice = result.as_mut_slice();
let ip: u32 = (*address.ip()).into();
slice.write(&address_family.to_le_bytes())?;
slice.write(&address.port().to_be_bytes())?;
slice.write(&ip.to_be_bytes())?;
slice.write(&[socket.v, ssl_flags])?;
slice.write(&socket.s.to_le_bytes())?;
Ok(result)
}
pub fn write_sendto_req(
socket: Socket,
address_family: u16,
address: SocketAddrV4,
len: usize,
) -> Result<[u8; 16], BufferOverflow> {
let mut result = [0x0u8; 16];
let mut slice = result.as_mut_slice();
let ip: u32 = (*address.ip()).into();
slice.write(&[socket.v, 0])?;
slice.write(&(len as u16).to_le_bytes())?;
slice.write(&address_family.to_le_bytes())?;
slice.write(&address.port().to_be_bytes())?;
slice.write(&ip.to_be_bytes())?;
slice.write(&socket.s.to_le_bytes())?;
slice.write(&[0, 0])?;
Ok(result)
}
pub fn write_listen_req(socket: Socket, backlog: u8) -> Result<[u8; 4], BufferOverflow> {
let mut result = [0x0u8; 4];
let mut slice = result.as_mut_slice();
slice.write(&[socket.v, backlog])?;
slice.write(&socket.s.to_le_bytes())?;
Ok(result)
}
pub fn write_recv_req(socket: Socket, timeout: u32) -> Result<[u8; 8], BufferOverflow> {
let mut result = [0x0u8; 8];
let mut slice = result.as_mut_slice();
slice.write(&timeout.to_le_bytes())?;
slice.write(&[socket.v, 0])?;
slice.write(&socket.s.to_le_bytes())?;
Ok(result)
}
pub fn write_close_req(socket: Socket) -> Result<[u8; 4], BufferOverflow> {
let mut result = [0x0u8; 4];
let mut slice = result.as_mut_slice();
slice.write(&[socket.v, 0])?;
slice.write(&socket.s.to_le_bytes())?;
Ok(result)
}
pub fn write_setsockopt_req(
socket: Socket,
option: u8,
value: u32,
) -> Result<[u8; 8], BufferOverflow> {
let mut result = [0x0u8; 8];
let mut slice = result.as_mut_slice();
slice.write(&value.to_le_bytes())?;
slice.write(&[socket.v, option])?;
slice.write(&socket.s.to_le_bytes())?;
Ok(result)
}
pub fn write_prng_req(addr: u32, len: u16) -> Result<[u8; 8], BufferOverflow> {
let mut req = [0x00u8; 8];
let mut slice = req.as_mut_slice();
slice.write(&addr.to_le_bytes())?;
slice.write(&len.to_le_bytes())?;
Ok(req)
}
pub fn write_start_provisioning_req(
ap: &AccessPoint,
hostname: &HostName,
http_redirect: bool,
) -> Result<[u8; START_PROVISION_PACKET_SIZE], BufferOverflow> {
let mut req = [0u8; START_PROVISION_PACKET_SIZE];
let mut slice = req.as_mut_slice();
let wep_key_index: u8;
let wep_key: WepKey;
#[cfg(feature = "wep")]
{
if let Credentials::Wep(key, index) = ap.key {
wep_key_index = index.into();
wep_key = key;
} else {
wep_key_index = 0;
wep_key = WepKey::new();
}
}
#[cfg(not(feature = "wep"))]
{
wep_key_index = 0;
wep_key = WepKey::new();
}
let wpa_key = if let Credentials::WpaPSK(key) = ap.key {
key
} else {
WpaKey::new()
};
let dhcp: u32 = ap.ip.into();
slice.write(ap.ssid.as_bytes())?;
slice = &mut req[32..];
slice.write(&[0u8])?;
slice.write(&[(ap.channel).into()])?;
slice.write(&[wep_key_index])?;
slice.write(&[ap.key.key_len() as u8])?;
slice.write(wep_key.as_bytes())?;
slice = &mut req[62..];
slice.write(&[0u8])?;
slice.write(&[(ap.key).into()])?;
slice.write(&[ap.ssid_hidden as u8])?;
slice.write(&dhcp.to_be_bytes())?;
slice.write(wpa_key.as_bytes())?;
slice = &mut req[132..];
slice.write(&[0u8, 0u8])?;
slice.write(&[0u8, 0u8])?;
slice.write(hostname.as_bytes())?;
slice = &mut req[199..];
slice.write(&[0u8])?;
slice.write(&[http_redirect as u8])?;
slice.write(&[0u8, 0u8, 0u8])?;
Ok(req)
}
#[cfg(test)]
mod tests {
use crate::Ssid;
use super::*;
#[test]
fn test_scan() {
assert_eq!(write_scan_req(1, 12).unwrap(), [1, 0, 12, 0]);
assert_eq!(write_scan_req(255, 258).unwrap(), [255, 0, 2, 1]);
}
#[test]
fn test_ping() {
assert_eq!(
write_ping_req(Ipv4Addr::new(1, 2, 3, 4), 5, 258, 0xDE).unwrap(),
[1, 2, 3, 4, 0xDE, 0xBE, 0xBE, 0xBE, 2, 1, 5, 0]
);
assert_eq!(
write_ping_req(Ipv4Addr::new(255, 2, 3, 4), 4, 258, 0xBA).unwrap(),
[0xFF, 2, 3, 4, 0xBA, 0xBE, 0xBE, 0xBE, 2, 1, 4, 0]
);
}
#[test]
fn test_dns() {
let mut buff = [0u8; 6];
assert_eq!(
write_gethostbyname_req("abc", &mut buff).unwrap(),
[97, 98, 99, 0]
);
assert_eq!(
write_gethostbyname_req("abcde", &mut buff).unwrap(),
[97, 98, 99, 100, 101, 0]
);
assert!(matches!(
write_gethostbyname_req("abcdef", &mut buff),
Err(BufferOverflow)
));
}
#[test]
fn test_bind() {
assert_eq!(
write_bind_req(
Socket::new(7, 521),
2,
SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 32769)
)
.unwrap(),
[
2, 0, 128, 1, 1, 2, 3, 4, 7, 0, 9, 2
]
);
assert_eq!(
write_bind_req(
Socket::new(0, 3),
257,
SocketAddrV4::new(Ipv4Addr::new(255, 2, 3, 4), 1000)
)
.unwrap(),
[1, 1, 3, 232, 0xFF, 2, 3, 4, 0, 0, 3, 0]
)
}
#[test]
fn test_connect() {
assert_eq!(
write_connect_req(
Socket::new(7, 1030),
2,
SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 0xFABA),
42
)
.unwrap(),
[
2, 0, 0xFA, 0xBA, 1, 2, 3, 4, 7, 42, 6, 4
]
);
assert_eq!(
write_connect_req(
Socket::new(0, 1),
2,
SocketAddrV4::new(Ipv4Addr::new(192, 168, 5, 196), 20002),
0
)
.unwrap(),
[
2, 0, 0x4E, 0x22, 0xC0, 0xA8, 0x5, 0xC4, 0x00, 0, 0x1, 00 ]
);
}
#[test]
fn test_sendto() {
assert_eq!(
write_sendto_req(
Socket::new(7, 521),
2,
SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 0xFABA),
10
)
.unwrap(),
[7, 0, 10, 0, 2, 0, 0xFA, 0xBA, 1, 2, 3, 4, 9, 2, 0, 0,]
);
assert_eq!(
write_sendto_req(
Socket::new(7, 521),
2,
SocketAddrV4::new(Ipv4Addr::new(192, 168, 5, 196), 0x214E),
10
)
.unwrap(),
[7, 0, 10, 0, 2, 0, 0x21, 0x4E, 192, 168, 5, 196, 9, 2, 0, 0,]
)
}
#[test]
fn test_listen() {
assert_eq!(
write_listen_req(Socket::new(1, 258), 2).unwrap(),
[1, 2, 2, 1]
);
}
#[test]
fn test_recv() {
assert_eq!(
write_recv_req(Socket::new(1, 258), 0xDEADBEEF).unwrap(),
[0xEF, 0xBE, 0xAD, 0xDE, 1, 0, 2, 1]
)
}
#[test]
fn test_close() {
assert_eq!(write_close_req(Socket::new(1, 258)).unwrap(), [1, 0, 2, 1]);
}
#[test]
fn test_setsockopt() {
assert_eq!(
write_setsockopt_req(Socket::new(1, 258), 42, 0xDEADBEEF).unwrap(),
[0xEF, 0xBE, 0xAD, 0xDE, 1, 42, 2, 1]
);
}
#[test]
fn test_wpa_connect() {
let mut test_vector = [
0x73u8, 0x75, 0x70, 0x65, 0x72, 0x5F, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5F, 0x70,
0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x02, 0xCC, 0xCC, 0x09, 0x00,
0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x73, 0x73, 0x69, 0x64, 0x00, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x01, 0xCC, 0xCC, 0xCC, 0xCC,
];
let test_ssid = "sample_ssid";
let test_pass = "super_secret_password";
assert_eq!(
test_vector,
write_connect_request(AuthType::WpaPSK, test_ssid, test_pass, 9, true).unwrap()
);
test_vector[65] = 1;
test_vector[68] = 2;
test_vector[103] = 0;
assert_eq!(
test_vector,
write_connect_request(AuthType::Open, test_ssid, test_pass, 2, false).unwrap()
);
assert!(matches!(
write_connect_request(
AuthType::Open,
"how about them ssid be way overly verbose \
without anyones approval at all",
test_pass,
2,
false
),
Err(BufferOverflow)
));
assert!(matches!(
write_connect_request(
AuthType::Open,
test_ssid,
"this password may be way too long for anything \
to fit into the buffer here",
2,
false
),
Err(BufferOverflow)
));
}
#[test]
fn test_prng_request() {
let request = [0xDC, 0x65, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00];
let addr = 0x200065DC;
let len = 32;
assert_eq!(write_prng_req(addr, len).unwrap(), request);
}
#[test]
fn test_start_provisioning_request() {
let valid_req: [u8; START_PROVISION_PACKET_SIZE] = [
116, 101, 115, 116, 95, 115, 115, 105, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0xC0,
0xA8, 0x01, 0x01, 116, 101, 115, 116, 95, 112, 97, 115, 115, 119,
111, 114, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 97, 100, 109, 105, 110, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
let ap_ssid = Ssid::from("test_ssid").unwrap();
let psk = WpaKey::from("test_password").unwrap();
let access_point = AccessPoint::wpa(&ap_ssid, &psk);
let hostname = HostName::from("admin").unwrap();
let result = write_start_provisioning_req(&access_point, &hostname, false).unwrap();
assert_eq!(result, valid_req);
}
}