/* when an outbound packet comes, check the cached packets, if ip_dst and port_server matches, drop the cached unsolicited packets */ void drop_unsolicited_packet(struct sr_nat *nat, uint8_t *packet) { pthread_mutex_lock(&(nat->lock)); /* get ip hdr and tcp hdr */ sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet); sr_tcp_hdr_t *tcp_hdr = get_tcp_hdr(packet); struct sr_tcp_unsolicited_packet *my_pkt = nat->unsolicited_packet; if (my_pkt != NULL) { struct sr_tcp_unsolicited_packet *next_pkt = my_pkt->next; if (next_pkt == NULL) { sr_ip_hdr_t *my_pkt_ip_hdr = get_ip_hdr(my_pkt->buf); sr_tcp_hdr_t *my_pkt_tcp_hdr = get_tcp_hdr(my_pkt->buf); if (ip_hdr->ip_dst == my_pkt_ip_hdr->ip_src && tcp_hdr->dst_port == my_pkt_tcp_hdr->src_port) { nat->unsolicited_packet = NULL; } } else { struct sr_tcp_unsolicited_packet *prev_pkt = my_pkt; while (next_pkt != NULL) { sr_ip_hdr_t *my_pkt_ip_hdr = get_ip_hdr(my_pkt->buf); sr_tcp_hdr_t *my_pkt_tcp_hdr = get_tcp_hdr(my_pkt->buf); if (ip_hdr->ip_dst == my_pkt_ip_hdr->ip_src && tcp_hdr->dst_port == my_pkt_tcp_hdr->src_port) { if (my_pkt == nat->unsolicited_packet) { nat->unsolicited_packet = next_pkt; prev_pkt = next_pkt; my_pkt = next_pkt; next_pkt = next_pkt->next; } else { prev_pkt->next = next_pkt; my_pkt = next_pkt; next_pkt = next_pkt->next; } } prev_pkt = my_pkt; my_pkt = next_pkt; next_pkt = next_pkt->next; } /* check the last packet */ sr_ip_hdr_t *my_pkt_ip_hdr = get_ip_hdr(my_pkt->buf); sr_tcp_hdr_t *my_pkt_tcp_hdr = get_tcp_hdr(my_pkt->buf); if (ip_hdr->ip_dst == my_pkt_ip_hdr->ip_src && tcp_hdr->dst_port == my_pkt_tcp_hdr->src_port) { prev_pkt->next = NULL; } } } pthread_mutex_unlock(&(nat->lock)); return; }
/* Expects everything but len in network order */ void send_time_exceeded(struct sr_instance *sr, uint8_t *pkt) { /* Need to buffer enough space to include the unused 32 bits, the IP header length, and 64 bits first bits of original datagrams data */ unsigned int packet_size = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t) + UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP + ICMP_DATA_SIZE; uint8_t *outgoing_pkt = malloc(packet_size); sr_ethernet_hdr_t *outgoing_eth_hdr = get_ethernet_hdr(outgoing_pkt); sr_ip_hdr_t *outgoing_ip_hdr = get_ip_hdr(outgoing_pkt); sr_icmp_hdr_t *outgoing_icmp_hdr = get_icmp_hdr(outgoing_pkt); uint32_t ip_dst = get_ip_hdr(pkt)->ip_src; struct sr_rt *outgoing_routing_entry = find_lpm_in_routing_table(sr->routing_table, ntohl(ip_dst)); if (!outgoing_routing_entry) { free(pkt); free(outgoing_pkt); return; } struct sr_if *outgoing_inf = sr_get_interface(sr, outgoing_routing_entry->interface); /*Ethernet*/ memcpy(outgoing_eth_hdr->ether_shost, outgoing_inf->addr, ETHER_ADDR_LEN); outgoing_eth_hdr->ether_type = htons(ethertype_ip); /*IP*/ populate_ip_hdr_normal(outgoing_ip_hdr); outgoing_ip_hdr->ip_len = htons(packet_size - sizeof(sr_ethernet_hdr_t)); outgoing_ip_hdr->ip_p = ip_protocol_icmp; outgoing_ip_hdr->ip_sum = 0; outgoing_ip_hdr->ip_src = outgoing_inf->ip; outgoing_ip_hdr->ip_dst = ip_dst; outgoing_ip_hdr->ip_sum = cksum(outgoing_ip_hdr, sizeof(sr_ip_hdr_t)); /*ICMP*/ outgoing_icmp_hdr->icmp_type = ICMP_TYPE_TIME_EXCEEDED; outgoing_icmp_hdr->icmp_code = ICMP_CODE_TIME_EXCEEDED; outgoing_icmp_hdr->icmp_sum = 0; memset((char *)outgoing_icmp_hdr + sizeof(sr_icmp_hdr_t), 0, UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP); memcpy((char *)outgoing_icmp_hdr + sizeof(sr_icmp_hdr_t) + UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP, get_ip_hdr(pkt), ICMP_DATA_SIZE); outgoing_icmp_hdr->icmp_sum = cksum(outgoing_icmp_hdr, sizeof(sr_icmp_hdr_t) + UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP + ICMP_DATA_SIZE); send_or_queue_packet_based_on_arp_entry_existence(sr, outgoing_routing_entry, outgoing_pkt, packet_size); }
void print_packet(const uint8_t *packet, unsigned int len) { assert(packet); printf("\n"); print_eth_hdr(packet, len); printf("\n"); eth_hdr *eth = (eth_hdr *)packet; if (ntohs(eth->eth_type) == ETH_TYPE_ARP) { print_arp_hdr(packet, len); printf("\n"); } else if (ntohs(eth->eth_type) == ETH_TYPE_IP) { ip_hdr *ip = get_ip_hdr(packet, len); indent(1); printf("IPv4 Packet (%d bytes)\n", len - sizeof(eth_hdr)); print_ip_hdr(packet, len); switch(ip->ip_p) { case 1: { print_icmp_load(packet, len); break; } case 6: { print_tcp_load(packet, len); break; } case 89: { print_pwospf_load(packet, len); break; } default: { printf("UNRECOGNIZABLE PROTOCOL\n"); break;} } } }
// return false to exit this stalker thread unsigned int stalker_callback(void *si, void *pi) { // uri_logout(pi); // http_hdr_logout(pi); void *tr = stalker_get_exptr(si); if(!tr) { struct _tcphdr *tcp = get_tcp_hdr(pi); tr = tr_init_c2s(pi); if(!tr) return false; stalker_set_exptr(si, tr); #if 1 struct _iphdr *ip = get_ip_hdr(pi); _MESSAGE_OUT("\033[1mlog out switch in file : %s:%d\n", __FILE__, __LINE__ - 3); _MESSAGE_OUT("ip.addr == %s && tcp.port == %u\033[0m\n", _netint32toip(ip->daddr), _ntoh16(tcp->source)); #endif } tr_receive(tr, pi); // route_packet(pi); pi_destory(pi); return true; }
unsigned int i_wanna_fuck_this_beauty(void *pi) { unsigned char *http = get_http_ptr(pi); unsigned int tdl = get_tcp_data_len(pi); if(!http || !tdl) return false; if(http - get_pkt_ptr(pi) + 4 >= tdl) return false; if('G'==http[0] && 'E'==http[1] && 'T'==http[2] && ' '==http[3]) { #if 0 static int i = 0; if(i) return false; struct _tcphdr *tcp = get_tcp_hdr(pi); struct _iphdr *ip = get_ip_hdr(pi); _MESSAGE_OUT("Hook one ip test !!! switch in file : %s:%d\n", __FILE__, __LINE__ - 6); _MESSAGE_OUT("=============\nip.addr == %s && tcp.port == %u\n", _netint32toip(ip->daddr), _ntoh16(tcp->source)); i = 1; #endif return true; } return false; }
struct sr_tcp_unsolicited_packet *sr_nat_unsolicited_queue(struct sr_nat *nat, uint8_t *packet, unsigned int packet_len) { pthread_mutex_lock(&(nat->lock)); /* get ethernet header, ip header, tcp header */ /*sr_ethernet_hdr_t *eth_hdr = get_eth_hdr(packet);*/ sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet); sr_tcp_hdr_t *tcp_hdr = get_tcp_hdr(packet); struct sr_tcp_unsolicited_packet *my_pkt = NULL; int found = 0; for (my_pkt = nat->unsolicited_packet; my_pkt != NULL; my_pkt = my_pkt->next) { /*sr_ethernet_hdr_t *my_pkt_eth_hdr = get_eth_hdr(my_pkt->buf);*/ sr_ip_hdr_t *my_pkt_ip_hdr = get_ip_hdr(my_pkt->buf); sr_tcp_hdr_t *my_pkt_tcp_hdr = get_tcp_hdr(my_pkt->buf); /* check if the ip_src/dst and src/dst_port match */ if (ip_hdr->ip_src == my_pkt_ip_hdr->ip_src && ip_hdr->ip_dst == my_pkt_ip_hdr->ip_dst && tcp_hdr->src_port == my_pkt_tcp_hdr->src_port && tcp_hdr->dst_port == my_pkt_tcp_hdr->dst_port) { found = 1; break; } } /* If the packet wasn't found, add it */ if (found == 0) { struct sr_tcp_unsolicited_packet *new_pkt = (struct sr_tcp_unsolicited_packet *)malloc(sizeof(struct sr_tcp_unsolicited_packet)); new_pkt->buf = (uint8_t *)malloc(packet_len); memcpy(new_pkt->buf, packet, packet_len); new_pkt->len = packet_len; new_pkt->time_updated = time(NULL); new_pkt->next = nat->unsolicited_packet; nat->unsolicited_packet = new_pkt; pthread_mutex_unlock(&(nat->lock)); return new_pkt; } pthread_mutex_unlock(&(nat->lock)); return my_pkt; }
/* Expects everything but len in network order */ void send_echo_reply(struct sr_instance *sr, uint8_t *pkt, unsigned int len) { uint8_t *outgoing_pkt = malloc(len); sr_ethernet_hdr_t *outgoing_eth_hdr = get_ethernet_hdr(outgoing_pkt); sr_ip_hdr_t *outgoing_ip_hdr = get_ip_hdr(outgoing_pkt); sr_icmp_hdr_t *outgoing_icmp_hdr = get_icmp_hdr(outgoing_pkt); uint32_t ip_dst = get_ip_hdr(pkt)->ip_src; struct sr_rt *outgoing_routing_entry = find_lpm_in_routing_table(sr->routing_table, ntohl(ip_dst)); if (!outgoing_routing_entry) { free(pkt); free(outgoing_pkt); return; } struct sr_if *outgoing_inf = sr_get_interface(sr, outgoing_routing_entry->interface); /*Ethernet*/ memcpy(outgoing_eth_hdr->ether_shost, outgoing_inf->addr, ETHER_ADDR_LEN); outgoing_eth_hdr->ether_type = htons(ethertype_ip); /*IP*/ populate_ip_hdr_normal(outgoing_ip_hdr); outgoing_ip_hdr->ip_len = htons(len - sizeof(sr_ethernet_hdr_t)); outgoing_ip_hdr->ip_p = ip_protocol_icmp; outgoing_ip_hdr->ip_sum = 0; outgoing_ip_hdr->ip_src = get_ip_hdr(pkt)->ip_dst; outgoing_ip_hdr->ip_dst = ip_dst; outgoing_ip_hdr->ip_sum = cksum(outgoing_ip_hdr, sizeof(sr_ip_hdr_t)); /*ICMP*/ outgoing_icmp_hdr->icmp_type = ICMP_TYPE_ECHO_REPLY; outgoing_icmp_hdr->icmp_code = ICMP_CODE_ECHO_REPLY; outgoing_icmp_hdr->icmp_sum = 0; memcpy((char *)outgoing_icmp_hdr + sizeof(sr_icmp_hdr_t), pkt + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t), len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t) - sizeof(sr_icmp_hdr_t)); outgoing_icmp_hdr->icmp_sum = cksum(outgoing_icmp_hdr, ntohs(outgoing_ip_hdr->ip_len) - sizeof(sr_ip_hdr_t)); send_or_queue_packet_based_on_arp_entry_existence(sr, outgoing_routing_entry, outgoing_pkt, len); }
/* Expects entire ethernet frame, still in network order, and ip destination in host order */ void handle_ip_packet_not_destined_to_router(struct sr_instance *sr, uint8_t *pkt, uint32_t ip_dst, unsigned int len) { struct sr_rt *table_match = find_lpm_in_routing_table(sr->routing_table,ip_dst); if (table_match) { send_or_queue_packet_based_on_arp_entry_existence(sr, table_match, pkt, len); } else { sr_ip_hdr_t *ip_hdr = get_ip_hdr(pkt); send_icmp_type3_pkt(sr, ip_hdr->ip_src, ip_hdr, ICMP_CODE_NETWORK_UNREACHABLE); } }
/*All passed in params are lent and will not be modified, all in network order*/ void send_icmp_type3_pkt(struct sr_instance *sr, uint32_t ip_dst, void *icmp3_data, uint8_t icmp_code) { uint8_t *outgoing_pkt = malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t)); sr_ethernet_hdr_t *outgoing_eth_hdr = get_ethernet_hdr(outgoing_pkt); sr_ip_hdr_t *outgoing_ip_hdr = get_ip_hdr(outgoing_pkt); sr_icmp_t3_hdr_t *outgoing_icmp_hdr = get_icmp_t3_hdr(outgoing_pkt); struct sr_rt *outgoing_routing_entry = find_lpm_in_routing_table(sr->routing_table, ntohl(ip_dst)); if (!outgoing_routing_entry) { /*Drop constructed packet if not possible to send from routing table*/ return; } struct sr_if *outgoing_inf = sr_get_interface(sr, outgoing_routing_entry->interface); /*Ethernet*/ /*Find destination MAC later, source MAC is outgoing interface MAC*/ memcpy(outgoing_eth_hdr->ether_shost, outgoing_inf->addr, ETHER_ADDR_LEN); outgoing_eth_hdr->ether_type = htons(ethertype_ip); /*IP*/ /*IP src is outgoing interface's source*/ populate_ip_hdr_normal(outgoing_ip_hdr); outgoing_ip_hdr->ip_len = htons(sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t)); outgoing_ip_hdr->ip_p = ip_protocol_icmp; outgoing_ip_hdr->ip_sum = 0; outgoing_ip_hdr->ip_src = outgoing_inf->ip; outgoing_ip_hdr->ip_dst = ip_dst; outgoing_ip_hdr->ip_sum = cksum(outgoing_ip_hdr, sizeof(sr_ip_hdr_t)); /*ICMP*/ outgoing_icmp_hdr->icmp_type = 3; /*OK to hardcode because of function name*/ outgoing_icmp_hdr->icmp_code = icmp_code; outgoing_icmp_hdr->icmp_sum = 0; /*Specifics to an ICMP type 3 packet- hence stylistically decided not to combine this function with other ICMP creation functions*/ memset((char *)outgoing_icmp_hdr + sizeof(sr_icmp_hdr_t), 0, UNUSED_BYTE_LENGTH_TYPE_3_ICMP); memcpy(outgoing_icmp_hdr->data, icmp3_data, ICMP_DATA_SIZE); outgoing_icmp_hdr->icmp_sum = cksum(outgoing_icmp_hdr, ntohs(outgoing_ip_hdr->ip_len) - sizeof(sr_ip_hdr_t)); send_or_queue_packet_based_on_arp_entry_existence(sr, outgoing_routing_entry, outgoing_pkt, sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t)); }
/* Expects entire ethernet frame, still in network order. */ void handle_ip(struct sr_instance *sr, uint8_t *pkt, unsigned int len) { sr_ip_hdr_t *ip_hdr = get_ip_hdr(pkt); uint32_t ip_dst = ntohl(ip_hdr->ip_dst); if (!ip_packet_sanity_check(pkt, ip_hdr)) { free(pkt); return; } if (find_interface_with_ip(sr, ip_dst)) { handle_ip_packet_destined_to_router(sr, pkt, ip_hdr, len); } else { /*Endian conversion not necessary because only 1 byte*/ if (ip_hdr->ip_ttl == 1) { send_time_exceeded(sr, pkt); return; } ip_hdr->ip_ttl--; ip_hdr->ip_sum = 0; ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t)); handle_ip_packet_not_destined_to_router(sr, pkt, ip_dst, len); } }
void print_ip_hdr(const uint8_t *packet, unsigned int len) { assert(packet); ip_hdr *ip = get_ip_hdr(packet, len); indent(1); printf("IPv4 Packet Header (%d bytes)\n", 4*ip->ip_hl); indent(2); printf("Version = %d\n", ip->ip_v); indent(2); printf("Header Length = %d\n", 4*ip->ip_hl); indent(2); printf("Terms of Service = 0x%X\n", ip->ip_tos); indent(2); printf("Total Length = %d\n", ntohs(ip->ip_len)); indent(2); printf("Identification = 0x%X\n", ntohs(ip->ip_id)); indent(2); printf("Fragment Offset Field = 0x%X\n", ntohs(ip->ip_off)); indent(2); printf("TTL (Time to Live) = %d\n", ip->ip_ttl); indent(2); printf("Protocol = "); switch(ip->ip_p) { case 1: { printf("ICMP\n"); break; } case 6: { printf("TCP\n"); break; } default: { printf("%d\n", ip->ip_p); break; } } indent(2); printf("Header Checksum = 0x%X\n", ntohs(ip->ip_sum)); indent(2); print_ip_address("Src IP Address", ip->ip_src); indent(2); print_ip_address("Dst IP Address", ip->ip_dst); }
/* Expects everything but len in network order */ void send_icmp_port_unreachable(struct sr_instance *sr, uint8_t *pkt, unsigned int len) { sr_ip_hdr_t *ip_hdr = get_ip_hdr(pkt); send_icmp_type3_pkt(sr, ip_hdr->ip_src, ip_hdr, ICMP_CODE_PORT_UNREACHABLE); }
/* Send ARP request if the request in our cache is not sent more than 5 times */ void handle_arpreq (struct sr_arpreq * req, struct sr_instance *sr) { struct sr_arpcache *sr_cache = &sr->cache; time_t curr_time; time(&curr_time); double one_sec = 1.0; if (difftime(curr_time, req->sent) > one_sec){ struct sr_packet *packet = req->packets; /* If packet is sent more than equal or more than 5 times, send ICMP host unreachable message */ if ((req->times_sent) >= 5) { printf("Packet sent more than 5 times\n"); while (packet) { uint8_t *buf = packet->buf; char *interface = packet->iface; int packet_len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t); uint8_t *new_packet = malloc(packet_len); /* Get Ethernet header */ sr_ethernet_hdr_t* eth_hdr = get_eth_hdr(buf); /* Get IP header */ sr_ip_hdr_t * ip_hdr = get_ip_hdr(buf); /* Create ethernet header */ create_ethernet_header (eth_hdr, new_packet, eth_hdr->ether_dhost, eth_hdr->ether_shost, htons(ethertype_ip)); /* Create IP header */ create_ip_header (ip_hdr, new_packet, sr_get_interface(sr, interface)->ip, ip_hdr->ip_src); /* Create ICMP Header */ create_icmp_type3_header (ip_hdr, new_packet, dest_host_unreachable_type, dest_host_unreachable_code); /* Look up routing table for rt entry that is mapped to the source of received packet */ struct sr_rt *src_lpm = sr_routing_lpm(sr, ip_hdr->ip_src); /* Send ICMP host unreachable message */ send_icmp_type3_msg (new_packet, src_lpm, sr_cache, sr, interface, packet_len); free(new_packet); packet = packet->next; } sr_arpreq_destroy(sr_cache, req); } else { /* Send out arp request */ struct sr_if *target_iface = sr_get_interface(sr, packet->iface); int packet_len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t); uint8_t *new_packet = malloc(packet_len); /* Createn ethernet header */ sr_ethernet_hdr_t *new_eth_hdr = (sr_ethernet_hdr_t *) new_packet; memset(new_eth_hdr->ether_dhost, 255, sizeof(uint8_t)*ETHER_ADDR_LEN); memcpy(new_eth_hdr->ether_shost, target_iface->addr, sizeof(uint8_t)*ETHER_ADDR_LEN); new_eth_hdr->ether_type = htons(ethertype_arp); /* Create ARP header */ sr_arp_hdr_t *new_arp_hdr = (sr_arp_hdr_t *)(new_packet + sizeof(sr_ethernet_hdr_t)); new_arp_hdr->ar_hrd = htons(arp_hrd_ethernet); new_arp_hdr->ar_pro = htons(ethertype_ip); new_arp_hdr->ar_hln = ETHER_ADDR_LEN; new_arp_hdr->ar_pln = sizeof(uint32_t); new_arp_hdr->ar_op = htons(arp_op_request); memcpy(new_arp_hdr->ar_sha, target_iface->addr, sizeof(unsigned char)*ETHER_ADDR_LEN); new_arp_hdr->ar_sip = target_iface->ip; memset(new_arp_hdr->ar_tha, 255, sizeof(unsigned char)*ETHER_ADDR_LEN); new_arp_hdr->ar_tip = req->ip; sr_send_packet(sr, new_packet, packet_len, target_iface->name); free(new_packet); } req->sent = curr_time; req->times_sent = req->times_sent + 1; } }
/* * HELPER function called from arp_thread */ void process_arp_queue(struct sr_instance* sr) { router_state* rs = get_router_state(sr); node* n = get_router_state(sr)->arp_queue; node* next = NULL; time_t now; double diff; while (n) { next = n->next; arp_queue_entry* aqe = (arp_queue_entry*)n->data; /* has it been over a second since the last arp request was sent? */ time(&now); diff = difftime(now, aqe->last_req_time); if (diff > 1) { /* have we sent less than 5 arp requests? */ if (aqe->requests < 5) { /* send another */ time(&(aqe->last_req_time)); ++(aqe->requests); send_arp_request(sr, aqe->next_hop.s_addr, aqe->out_iface_name); } else { /* we have exceeded the max arp requests, return packets to sender */ node* cur_packet_node = aqe->head; node* next_packet_node = NULL; while (cur_packet_node) { /* send icmp for the packet, free it, and its encasing entry */ arp_queue_packet_entry* aqpe = (arp_queue_packet_entry*)cur_packet_node->data; /* only send an icmp error if the packet is not icmp, or if it is, its an echo request or reply * also ensure we don't send an icmp error back to one of our interfaces */ if ((get_ip_hdr(aqpe->packet, aqpe->len)->ip_p != IP_PROTO_ICMP) || (get_icmp_hdr(aqpe->packet, aqpe->len)->icmp_type == ICMP_TYPE_ECHO_REPLY) || (get_icmp_hdr(aqpe->packet, aqpe->len)->icmp_type == ICMP_TYPE_ECHO_REQUEST)) { /* also ensure we don't send an icmp error back to one of our interfaces */ if (!iface_match_ip(rs, get_ip_hdr(aqpe->packet, aqpe->len)->ip_src.s_addr)) { /* Total hack here to increment the TTL since we already decremented it earlier in the pipeline * and the ICMP error should return the original packet. * TODO: Don't decrement the TTL until the packet is ready to be put on the wire * and we have the next hop ARP address, although checking should be done * where it is currently being decremented to minimize effort on a doomed packet */ ip_hdr *ip = get_ip_hdr(aqpe->packet, aqpe->len); if (ip->ip_ttl < 255) { ip->ip_ttl++; /* recalculate checksum */ bzero(&ip->ip_sum, sizeof(uint16_t)); uint16_t checksum = htons(compute_ip_checksum(ip)); ip->ip_sum = checksum; } send_icmp_packet(sr, aqpe->packet, aqpe->len, ICMP_TYPE_DESTINATION_UNREACHABLE, ICMP_CODE_HOST_UNREACHABLE); } } free(aqpe->packet); next_packet_node = cur_packet_node->next; //free(cur_packet_node); /* IS THIS CORRECT TO FREE IT ? */ node_remove(&(aqe->head), cur_packet_node); cur_packet_node = next_packet_node; } /* free the arp queue entry for this destination ip, and patch the list */ node_remove(&(get_router_state(sr)->arp_queue), n); } } n = next; } }
/* Handle IP packet */ void sr_handle_ippacket(struct sr_instance* sr, uint8_t * packet/* lent */, unsigned int len, char* interface/* lent */) { assert(sr); assert(packet); assert(interface); /* Get ethernet header */ sr_ethernet_hdr_t *eth_hdr = get_eth_hdr(packet); if (eth_hdr == NULL) { printf("ethernet header NULL!!!\n"); return; } /* Get ip header */ sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet); if (ip_hdr == NULL) { printf("ip header NULL!!!\n"); return; } /* Before doing ttl decrement, check checksum */ uint16_t old_ip_sum = ip_hdr->ip_sum; ip_hdr->ip_sum = 0; if (!verify_checksum(ip_hdr, sizeof(sr_ip_hdr_t), old_ip_sum)) { fprintf(stderr, "CHECKSUM FAILED!!\n"); return; } ip_hdr->ip_sum = old_ip_sum; /* Get the arp cache */ struct sr_arpcache *sr_arp_cache = &sr->cache; /* Get the destination interface on the router */ struct sr_if *sr_iface = sr_get_router_if(sr, ip_hdr->ip_dst); /* Get the connected interface on the router */ struct sr_if *sr_con_if = sr_get_interface(sr, interface); /* Check the time exceeded condition, if ttl==0, we need to form icmp 11 and send back */ if (ip_hdr->ip_ttl <= 1) { /* time exceeded message and icmp type 11 */ printf("TTL time exceeded\n"); int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_con_if); /* Create ip header */ create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_con_if); /* Send icmp type 11 time exceeded */ /* icmp_t3 type=11, code=0 */ create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 11, 0); /* Send icmp type 11 packet */ struct sr_arpentry *arp_entry = sr_arpcache_lookup(sr_arp_cache, ip_hdr->ip_src); if (arp_entry != NULL) { sr_send_packet(sr, icmp_t3_hdr, packet_len, sr_con_if->name); free(icmp_t3_hdr); } else { struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, sr_con_if->name); handle_arpreq(arp_req, sr); } return; } /* Get the protocol from IP */ uint8_t ip_p = ip_hdr->ip_p; /* If the packet is sent to self, meaning the ip is sent to the router */ if (sr_iface) { /* Check the protocol if it is icmp */ if (ip_p == ip_protocol_icmp) { /* Get the icmp header */ sr_icmp_hdr_t *icmp_hdr = get_icmp_hdr(packet); /* Check if it is ICMP echo request */ /* icmp_echo_req = 8 */ if (icmp_hdr->icmp_type == 8) { /* Do LPM on the routing table */ /* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */ struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src); if (longest_pref_match) { /* check ARP cache */ struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr); struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface); /* If hit, meaning the arp mapping has been cached */ if (arp_entry != NULL) { /* We need to send the icmp echo reply */ /* Modify ethernet header */ memcpy(eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN); memcpy(eth_hdr->ether_shost, out_iface->addr, ETHER_ADDR_LEN); /* Modify ip header */ ip_hdr->ip_off = htons(0b0100000000000000); /* fragment offset field */ ip_hdr->ip_ttl = 100; /* time to live */ uint32_t temp = ip_hdr->ip_src; ip_hdr->ip_src = ip_hdr->ip_dst; /* source address */ ip_hdr->ip_dst = temp; /* dest address */ ip_hdr->ip_sum = 0; ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t)); /* checksum */ /* Modify icmp header */ unsigned int icmp_whole_size = len - IP_PACKET_LEN; icmp_hdr->icmp_type = 0; icmp_hdr->icmp_code = 0; icmp_hdr->icmp_sum = 0; icmp_hdr->icmp_sum = cksum(icmp_hdr, icmp_whole_size); /* Send icmp echo reply */ sr_send_packet(sr, packet, len, out_iface->name); return; } /* Else no hit, we cache it to the queue and send arp request */ else { /* Add reply to the ARP queue */ /* We need to send the icmp echo reply */ /* Modify ethernet header */ memcpy(eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN); memcpy(eth_hdr->ether_shost, sr_con_if->addr, ETHER_ADDR_LEN); /* Modify ip header */ ip_hdr->ip_off = htons(0b0100000000000000); /* fragment offset field */ ip_hdr->ip_ttl = 100; /* time to live */ uint32_t temp = ip_hdr->ip_src; ip_hdr->ip_src = ip_hdr->ip_dst; /* source address */ ip_hdr->ip_dst = temp; /* dest address */ ip_hdr->ip_sum = 0; ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t)); /* checksum */ /* Modify icmp header */ unsigned int icmp_whole_size = len - IP_PACKET_LEN; icmp_hdr->icmp_type = 0; icmp_hdr->icmp_code = 0; icmp_hdr->icmp_sum = 0; icmp_hdr->icmp_sum = cksum(icmp_hdr, icmp_whole_size); struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_dst, packet, len, out_iface->name); /* Send ARP request, which is a broadcast */ handle_arpreq(arp_req, sr); return; } } else { fprintf(stderr, "Longest prefix doesnt match!!\n"); return; } } else { fprintf(stderr, "Not an ICMP request!\n"); return; } } /* Else it is TCP/UDP request */ else { fprintf(stderr, "*** -> Received TCP/UDP!\n"); /* Do LPM on the routing table */ /* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */ struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src); if (longest_pref_match) { /* check ARP cache */ struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr); struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface); /* Send ICMP port unreachable */ if (arp_entry != NULL) { int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); /* Create ethernet header */ create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_iface); /*memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN); memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN);*/ /* Create ip header */ create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_iface); /*sr_ip_hdr_t *icmp_t3_hdr_ip = (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN); icmp_t3_hdr_ip->ip_src = ip_hdr->ip_dst; icmp_t3_hdr_ip->ip_sum = 0; icmp_t3_hdr_ip->ip_sum = cksum(icmp_t3_hdr_ip, sizeof(sr_ip_hdr_t));*/ /* Should update source address to be interface address */ /* Send icmp type 3 port unreachable */ /* Create icmp port unreachable packet */ /* icmp_t3 type=3, code=3 */ create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 3); /* Send icmp type 3 packet */ sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name); free(icmp_t3_hdr); return; } else { int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); /* Create ethernet header */ create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_iface); /*memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN); memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN);*/ /* Create ip header */ create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_iface); /*sr_ip_hdr_t *icmp_t3_hdr_ip = (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN); icmp_t3_hdr_ip->ip_src = ip_hdr->ip_dst; icmp_t3_hdr_ip->ip_sum = 0; icmp_t3_hdr_ip->ip_sum = cksum(icmp_t3_hdr_ip, sizeof(sr_ip_hdr_t));*/ /* Send icmp type 3 port unreachable */ /* Create icmp port unreachable packet */ /* icmp_t3 type=3, code=3 */ create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 3); struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, out_iface->name); /* Send ARP request, which is a broadcast */ handle_arpreq(arp_req, sr); return; } } else { fprintf(stderr, "Longest prefix doesnt match!!\n"); return; } } } /* Else Check the routing table, perfomr LPM */ else { /* Sanity-check the packet */ /* minimum length */ if (!check_min_length(len, IP_PACKET_LEN)) { fprintf(stderr, "The packet length is not enough:(\n"); return; } /* Do LPM on the routing table */ /* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */ struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_dst); if (longest_pref_match) { /* check ARP cache */ struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface); struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr); /* ip_hdr->ip_dst */ /* If hit, meaning the arp_entry is found */ if (arp_entry) { /*fprintf(stderr, "************ found the lpm router entry ***********\n");*/ /* Send frame to next hop */ /* update the eth_hdr source and destination ethernet address */ /* use next_hop_ip->mac mapping in the entry to send the packet */ ip_hdr->ip_ttl--; /* recompute the packet checksum over the modified header */ ip_hdr->ip_sum = 0; uint16_t new_ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t)); ip_hdr->ip_sum = new_ip_sum; memcpy(eth_hdr->ether_shost, out_iface->addr, ETHER_ADDR_LEN); memcpy(eth_hdr->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN); sr_send_packet(sr, packet, len, out_iface->name); print_hdr_ip((uint8_t*)ip_hdr); /* free the entry */ free(arp_entry); return; } else/* No Hit */ { /* send an ARP request for the next-hop IP */ /* add the packet to the queue of packets waiting on this ARP request */ /* Add request to ARP queue*/ ip_hdr->ip_ttl--; /* recompute the packet checksum over the modified header */ ip_hdr->ip_sum = 0; uint16_t new_ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t)); ip_hdr->ip_sum = new_ip_sum; struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_dst, packet, len, out_iface->name); /* send ARP request, this is a broadcast */ handle_arpreq(arp_req, sr); return; } } else /* if not matched */ { /* Send ICMP net unreachable */ printf("--------------- Net Unreachable ---------------\n"); /* Do LPM on the routing table */ /* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */ struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src); if (longest_pref_match) { /* check ARP cache */ struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr); struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface); if (arp_entry) { int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); /* Create ethernet header */ create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, out_iface); /* Create ip header */ create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), out_iface); /* Create icmp net unreachable */ /* icmp_t3 type=3, code=0 */ create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 0); /* Send icmp type 3 packet */ sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name); free(icmp_t3_hdr); return; } else { int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); /* Create ethernet header */ create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, out_iface); /* Create ip header */ create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), out_iface); /* ((sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN))->ip_ttl += 1; */ /* Send icmp type 3 net unreachable */ /* Create icmp net unreachable packet */ /* icmp_t3 type=3, code=0 */ create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 0); struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, out_iface->name); /* Send ARP request, which is a broadcast */ handle_arpreq(arp_req, sr); return; } } else { fprintf(stderr, "Longest prefix doesnt match!!\n"); return; } } } return; }
void *sr_nat_timeout(void *sr_ptr) { /* Periodic Timout handling */ struct sr_instance *sr = (struct sr_instance *)sr_ptr; struct sr_nat *nat = sr->nat; while (1) { sleep(1.0); pthread_mutex_lock(&(nat->lock)); /* handle periodic tasks here */ time_t curtime = time(NULL); struct sr_tcp_unsolicited_packet *my_pkt = nat->unsolicited_packet; /* if my_pkt is NULL, finish! */ if (my_pkt == NULL) { pthread_mutex_unlock(&(nat->lock)); } else { /* get the next packet */ struct sr_tcp_unsolicited_packet *next_pkt = my_pkt->next; /* if next pkt is NULL, only check my_pkt */ if (next_pkt == NULL) { time_t pkt_time = my_pkt->time_updated; /* if the time difference is bigger than 6 seconds */ if (difftime(curtime, pkt_time) >= 6) { /* get all the headers */ uint8_t *packet = my_pkt->buf; sr_ethernet_hdr_t *eth_hdr = get_eth_hdr(packet); sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet); /* create a new icmp t3 port unreachable */ int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); /* create ethernet header */ sr_ethernet_hdr_t *new_eth_hdr = (sr_ethernet_hdr_t *)icmp_t3_hdr; memcpy(new_eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN); memcpy(new_eth_hdr->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN); /* create ip header */ sr_ip_hdr_t *new_ip_hdr = (sr_ip_hdr_t *)((char *)icmp_t3_hdr + ETHER_PACKET_LEN); new_ip_hdr->ip_hl = ip_hdr->ip_hl; /* header length */ new_ip_hdr->ip_v = ip_hdr->ip_v; /* header version */ new_ip_hdr->ip_tos = ip_hdr->ip_tos; /* type of service */ new_ip_hdr->ip_len = htons(56); /* total length */ new_ip_hdr->ip_id = 0; /* identification */ new_ip_hdr->ip_off = htons(0b0100000000000000); /* fragment offset field */ new_ip_hdr->ip_ttl = 64; /* time to live */ new_ip_hdr->ip_p = ip_protocol_icmp; /* protocol */ new_ip_hdr->ip_src = ip_hdr->ip_dst; /* source address */ new_ip_hdr->ip_dst = ip_hdr->ip_src; /* dest address */ new_ip_hdr->ip_sum = 0; new_ip_hdr->ip_sum = cksum(new_ip_hdr, sizeof(sr_ip_hdr_t));; /* checksum */ /* create icmp t3 header */ sr_icmp_t3_hdr_t *new_icmp_t3_hdr = (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr + IP_PACKET_LEN); new_icmp_t3_hdr->icmp_type = htons(3); new_icmp_t3_hdr->icmp_code = htons(3); new_icmp_t3_hdr->unused = 0; new_icmp_t3_hdr->next_mtu = 0; memcpy(new_icmp_t3_hdr->data, new_ip_hdr, ICMP_DATA_SIZE); new_icmp_t3_hdr->icmp_sum = 0; new_icmp_t3_hdr->icmp_sum = cksum(new_icmp_t3_hdr, sizeof(sr_icmp_t3_hdr_t)); struct sr_if *out_iface = sr_get_router_if(sr, ip_hdr->ip_dst); sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name); /* set unsolicited_packet to be NULL */ nat->unsolicited_packet = NULL; } pthread_mutex_unlock(&(nat->lock)); } /* otherwise we need to loop through the packets */ else { struct sr_tcp_unsolicited_packet *prev_pkt = my_pkt; while (next_pkt != NULL) { time_t pkt_time = my_pkt->time_updated; /* if the time difference is bigger than 6 seconds */ if (difftime(curtime, pkt_time) >= 6) { /* get all the headers */ uint8_t *packet = my_pkt->buf; sr_ethernet_hdr_t *eth_hdr = get_eth_hdr(packet); sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet); /* create a new icmp t3 port unreachable */ int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); /* create ethernet header */ sr_ethernet_hdr_t *new_eth_hdr = (sr_ethernet_hdr_t *)icmp_t3_hdr; memcpy(new_eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN); memcpy(new_eth_hdr->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN); /* create ip header */ sr_ip_hdr_t *new_ip_hdr = (sr_ip_hdr_t *)((char *)icmp_t3_hdr + ETHER_PACKET_LEN); new_ip_hdr->ip_hl = ip_hdr->ip_hl; /* header length */ new_ip_hdr->ip_v = ip_hdr->ip_v; /* header version */ new_ip_hdr->ip_tos = ip_hdr->ip_tos; /* type of service */ new_ip_hdr->ip_len = htons(56); /* total length */ new_ip_hdr->ip_id = 0; /* identification */ new_ip_hdr->ip_off = htons(0b0100000000000000); /* fragment offset field */ new_ip_hdr->ip_ttl = 64; /* time to live */ new_ip_hdr->ip_p = ip_protocol_icmp; /* protocol */ new_ip_hdr->ip_src = ip_hdr->ip_dst; /* source address */ new_ip_hdr->ip_dst = ip_hdr->ip_src; /* dest address */ new_ip_hdr->ip_sum = 0; new_ip_hdr->ip_sum = cksum(new_ip_hdr, sizeof(sr_ip_hdr_t));; /* checksum */ /* create icmp t3 header */ sr_icmp_t3_hdr_t *new_icmp_t3_hdr = (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr + IP_PACKET_LEN); new_icmp_t3_hdr->icmp_type = htons(3); new_icmp_t3_hdr->icmp_code = htons(3); new_icmp_t3_hdr->unused = 0; new_icmp_t3_hdr->next_mtu = 0; memcpy(new_icmp_t3_hdr->data, new_ip_hdr, ICMP_DATA_SIZE); new_icmp_t3_hdr->icmp_sum = 0; new_icmp_t3_hdr->icmp_sum = cksum(new_icmp_t3_hdr, sizeof(sr_icmp_t3_hdr_t)); struct sr_if *out_iface = sr_get_router_if(sr, ip_hdr->ip_dst); sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name); /* unlist the my_pkt */ if (my_pkt == nat->unsolicited_packet) { nat->unsolicited_packet = next_pkt; prev_pkt = next_pkt; my_pkt = next_pkt; next_pkt = next_pkt->next; } else { prev_pkt->next = next_pkt; my_pkt = next_pkt; next_pkt = next_pkt->next; } } prev_pkt = my_pkt; my_pkt = next_pkt; next_pkt = next_pkt->next; } time_t pkt_time = my_pkt->time_updated; /* if the time difference is bigger than 6 seconds */ if (difftime(curtime, pkt_time) >= 6) { /* get all the headers */ uint8_t *packet = my_pkt->buf; sr_ethernet_hdr_t *eth_hdr = get_eth_hdr(packet); sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet); /* create a new icmp t3 port unreachable */ int packet_len = ICMP_T3_PACKET_LEN; uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len); /* create ethernet header */ sr_ethernet_hdr_t *new_eth_hdr = (sr_ethernet_hdr_t *)icmp_t3_hdr; memcpy(new_eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN); memcpy(new_eth_hdr->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN); /* create ip header */ sr_ip_hdr_t *new_ip_hdr = (sr_ip_hdr_t *)((char *)icmp_t3_hdr + ETHER_PACKET_LEN); new_ip_hdr->ip_hl = ip_hdr->ip_hl; /* header length */ new_ip_hdr->ip_v = ip_hdr->ip_v; /* header version */ new_ip_hdr->ip_tos = ip_hdr->ip_tos; /* type of service */ new_ip_hdr->ip_len = htons(56); /* total length */ new_ip_hdr->ip_id = 0; /* identification */ new_ip_hdr->ip_off = htons(0b0100000000000000); /* fragment offset field */ new_ip_hdr->ip_ttl = 64; /* time to live */ new_ip_hdr->ip_p = ip_protocol_icmp; /* protocol */ new_ip_hdr->ip_src = ip_hdr->ip_dst; /* source address */ new_ip_hdr->ip_dst = ip_hdr->ip_src; /* dest address */ new_ip_hdr->ip_sum = 0; new_ip_hdr->ip_sum = cksum(new_ip_hdr, sizeof(sr_ip_hdr_t));; /* checksum */ /* create icmp t3 header */ sr_icmp_t3_hdr_t *new_icmp_t3_hdr = (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr + IP_PACKET_LEN); new_icmp_t3_hdr->icmp_type = htons(3); new_icmp_t3_hdr->icmp_code = htons(3); new_icmp_t3_hdr->unused = 0; new_icmp_t3_hdr->next_mtu = 0; memcpy(new_icmp_t3_hdr->data, new_ip_hdr, ICMP_DATA_SIZE); new_icmp_t3_hdr->icmp_sum = 0; new_icmp_t3_hdr->icmp_sum = cksum(new_icmp_t3_hdr, sizeof(sr_icmp_t3_hdr_t)); struct sr_if *out_iface = sr_get_router_if(sr, ip_hdr->ip_dst); sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name); /* set the last packet to be NULL */ prev_pkt->next = NULL; } pthread_mutex_unlock(&(nat->lock)); } } } return NULL; }