use std::io::Cursor;
use byteorder::{WriteBytesExt, BigEndian};
use crate::error::*;
use crate::buffer::{self, Buffer};
use crate::builder::{Builder as Build, Finalization};
use crate::packet::{AsPacket, AsPacketMut};
use crate::ip;
use crate::tcp::Packet;
use crate::tcp::Flags;
use crate::tcp::checksum;
#[derive(Debug)]
pub struct Builder<B: Buffer = buffer::Dynamic> {
buffer: B,
finalizer: Finalization,
ip: (usize, usize),
options: bool,
payload: bool,
payload_length: usize,
}
impl<B: Buffer> Build<B> for Builder<B> {
fn with(mut buffer: B) -> Result<Self> {
let ip = (buffer.offset(), buffer.length());
use crate::size::header::Min;
buffer.next(Packet::<()>::min())?;
buffer.data_mut()[12] = ((Packet::<()>::min() / 4) as u8) << 4;
Ok(Builder {
buffer: buffer,
finalizer: Default::default(),
ip: ip,
options: false,
payload: false,
payload_length: 0,
})
}
fn finalizer(&mut self) -> &mut Finalization {
&mut self.finalizer
}
fn build(mut self) -> Result<B::Inner> {
self.prepare();
let mut buffer = self.buffer.into_inner();
self.finalizer.finalize(buffer.as_mut())?;
Ok(buffer)
}
}
impl Default for Builder<buffer::Dynamic> {
fn default() -> Self {
Builder::with(buffer::Dynamic::default()).unwrap()
}
}
impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder<B> {
fn as_packet(&self) -> Result<Packet<&[u8]>> {
Packet::new(self.buffer.data())
}
}
impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder<B> {
fn as_packet_mut(&mut self) -> Result<Packet<&mut [u8]>> {
Packet::new(self.buffer.data_mut())
}
}
impl<B: Buffer> Builder<B> {
pub fn source(mut self, value: u16) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_source(value)?;
Ok(self)
}
pub fn destination(mut self, value: u16) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_destination(value)?;
Ok(self)
}
pub fn sequence(mut self, value: u32) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_sequence(value)?;
Ok(self)
}
pub fn acknowledgment(mut self, value: u32) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_acknowledgment(value)?;
Ok(self)
}
pub fn flags(mut self, value: Flags) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_flags(value)?;
Ok(self)
}
pub fn window(mut self, value: u16) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_window(value)?;
Ok(self)
}
pub fn pointer(mut self, value: u16) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_pointer(value)?;
Ok(self)
}
pub fn payload<'a, T: IntoIterator<Item = &'a u8>>(mut self, value: T) -> Result<Self> {
if self.payload {
Err(Error::AlreadyDefined)?
}
self.payload = true;
for byte in value {
self.buffer.more(1)?;
self.payload_length += 1;
*self.buffer.data_mut().last_mut().unwrap() = *byte;
}
Ok(self)
}
fn prepare(&mut self) {
let ip = self.ip;
let length = self.buffer.length();
let payload_length = self.payload_length;
self.finalizer.add(move |out| {
let (before, after) = out.split_at_mut(ip.0 + ip.1);
let ip = &mut before[ip.0 ..];
let tcp = &mut after[.. length];
let flags = tcp[12] & 0b1111;
let offset = ((length - payload_length) / 4) as u8;
tcp[12] = offset << 4 | flags;
let checksum = checksum(&ip::Packet::no_payload(&ip)?, tcp);
Cursor::new(&mut tcp[16 ..])
.write_u16::<BigEndian>(checksum)?;
Ok(())
});
}
}
#[cfg(test)]
mod test {
use std::net::Ipv4Addr;
use crate::builder::Builder;
use crate::packet::Packet;
use crate::ip;
use crate::tcp;
#[test]
fn simple() {
let packet = ip::v4::Builder::default()
.id(0x2d87).unwrap()
.ttl(64).unwrap()
.source("66.102.1.108".parse().unwrap()).unwrap()
.destination("192.168.0.79".parse().unwrap()).unwrap()
.tcp().unwrap()
.source(1337).unwrap()
.destination(9001).unwrap()
.flags(tcp::flag::SYN).unwrap()
.payload(b"lol").unwrap()
.build().unwrap();
let ip = ip::v4::Packet::new(packet).unwrap();
assert_eq!(ip.id(), 0x2d87);
assert!(ip.flags().is_empty());
assert_eq!(ip.length(), 43);
assert_eq!(ip.ttl(), 64);
assert_eq!(ip.protocol(), ip::Protocol::Tcp);
assert_eq!(ip.source(), "66.102.1.108".parse::<Ipv4Addr>().unwrap());
assert_eq!(ip.destination(), "192.168.0.79".parse::<Ipv4Addr>().unwrap());
assert!(ip.is_valid());
let tcp = tcp::Packet::new(ip.payload()).unwrap();
assert_eq!(tcp.source(), 1337);
assert_eq!(tcp.destination(), 9001);
assert_eq!(tcp.flags(), tcp::flag::SYN);
assert!(tcp.is_valid(&ip::Packet::from(&ip)));
}
}