def ping(client_socket, dest_host, client_id, seq_no=0): """ Sends echo request, receives response, and returns RTT. """ def icmp_header(host_checksum): message = ICMPMessage(type=ECHO_REQUEST.type, code=ECHO_REQUEST.code, checksum=socket.htons(host_checksum), identifier=client_id, sequence_number=seq_no) return struct.pack(ICMP_STRUCT_FIELDS, *message) # Create payload for ICMP packet, being the time of its creation icmp_payload = struct.pack('d', this_instant()) # double-precision float # Structure packet with checksum value initialised as zero icmp_packet_without_checksum = icmp_header(0) + icmp_payload # Calculate checksum value to be used checksum = internet_checksum(icmp_packet_without_checksum) # Create final packet to send, with checksum in header, and payload icmp_packet = icmp_header(checksum) + icmp_payload # Create variable of the IPv4 destination address, for future use dest_host = socket.gethostbyname(dest_host) # Send previously created ICMP packet, to dest host, via client socket client_socket.sendto(icmp_packet, (dest_host, ICMP_PORT_PLACEHOLDER)) # Blocking code, that waits for reply from the receiver of ICMP packet datagram, address = client_socket.recvfrom(BUFFER_SIZE) # Store this_instant() at which datagram was received time_recv = this_instant() # Strip IP header off of received datagram (to isolate ICMP packet) icmp_packet = datagram[20:] # Use checksum to validate contents of ICMP packet checksum = internet_checksum(icmp_packet) if (checksum != 0): raise ChecksumError # Extract header information of response ICMP packet icmp_header_response = ICMPMessage( *struct.unpack(ICMP_STRUCT_FIELDS, icmp_packet[:8])) # Extract body of response of ICMP response packet icmp_message_response = icmp_packet[8:] # Unpack binary data to recover what time the packet was sent at time_sent = struct.unpack('d', icmp_message_response)[0] # Calculate round-trip time by finding the diff between time sent/received RTT = (time_recv - time_sent) * MILLISEC_PER_SEC # Return both the RTT, and the header of the response return (RTT, icmp_header_response)
def ping(client_socket, dest_host, client_id, seq_no=0): """ Sends echo request, receives response, and returns RTT. """ def icmp_header(host_checksum): message = ICMPMessage(type=ECHO_REQUEST.type, code=ECHO_REQUEST.code, checksum=host_checksum, identifier=client_id, sequence_number=seq_no) return struct.pack(ICMP_STRUCT_FIELDS, *message) icmp_payload = struct.pack('d', this_instant()) # double-precision float icmp_packet_without_checksum = icmp_header(0) + icmp_payload checksum = internet_checksum(icmp_packet_without_checksum) checksum_string = hex(checksum) checksum_string_reversed = checksum_string[4:] + checksum_string[2:4] checksum_int_reversed = int(checksum_string_reversed, 16) icmp_packet = icmp_header(checksum_int_reversed) + icmp_payload # Get the host name (unchanged if already in IPv4 address format) dest_host = socket.gethostbyname(dest_host) # Send packet to destination host client_socket.sendto(icmp_packet, (dest_host, ICMP_PORT_PLACEHOLDER)) # Try to get response datagram, addr = client_socket.recvfrom(BUFFER_SIZE) time_recv = this_instant() # Extract ICMP packet from datagram (drop IP Header) icmp_packet_recv = datagram[IP_HEADER_LENGTH:] # Compute checksum on ICMP response packet (header and payload) checksum_recv = internet_checksum(icmp_packet_recv) if checksum_recv != 0: raise ChecksumError() # Extract ICMP response header from ICMP packet (8 bytes) and unpack icmp_recv_header = icmp_packet_recv[0:ICMP_HEADER_LENGTH] recv_header = struct.unpack(ICMP_STRUCT_FIELDS, icmp_recv_header) # Extract ICMP response payload (remaining bytes) and unpack icmp_recv_payolad = icmp_packet_recv[ICMP_HEADER_LENGTH:] time_sent = struct.unpack('d', icmp_recv_payolad)[0] # Compute round-trip time from "time sent" rtt = (time_recv - time_sent) * MILLISEC_PER_SEC return (rtt, recv_header)
def ping(client_socket, dest_host, client_id, seq_no=0): """ Sends echo request, receives response, and returns RTT. """ def icmp_header(host_checksum): message = ICMPMessage( type=None, # TODO: Use appropriate argument here code=None, # TODO: Use appropriate argument here checksum=host_checksum, identifier=client_id, sequence_number=seq_no) return struct.pack(ICMP_STRUCT_FIELDS, *message) # TODO: Please study these lines carefully, # noting that "icmp_pack()" (defined above) is called *twice* icmp_payload = struct.pack('d', this_instant()) # double-precision float icmp_packet_without_checksum = icmp_header(0) + icmp_payload checksum = internet_checksum(icmp_packet_without_checksum) icmp_packet = icmp_header(checksum) + icmp_payload # # TODO: Please note that that "icmp_packet" is the # payload that we'll send through for our INET raw socket # # Note: socket.gethostbyname() returns the host name # unchanged if it is already in IPv4 address format. dest_host = socket.gethostbyname(dest_host)
def ping(client_socket, dest_host, client_id, seq_no=0): """ Sends echo request, receives response, and returns RTT. """ def icmp_header(host_checksum): message = ICMPMessage( type=ECHO_REQUEST.type, # TODO: Use appropriate argument here code=ECHO_REQUEST.code, # TODO: Use appropriate argument here checksum=host_checksum, identifier=client_id, sequence_number=seq_no) return struct.pack(ICMP_STRUCT_FIELDS, *message) # TODO: Please study these lines carefully, # noting that "icmp_pack()" (defined above) is called *twice* icmp_payload = struct.pack('d', this_instant()) # double-precision float icmp_packet_without_checksum = icmp_header(0) + icmp_payload checksum = internet_checksum(icmp_packet_without_checksum) icmp_packet = icmp_header(checksum) + icmp_payload # # TODO: Please note that that "icmp_packet" is the # payload that we'll send through for our INET raw socket # # Note: socket.gethostbyname() returns the host name # unchanged if it is already in IPv4 address format. dest_host = socket.gethostbyname(dest_host) client_socket.sendto(icmp_packet,(dest_host,ICMP_PORT_PLACEHOLDER)) client_socket.shutdown(socket.SHUT_WR) reply,addr=client_socket.recvfrom(2048) #hanging recieve_time = this_instant() rpacket = reply[20:] rheader = rpacket[:8] rimcp_packet = struct.unpack('d',rheader) rpayload = rpacket [8:] time_sent = struct.unpack('d',rpayload) rtt = recieve_time - time_sent[0] #time recieved minus time sent formatted_output = "ICMPMessage: type= 8, code = 0, checksum= {}, identifier = {}, sequence number = {}".format( checksum, client_id, seq_no) return round(rtt*MILLISEC_PER_SEC), formatted_output
def ping(client_socket, dest_host, client_id, seq_no=0): """ Sends echo request, receives response, and returns RTT. """ def icmp_header(host_checksum): message = ICMPMessage( type=ECHO_REQUEST.type, # TODO: Use appropriate argument here code=ECHO_REQUEST.code, # TODO: Use appropriate argument here checksum=host_checksum, identifier=client_id, sequence_number=seq_no) return struct.pack(ICMP_STRUCT_FIELDS, *message) # Please study these lines carefully, # noting that "icmp_pack()" (defined above) is called *twice* icmp_payload = struct.pack('d', this_instant()) # double-precision float icmp_packet_without_checksum = icmp_header(0) + icmp_payload checksum = internet_checksum(icmp_packet_without_checksum) icmp_packet = icmp_header(checksum) + icmp_payload # Please note that that "icmp_packet" is the # payload that we'll send through for our INET raw socket # # Note: socket.gethostbyname() returns the host name # unchanged if it is already in IPv4 address format. dest_host = socket.gethostbyname(dest_host) #. # 1. Call sendto() on socket to send packet to destination host client_socket.sendto(icmp_packet, (dest_host, ICMP_PORT_PLACEHOLDER)) # 2. Call recvfrom() on socket to receive datagram try: dgram, address = client_socket.recvfrom(BUFFER_SIZE) except socket.timeout as error: raise TimeoutError() # (Note: A time-out exception might be raised here). # 2. Store this_instant() at which datagram was received time_received = this_instant() # 3. Extract ICMP packet from datagram i.e. drop IP header (20 bytes) # e.g. "icmp_packet = datagram[20:]" icmp_packet = dgram[20:] # 4. Compute checksum on ICMP response packet (header and payload); # this will hopefully come to zero # get checksum fields checksum = int.from_bytes(icmp_packet[2:4], byteorder='big') # zero out checksum fields (third and fourth byte) on response icmp_packet_copy = icmp_packet[:2] + icmp_packet[4:] # verify checksum value = internet_checksum(icmp_packet_copy, checksum) if value != 0: raise ChecksumError() # 5. Raise exception if checksum is nonzero # 6. Extract ICMP response header from ICMP packet (8 bytes) and # unpack binary response data to obtain ICMPMessage "response" # that we'll return with the round-trip time (Step 9, below); # notice that this namedstruct is printed in the sample # command line output given in the assignment description. # e.g. "Reply from 151.101.0.223 in 5ms: ICMPMessage(type=0, code=0, checksum=48791, identifier=33540, sequence_number=0)" icmp_header = icmp_packet[:8] response = ICMPMessage(*struct.unpack(ICMP_STRUCT_FIELDS, icmp_header)) # 7. Extract ICMP response payload (remaining bytes) and unpack # binary data to recover "time sent" icmp_payload = icmp_packet[8:] bytes_in_double = struct.calcsize('d') time_sent = struct.unpack('d', icmp_payload[0:bytes_in_double])[0] round_trip_time = time_received - time_sent return round(round_trip_time * MILLISEC_PER_SEC), response
from checksum import hextat_complement from checksum import internet_checksum if __name__ == '__main__': data = bytes.fromhex('0001f203f4f5f6f7') checksum = internet_checksum(data) assert checksum == 0x0d22 print('Test 1 passed') data = bytes.fromhex('e34f2396442799f3') checksum = internet_checksum(data) assert checksum == 0xff1a print('Test 2 passed')
def ping(client_socket, dest_host, client_id, seq_no=0): """ Sends echo request, receives response, and returns RTT. """ def icmp_header(host_checksum): message = ICMPMessage( type=8, # TODO: Use appropriate argument here code=0, # TODO: Use appropriate argument here checksum=host_checksum, identifier=client_id, sequence_number=seq_no) return struct.pack(ICMP_STRUCT_FIELDS, *message) # TODO: Please study these lines carefully, # noting that "icmp_pack()" (defined above) is called *twice* icmp_payload = struct.pack('d', this_instant()) # double-precision float icmp_packet_without_checksum = icmp_header(0) + icmp_payload checksum = internet_checksum(icmp_packet_without_checksum) icmp_packet = icmp_header(checksum) + icmp_payload # # TODO: Please note that that "icmp_packet" is the # payload that we'll send through for our INET raw socket # # Note: socket.gethostbyname() returns the host name # unchanged if it is already in IPv4 address format. dest_host = socket.gethostbyname(dest_host) # # TODO: # 1. Call sendto() on socket to send packet to destination host # 2. Call recvfrom() on socket to receive datagram # (Note: A time-out exception might be raised here). # 2. Store this_instant() at which datagram was received # 3. Extract ICMP packet from datagram i.e. drop IP header (20 bytes) # e.g. "icmp_packet = datagram[20:]" # 4. Compute checksum on ICMP response packet (header and payload); # this will hopefully come to zero # 5. Raise exception if checksum is nonzero # 6. Extract ICMP response header from ICMP packet (8 bytes) and # unpack binary response data to obtain ICMPMessage "response" # that we'll return with the round-trip time (Step 9, below); # notice that this namedstruct is printed in the sample # command line output given in the assignment description. # e.g. "Reply from 151.101.0.223 in 5ms: ICMPMessage(type=0, code=0, checksum=48791, identifier=33540, sequence_number=0)" # 7. Extract ICMP response payload (remaining bytes) and unpack # binary data to recover "time sent" # 8. Compute round-trip time from "time sent" # 9. Return "(round-trip time in milliseconds, response)" # # If things go wrong # ================== # You might like to check ("assert") that: # 1. Type field of ICMP response header is ICMP echo reply type # 2. Code field of ICMP response header is ICMP echo reply code # 3. Identifier field of ICMP response header is client_id # 4. len() of ICMP response payload is struct.calcsize('d') # # Sending packet client_socket.sendto(icmp_packet, (dest_host, ICMP_PORT_PLACEHOLDER)) # Getting packet back and the time it was received try: datagram, addr = client_socket.recvfrom(ICMP_MAX_SIZE) log_time = this_instant() except TimeoutError: raise # Extracting datagram header icmp_packet_rec = datagram[20:] # Checking validity of received packet if internet_checksum(icmp_packet_rec) != 0: raise ChecksumError icmp_header_rec = icmp_packet_rec[:8] # Getting ICMP header response_header = ICMPMessage( *struct.unpack(ICMP_STRUCT_FIELDS, icmp_header_rec)) # Getting the time sent from the payload time_sent = struct.unpack("d", datagram[28:28 + struct.calcsize("d")])[0] rtt = log_time - time_sent return rtt * MILLISEC_PER_SEC, response_header