use super::*;
use std::{io, marker};
pub struct PacketBuilder {}
impl PacketBuilder {
pub fn ethernet2(source: [u8;6], destination: [u8;6]) -> PacketBuilderStep<Ethernet2Header> {
PacketBuilderStep {
state: PacketImpl {
ethernet2_header: Some(Ethernet2Header{
source,
destination,
ether_type: 0 }),
vlan_header: None,
ip_header: None,
transport_header: None
},
_marker: marker::PhantomData::<Ethernet2Header>{}
}
}
pub fn ipv4(source: [u8;4], destination: [u8;4], time_to_live: u8) -> PacketBuilderStep<IpHeader> {
PacketBuilderStep {
state: PacketImpl {
ethernet2_header: None,
vlan_header: None,
ip_header: None,
transport_header: None
},
_marker: marker::PhantomData::<Ethernet2Header>{}
}.ipv4(source, destination, time_to_live)
}
pub fn ipv6(source: [u8;16], destination: [u8;16], hop_limit: u8) -> PacketBuilderStep<IpHeader> {
PacketBuilderStep {
state: PacketImpl {
ethernet2_header: None,
vlan_header: None,
ip_header: None,
transport_header: None
},
_marker: marker::PhantomData::<Ethernet2Header>{}
}.ipv6(source, destination, hop_limit)
}
pub fn ip(ip_header: IpHeader) -> PacketBuilderStep<IpHeader> {
PacketBuilderStep {
state: PacketImpl {
ethernet2_header: None,
vlan_header: None,
ip_header: None,
transport_header: None
},
_marker: marker::PhantomData::<Ethernet2Header>{}
}.ip(ip_header)
}
}
struct PacketImpl {
ethernet2_header: Option<Ethernet2Header>,
ip_header: Option<IpHeader>,
vlan_header: Option<VlanHeader>,
transport_header: Option<TransportHeader>
}
pub struct PacketBuilderStep<LastStep> {
state: PacketImpl,
_marker: marker::PhantomData<LastStep>
}
impl PacketBuilderStep<Ethernet2Header> {
pub fn ipv4(mut self, source: [u8;4], destination: [u8;4], time_to_live: u8) -> PacketBuilderStep<IpHeader> {
self.state.ip_header = Some(IpHeader::Version4({
let mut value: Ipv4Header = Default::default();
value.source = source;
value.destination = destination;
value.time_to_live = time_to_live;
value
}, Default::default()));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<IpHeader>{}
}
}
pub fn ip(mut self, ip_header: IpHeader) -> PacketBuilderStep<IpHeader> {
self.state.ip_header = Some(ip_header);
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<IpHeader>{}
}
}
pub fn ipv6(mut self, source: [u8;16], destination: [u8;16], hop_limit: u8) -> PacketBuilderStep<IpHeader> {
self.state.ip_header = Some(IpHeader::Version6(Ipv6Header{
traffic_class: 0,
flow_label: 0,
payload_length: 0, next_header: 0, hop_limit,
source,
destination
}, Default::default()));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<IpHeader>{}
}
}
pub fn vlan(mut self, vlan: VlanHeader) -> PacketBuilderStep<VlanHeader> {
self.state.vlan_header = Some(vlan);
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<VlanHeader>{}
}
}
pub fn single_vlan(mut self, vlan_identifier: u16) -> PacketBuilderStep<VlanHeader> {
self.state.vlan_header = Some(VlanHeader::Single(SingleVlanHeader {
priority_code_point: 0,
drop_eligible_indicator: false,
vlan_identifier,
ether_type: 0, }));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<VlanHeader>{}
}
}
pub fn double_vlan(mut self, outer_vlan_identifier: u16, inner_vlan_identifier: u16) -> PacketBuilderStep<VlanHeader> {
self.state.vlan_header = Some(VlanHeader::Double(DoubleVlanHeader {
outer: SingleVlanHeader {
priority_code_point: 0,
drop_eligible_indicator: false,
vlan_identifier: outer_vlan_identifier,
ether_type: 0, },
inner: SingleVlanHeader {
priority_code_point: 0,
drop_eligible_indicator: false,
vlan_identifier: inner_vlan_identifier,
ether_type: 0, }
}));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<VlanHeader>{}
}
}
}
impl PacketBuilderStep<VlanHeader> {
pub fn ip(self, ip_header: IpHeader) -> PacketBuilderStep<IpHeader> {
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Ethernet2Header>{}
}.ip(ip_header)
}
pub fn ipv6(self, source: [u8;16], destination: [u8;16], hop_limit: u8) -> PacketBuilderStep<IpHeader> {
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Ethernet2Header>{}
}.ipv6(source, destination, hop_limit)
}
pub fn ipv4(self, source: [u8;4], destination: [u8;4], time_to_live: u8) -> PacketBuilderStep<IpHeader> {
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Ethernet2Header>{}
}.ipv4(source, destination, time_to_live)
}
}
impl PacketBuilderStep<IpHeader> {
pub fn icmpv4(mut self, icmp_type: Icmpv4Type) -> PacketBuilderStep<Icmpv4Header> {
self.state.transport_header = Some(TransportHeader::Icmpv4(Icmpv4Header{
icmp_type,
checksum: 0, }));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv4Header>{}
}
}
pub fn icmpv4_raw(mut self, type_u8: u8, code_u8: u8, bytes5to8: [u8;4]) -> PacketBuilderStep<Icmpv4Header> {
let icmp_type = Icmpv4Type::Unknown{type_u8, code_u8, bytes5to8};
self.state.transport_header = Some(TransportHeader::Icmpv4(Icmpv4Header{
icmp_type,
checksum: 0, }));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv4Header>{}
}
}
pub fn icmpv4_echo_request(mut self, id: u16, seq: u16) -> PacketBuilderStep<Icmpv4Header> {
let echo_header = IcmpEchoHeader{
id,
seq,
};
let icmpv4_echo = Icmpv4Header::new(Icmpv4Type::EchoRequest(echo_header));
self.state.transport_header = Some(TransportHeader::Icmpv4(icmpv4_echo));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv4Header>{}
}
}
pub fn icmpv4_echo_reply(mut self, id: u16, seq: u16) -> PacketBuilderStep<Icmpv4Header> {
let echo_header = IcmpEchoHeader{
id,
seq,
};
let icmpv4_echo = Icmpv4Header::new(Icmpv4Type::EchoReply(echo_header));
self.state.transport_header = Some(TransportHeader::Icmpv4(icmpv4_echo));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv4Header>{}
}
}
pub fn icmpv6(mut self, icmp_type: Icmpv6Type) -> PacketBuilderStep<Icmpv6Header> {
self.state.transport_header = Some(TransportHeader::Icmpv6(Icmpv6Header{
icmp_type,
checksum: 0, }));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv6Header>{}
}
}
pub fn icmpv6_raw(mut self, type_u8: u8, code_u8: u8, bytes5to8: [u8;4]) -> PacketBuilderStep<Icmpv6Header> {
let icmp_type = Icmpv6Type::Unknown{type_u8, code_u8, bytes5to8};
self.state.transport_header = Some(TransportHeader::Icmpv6(Icmpv6Header{
icmp_type,
checksum: 0, }));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv6Header>{}
}
}
pub fn icmpv6_echo_request(mut self, id: u16, seq: u16) -> PacketBuilderStep<Icmpv6Header> {
let echo_header = IcmpEchoHeader{
id,
seq,
};
let icmpv6_echo = Icmpv6Header::new(Icmpv6Type::EchoRequest(echo_header));
self.state.transport_header = Some(TransportHeader::Icmpv6(icmpv6_echo));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv6Header>{}
}
}
pub fn icmpv6_echo_reply(mut self, id: u16, seq: u16) -> PacketBuilderStep<Icmpv6Header> {
let echo_header = IcmpEchoHeader{
seq,
id,
};
let icmpv6_echo = Icmpv6Header::new(Icmpv6Type::EchoReply(echo_header));
self.state.transport_header = Some(TransportHeader::Icmpv6(icmpv6_echo));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<Icmpv6Header>{}
}
}
pub fn udp(mut self, source_port: u16, destination_port: u16) -> PacketBuilderStep<UdpHeader> {
self.state.transport_header = Some(TransportHeader::Udp(UdpHeader{
source_port,
destination_port,
length: 0, checksum: 0 }));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<UdpHeader>{}
}
}
pub fn tcp(mut self, source_port: u16, destination_port: u16, sequence_number: u32, window_size: u16) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header = Some(TransportHeader::Tcp(
TcpHeader::new(source_port, destination_port, sequence_number, window_size)
));
PacketBuilderStep {
state: self.state,
_marker: marker::PhantomData::<TcpHeader>{}
}
}
pub fn write<T: io::Write + Sized>(mut self, writer: &mut T, last_next_header_ip_number: u8, payload: &[u8]) -> Result<(),WriteError> {
self.state.ip_header.as_mut().unwrap().set_next_headers(last_next_header_ip_number);
final_write(self, writer, payload)
}
pub fn size(&self, payload_size: usize) -> usize {
final_size(self, payload_size)
}
}
impl PacketBuilderStep<Icmpv4Header> {
pub fn write<T: io::Write + Sized>(self, writer: &mut T, payload: &[u8]) -> Result<(),WriteError> {
final_write(self, writer, payload)
}
pub fn size(&self, payload_size: usize) -> usize {
final_size(self, payload_size)
}
}
impl PacketBuilderStep<Icmpv6Header> {
pub fn write<T: io::Write + Sized>(self, writer: &mut T, payload: &[u8]) -> Result<(),WriteError> {
final_write(self, writer, payload)
}
pub fn size(&self, payload_size: usize) -> usize {
final_size(self, payload_size)
}
}
impl PacketBuilderStep<UdpHeader> {
pub fn write<T: io::Write + Sized>(self, writer: &mut T, payload: &[u8]) -> Result<(),WriteError> {
final_write(self, writer, payload)
}
pub fn size(&self, payload_size: usize) -> usize {
final_size(self, payload_size)
}
}
impl PacketBuilderStep<TcpHeader> {
pub fn ns(mut self) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().ns = true;
self
}
pub fn fin(mut self) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().fin = true;
self
}
pub fn syn(mut self) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().syn = true;
self
}
pub fn rst(mut self) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().rst = true;
self
}
pub fn psh(mut self) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().psh = true;
self
}
pub fn ack(mut self, acknowledgment_number: u32) -> PacketBuilderStep<TcpHeader> {
{
let header = self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap();
header.ack = true;
header.acknowledgment_number = acknowledgment_number;
}
self
}
pub fn urg(mut self, urgent_pointer: u16) -> PacketBuilderStep<TcpHeader> {
{
let header = self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap();
header.urg = true;
header.urgent_pointer = urgent_pointer;
}
self
}
pub fn ece(mut self) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().ece = true;
self
}
pub fn cwr(mut self) -> PacketBuilderStep<TcpHeader> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().cwr = true;
self
}
pub fn options(mut self, options: &[TcpOptionElement]) -> Result<PacketBuilderStep<TcpHeader>, TcpOptionWriteError> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().set_options(options)?;
Ok(self)
}
pub fn options_raw(mut self, options: &[u8]) -> Result<PacketBuilderStep<TcpHeader>, TcpOptionWriteError> {
self.state.transport_header.as_mut().unwrap().mut_tcp().unwrap().set_options_raw(options)?;
Ok(self)
}
pub fn write<T: io::Write + Sized>(self, writer: &mut T, payload: &[u8]) -> Result<(),WriteError> {
final_write(self, writer, payload)
}
pub fn size(&self, payload_size: usize) -> usize {
final_size(self, payload_size)
}
}
fn final_write<T: io::Write + Sized, B>(builder: PacketBuilderStep<B>, writer: &mut T, payload: &[u8]) -> Result<(),WriteError> {
let ip_ether_type = {
use crate::IpHeader::*;
match builder.state.ip_header {
Some(Version4(_,_)) => ether_type::IPV4,
Some(Version6(_,_)) => ether_type::IPV6,
None => panic!("Missing ip header")
}
};
if let Some(mut eth) = builder.state.ethernet2_header {
eth.ether_type = {
use crate::VlanHeader::*;
match builder.state.vlan_header {
Some(Single(_)) => ether_type::VLAN_TAGGED_FRAME,
Some(Double(_)) => ether_type::PROVIDER_BRIDGING,
None => ip_ether_type
}
};
eth.write(writer)?;
}
use crate::VlanHeader::*;
match builder.state.vlan_header {
Some(Single(mut value)) => {
value.ether_type = ip_ether_type;
value.write(writer)?;
},
Some(Double(mut value)) => {
value.outer.ether_type = ether_type::VLAN_TAGGED_FRAME;
value.inner.ether_type = ip_ether_type;
value.write(writer)?;
},
None => {}
}
use crate::IpHeader::*;
let ip_header = builder.state.ip_header.unwrap();
let transport = builder.state.transport_header;
match transport {
None => {
match ip_header {
Version4(mut ip, ext) => {
ip.set_payload_len(ext.header_len() + payload.len())?;
ip.write(writer)?;
ext.write(writer, ip.protocol)?;
},
Version6(mut ip, ext) => {
ip.set_payload_length(ext.header_len() + payload.len())?;
ip.write(writer)?;
ext.write(writer, ip.next_header)?;
}
}
},
Some(mut transport) => {
match ip_header {
Version4(mut ip, mut ext) => {
let transport_size = transport.header_len() + payload.len();
ip.set_payload_len(ext.header_len() + transport_size)?;
use crate::TransportHeader::*;
match transport {
Icmpv4(_) => {},
Icmpv6(_) => {},
Udp(ref mut udp) => { udp.length = transport_size as u16; }
Tcp(_) => {},
}
ip.protocol = ext.set_next_headers(
match transport {
Icmpv4(_) => ip_number::ICMP,
Icmpv6(_) => ip_number::IPV6_ICMP,
Udp(_) => ip_number::UDP,
Tcp(_) => ip_number::TCP
}
);
transport.update_checksum_ipv4(&ip, payload)?;
ip.write(writer)?;
ext.write(writer, ip.protocol)?;
},
Version6(mut ip, mut ext) => {
let transport_size = transport.header_len() + payload.len();
ip.set_payload_length(ext.header_len() + transport_size)?;
use crate::TransportHeader::*;
match transport {
Icmpv4(_) => {},
Icmpv6(_) => {},
Udp(ref mut udp) => { udp.length = transport_size as u16; }
Tcp(_) => {}
}
ip.next_header = ext.set_next_headers(
match transport {
Icmpv4(_) => ip_number::ICMP,
Icmpv6(_) => ip_number::IPV6_ICMP,
Udp(_) => ip_number::UDP,
Tcp(_) => ip_number::TCP
}
);
transport.update_checksum_ipv6(&ip, payload)?;
ip.write(writer)?;
ext.write(writer, ip.next_header)?;
}
}
transport.write(writer)?;
},
}
writer.write_all(payload)?;
Ok(())
}
fn final_size<B>(builder: &PacketBuilderStep<B>, payload_size: usize) -> usize {
use crate::IpHeader::*;
use crate::VlanHeader::*;
use crate::TransportHeader::*;
(match builder.state.ethernet2_header {
Some(_) => Ethernet2Header::SERIALIZED_SIZE,
None => 0
}) + match builder.state.vlan_header {
Some(Single(_)) => SingleVlanHeader::SERIALIZED_SIZE,
Some(Double(_)) => DoubleVlanHeader::SERIALIZED_SIZE,
None => 0
} + match builder.state.ip_header {
Some(Version4(ref value, ref ext)) => value.header_len() + ext.header_len(),
Some(Version6(_, ref ext)) => Ipv6Header::SERIALIZED_SIZE + ext.header_len(),
None => 0
} + match builder.state.transport_header {
Some(Icmpv4(ref value)) => value.header_len(),
Some(Icmpv6(ref value)) => value.header_len(),
Some(Udp(_)) => UdpHeader::SERIALIZED_SIZE,
Some(Tcp(ref value)) => value.header_len() as usize,
None => 0
} + payload_size
}
#[cfg(test)]
mod whitebox_tests {
use super::*;
#[test]
fn size() {
assert_eq!(0,
PacketBuilderStep::<UdpHeader> {
state: PacketImpl {
ethernet2_header: None,
ip_header: None,
vlan_header: None,
transport_header: None
},
_marker: marker::PhantomData::<UdpHeader>{}
}.size(0));
}
#[test]
#[should_panic]
fn final_write_panic_missing_ip() {
let mut writer = Vec::new();
final_write(
PacketBuilderStep::<UdpHeader> {
state: PacketImpl {
ethernet2_header: None,
ip_header: None,
vlan_header: None,
transport_header: None
},
_marker: marker::PhantomData::<UdpHeader>{}
},
&mut writer,
&[]
).unwrap();
}
}