Implement TCP representation parsing and emission.
This commit is contained in:
parent
31040bf0fc
commit
513923725e
|
@ -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[..]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[..]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
130
src/wire/tcp.rs
130
src/wire/tcp.rs
|
@ -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[..]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[..]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue