use std::net::{Ipv4Addr, Ipv6Addr};
use crate::{DhcpError, ErrorKind};
#[derive(Debug)]
pub(crate) struct Buffer<'a> {
index: usize,
data: &'a [u8],
}
impl<'a> Buffer<'a> {
pub(crate) fn new(data: &'a [u8]) -> Self {
Self { index: 0, data }
}
pub(crate) fn is_empty(&self) -> bool {
self.remain_len() == 0
}
pub(crate) fn remain_len(&self) -> usize {
if self.index > self.data.len() {
0
} else {
self.data.len() - self.index
}
}
pub(crate) fn peek_u16_be(&self) -> Result<u16, DhcpError> {
if self.remain_len() < 2 {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
"Remain buffer not enough for getting u16".to_string(),
));
}
let ret = u16::from_be_bytes([
self.data[self.index],
self.data[self.index + 1],
]);
Ok(ret)
}
pub(crate) fn peek_u16_be_offset(
&self,
offset: usize,
) -> Result<u16, DhcpError> {
if self.remain_len() < 2 + offset {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
"Remain buffer not enough for getting u16".to_string(),
));
}
let ret = u16::from_be_bytes([
self.data[self.index + offset],
self.data[self.index + offset + 1],
]);
Ok(ret)
}
pub(crate) fn peek_bytes(&self, len: usize) -> Result<&[u8], DhcpError> {
if self.remain_len() < len {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
format!(
"Remain buffer not enough for getting {len} bytes array"
),
));
}
Ok(&self.data[self.index..self.index + len])
}
pub(crate) fn get_u8(&mut self) -> Result<u8, DhcpError> {
if self.is_empty() {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
"Remain buffer not enough for getting u8".to_string(),
));
}
let ret = self.data[self.index];
self.index += 1;
Ok(ret)
}
pub(crate) fn get_u16_be(&mut self) -> Result<u16, DhcpError> {
let ret = self.peek_u16_be()?;
self.index += 2;
Ok(ret)
}
pub(crate) fn get_u32_be(&mut self) -> Result<u32, DhcpError> {
if self.remain_len() < 4 {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
"Remain buffer not enough for getting u32".to_string(),
));
}
let ret = u32::from_be_bytes([
self.data[self.index],
self.data[self.index + 1],
self.data[self.index + 2],
self.data[self.index + 3],
]);
self.index += 4;
Ok(ret)
}
pub(crate) fn get_u128_be(&mut self) -> Result<u128, DhcpError> {
if self.remain_len() < 16 {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
"Remain buffer not enough for getting u128".to_string(),
));
}
let ret = u128::from_be_bytes([
self.data[self.index],
self.data[self.index + 1],
self.data[self.index + 2],
self.data[self.index + 3],
self.data[self.index + 4],
self.data[self.index + 5],
self.data[self.index + 6],
self.data[self.index + 7],
self.data[self.index + 8],
self.data[self.index + 9],
self.data[self.index + 10],
self.data[self.index + 11],
self.data[self.index + 12],
self.data[self.index + 13],
self.data[self.index + 14],
self.data[self.index + 15],
]);
self.index += 16;
Ok(ret)
}
pub(crate) fn get_bytes(&mut self, len: usize) -> Result<&[u8], DhcpError> {
if self.remain_len() < len {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
format!(
"Remain buffer not enough for getting {len} bytes array"
),
));
}
let ret = &self.data[self.index..self.index + len];
self.index += len;
Ok(ret)
}
pub(crate) fn get_ipv4(&mut self) -> Result<Ipv4Addr, DhcpError> {
if self.remain_len() < 4 {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
"Remain buffer not enough for getting IPv4 address".to_string(),
));
}
let ret = Ipv4Addr::new(
self.data[self.index],
self.data[self.index + 1],
self.data[self.index + 2],
self.data[self.index + 3],
);
self.index += 4;
Ok(ret)
}
pub(crate) fn get_ipv6(&mut self) -> Result<Ipv6Addr, DhcpError> {
if self.remain_len() < 16 {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
"Remain buffer not enough for getting IPv6 address".to_string(),
));
}
let ret = Ipv6Addr::new(
self.get_u16_be().unwrap(),
self.get_u16_be().unwrap(),
self.get_u16_be().unwrap(),
self.get_u16_be().unwrap(),
self.get_u16_be().unwrap(),
self.get_u16_be().unwrap(),
self.get_u16_be().unwrap(),
self.get_u16_be().unwrap(),
);
Ok(ret)
}
pub(crate) fn get_string_with_null(
&mut self,
fix_size: usize,
) -> Result<String, DhcpError> {
if self.remain_len() < fix_size {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
format!(
"Remain buffer not enough for getting {fix_size} bytes \
string"
),
));
}
let pos = if let Some(p) = self.data[self.index..self.index + fix_size]
.iter()
.position(|c| *c == 0)
{
p
} else {
fix_size
};
let vec = self.data[self.index..self.index + pos].to_vec();
self.index += fix_size;
String::from_utf8(vec).map_err(|e| {
DhcpError::new(
ErrorKind::InvalidDhcpMessage,
format!("Not valid UTF-8 string: {e}"),
)
})
}
pub(crate) fn get_string_without_null(
&mut self,
size: usize,
) -> Result<String, DhcpError> {
if self.remain_len() < size {
return Err(DhcpError::new(
ErrorKind::InvalidDhcpMessage,
format!(
"Remain buffer not enough for getting {size} bytes string"
),
));
}
let vec = self.data[self.index..self.index + size].to_vec();
self.index += size;
String::from_utf8(vec).map_err(|e| {
DhcpError::new(
ErrorKind::InvalidDhcpMessage,
format!("Not valid UTF-8 string: {e}"),
)
})
}
pub(crate) fn get_remains(&mut self) -> &[u8] {
if self.index > self.data.len() {
&[]
} else {
&self.data[self.index..]
}
}
}
pub(crate) struct BufferMut {
pub(crate) data: Vec<u8>,
}
impl BufferMut {
pub(crate) fn new() -> Self {
Self { data: Vec::new() }
}
pub(crate) fn len(&self) -> usize {
self.data.len()
}
pub(crate) fn write_u8(&mut self, value: u8) {
self.data.push(value);
}
pub(crate) fn write_u16_be(&mut self, value: u16) {
self.data.extend_from_slice(&value.to_be_bytes());
}
pub(crate) fn write_u32_be(&mut self, value: u32) {
self.data.extend_from_slice(&value.to_be_bytes());
}
pub(crate) fn write_u128_be(&mut self, value: u128) {
self.data.extend_from_slice(&value.to_be_bytes());
}
pub(crate) fn write_bytes(&mut self, bytes: &[u8]) {
self.data.extend_from_slice(bytes);
}
pub(crate) fn write_ipv4(&mut self, addr: Ipv4Addr) {
self.data.extend_from_slice(&addr.octets());
}
pub(crate) fn write_ipv6(&mut self, addr: Ipv6Addr) {
self.data.extend_from_slice(&addr.octets());
}
pub(crate) fn write_string_without_null(&mut self, value: &str) {
self.data.extend_from_slice(value.as_bytes());
}
pub(crate) fn write_string_with_null(
&mut self,
value: &str,
fix_size: usize,
) {
let value_bytes = if (value.len() + 1) > fix_size {
&value.as_bytes()[..fix_size - 1]
} else {
value.as_bytes()
};
let remains = fix_size - value_bytes.len() - 1;
self.data.extend_from_slice(value_bytes);
if remains > 0 {
self.data.extend_from_slice(vec![0u8; remains].as_slice());
}
self.write_u8(0);
}
}