/*--------------------------------------------------------------------- * Method: handle_outgoing_icmp * * Scope: Global * * This function contains the logic for handling outbound ICMP packets. * in concludes the appropriate response to take, either to route, drop * or generate a host unreachable ICMP error. It also translates the * outgoing packet if necessary. The router will then implements the NAT's * recommendation on the potentially modified ip packet. * * parameters: * sr - a reference to the router structure * iphdr - a struct containing the NAT's translation policy * *---------------------------------------------------------------------*/ nat_action_type handle_outgoing_icmp(struct sr_instance *sr, sr_ip_hdr_t *iphdr) { DebugNAT("+++ NAT handling outbound ICMP +++\n"); struct sr_nat *nat = &sr->nat; unsigned int iplen = ntohs(iphdr->ip_len); unsigned int icmplen = 0; sr_icmp_echo_hdr_t *icmphdr = (sr_icmp_echo_hdr_t *) extract_ip_payload(iphdr, iplen, &icmplen); if ((icmphdr->icmp_type != icmp_type_echoreply) && (icmphdr->icmp_type != icmp_type_echoreq)) { DebugNAT("+++ Unsupported ICMP type. +++\n"); return nat_action_drop; //ignore icmp packets other then echo requests/replies } uint32_t ip_src = iphdr->ip_src; //uint32_t ip_dst = ntohl(iphdr->ip_dst); uint16_t aux_src = icmphdr->icmp_id; sr_nat_mapping_t *map = sr_nat_lookup_internal(nat,ip_src,aux_src,nat_mapping_icmp); if (map == NULL) { //insert new mapping into the translation table map = sr_nat_insert_mapping(sr,ip_src,aux_src,0,0,nat_mapping_icmp); DebugNAT("+++ Created NAT mapping from id [%d] to [%d]. +++\n",ntohs(map->aux_int),ntohs(map->aux_ext)); } //translate entry translate_outgoing_icmp(iphdr,map); //update connection state update_icmp_connection(map); return nat_action_route; }
/** * ICMP Echo reply (on receipt of an ICMP Echo request to one of the router’s interfaces) */ int nat_icmp(uint8_t* buf, unsigned int len, struct sr_instance* sr, char* interface) { //sr_ethernet_hdr_t *p_ehdr = (sr_ethernet_hdr_t *) buf; sr_ip_hdr_t* p_iphdr = (sr_ip_hdr_t *) (buf + sizeof(sr_ethernet_hdr_t)); struct icmphdr* p_icmphdr = (struct icmphdr*) ((uint8_t *) p_iphdr + 4 * (p_iphdr->ip_hl & 0x0f)); /** check sum verify, temporary set the chksum part to 0 */ uint16_t lenIcmp = ntohs(p_iphdr->ip_len) - (p_iphdr->ip_hl & 0x0f) * 4; uint16_t calculatedsum = cksum(p_icmphdr, lenIcmp); if (calculatedsum + 1 != 0x010000) { printf("icmp sum check fails: %d, length: %d\n", calculatedsum, lenIcmp); return -1; } printf("[icmp nat]icmp sum check pass\n"); //printf("------------------> %d, %d\n", ICMP_ECHOREPLY , p_icmphdr->type &0x0ff); if (p_icmphdr->type == ICMP_ECHO) { printf("[icmp nat info] get the request, start to nat forwarding, ip: %d, id: %d\n",ntohl(p_iphdr->ip_src), ntohs(p_icmphdr->un.echo.id)); /* if the echo request come from external network, drop it */ if (memcmp(if_nat->name, interface, strlen(if_nat->name)) != 0) { printf( "[warning] echo request comes from external network, drop it. source interface: %s\n", interface); return 1; } /* looking up the mapping entry, or insert a new one */ struct sr_nat_mapping *m = sr_nat_lookup_internal(&(sr->nat), ntohl(p_iphdr->ip_src), ntohs(p_icmphdr->un.echo.id), nat_mapping_icmp); if (m == NULL ) { printf("[echo id: %d]\n", ntohs(p_icmphdr->un.echo.id)); m = sr_nat_insert_mapping(&(sr->nat), ntohl(p_iphdr->ip_src), ntohs(p_icmphdr->un.echo.id), ntohl(p_iphdr->ip_dst),nat_mapping_icmp, 0, 0); printf("[nat-------------------------------------------------] insert new nat icmp entry, now table: \n"); print_mapping_table(sr->nat.mappings); } assert(m); /* rewrite the package */ p_icmphdr->un.echo.id = htons(m->aux_ext); sr_nat_update_icmp_mapping(&(sr->nat), p_icmphdr->un.echo.id); p_icmphdr->checksum = 0; p_icmphdr->checksum = cksum(p_icmphdr, lenIcmp); struct in_addr dest; //dest.s_addr = ntohl(pIpHdr->ip_dst); dest.s_addr =( p_iphdr->ip_dst); struct sr_rt *tSr = sr_find_routing_entry(sr, dest, buf, len); printf("[nat icmp] find exit interface: %s\n", tSr->interface); printf("[nat icmp] --------------find the out ip for destination ip: "); printf("destinate: "); print_ip_int(dest.s_addr); printf("\n"); uint32_t ipOut = find_ip_by_interface(tSr->interface, sr->if_list); printf("interface: %s , exit ip ", tSr->interface); print_ip_int(ipOut); printf("\n"); p_iphdr->ip_src = ipOut; sr_forward_ippacket(sr, buf, len); printf("[nat] forward a icmp request, [id= %d]\n", m->aux_ext); free(m); return 0; } else if (ICMP_ECHOREPLY == (p_icmphdr->type & 0x0ff)) { printf("get icmp response from "); print_ip_int(ntohl(p_iphdr->ip_src)); printf("\n"); struct sr_nat_mapping *m = sr_nat_lookup_external(&(sr->nat), ntohs(p_icmphdr->un.echo.id), nat_mapping_icmp); if (NULL == m) { printf("unknown icmp reply [id = %d ], drop it\n", ntohs(p_icmphdr->un.echo.id)); return 1; } /* rewrite the icmp header */ p_icmphdr->un.echo.id = htons(m->aux_int); p_icmphdr->checksum = 0; p_icmphdr->checksum = cksum(p_icmphdr, lenIcmp); // printf("[nat] ----------------\n"); // print_ip_int(p_iphdr->ip_dst); // printf("[nat] ----------------\n"); // print_ip_int(m->ip_int); // printf("[nat] ----------------\n"); /*rewrite the dst ip */ p_iphdr->ip_dst = htonl(m->ip_int); sr_forward_ippacket(sr, buf, len); sr_nat_update_icmp_mapping(&(sr->nat), p_icmphdr->un.echo.id); free(m); return 0; } else { printf("[nat icmp]get other type of icmp packet, type(%d), ignore\n", p_icmphdr->type & 0x0ff); return 0; } //return 1; }
// New NAT handling function void processNatIP(struct sr_instance *sr, uint8_t *packet, unsigned int len, struct sr_if *interface){ sr_ip_hdr_t *ipHeader = (sr_ip_hdr_t *) (packet + ethernetHeaderSize); uint8_t protocolType = ipHeader->ip_p; if (protocolType == TCP){ // Create the tcp header and print it //TODO:sr_tcp_hdr_t *tcpHeader = (sr_tcp_hdr_t *) (packet + sizeof(sr_ethernet_hdr_t) + (ipHeader->ip_hl * 4)); //TODO: Need to Update the port and Update the checksum } if (protocolType == ICMP){ // If the interface name matches the internal nat interface if (!strncmp(interface->name, internalNat, sr_IFACE_NAMELEN)) { /* received from internal interface */ // Check if this this router is the destination struct sr_if *destination = getIpInterface(sr, ipHeader->ip_dst); // If the destination is not for us, handle it with ICMP if (destination != NULL) { processICMP(sr, packet, len); } // Otherwise, if the destination is not for us, need to forward it else { /* outbound */ // Construct Type 0 ICMP Header sr_icmp_t0_hdr_t *icmpHeader = (sr_icmp_t0_hdr_t *) (packet + ethernetHeaderSize + (ipHeader->ip_hl * 4)); // Look up the mapping associated with given internal ip port pair struct sr_nat_mapping *natMapping = sr_nat_lookup_internal(&(sr->nat), ipHeader->ip_src, icmpHeader->icmp_id, nat_mapping_icmp); // No such nat mapping => insert into the mapping list if (!natMapping) { natMapping = sr_nat_insert_mapping(&(sr->nat), ipHeader->ip_src, icmpHeader->icmp_id, nat_mapping_icmp); } // Get external Nat Interface struct sr_if *externalNatInterface = sr_get_interface(sr, externalNat); /* Update the ICMP and IP Header */ ipHeader->ip_src = externalNatInterface->ip; ipHeader->ip_sum = 0; ipHeader->ip_sum = cksum(ipHeader, ipHeader->ip_hl * 4); icmpHeader->icmp_id = natMapping->aux_ext; icmpHeader->icmp_sum = 0; icmpHeader->icmp_sum = cksum(icmpHeader, ntohs(ipHeader->ip_len) - (ipHeader->ip_hl * 4)); free(natMapping); // Forward th IP ipForwarding(sr, packet, len); } } // Otherwise: if the interface name does match external nat interface else if (!strncmp(interface->name, externalNat, sr_IFACE_NAMELEN)) { /* received from external interface */ // Check the destination struct sr_if *destination = getIpInterface(sr, ipHeader->ip_dst); // If the destination isn't for us, just drop it if (destination == NULL) { return; } // If the destination is for us: Same behaviour else { /* inbound */ sr_icmp_t0_hdr_t *icmpHeader = (sr_icmp_t0_hdr_t *)(packet + ethernetHeaderSize + (ipHeader->ip_hl * 4)); struct sr_nat_mapping *natMapping = sr_nat_lookup_external(&(sr->nat), icmpHeader->icmp_id, nat_mapping_icmp); if (!natMapping) { return; } /* Update the ICMP and IP Header */ ipHeader->ip_dst = natMapping->ip_int; ipHeader->ip_sum = 0; ipHeader->ip_sum = cksum(ipHeader, ipHeader->ip_hl * 4); icmpHeader->icmp_id = natMapping->aux_int; icmpHeader->icmp_sum = 0; icmpHeader->icmp_sum = cksum(icmpHeader, ntohs(ipHeader->ip_len) - (ipHeader->ip_hl * 4)); free(natMapping); ipForwarding(sr, packet, len); } } } }