use std::io::Cursor;
use std::net::Ipv4Addr;
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::Protocol;
use crate::ip::v4::Packet;
use crate::ip::v4::Flags;
use crate::ip::v4::checksum;
#[derive(Debug)]
pub struct Builder<B: Buffer = buffer::Dynamic> {
buffer: B,
finalizer: Finalization,
options: bool,
payload: bool,
}
impl<B: Buffer> Build<B> for Builder<B> {
fn with(mut buffer: B) -> Result<Self> {
use crate::size::header::Min;
buffer.next(Packet::<()>::min())?;
buffer.data_mut()[0] = (4 << 4) | ((Packet::<()>::min() / 4) as u8);
Ok(Builder {
buffer: buffer,
finalizer: Default::default(),
options: false,
payload: false,
})
}
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())
}
}
macro_rules! protocol {
($(#[$attr:meta])* fn $module:ident($protocol:ident)) => (
$(#[$attr])*
pub fn $module(mut self) -> Result<crate::$module::Builder<B>> {
if self.payload {
Err(Error::AlreadyDefined)?
}
self = self.protocol(Protocol::$protocol)?;
self.prepare();
let mut builder = crate::$module::Builder::with(self.buffer)?;
builder.finalizer().extend(self.finalizer);
Ok(builder)
}
)
}
impl<B: Buffer> Builder<B> {
pub fn dscp(mut self, value: u8) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_dscp(value)?;
Ok(self)
}
pub fn ecn(mut self, value: u8) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_ecn(value)?;
Ok(self)
}
pub fn id(mut self, value: u16) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_id(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 offset(mut self, value: u16) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_offset(value)?;
Ok(self)
}
pub fn ttl(mut self, value: u8) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_ttl(value)?;
Ok(self)
}
pub fn source(mut self, value: Ipv4Addr) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_source(value)?;
Ok(self)
}
pub fn destination(mut self, value: Ipv4Addr) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_destination(value)?;
Ok(self)
}
pub fn protocol(mut self, value: Protocol) -> Result<Self> {
Packet::unchecked(self.buffer.data_mut()).set_protocol(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.buffer.data_mut().last_mut().unwrap() = *byte;
}
Ok(self)
}
fn prepare(&mut self) {
let offset = self.buffer.offset();
let length = self.buffer.length();
self.finalizer.add(move |out| {
let header = length / 4;
out[offset] = (4 << 4) | header as u8;
let length = length + (out.len() - (offset + length));
Cursor::new(&mut out[offset + 2 ..])
.write_u16::<BigEndian>(length as u16)?;
let checksum = checksum(&out[offset .. offset + header * 4]);
Cursor::new(&mut out[offset + 10 ..])
.write_u16::<BigEndian>(checksum)?;
Ok(())
});
}
protocol!( fn icmp(Icmp));
protocol!( fn tcp(Tcp));
protocol!( fn udp(Udp));
}
#[cfg(test)]
mod test {
use std::net::Ipv4Addr;
use crate::builder::Builder;
use crate::ip;
use crate::tcp;
#[test]
fn icmp() {
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()
.icmp().unwrap()
.echo().unwrap().request().unwrap()
.identifier(42).unwrap()
.sequence(2).unwrap()
.payload(b"test").unwrap()
.build().unwrap();
let packet = ip::v4::Packet::new(packet).unwrap();
assert_eq!(packet.id(), 0x2d87);
assert!(packet.flags().is_empty());
assert_eq!(packet.length(), 32);
assert_eq!(packet.ttl(), 64);
assert_eq!(packet.protocol(), ip::Protocol::Icmp);
assert_eq!(packet.source(), "66.102.1.108".parse::<Ipv4Addr>().unwrap());
assert_eq!(packet.destination(), "192.168.0.79".parse::<Ipv4Addr>().unwrap());
assert!(packet.is_valid());
}
#[test]
fn tcp() {
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()
.build().unwrap();
let packet = ip::v4::Packet::new(packet).unwrap();
assert_eq!(packet.id(), 0x2d87);
assert!(packet.flags().is_empty());
assert_eq!(packet.length(), 40);
assert_eq!(packet.ttl(), 64);
assert_eq!(packet.protocol(), ip::Protocol::Tcp);
assert_eq!(packet.source(), "66.102.1.108".parse::<Ipv4Addr>().unwrap());
assert_eq!(packet.destination(), "192.168.0.79".parse::<Ipv4Addr>().unwrap());
assert!(packet.is_valid());
}
}