Implement TCP representation parsing and emission.

This commit is contained in:
whitequark 2016-12-20 12:52:33 +00:00
parent 31040bf0fc
commit 513923725e
5 changed files with 145 additions and 8 deletions

View File

@ -462,9 +462,10 @@ mod test {
#[test]
fn test_echo_emit() {
let mut bytes = vec![0; 12];
let repr = echo_packet_repr();
let mut bytes = vec![0; repr.buffer_len()];
let mut packet = Packet::new(&mut bytes).unwrap();
echo_packet_repr().emit(&mut packet);
repr.emit(&mut packet);
assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
}
}

View File

@ -555,7 +555,10 @@ mod test {
0x40, 0x01, 0xd2, 0x79,
0x11, 0x12, 0x13, 0x14,
0x21, 0x22, 0x23, 0x24,
0x00, 0x00, 0x00, 0x00];
0xaa, 0x00, 0x00, 0xff];
static REPR_PAYLOAD_BYTES: [u8; 4] =
[0xaa, 0x00, 0x00, 0xff];
fn packet_repr() -> Repr {
Repr {
@ -574,9 +577,11 @@ mod test {
#[test]
fn test_emit() {
let mut bytes = vec![0; 24];
let repr = packet_repr();
let mut bytes = vec![0; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
let mut packet = Packet::new(&mut bytes).unwrap();
packet_repr().emit(&mut packet, 4);
repr.emit(&mut packet, REPR_PAYLOAD_BYTES.len());
packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
assert_eq!(&packet.into_inner()[..], &REPR_PACKET_BYTES[..]);
}
}

View File

@ -119,3 +119,5 @@ pub use self::udp::Packet as UdpPacket;
pub use self::udp::Repr as UdpRepr;
pub use self::tcp::Packet as TcpPacket;
pub use self::tcp::Repr as TcpRepr;
pub use self::tcp::Control as TcpControl;

View File

@ -239,7 +239,9 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
#[inline(always)]
pub fn clear_flags(&mut self) {
let data = self.buffer.as_mut();
NetworkEndian::write_u16(&mut data[field::FLAGS], 0)
let raw = NetworkEndian::read_u16(&data[field::FLAGS]);
let raw = raw & !0x0fff;
NetworkEndian::write_u16(&mut data[field::FLAGS], raw)
}
/// Set the FIN flag.
@ -382,6 +384,96 @@ impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
}
}
/// A high-level representation of a Transmission Control Protocol packet.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Repr<'a> {
src_port: u16,
dst_port: u16,
seq_number: u32,
ack_number: Option<u32>,
window_len: u16,
control: Control,
payload: &'a [u8]
}
/// The control flags of a Transmission Control Protocol packet.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Control {
None,
Syn,
Fin,
Rst
}
impl<'a> Repr<'a> {
/// Parse a Transmission Control Protocol packet and return a high-level representation.
pub fn parse<T: ?Sized>(packet: &Packet<&'a T>,
src_addr: &InternetAddress,
dst_addr: &InternetAddress) -> Result<Repr<'a>, Error>
where T: AsRef<[u8]> {
// Source and destination ports must be present.
if packet.src_port() == 0 { return Err(Error::Malformed) }
if packet.dst_port() == 0 { return Err(Error::Malformed) }
// Valid checksum is expected...
if !packet.verify_checksum(src_addr, dst_addr) { return Err(Error::Checksum) }
let control =
match (packet.syn(), packet.fin(), packet.rst()) {
(false, false, false) => Control::None,
(true, false, false) => Control::Syn,
(false, true, false) => Control::Fin,
(false, false, true ) => Control::Rst,
_ => return Err(Error::Malformed)
};
let ack_number =
match packet.ack() {
true => Some(packet.ack_number()),
false => None
};
// The PSH flag is ignored.
// The URG flag and the urgent field is ignored. This behavior is standards-compliant,
// however, most deployed systems (e.g. Linux) are *not* standards-compliant, and would
// cut the byte at the urgent pointer from the stream.
Ok(Repr {
src_port: packet.src_port(),
dst_port: packet.dst_port(),
seq_number: packet.seq_number(),
ack_number: ack_number,
window_len: packet.window_len(),
control: control,
payload: packet.payload()
})
}
/// Return the length of a packet that will be emitted from this high-level representation.
pub fn buffer_len(&self) -> usize {
field::URGENT.end + self.payload.len()
}
/// Emit a high-level representation into a Transmission Control Protocol packet.
pub fn emit<T: ?Sized>(&self, packet: &mut Packet<&mut T>,
src_addr: &InternetAddress,
dst_addr: &InternetAddress)
where T: AsRef<[u8]> + AsMut<[u8]> {
packet.set_src_port(self.src_port);
packet.set_dst_port(self.dst_port);
packet.set_seq_number(self.seq_number);
packet.set_ack_number(self.ack_number.unwrap_or(0));
packet.set_window_len(self.window_len);
packet.set_header_len(20);
packet.clear_flags();
match self.control {
Control::None => (),
Control::Syn => packet.set_syn(true),
Control::Fin => packet.set_fin(true),
Control::Rst => packet.set_rst(true)
}
packet.payload_mut().copy_from_slice(self.payload);
packet.fill_checksum(src_addr, dst_addr)
}
}
#[cfg(test)]
mod test {
use wire::Ipv4Address;
@ -444,4 +536,40 @@ mod test {
packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
}
static SYN_PACKET_BYTES: [u8; 24] =
[0xbf, 0x00, 0x00, 0x50,
0x01, 0x23, 0x45, 0x67,
0x00, 0x00, 0x00, 0x00,
0x50, 0x02, 0x01, 0x23,
0x7a, 0x8d, 0x00, 0x00,
0xaa, 0x00, 0x00, 0xff];
fn packet_repr() -> Repr<'static> {
Repr {
src_port: 48896,
dst_port: 80,
seq_number: 0x01234567,
ack_number: None,
window_len: 0x0123,
control: Control::Syn,
payload: &PAYLOAD_BYTES
}
}
#[test]
fn test_parse() {
let packet = Packet::new(&SYN_PACKET_BYTES[..]).unwrap();
let repr = Repr::parse(&packet, &SRC_ADDR.into(), &DST_ADDR.into()).unwrap();
assert_eq!(repr, packet_repr());
}
#[test]
fn test_emit() {
let repr = packet_repr();
let mut bytes = vec![0; repr.buffer_len()];
let mut packet = Packet::new(&mut bytes).unwrap();
repr.emit(&mut packet, &SRC_ADDR.into(), &DST_ADDR.into());
assert_eq!(&packet.into_inner()[..], &SYN_PACKET_BYTES[..]);
}
}

View File

@ -298,9 +298,10 @@ mod test {
#[test]
fn test_emit() {
let mut bytes = vec![0; 12];
let repr = packet_repr();
let mut bytes = vec![0; repr.buffer_len()];
let mut packet = Packet::new(&mut bytes).unwrap();
packet_repr().emit(&mut packet, &SRC_ADDR.into(), &DST_ADDR.into());
repr.emit(&mut packet, &SRC_ADDR.into(), &DST_ADDR.into());
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
}
}