def build_ip_header(): ihl = 5 ver = 4 tos = 0 id_of_ip_pkt = 54321 fragm_off = 0 ttl = 225 protocol = socket.IPPROTO_TCP checksum_for_ip = 0 source_add_for_ip = socket.inet_aton(global_data.get_value("local_ip")) dest_add_for_ip = socket.inet_aton(global_data.get_value("server_ip")) ihl_ver = (ver << 4) + ihl tot_length = 4 * ihl + len(global_data.get_value("tcp_header")) ip_header = struct.pack('!BBHHHBBH4s4s', ihl_ver, tos, tot_length, id_of_ip_pkt, fragm_off, ttl, protocol, checksum_for_ip, source_add_for_ip, dest_add_for_ip) checksum = util.ip_checksum(ip_header) """ add checksum into ip header """ ip_header = struct.pack('!BBHHHBBH4s4s', ihl_ver, tos, tot_length, id_of_ip_pkt, fragm_off, ttl, protocol, checksum, source_add_for_ip, dest_add_for_ip) ip_header = ''.join([ip_header, global_data.get_value("tcp_header")]) global_data.set_value("ip_header", ip_header)
def get_gateway_mac_binary(): interface = global_data.get_value("interface") main_socket = global_data.get_value("main_socket") # simulate a broadcast address to find the gateway mac address arp_header = ethernet.build_arp_header() ethernet_header = ethernet.build_ethernet_header_for_arp() ethernet_packet = ''.join([ethernet_header, arp_header]) # bind with interface main_socket.bind((interface, socket.SOCK_RAW)) # send ethernet packet, so that MAC address of gateway can be retrieved from its response. main_socket.send(ethernet_packet) # we store the size of struct, will be used while unpacking the packets, corresponding to the given format. ethernet_header_length = struct.calcsize('!6s6sH') arp_header_length = struct.calcsize('!HHBBH6s4s6s4s') while True: packet = main_socket.recv(65565) # unpack the ethernet_packet fields = struct.unpack('!6s6sH', packet[:ethernet_header_length]) if fields[2] == 2054: break # unpack arp packet from eth packet arp_fields = struct.unpack( '!HHBBH6s4s6s4s', packet[ethernet_header_length:][:arp_header_length]) gateway_mac_binary = arp_fields[5] print "gateway_mac_binary:", gateway_mac_binary return gateway_mac_binary
def send_ack_to_server(seq_no): http.build_empty_http_header() tcp.build_tcp_header(global_data.get_value("local_port"), 80, 1 + global_data.get_value("http_request_length"), seq_no + 1, 5, 0, 0, 0, 0, 1) ip.build_ip_header() ethernet.build_ethernet_header_for_ip() send_packet_to_server()
def handshake_step_three(): http.build_empty_http_header() tcp.build_tcp_header(global_data.get_value("local_port"), 80, 1, global_data.get_value("sequence_number") + 1, 5, 0, 0, 0, 0, 1) ip.build_ip_header() ethernet.build_ethernet_header_for_ip() data_transfer.send_packet_to_server()
def build_tcp_header(source_of_tcp_p, dest_of_tcp_p, seq_of_tcp_p, ack_seq_of_tcp_p, d_off_tcp_p, fin_p, syn_p, rst_p, psh_p, ack_p): # TCP Header Section # source port source_port = source_of_tcp_p # destination port destination_port = dest_of_tcp_p seq_num = seq_of_tcp_p ack_num = ack_seq_of_tcp_p d_offset = 5 # flags fin = fin_p syn = syn_p rst = rst_p psh = psh_p ack = ack_p urg = 0 # size of max allowed window size window_size = socket.htons(5840) checksum = 0 urg_pointer = 0 offset_res_of_tcp = (d_offset << 4) + 0 flags = fin + (syn << 1) + (rst << 2) + (psh << 3) + (ack << 4) + ( urg << 5) tcp_header_p = struct.pack("!HHLLBBHHH", source_port, destination_port, seq_num, ack_num, offset_res_of_tcp, flags, window_size, checksum, urg_pointer) source_address = socket.inet_aton(global_data.get_value("local_ip")) dest_address = socket.inet_aton(global_data.get_value("server_ip")) placeholder = 0 protocol = socket.IPPROTO_TCP tcp_length = len(tcp_header_p) + len(global_data.get_value("http_request")) psh = struct.pack('!4s4sBBH', source_address, dest_address, placeholder, protocol, tcp_length) psh = psh + tcp_header_p + global_data.get_value("http_request") checksum = util.tcp_checksum(psh) # add correct tcp header checksum tcp_header = struct.pack( '!HHLLBBH', source_port, destination_port, seq_num, ack_num, offset_res_of_tcp, flags, window_size) + struct.pack( 'H', checksum) + struct.pack('!H', urg_pointer) tcp_header = ''.join([tcp_header, global_data.get_value("http_request")]) # save into global data value global_data.set_value("tcp_header", tcp_header)
def send_fin_ack_to_server(): http.build_empty_http_header() tcp.build_tcp_header(global_data.get_value("local_port"), 80, global_data.get_value("acknowledge_number"), int(global_data.get_value("sequence_number")) + 1, 5, 1, 0, 0, 0, 1) ip.build_ip_header() ethernet.build_ethernet_header_for_ip() send_packet_to_server()
def send_data_to_server(): """ send http request to server """ http.build_http_header() tcp.build_tcp_header(global_data.get_value("local_port"), 80, 1, int(global_data.get_value("sequence_number")), 5, 0, 0, 0, 1, 1) ip.build_ip_header() ethernet.build_ethernet_header_for_ip() send_packet_to_server()
def build_arp_header(): hardware_type = 1 protocol_type = 2048 hardware_length = 6 protocol_length = 4 broadcast_mac_address = struct.pack('!6B', 255, 255, 255, 255, 255, 255) operation = 1 arp_pkt = struct.pack('!HHBBH6s4s6s4s', hardware_type, protocol_type, hardware_length, protocol_length, operation, global_data.get_value("local_mac_binary"), global_data.get_value("local_ip_binary"), broadcast_mac_address, global_data.get_value("gateway_ip_binary")) return arp_pkt
def build_ethernet_header_for_arp(): ether_type = 2054 # 0x0806 broadcast_mac_address = struct.pack('!6B', 255, 255, 255, 255, 255, 255) header_of_eth = struct.pack('!6s6sH', broadcast_mac_address, global_data.get_value("local_mac_binary"), ether_type) eth_pkt = header_of_eth return eth_pkt
def handshake_step_one(): http.build_empty_http_header() tcp.build_tcp_header(global_data.get_value("local_port"), 80, 0, 0, 5, 0, 1, 0, 0, 0) ip.build_ip_header() ethernet.build_ethernet_header_for_ip() data_transfer.send_packet_to_server()
def build_http_header(): http_header = "GET " + global_data.get_value("url") + " HTTP/1.0\r\n\r\n" http_request = http_header global_data.set_value("http_request", http_request) http_request_length = len(http_header) global_data.set_value("http_request_length", http_request_length)
def send_packet_to_server(): global_data.get_value("main_socket").bind( (global_data.get_value("interface"), 0)) global_data.get_value("main_socket").send( global_data.get_value("eth_header")) last_packet_sent_time = time.time() global_data.set_value("last_packet_sent_time", last_packet_sent_time)
def build_ethernet_header_for_ip(): ether_type = 2048 header_of_eth = struct.pack('!6s6sH', global_data.get_value("gateway_mac_binary"), global_data.get_value("local_mac_binary"), ether_type) eth_header = ''.join([header_of_eth, global_data.get_value("ip_header")]) global_data.set_value("eth_header", eth_header)
def get_local_ip_binary(): local_ip = global_data.get_value("local_ip") local_ip_binary = socket.inet_aton(local_ip) print "local_ip_binary:", local_ip_binary return local_ip_binary
def receive_data_from_server(): """ receive data from the server, for three way handshake and for receive http response data """ downloaded_file_name = global_data.get_value("downloaded_file_name") main_socket = global_data.get_value("main_socket") local_port = global_data.get_value("local_port") server_ip = global_data.get_value("server_ip") local_ip = global_data.get_value("local_ip") f = open(downloaded_file_name, 'a') while True: if (time.time() - global_data.get_value("last_packet_sent_time")) > 180: print "Program, rawhttpget, does not receive any data from the remote server for three minutes. Please retry again." sys.exit(0) packet = main_socket.recvfrom(65565) packet = packet[0] ethernet_header_length = struct.calcsize('!6s6sH') ip_header = packet[ethernet_header_length:ethernet_header_length + 20] global_data.set_value("ip_header", ip_header) iph = struct.unpack('!BBHHHBBH4s4s', ip_header) version_ihl = iph[0] ihl = version_ihl & 0xF iph_length = ihl * 4 server_as_source_address = socket.inet_ntoa(iph[8]) local_as_destination_address = socket.inet_ntoa(iph[9]) tcp_header = packet[ethernet_header_length + iph_length:ethernet_header_length + iph_length + 20] global_data.set_value("tcp_header", tcp_header) tcph = struct.unpack('!HHLLBBHHH', tcp_header) server_as_source_port = tcph[0] local_as_destination_port = tcph[1] sequence_number = tcph[2] global_data.set_value("sequence_number", sequence_number) acknowledge_number = tcph[3] global_data.set_value("acknowledge_number", acknowledge_number) data_offset_reserved = tcph[4] tcp_flags = tcph[5] flag_fin = tcp_flags & int(hex(1), 16) flag_syn = (tcp_flags >> 1) & int(hex(1), 16) flag_ack = (tcp_flags >> 4) & int(hex(1), 16) tcph_length = data_offset_reserved >> 4 header_size = ethernet_header_length + iph_length + tcph_length * 4 data_size = len(packet) - header_size data = packet[header_size:] if local_as_destination_port != local_port or server_as_source_port != 80 \ or server_as_source_address != server_ip or local_as_destination_address != local_ip: continue else: if flag_ack == 1 and flag_syn == 1: old_sequence_number = sequence_number + 1 global_data.set_value("old_sequence_number", old_sequence_number) break if data_size > 6 and global_data.get_value( "current_cwnd_size") <= 1000: if global_data.get_value("old_sequence_number") + global_data.get_value("old_data_length") == \ global_data.get_value("sequence_number") and util.tcp_checksum(global_data.get_value("ip_header")) == 0: if (time.time() - global_data.get_value("last_packet_sent_time") ) < 60: if data.split('\r\n\r\n')[0] == data: """ directly write data into file """ f.write(data) else: data_containing_header = data.split('\r\n\r\n')[0] http_status = data_containing_header.split(' ')[1] if http_status == "200": f.write(data.split('\r\n\r\n')[1]) else: print "Only 200 will be considered!" break old_sequence_number = global_data.get_value( "sequence_number") global_data.set_value("old_sequence_number", old_sequence_number) old_data_length = data_size global_data.set_value("old_data_length", old_data_length) """ solve the retransmit packet needs to be ACK """ if global_data.get_value( "number_of_retransmit_packet_to_be_ACK") > 0: new_number_of_retransmit_packet_to_be_ACK = global_data.get_value( "number_of_retransmit_packet_to_be_ACK") - 1 global_data.set_value( "number_of_retransmit_packet_to_be_ACK", new_number_of_retransmit_packet_to_be_ACK) """ normal cwnd size """ if 0 < global_data.get_value( "current_cwnd_size") + 1 < 1000: new_current_cwnd_size = global_data.get_value( "current_cwnd_size") + 1 global_data.set_value("current_cwnd_size", new_current_cwnd_size) else: new_current_cwnd_size = 1 global_data.set_value("current_cwnd_size", new_current_cwnd_size) send_ack_to_server( global_data.get_value("sequence_number")) else: print "retransmit because the 60 seconds limit" send_ack_retransmit_to_server( global_data.get_value("old_sequence_number")) else: if global_data.get_value( "current_cwnd_size" ) + 1 <= 0 or global_data.get_value( "current_cwnd_size") + 1 >= 1000: new_current_cwnd_size = 1 global_data.set_value("current_cwnd_size", new_current_cwnd_size) else: new_current_cwnd_size = global_data.get_value( "current_cwnd_size") + 1 global_data.set_value("current_cwnd_size", new_current_cwnd_size) new_number_of_retransmit_packet_to_be_ACK = 1 global_data.set_value( "number_of_retransmit_packet_to_be_ACK", new_number_of_retransmit_packet_to_be_ACK) print "retransmit because sequence number or checksum error" send_ack_retransmit_to_server( global_data.get_value("old_sequence_number")) if flag_fin == 1 and global_data.get_value( "number_of_retransmit_packet_to_be_ACK") == 0: f.close() send_fin_ack_to_server() break sys.exit(0)