def test_to_bytes(self): tcp_packet1 = TcpPacket( source_port=59700, dest_port=443, sequence_number=1407506493, ack_number=3676709599, flags=TcpControlBits(ack=True), win_size=501, urg_pointer=0, options=TcpOptions([ TcpOptions.NOP, TcpOptions.NOP, (TcpOptions.TIMESTAMPS, [3252488245, 365238493]) ]), ) tcp_packet1 = IpPacket(source_addr_str="192.168.1.32", dest_addr_str="35.160.240.60") / tcp_packet1 self.__test_tcp_packet(PACKET_DUMP_1, tcp_packet1) tcp_packet2 = TcpPacket(source_port=44134, dest_port=443, sequence_number=2302261952, ack_number=1291093731, flags=TcpControlBits(ack=True), win_size=496) tcp_packet2 = IpPacket(source_addr_str="10.10.128.44", dest_addr_str="40.101.18.242") / tcp_packet2 self.__test_tcp_packet(PACKET_DUMP_2, tcp_packet2) tcp_packet3 = TcpPacket( source_port=43480, dest_port=2193, sequence_number=703011338, ack_number=2915529351, flags=TcpControlBits(ack=True, psh=True), win_size=22461, options=TcpOptions([ TcpOptions.NOP, TcpOptions.NOP, (TcpOptions.TIMESTAMPS, [1314978149, 3029537658]) ]), ) / bytearray.fromhex(PACKET_DUMP_3_PAYLOAD) tcp_packet3 = IpPacket(source_addr_str="10.10.128.44", dest_addr_str="10.10.144.153") / tcp_packet3 self.__test_tcp_packet(PACKET_DUMP_3, tcp_packet3) tcp_packet4 = TcpPacket( source_port=59058, dest_port=443, sequence_number=746641599, ack_number=1952224292, flags=TcpControlBits(ack=True, psh=True), win_size=2483, options=TcpOptions([ TcpOptions.NOP, TcpOptions.NOP, (TcpOptions.TIMESTAMPS, [4044761679, 555562620]) ]), ) / bytearray.fromhex(PACKET_DUMP_4_PAYLOAD) tcp_packet4 = IpPacket(source_addr_str="192.168.1.32", dest_addr_str="93.186.225.198") / tcp_packet4 self.__test_tcp_packet(PACKET_DUMP_4, tcp_packet4)
def test_from_int(self): flags_syn = TcpControlBits.from_int(self.FLAGS_SYN) self.assertEqual(self.FLAGS_SYN, flags_syn.flags) flags_psh_ack = TcpControlBits.from_int(self.FLAGS_PSH_ACK) self.assertEqual(self.FLAGS_PSH_ACK, flags_psh_ack.flags) flags_all = TcpControlBits.from_int(self.FLAGS_ALL) self.assertEqual(self.FLAGS_ALL, flags_all.flags)
def test_flags_some_set(self): tcp_control_flags = TcpControlBits(ack=True, psh=True) self.assertEqual(self.FLAGS_PSH_ACK, tcp_control_flags.flags) self.assertTrue(tcp_control_flags.is_flag_set(TcpControlBits.ACK)) self.assertTrue(tcp_control_flags.is_flag_set(TcpControlBits.PSH)) self.assertFalse(tcp_control_flags.ns or tcp_control_flags.cwr or tcp_control_flags.urg or tcp_control_flags.ece or tcp_control_flags.rst or tcp_control_flags.syn or tcp_control_flags.fin) self.assertTrue(tcp_control_flags.ack and tcp_control_flags.psh)
def __init__(self, source_port: int, dest_port: int, sequence_number: int = 0, ack_number: int = 0, flags: TcpControlBits = TcpControlBits(), win_size: int = 65535, urg_pointer: int = 0, options: TcpOptions = TcpOptions()): """ Initializes TCP packet instance :param source_port: Source port field value, integer in range [0; 65535] :param dest_port: Destination port field value, integer in range [0; 65535] :param sequence_number: Sequence number field value. Has a dual role: If the SYN flag is set (1), then this is the initial sequence number. The sequence number of the actual first data byte and the acknowledged number in the corresponding ACK are then this sequence number plus 1. If the SYN flag is clear (0), then this is the accumulated sequence number of the first data byte of this segment for the current session. :param ack_number: Acknowledgment number field value. If the ACK flag is set then the value of this field is the next sequence number that the sender of the ACK is expecting.This acknowledges receipt of all prior bytes (if any). The first ACK sent by each end acknowledges the other end's initial sequence number itself, but no data. :param flags: Flags field. Instance of TcpControlBits class. Contains 9 1-bit flags (control bits) :param win_size: Window size field value. The size of the receive window, which specifies the number of window size units that the sender of this segment is currently willing to receive. :param urg_pointer: Urgent pointer field value. If the URG flag is set, then this 16-bit field is an offset from the sequence number indicating the last urgent data byte. :param options: Options field. Instance of TcpOptions class. """ super().__init__() self.__source_port = TransportLayerUtils.validate_port_num(source_port) self.__dest_port = TransportLayerUtils.validate_port_num(dest_port) self.__sequence_number = sequence_number self.__ack_number = ack_number self.__flags = flags self.__win_size = win_size self.__urg_pointer = urg_pointer self.__options = options
def test_flags_all_set(self): tcp_control_flags = TcpControlBits(ns=True, cwr=True, urg=True, ece=True, ack=True, psh=True, rst=True, syn=True, fin=True) self.assertTrue(tcp_control_flags.ns and tcp_control_flags.cwr and tcp_control_flags.urg and tcp_control_flags.ece and tcp_control_flags.ack and tcp_control_flags.psh and tcp_control_flags.rst and tcp_control_flags.syn and tcp_control_flags.fin) self.assertEqual(self.FLAGS_ALL, tcp_control_flags.flags)
def from_bytes(packet_bytes: bytes): header_bytes = packet_bytes[:TcpUtils.TCP_HEADER_LENGTH_BYTES] payload_and_options = packet_bytes[TcpUtils.TCP_HEADER_LENGTH_BYTES:] header_fields = struct.unpack(TcpPacket.TCP_HEADER_FORMAT, header_bytes) source_port = header_fields[0] dest_port = header_fields[1] seq_num = header_fields[2] ack_num = header_fields[3] data_offset_flags = header_fields[4] win_size = header_fields[5] # 6-th item is checksum, don't need to extract it, # since it will be calculated later urg_pointer = header_fields[7] # take first 4 bits data_offset = data_offset_flags >> 12 # take 5-th, 6-th, 7-th bits reserved_bits = (data_offset_flags >> 9) & 7 if reserved_bits != 0: raise ValueError("Reserved bits should be set to zero") # take last 9 bits flags = TcpControlBits.from_int(data_offset_flags & 511) # compute options field length in bytes options_len = (data_offset - TcpUtils.TCP_HEADER_LENGTH) * 4 options = TcpOptions.from_bytes(payload_and_options[:options_len]) tcp_header = TcpPacket( dest_port=dest_port, source_port=source_port, sequence_number=seq_num, ack_number=ack_num, flags=flags, win_size=win_size, urg_pointer=urg_pointer, options=options, ) payload = payload_and_options[options_len:] return tcp_header / payload if len(payload) else tcp_header
def test_tcp_ip_payload(self): ethernet_header_hex = TCP_IP_PAYLOAD_TEST_CONTEXT["ETHERNET_HEADER"] ip_payload_hex = TCP_IP_PAYLOAD_TEST_CONTEXT["IP_PAYLOAD"] tcp_payload_hex = TCP_IP_PAYLOAD_TEST_CONTEXT["TCP_PAYLOAD"] packet_hex = ethernet_header_hex + ip_payload_hex + tcp_payload_hex ethernet_packet = EthernetPacket(dest_mac="e0:d5:5e:21:b0:cb", source_mac="00:7e:95:02:61:42") self.assertEqual(ethernet_header_hex, ethernet_packet.to_bytes().hex()) ip_packet = IpPacket(source_addr_str="3.123.217.208", dest_addr_str="10.10.128.44", identification=11150, flags=IpFragmentationFlags(df=True), ttl=47, protocol=socket.IPPROTO_TCP) tcp_packet = TcpPacket( source_port=443, dest_port=55978, sequence_number=2555500760, ack_number=1254966751, flags=TcpControlBits(ack=True), win_size=10, options=TcpOptions([ TcpOptions.NOP, TcpOptions.NOP, (TcpOptions.TIMESTAMPS, [654701382, 3921945890]) ]), ) packet = ethernet_packet / ip_packet / tcp_packet self.assertEqual(packet_hex, packet.to_bytes().hex()) self.assertEqual(packet, EthernetPacket.from_bytes(bytes.fromhex(packet_hex))) self.assertTrue(EthernetPacket in packet) self.assertTrue(IpPacket in packet) self.assertTrue(TcpPacket in packet)
def test_is_response(self): # 'syn' sent, wait for 'syn/ack' tcp_packet = TcpPacket(source_port=44134, dest_port=443, sequence_number=2302261952, flags=TcpControlBits(syn=True)) tcp_response = TcpPacket(source_port=443, dest_port=44134, ack_number=2302261952 + 1, flags=TcpControlBits(syn=True, ack=True)) self.assertTrue(tcp_response.is_response(tcp_packet)) # 'syn/ack' sent, wait for 'ack' tcp_packet2 = TcpPacket(source_port=44134, dest_port=443, sequence_number=2302261952, flags=TcpControlBits(syn=True, ack=True)) tcp_response2 = TcpPacket(source_port=443, dest_port=44134, ack_number=2302261952 + 1, flags=TcpControlBits(ack=True)) self.assertTrue(tcp_response2.is_response(tcp_packet2)) # 'syn' sent, wait for 'rst' received tcp_packet3 = TcpPacket(source_port=44134, dest_port=443, flags=TcpControlBits(syn=True)) tcp_response3 = TcpPacket(source_port=443, dest_port=44134, flags=TcpControlBits(rst=True)) self.assertTrue(tcp_response3.is_response(tcp_packet3)) # ports mismatch tcp_packet4 = TcpPacket(source_port=44134, dest_port=443) tcp_response4 = TcpPacket(source_port=443, dest_port=44135) self.assertFalse(tcp_response4.is_response(tcp_packet4)) # 'syn' sent, but no 'syn/ack' received tcp_packet5 = TcpPacket(source_port=44134, dest_port=443, sequence_number=2302261952, flags=TcpControlBits(syn=True)) tcp_response5 = TcpPacket( source_port=443, dest_port=44134, ack_number=2302261953, ) self.assertFalse(tcp_response5.is_response(tcp_packet5)) # 'syn' sent, 'syn/ack' received, but seq/ack numbers mismatch tcp_packet6 = TcpPacket(source_port=44134, dest_port=443, sequence_number=2302261952, flags=TcpControlBits(syn=True)) tcp_response6 = TcpPacket(source_port=443, dest_port=44134, flags=TcpControlBits(syn=True, ack=True)) self.assertFalse(tcp_response6.is_response(tcp_packet6)) # 'rst' sent, no response expected tcp_packet7 = TcpPacket(source_port=44134, dest_port=443, flags=TcpControlBits(rst=True)) tcp_response7 = TcpPacket( source_port=443, dest_port=44134, ) self.assertFalse(tcp_response7.is_response(tcp_packet7)) # 20 bytes of data sent, 'ack' expected tcp_packet8 = TcpPacket( source_port=44134, dest_port=443, flags=TcpControlBits(ack=True), sequence_number=2302261952, ) / bytes(20) tcp_response8 = TcpPacket(source_port=443, dest_port=44134, flags=TcpControlBits(ack=True), ack_number=2302261952 + 20) self.assertTrue(tcp_response8.is_response(tcp_packet8))
def test_flags_none_set(self): tcp_control_flags = TcpControlBits() self.assertEqual(0, tcp_control_flags.flags)
def test_flags_one_set(self): tcp_control_flags = TcpControlBits(syn=True) self.assertEqual(self.FLAGS_SYN, tcp_control_flags.flags) self.assertTrue(tcp_control_flags.is_flag_set(TcpControlBits.SYN)) self.assertTrue(tcp_control_flags.syn)