Implement TCP representation parsing and emission.
This commit is contained in:
parent
31040bf0fc
commit
513923725e
|
@ -462,9 +462,10 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_echo_emit() {
|
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();
|
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[..]);
|
assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,7 +555,10 @@ mod test {
|
||||||
0x40, 0x01, 0xd2, 0x79,
|
0x40, 0x01, 0xd2, 0x79,
|
||||||
0x11, 0x12, 0x13, 0x14,
|
0x11, 0x12, 0x13, 0x14,
|
||||||
0x21, 0x22, 0x23, 0x24,
|
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 {
|
fn packet_repr() -> Repr {
|
||||||
Repr {
|
Repr {
|
||||||
|
@ -574,9 +577,11 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_emit() {
|
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();
|
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[..]);
|
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::udp::Repr as UdpRepr;
|
||||||
|
|
||||||
pub use self::tcp::Packet as TcpPacket;
|
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)]
|
#[inline(always)]
|
||||||
pub fn clear_flags(&mut self) {
|
pub fn clear_flags(&mut self) {
|
||||||
let data = self.buffer.as_mut();
|
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.
|
/// 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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use wire::Ipv4Address;
|
use wire::Ipv4Address;
|
||||||
|
@ -444,4 +536,40 @@ mod test {
|
||||||
packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
|
packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
|
||||||
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
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]
|
#[test]
|
||||||
fn test_emit() {
|
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();
|
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[..]);
|
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue