def test_synack_packet_invalid(self): # Input: packet with any flag other than SYN set p = Packet( packet.Type.DATA, 0, 0, None) with self.assertRaises(TypeError) as cm: packet.create_synack_packet(p) self.assertEqual(str(cm.exception), "packet must have only SYN flag set")
def test_data(self, mock_socket): data = bytes([128] * packet.MAX_LENGTH * 10) data_packets = packet.create_data_packets(data, 1) # return a different value on each call mock_socket.recvfrom.side_effect = [(packet.pack_packet(data_packets[0]), "127.0.0.1"), (packet.pack_packet(data_packets[1]), "127.0.0.1"), (packet.pack_packet(data_packets[2]), "127.0.0.1"), (packet.pack_packet(data_packets[3]), "127.0.0.1"), (packet.pack_packet(data_packets[4]), "127.0.0.1"), (packet.pack_packet(data_packets[5]), "127.0.0.1"), (packet.pack_packet(data_packets[6]), "127.0.0.1"), (packet.pack_packet(data_packets[7]), "127.0.0.1"), (packet.pack_packet(data_packets[8]), "127.0.0.1"), (packet.pack_packet(data_packets[9]), "127.0.0.1"), (packet.pack_packet(packet.create_fin_packet()), "127.0.0.1")] expected_ack = packet.create_ack_packet_from_data(data_packets[9], 0) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.latest_ack = packet.create_synack_packet(packet.create_syn_packet()) r.ack_num = 1 for i in range(11): r.handle_next_packet() mock_socket.sendto.assert_called_with(packet.pack_packet(expected_ack), ("127.0.0.1", 10)) self.assertEqual(r.ack_num, 14611)
def test_syn(self, mock_socket): # mock variables syn_packet = packet.create_syn_packet() mock_socket.recvfrom.return_value = (packet.pack_packet(syn_packet), "127.0.0.1") expected_response = packet.pack_packet(packet.create_synack_packet(syn_packet)) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.wait_for_syn() mock_socket.sendto.assert_called_with(expected_response, ("127.0.0.1", 10))
def test_data_timeout(self, mock_socket): mock_socket.recvfrom.side_effect = socket.timeout("timed out") latest_ack = packet.create_synack_packet(packet.create_syn_packet()) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.latest_ack = latest_ack r.handle_next_packet() mock_socket.sendto.assert_called_with(packet.pack_packet(latest_ack), ("127.0.0.1", 10))
def test_dup_syn(self, mock_socket): syn_packet = packet.create_syn_packet() mock_socket.recvfrom.side_effect = [(packet.pack_packet(syn_packet), "127.0.0.1"), (packet.pack_packet(syn_packet), "127.0.0.1")] expected_response = packet.pack_packet(packet.create_synack_packet(syn_packet)) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.wait_for_syn() r.handle_next_packet() mock_socket.sendto.assert_called_with(expected_response, ("127.0.0.1", 10)) # assert_called_with = most recent call
def test_synack_packet_valid(self): # Input: packet with SYN flag set, data len 0, seq 0 (other vars ignored) p = Packet( packet.Type.SYN, 0, 0, None) # Expected output: packet with # sequence number: 0 # ack number: 1 (next expected byte) # data len: 0 # data: none result = packet.create_synack_packet(p) self.assertEqual(result.flags, packet.Type.SYN | packet.Type.ACK) self.assertEqual(result.seq_num, 0) self.assertEqual(result.ack_num, 1) self.assertEqual(result.data_len, 0) self.assertEqual(result.data, None)
def wait_for_syn(self): while(True): pkt = self.wait_for_packet(False) if(pkt.flags == packet.Type.FIN): print("received FIN packet, finishing up") self.is_done = True self.finish_status = DONE return elif(pkt.flags == (packet.Type.EOT | packet.Type.ACK)): print("received EOT/ACK packet while waiting for SYN; remote side didn't receive final ACK, retransmitting") self.sock.sendto(packet.pack_packet(packet.create_ack_packet(0, 0)), (self.emulator, self.port)) elif(pkt.flags == packet.Type.SYN): break print("received SYN packet; responding with SYN/ACK") self.latest_ack = packet.create_synack_packet(pkt) response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) self.ack_num = 1
def handle_next_packet(self): if(self.rcvd_window_bytes == (self.window_size * packet.MAX_DATA_LENGTH) or self.ack_now): print("sending ack {}".format(self.ack_num)) response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) self.ack_now = False self.reacked = False self.rcvd_window_bytes = 0 # write buffer to file and create an empty buffer self.file.write(self.buf) self.buf = bytearray() print("waiting for next packet...") rcvd = self.wait_for_packet(True) # wait_for_packet returns None on timeout if(rcvd == None): self.reacked = False if(not self.got_eot): # re-send last ACK print("timed out while waiting for packet; retransmitting ack with ack number {}".format(self.ack_num)) response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) else: # need to resend EOT/ACK print("timed out while waiting for final ACK; retransmitting EOT/ACK") self.sock.sendto(packet.pack_packet(packet.create_eot_ack_packet()), (self.emulator, self.port)) elif(rcvd.flags == packet.Type.SYN): print("received another SYN packet; responding with SYN/ACK") response = packet.pack_packet(packet.create_synack_packet(rcvd)) self.sock.sendto(response, (self.emulator, self.port)) elif(rcvd.flags == packet.Type.FIN): print("received FIN packet, finishing up") self.is_done = True self.finish_status = DONE elif(rcvd.flags == packet.Type.ACK and self.got_eot): print("received ACK for EOT/ACK, switching modes") self.is_done = True self.finish_status = SWITCH elif(rcvd.flags == packet.Type.EOT and not self.got_eot): print("received EOT packet, responding with EOT/ACK") self.sock.sendto(packet.pack_packet(packet.create_eot_ack_packet()), (self.emulator, self.port)) self.got_eot = True elif(rcvd.flags == packet.Type.DATA): # we got a spurious retransmission if(rcvd.seq_num != self.ack_num): if(rcvd.seq_num < self.ack_num): print("spurious retransmission with sequence number {}".format(rcvd.seq_num)) if(not self.reacked): print("retransmitting ACK in response to spurious retransmission") response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) self.reacked_seq_num = rcvd.seq_num self.reacked = True elif(rcvd.seq_num == self.reacked_seq_num): print("retransmitting ACK in response to spurious retransmission") response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) return else: # != and ! < , so it's greater than the ACK number we were expecting, AKA packets were dropped (or re-ordered, but that's unlikely) print("received packet with sequence number {}, packet with sequence number {} was dropped".format(rcvd.seq_num, self.ack_num)) return # the sender will always send max data unless it's almost out of data # in that case, we don't want to wait for the timeout # we should receive an EOT after this (but it shouldn't actually cause problems if not) if(rcvd.data_len < packet.MAX_DATA_LENGTH): print("packet had length {}; acking now".format(str(rcvd.data_len))) self.ack_now = True self.rcvd_window_bytes += rcvd.data_len self.latest_ack = packet.create_ack_packet_from_data(rcvd, self.seq_num) self.ack_num += rcvd.data_len print("received packet with sequence number {}; received {} bytes this window, current ack number is {}".format(rcvd.seq_num, self.rcvd_window_bytes, self.ack_num)) self.buf.extend(rcvd.data)
print("{}".format(commands[args[0]])) else: print("Type help [command] to view more detail for a command") for cmd in command_briefs: print(cmd) elif(command == "SYN"): if(args): print("SYN doesn't take any arguments. Sending SYN anyway") sock.sendto(packet.pack_packet(packet.create_syn_packet()), (dest, port)) print("sent SYN packet to {} on port {}".format(dest, port)) elif(command == "SYNACK"): if(args): print("SYNACK doesn't take any arguments. Sending SYN/ACK anyway") sock.sendto(packet.pack_packet(packet.create_synack_packet(packet.create_syn_packet())), (dest, port)) print("sent SYN/ACK packet with to {} on port {}".format(dest, port)) elif(command == "ACK"): if(len(args) != 1): print("usage: ACK [ack_num] (enter 'help ACK' for more)") else: sock.sendto(packet.pack_packet(packet.create_ack_packet(int(args[0]), 0)), (dest, port)) print("sent ACK packet with ack {} to {} on port {}".format(args[0], dest, port)) elif(command == "DATA"): if(len(args) != 2): print("usage: DATA [start_seq] [length] (enter 'help DATA' for more')") else: packets = packet.create_data_packets(bytes([128] * int(args[1])), int(args[0])) for p in packets: