use n::packet::*;
use n::l4;
use std::cmp::min;
alias_protocol!(extract_source, tcp, l4, source);
alias_protocol!(fill_source, tcp, l4, source);
alias_protocol!(extract_source_u16, tcp, l4, source, source_u16);
alias_protocol!(apply_source, tcp, l4, source, source_u16);
alias_protocol!(extract_destination, tcp, l4, destination);
alias_protocol!(fill_destination, tcp, l4, destination);
alias_protocol!(extract_destination_u16, tcp, l4, destination, destination_u16);
alias_protocol!(apply_destination, tcp, l4, destination, destination_u16);
extract_field!(extract_sequence, tcp, 4, sequence);
fill_field!(fill_sequence, tcp, 4, sequence);
extract_field_value!(extract_sequence_u32, tcp, sequence, u32);
apply_field_value!(apply_sequence, tcp, sequence, u32);
extract_field!(extract_acknowledgment, tcp, 4, acknowledgment);
fill_field!(fill_acknowledgment, tcp, 4, acknowledgment);
extract_field_value!(extract_acknowledgment_u32, tcp, acknowledgment, u32);
apply_field_value!(apply_acknowledgment, tcp, acknowledgment, u32);
extract_field!(extract_offset_flags, tcp, 2, offset_flags);
fill_field!(fill_offset_flags, tcp, 2, offset_flags);
extract_field!(extract_window, tcp, 2, window);
fill_field!(fill_window, tcp, 2, window);
extract_field_value!(extract_window_u16, tcp, window, u16);
apply_field_value!(apply_window, tcp, window, u16);
extract_field!(extract_checksum, tcp, 2, checksum);
fill_field!(fill_checksum, tcp, 2, checksum);
extract_field_value!(extract_checksum_u16, tcp, checksum, u16);
apply_field_value!(apply_checksum, tcp, checksum, u16);
extract_field!(extract_urgent, tcp, 2, urgent);
fill_field!(fill_urgent, tcp, 2, urgent);
extract_field_value!(extract_urgent_u16, tcp, urgent, u16);
apply_field_value!(apply_urgent, tcp, urgent, u16);
#[millefeuille]
pub fn extract_header_length_u8(packet: Packet) -> Packet {
let mut packet = packet;
let offset;
{
let field = packet.context.get_field("tcp::offset_flags");
offset = field.read_u8(0) >> 4;
}
packet.context.set_u8("tcp::header_length_u8", offset << 2);
packet
}
#[millefeuille]
pub fn apply_header_length(packet: Packet) -> Packet {
let mut packet = packet;
let mut field = packet.context.take_field("tcp::offset_flags");
let value = packet.context.get_u8("tcp::header_length_u8");
let value = ((value >> 2) << 4) & 0xF0u8;
let value = value | (field.read_u8(0) & 0x01u8);
field.write_u8(0, value);
packet.context.set_field("tcp::offset_flags", field);
packet
}
#[millefeuille]
pub fn extract_flags_u16(packet: Packet) -> Packet {
let mut packet = packet;
let flags;
{
let field = packet.context.get_field("tcp::offset_flags");
flags = field.read_u16(0) & 0x01FF;
}
packet.context.set_u16("tcp::flags_u16", flags);
packet
}
#[millefeuille]
pub fn apply_flags(packet: Packet) -> Packet {
let mut packet = packet;
let mut field = packet.context.take_field("tcp::offset_flags");
let value = packet.context.get_u16("tcp::flags_u16");
let value = value & 0x01FF;
let value = value | (((field.read_u8(0) & 0xFE) as u16) << 8);
field.write_u16(0, value);
packet.context.set_field("tcp::offset_flags", field);
packet
}
#[millefeuille]
pub fn prepare_option_parsing(packet: Packet) -> Packet {
let mut packet = packet;
let tcp_hlen = packet.context.get_field("tcp::offset_flags").read_u8(0);
let tcp_hlen = (tcp_hlen >> 4) << 2;
assert!(tcp_hlen >= 20);
packet.context.set_u8("tcp::remaining_options_u8", tcp_hlen - 20);
packet
}
#[millefeuille]
pub fn prepare_option_filling(packet: Packet) -> Packet {
let mut packet = packet;
packet.context.set_u8("tcp::current_options_u8", 0);
packet
}
#[millefeuille]
pub fn has_more_options(packet: Packet) -> Packet {
let mut packet = packet;
let remaining = packet.context.get_u8("tcp::remaining_options_u8");
packet.context.set_bool_released("tcp::more_options_bool", remaining > 0);
packet
}
#[millefeuille]
pub fn extract_current_option(packet: Packet) -> Packet {
let mut remaining = packet.context.get_u8("tcp::remaining_options_u8");
assert!(remaining > 0);
let (mut packet, kind) = packet.right_packet(1);
remaining = remaining - 1;
match kind.read_u8(0) {
0 => {
packet.context.set_u8_released("tcp::remaining_options_u8", 0);
packet.right_strip(remaining as usize)
} 1 => {
packet.context.set_u8_released("tcp::remaining_options_u8", remaining);
packet
} _ => {
let (mut packet, size_field) = packet.right_packet(1);
remaining = remaining - 1;
let size = min(size_field.read_u8(0) - 2, remaining); remaining = remaining - size;
packet.context.set_u8_released("tcp::remaining_options_u8", remaining);
packet.right_strip(size as usize)
} }
}
#[millefeuille]
pub fn verify_header_checksum(packet: Packet) -> Packet {
let mut packet = packet;
let payload_length = min(packet.len(),
packet.context.get_u32("ip::payload_length_u32") as usize);
let mut sum = packet.ones_complement_sum_u16(payload_length) as u32;
sum = sum + packet.context.get_u16("ip::pseudo_csum_u16") as u32;
sum = (sum >> 16) + (sum & 0x0000FFFF);
let result = sum as u16;
packet.context.set_u16("tcp::current_csum_u16", result);
packet.context.set_bool("tcp::correct_csum_bool",
(result == 0xFFFF) || (result == 0x0000));
packet
}
#[millefeuille]
pub fn apply_current_checksum(packet: Packet) -> Packet {
let mut packet = packet;
let mut field = packet.context.take_field("tcp::checksum");
let current = packet.context.get_u16("tcp::current_csum_u16");
let csum = field.read_u16(0);
let current = (!csum) as u32 + current as u32;
let current = ((current >> 16) + (current & 0xFFFF)) as u16;
field.write_u16(0, !current);
packet.context.set_bool_released("tcp::correct_csum_bool", true);
packet.context.set_u16_released("tcp::current_csum_u16", 0);
packet.context.set_field("tcp::checksum", field);
packet
}
#[millefeuille]
pub fn extract(packet: Packet) -> Packet {
let packet = verify_header_checksum(packet);
let packet = extract_source(packet);
let packet = extract_destination(packet);
let packet = extract_sequence(packet);
let packet = extract_acknowledgment(packet);
let packet = extract_offset_flags(packet);
let packet = extract_window(packet);
let packet = extract_checksum(packet);
let packet = extract_urgent(packet);
let packet = prepare_option_parsing(packet);
let mut packet = packet;
loop {
packet = has_more_options(packet);
if !packet.context.get_bool("tcp::more_options_bool") {
break;
}
packet = extract_current_option(packet);
}
packet
}
#[millefeuille]
pub fn fill(packet: Packet) -> Packet {
let packet = prepare_option_filling(packet);
let packet = fill_urgent(packet);
let packet = fill_checksum(packet);
let packet = fill_window(packet);
let packet = fill_offset_flags(packet);
let packet = fill_acknowledgment(packet);
let packet = fill_sequence(packet);
let packet = fill_destination(packet);
let packet = fill_source(packet);
packet
}