void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req){ /*Debug("\nsr_handle_arpreq called\n");*/ time_t now; now = time(NULL); struct sr_arpcache *cache = &(sr->cache); /*if the arp_request has never been sent before or if the last time the arp_request was sent was more than 1 second ago*/ if ((req->times_sent == 0)||(difftime(now, req->sent)> 1.0)){ /*Debug("\nARP request not previously sent or have not been sent within the last second\n");*/ if (req->times_sent >= 5) { /*Debug("\nARP request was sent 5 times previously; destroy ARP request\n");*/ /*loop through all of the IP packets waiting for the request, call function to send ICMP msg -> host_unreachable*/ struct sr_packet *packet; for(packet = req->packets; packet != NULL; packet = packet->next) { /*这里的interface是outgoing interface,有问题,send_icmp_message要的是in_interface*/ send_icmp_message(sr, packet->buf, sizeof(struct sr_packet), sr_get_interface(sr, req->packets->iface), ICMP_DESTINATION_UNREACHABLE_TYPE, ICMP_HOST_UNREACHABLE_CODE); } sr_arpreq_destroy(cache, req); } else { /*Debug("\nSending ARP request\n");*/ /*这里的interface是outgoing interface,有问题,send_icmp_message要的是in_interface*/ printf("interface: %s", req->packets->iface); send_arp_request(sr, sr_get_interface(sr, req->packets->iface), req->ip); req->sent = now; req->times_sent++; } } }
void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) { time_t now = time(NULL); if (difftime(now, req->sent) >= 0.9) { if (req->times_sent >= 5) { struct sr_packet *pkt_pending = req->packets; struct sr_if *interface = sr_get_interface(sr, pkt_pending->iface); while (pkt_pending) { icmp_handler(sr, pkt_pending->buf, 0, interface->ip, HOST_UNREACHABLE); pkt_pending = pkt_pending->next; } sr_arpreq_destroy(&(sr->cache), req); } else { int packet_len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t); uint8_t *pkt = malloc(packet_len); struct sr_ethernet_hdr *eth_hdr = (struct sr_ethernet_hdr *)pkt; struct sr_if *interface = sr_get_interface(sr, req->packets->iface); uint8_t hrd_addr[ETHER_ADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; enum sr_ethertype eth_arp = ethertype_arp; enum sr_ethertype eth_ip = ethertype_ip; memcpy(eth_hdr->ether_dhost, hrd_addr, ETHER_ADDR_LEN); memcpy(eth_hdr->ether_shost, interface->addr, ETHER_ADDR_LEN); eth_hdr->ether_type = htons(eth_arp); struct sr_arp_hdr *arp_hdr = (struct sr_arp_hdr *)(sizeof(sr_ethernet_hdr_t) + pkt); enum sr_arp_hrd_fmt hrd_eth = arp_hrd_ethernet; enum sr_arp_opcode arp_op_req = arp_op_request; arp_hdr->ar_hrd = htons(hrd_eth); arp_hdr->ar_pro = htons(eth_ip); arp_hdr->ar_hln = ETHER_ADDR_LEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(arp_op_req); arp_hdr->ar_sip = interface->ip; arp_hdr->ar_tip = req->ip; memcpy(arp_hdr->ar_sha, interface->addr, ETHER_ADDR_LEN); memcpy(arp_hdr->ar_tha, hrd_addr, ETHER_ADDR_LEN); printf("Sending Packets.. [3].\n"); sr_send_packet(sr, pkt, packet_len, interface->name); free(pkt); req->sent = now; req->times_sent++; } } }
/*--------------------------------------------------------------------- * Method: handle_arp_request * Scope: local * * Handles an ARP request sent to an interface. * *---------------------------------------------------------------------*/ static void handle_arp_request(struct sr_instance *sr, struct sr_ethernet_hdr *ethernet_header, struct sr_arphdr *arp_header, char *interface) { printf("\tIt's an ARP request!\n"); // Get the interface address struct sr_if* iface = sr_get_interface(sr, interface); if ( iface == 0 ) { fprintf( stderr, "** Error, interface %s, does not exist\n", interface); } // Create ARP reply :) struct sr_arphdr arp_reply; memcpy(&arp_reply, arp_header, sizeof(struct sr_arphdr)); arp_reply.ar_op = htons(ARP_REPLY); memcpy(&arp_reply.ar_sha, iface->addr, ETHER_ADDR_LEN); memcpy(&arp_reply.ar_tha, arp_header->ar_sha, ETHER_ADDR_LEN); memcpy(&arp_reply.ar_sip, &(arp_header->ar_tip), sizeof(uint32_t)); memcpy(&arp_reply.ar_tip, &(arp_header->ar_sip), sizeof(uint32_t)); // Send the reply uint8_t *buffer = pack_ethernet_packet(ethernet_header->ether_shost, iface->addr, ETHERTYPE_ARP, (uint8_t *) &arp_reply, sizeof(struct sr_arphdr)); sr_send_packet(sr, buffer, sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arphdr), interface); }
/* * Send ARP request. */ void send_arp_request(struct sr_instance *sr, uint32_t dst_ip, char *interface) { uint8_t *packet = (uint8_t *)malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t)); unsigned int len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t); struct sr_if *rt_if = (struct sr_if *)sr_get_interface(sr, interface); uint8_t brdcst_addr[ETHER_ADDR_LEN]; int i = 0; for(i; i < ETHER_ADDR_LEN; i++){ brdcst_addr[i] = 255; } /* Prepare ethernet header. */ sr_ethernet_hdr_t *ether_hdr = (sr_ethernet_hdr_t *)(packet); ether_hdr->ether_type = htons(ethertype_arp); memcpy(ether_hdr->ether_shost, rt_if->addr, ETHER_ADDR_LEN); memcpy(ether_hdr->ether_dhost, brdcst_addr, ETHER_ADDR_LEN); /* Prepare ARP header. */ sr_arp_hdr_t *arp_hdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t)); arp_hdr->ar_hrd = htons(arp_hrd_ethernet); arp_hdr->ar_pro = htons(ethertype_ip); arp_hdr->ar_hln = ETHER_ADDR_LEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(arp_op_request); memcpy(arp_hdr->ar_sha, rt_if->addr, ETHER_ADDR_LEN); arp_hdr->ar_sip = rt_if->ip; memcpy(arp_hdr->ar_tha, brdcst_addr, ETHER_ADDR_LEN); arp_hdr->ar_tip = dst_ip; /* Send the packet. */ sr_send_packet(sr, packet, len, interface); }
/*----------------------------------------------------------------------------- * Method: void checkCachedPackets(struct sr_instance* sr, int cachedArp) * * searches our packet cache for a matching ip in arpCache[cachedArp]. if we * find a match, we forward the packet. if we do not find a match we need an * arp cache entry for it. make sure we have been waiting at least 3 seconds * before we send the src icmp unreachable packets. this does not drop the * packet, it just looks every 3rd second to see if we have a response. every * time we look, we try to increment the arp counter *---------------------------------------------------------------------------*/ void checkCachedPackets(struct sr_instance* sr, int cachedArp) { int i, arpMatch; for (i = 0; i < PACKET_CACHE_SIZE; i++) { if (packetCache[i].len > 0) { // if we have a packet waiting if (packetCache[i].arps <= 5) { // and we have not sent 5 arps for this packet yet if ((arpMatch = arpSearchCache(packetCache[i].tip)) > -1) { // and we have an arp match for our packet's next hop forwardPacket(sr, (uint8_t*)&packetCache[i].packet, packetCache[i].len, // send it along packetCache[i].nexthop->interface, arpReturnEntryMac(arpMatch)); packetCache[i].len = 0; } else { /* wait three seconds between each arp request */ if ((int)(difftime(time(NULL), packetCache[i].timeCached))%3 < 1) { arpSendRequest(sr, sr_get_interface(sr, packetCache[i].nexthop->interface), packetCache[i].nexthop->gw.s_addr); packetCache[i].arps++; } } } else { /* then */ icmpSendUnreachable(sr, (uint8_t*)&packetCache[i].packet, packetCache[i].len, packetCache[i].nexthop->interface, ICMP_HOST_UNREACHABLE); packetCache[i].len = 0; } } } }
/* Insert a new mapping into the nat's mapping table. Actually returns a copy to the new mapping, for thread safety. */ struct sr_nat_mapping *sr_nat_insert_mapping(struct sr_nat *nat, uint32_t ip_int, uint16_t aux_int, sr_nat_mapping_type type ) { pthread_mutex_lock(&(nat->lock)); /* handle insert here, create a mapping, and then return a copy of it */ struct sr_nat_mapping *mapping = malloc(sizeof(struct sr_nat_mapping)); mapping->ip_int = ip_int; mapping->aux_int = aux_int; mapping->type = type; mapping->last_updated = time(NULL); mapping->conns = NULL; /* find free port to assign mapping to 1024-2047 */ uint16_t nxt_prt = 0; for(nxt_prt; nxt_prt < NUM_PORTS; nxt_prt++) { if (nat->ports_used[nxt_prt] == 0) { break; } } mapping->aux_ext = 1024+nxt_prt; nat->ports_used[nxt_prt] == 1; /* get ext_ip */ struct sr_if *ext_iface = sr_get_interface(nat->sr, nat->out_if_name); mapping->ip_ext = ext_iface->ip; mapping->next = nat->mappings; /* add to front of table */ pthread_mutex_unlock(&(nat->lock)); struct sr_nat_mapping *copy = malloc(sizeof(struct sr_nat_mapping)); memcpy(copy, mapping, sizeof(struct sr_nat_mapping)); return copy; }
int send_packet(struct sr_instance* sr, char* iface, uint8_t* dstMAC, uint8_t* payload, unsigned int len, uint16_t type) { assert(sr); assert(payload); assert(iface); uint8_t* packet = (uint8_t*)malloc_or_die(len + 14); struct sr_ethernet_hdr* tmpHdr = (struct sr_ethernet_hdr*) malloc_or_die(14* sizeof(uint8_t)); struct sr_vns_if* interface = sr_get_interface(sr, iface); mac_copy(dstMAC, tmpHdr->ether_dhost); mac_copy(interface->addr, tmpHdr->ether_shost); tmpHdr->ether_type = htons(type); memcpy(packet, tmpHdr, 14); packet = packet + 14; memcpy(packet, payload, len); packet = packet - 14; if((sr_integ_low_level_output(sr, packet, (unsigned int)(len + 14), iface)) == 0) { printf("********** %s successfully sent a packet reply\n", __func__); return 1; } else { printf("\n @@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@ %s sending packet failed?\n", __func__); return 0; } return -1; }
/* Sends an ARP looking for target IP */ void sr_send_arp(struct sr_instance *sr, enum sr_arp_opcode code, char *iface, unsigned char *target_eth_addr, uint32_t target_ip){ sr_arp_hdr_t *arp_hdr = malloc(sizeof(sr_arp_hdr_t)); if(arp_hdr){ arp_hdr->ar_hrd = htons(arp_hrd_ethernet); arp_hdr->ar_pro = htons(ethertype_ip); arp_hdr->ar_hln = ETHER_ADDR_LEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(code); struct sr_if *node = sr_get_interface(sr, iface); memcpy(arp_hdr->ar_sha, node->addr, ETHER_ADDR_LEN); arp_hdr->ar_sip = node->ip; memcpy(arp_hdr->ar_tha, target_eth_addr, ETHER_ADDR_LEN); arp_hdr->ar_tip = target_ip; sr_send_eth(sr, (uint8_t *)arp_hdr, sizeof(sr_arp_hdr_t), (uint8_t *)target_eth_addr, iface, ethertype_arp); free(arp_hdr); } }
void sr_handlepacket(struct sr_instance* sr, uint8_t * packet/* lent */, unsigned int len, char* interface/* lent */) { /* REQUIRES */ assert(sr); assert(packet); assert(interface); printf("*** -> Received packet of length %d \n",len); /* Error handling */ if (len < sizeof(sr_ethernet_hdr_t)) { printf("Invalid packet, insufficient length.\n"); return; } struct sr_if* iface = sr_get_interface(sr, interface); if (iface == 0) { printf("Invalid interface, interface not found.\n"); } /* Handle ARP packet */ if (ethertype(packet) == ethertype_arp) { sr_handle_arp_packet(sr, packet, len, interface, iface); } /* Handle IP packet */ else if (ethertype(packet) == ethertype_ip) { sr_handle_ip_packet(sr, packet, len, interface, iface); } }/* end sr_ForwardPacket */
void sr_handlepacket(struct sr_instance* sr, uint8_t * packet/* lent */, unsigned int len, char* interface/* lent */) { /* REQUIRES */ assert(sr); assert(packet); assert(interface); printf("*** -> Received packet of length %d \n",len); /* check length */ if (len < sizeof(sr_ethernet_hdr_t)) { fprintf(stderr, "Failed to process ETHERNET header, insufficient length\n"); return; } sr_ethernet_hdr_t *eth_hdr = (sr_ethernet_hdr_t *)packet; uint16_t ether_type = ntohs(eth_hdr->ether_type); struct sr_if *iface = sr_get_interface(sr, interface); if (ether_type == ethertype_ip) { sr_handle_ip(sr, packet, len, iface); } else if (ether_type == ethertype_arp) { sr_handle_arp(sr, packet, len, iface); } }
void sr_forward_ip(struct sr_instance *sr, uint8_t *packet, unsigned int len) { assert(sr); assert(packet); sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t)); ip_hdr->ip_ttl--; if (ip_hdr->ip_ttl == 0) { sr_send_icmp(sr, packet, len, 11, 0); return; } ip_hdr->ip_sum = 0; ip_hdr->ip_sum = cksum(ip_hdr, ip_hdr->ip_hl * 4); struct sr_rt *rt = sr_longest_prefix_match_lookup(sr, ip_hdr->ip_dst); if (!rt) { sr_send_icmp(sr, packet, len, 3, 0); return; } struct sr_if *oiface = sr_get_interface(sr, rt->interface); sr_lookup_and_send(sr, packet, len, oiface, rt->gw.s_addr); }
void ipForwarding(struct sr_instance *sr, uint8_t *packet, unsigned int len){ // Construct IP Header sr_ip_hdr_t *ipHeader = (sr_ip_hdr_t *)(packet + ethernetHeaderSize); /* Forwading Logistics */ // Decrement TTL ipHeader->ip_ttl = ipHeader->ip_ttl - 1; // Check if TTL Expried if (ipHeader->ip_ttl == 0) { sendICMP(sr, packet, len, TIME_EXCEEDED, TTL_CODE); return; } // New Checksum ipHeader->ip_sum = 0; // reset to 0 first ipHeader->ip_sum = cksum(ipHeader, ipHeader->ip_hl * 4); /// Look for the LPM struct sr_rt *matchingEntry = findLPM(sr, ipHeader->ip_dst); // No LPM => Send ICMP if (matchingEntry == NULL) { printf("No LPM Match found... sending ICMP.\n"); sendICMP(sr, packet, len, DESTINATION_UNREACHABLE, NET_UNREACHABLE_CODE); return; } // Get the outgoing interface to send through struct sr_if *sendingInterface = sr_get_interface(sr, matchingEntry->interface); sendToInterface(sr, packet, len, sendingInterface, matchingEntry->gw.s_addr); }
void ip_handlepacket(struct sr_instance *sr, uint8_t *packet, unsigned int len, char *interface) { printf("** Recieved IP packet\n"); struct sr_ip_hdr *ip_hdr = ip_header(packet); struct sr_if *r_interface = sr_get_interface(sr, interface); if (!ip_validpacket(packet, len)) return; /* Check whether NAT is enabled */ if (!natEnabled(sr)){ printf("** NO NAT\n"); /* Check interface IP to determine whether this IP packet is for me */ if (sr_packet_is_for_me(sr, ip_hdr->ip_dst)) { ip_handlepacketforme(sr, ip_hdr, interface); } else { /* Packet is not for me,forward it */ ip_forwardpacket(sr, ip_hdr, len, interface); } } else { printf("** NAT ENABLED\n"); sr_nat_handle_ip_packet(sr, ip_hdr, ntohs(ip_hdr->ip_len), r_interface); } }
void arp_handle(struct sr_instance* sr, uint8_t * packet, unsigned int length, char* interface) { if(!arp_valid(packet, length)) { fprintf(stderr, "ARP packet does not match the recognized format.\n"); return; } struct sr_if *sr_interface = sr_get_interface(sr, interface); if(sr_interface == 0) { fprintf(stderr, "Failed to retrieve interface %s.\n", interface); return; } struct sr_arphdr *arp_hdr = (struct sr_arphdr *)(packet + sizeof(struct sr_ethernet_hdr)); if(ntohs(arp_hdr->ar_op) == ARP_REQUEST) { if(arp_hdr->ar_tip == sr_interface->ip) arp_respond(sr, packet, sr_interface); else printf("Received ARP packet destined for %d\n", arp_hdr->ar_tip); } else if(ntohs(arp_hdr->ar_op) == ARP_REPLY) { struct sr_arp_record *record = cache_add_record(sr, packet); if(record == NULL) { fprintf(stderr, "Received ARP response that does not match any outstanding ARP requests.\n"); return; } cache_send_outstanding(sr, record); } else { fprintf(stderr, "ARP packet opcode must be of type request or reply.\n"); } }
void sr_handleARPpacket(struct sr_instance *sr, uint8_t* packet, unsigned int len, struct sr_if * iface) { assert(packet); sr_ethernet_hdr_t* ethHeader = (sr_ethernet_hdr_t*) packet; sr_arp_hdr_t * arpHeader = (sr_arp_hdr_t *) (packet+14); enum sr_arp_opcode request = arp_op_request; enum sr_arp_opcode reply = arp_op_reply; struct sr_if *interface = sr_get_interface_from_ip(sr, htonl(arpHeader->ar_tip)); /* handle an arp request.*/ if (ntohs(arpHeader->ar_op) == request) { /* found an ip->mac mapping. send a reply to the requester's MAC addr */ if (interface){ arpHeader->ar_op = ntohs(reply); uint32_t temp = arpHeader->ar_sip; arpHeader->ar_sip = arpHeader->ar_tip; arpHeader->ar_tip = temp; memcpy(arpHeader->ar_tha, arpHeader->ar_sha,6); memcpy(arpHeader->ar_sha, iface->addr,6); /*swapping outgoing and incoming addr*/ set_addr(ethHeader, iface->addr, ethHeader->ether_shost); sr_send_packet(sr,(uint8_t*)ethHeader,len,iface->name); } } /* handle an arp reply */ else { struct sr_packet *req_packet = NULL; struct sr_arpreq *req = NULL; pthread_mutex_lock(&(sr->cache.lock)); for (req = sr->cache.requests; req != NULL; req = req->next){ if(req->ip == arpHeader->ar_sip){ /* find the interface the packets should be sent out of */ struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, req->ip); if (rt) { iface = sr_get_interface(sr, rt->interface); /* send all packets waiting on the request that was replied to */ for (req_packet = req->packets; req_packet != NULL; req_packet = req_packet->next) { sr_ethernet_hdr_t * outEther = (sr_ethernet_hdr_t *)req_packet->buf; memcpy(outEther->ether_shost, iface->addr,6); memcpy(outEther->ether_dhost, ethHeader->ether_shost,6); sr_ip_hdr_t * outIP = (sr_ip_hdr_t *)(req_packet->buf+14); outIP->ip_ttl = outIP->ip_ttl-1; outIP->ip_sum = 0; outIP->ip_sum = cksum((uint8_t *)outIP,20); sr_send_packet(sr,req_packet->buf,req_packet->len,iface->name); } sr_arpreq_destroy(&(sr->cache), req); } break; } } pthread_mutex_unlock(&(sr->cache.lock)); sr_arpcache_insert(&(sr->cache),arpHeader->ar_sha,arpHeader->ar_sip); } }
void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) { time_t curtime = time(NULL); if (difftime(curtime, req->sent) < 1.0) return; if (req->times_sent <= 4) { /* Find out which interface it's on */ char *interface = req->packets->iface; struct sr_if* iface = sr_get_interface(sr, interface); /* Allocate a new packet */ size_t out_len = ARP_REPLY_SIZE; uint8_t *packet_out = malloc(out_len); /* ====== Headers ====== */ /* Allow easy access to the headers */ sr_ethernet_hdr_t *eth_header_out = (sr_ethernet_hdr_t*) packet_out; sr_arp_hdr_t *arp_header_out = (sr_arp_hdr_t*) (packet_out + ARP_HEAD_OFF); /* Create the ethernet header */ char bcast_addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; memcpy(eth_header_out->ether_dhost, bcast_addr, ETHER_ADDR_LEN); memcpy(eth_header_out->ether_shost, iface->addr, ETHER_ADDR_LEN); eth_header_out->ether_type = htons(ethertype_arp); /* ====== Body ====== */ /* Create the ARP packet */ arp_header_out->ar_hrd = htons(0x1); arp_header_out->ar_pro = htons(ethertype_ip); arp_header_out->ar_hln = ETHER_ADDR_LEN; arp_header_out->ar_pln = IP_ADDR_LEN; arp_header_out->ar_op = htons(arp_op_request); memcpy(arp_header_out->ar_sha, iface->addr, ETHER_ADDR_LEN); arp_header_out->ar_sip = iface->ip; char zeroes[] = {0,0,0,0,0,0}; memcpy(arp_header_out->ar_tha, zeroes, ETHER_ADDR_LEN); arp_header_out->ar_tip = req->ip; /* Send the packet */ sr_send_packet(sr, packet_out, out_len, interface); free(packet_out); return; } else { struct sr_packet *packet = req->packets; while (packet) { struct sr_packet *next = packet->next; send_icmp_error(sr, packet->buf, packet->len, packet->iface, 3, 1); packet = next; } sr_arpreq_destroy(&(sr->cache), req); } return; }
sr_if_t *get_external_iface(struct sr_instance *sr) { sr_if_t *int_iface = sr_get_interface(sr,sr->nat.int_iface_name); for (sr_if_t *iface = sr->if_list; iface != NULL; iface = iface->next) { if (iface != int_iface) return iface; } return NULL; }
/******************************************************************* * Finds interface the ARP Request was received from and constructs ARP Reply to send back out of * the received interface. *******************************************************************/ void got_Request(struct packet_state * ps, struct sr_arphdr * arp_hdr, const struct sr_ethernet_hdr* eth) { assert(ps); assert(arp_hdr); assert(eth); struct sr_if *iface = sr_get_interface(ps->sr, ps->interface); assert(iface); construct_reply(ps, arp_hdr, iface->addr, eth); }
/*--------------------------------------------------------------------- * Method: destined_to_nat_external * * Scope: Local * * returns true if the destination IP address of a packet's is that * of the NAT itself (its external facing IP address) * * parameters: * sr - a reference to the router structure * ip_dst - the ip_dst of the received packet. * *---------------------------------------------------------------------*/ bool destined_to_nat_external(struct sr_instance* sr, uint32_t ip_dst) { sr_if_t *int_iface = sr_get_interface(sr,sr->nat.int_iface_name); for (sr_if_t *iface = sr->if_list; iface != NULL; iface = iface->next) { if (iface == int_iface) continue; if (ip_dst == iface->ip) return true; } return false; }
bool match_interface_etheraddr(struct sr_instance *sr,uint8_t *ethaddr,const char * interface) { sr_if_t *ifptr = sr_get_interface(sr,interface); //check if interface exists if (ifptr == 0) return false; return ether_addr_equals(ifptr->addr,ethaddr); }
void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) { time_t now = time(NULL); if(difftime(now, req->sent) > 1.0) { /* request timeout */ if(req->times_sent > 5) { struct sr_packet *packets = req->packets; /* iterate through all packets on queue */ while(packets) { uint8_t *reply_packet = 0; sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packets->buf+sizeof(sr_ethernet_hdr_t)); reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packets->buf, ip_hdr, sr_get_interface(sr, packets->iface), 3, 1); /* create ICMP type 3, code 1 (host unreachable) */ /* if ICMP packet fails to generate */ if(reply_packet == 0) { fprintf(stderr, "Error: failed to generate ICMP packet\n"); } /* send ICMP packet to ip of packet in queue */ if(sr_send_packet(sr, reply_packet, sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t), (const char*)(packets->iface)) == -1) { fprintf(stderr, "Error: sending packet failed (handle_arpreq)"); } packets = packets->next; free(reply_packet); } sr_arpreq_destroy(&(sr->cache), req); } else { /* generate ARP packet */ struct sr_if *iface = 0; /* if interface is not found */ if((iface = sr_get_interface(sr, req->packets->iface)) == 0) { fprintf(stderr, "Error: interface does not exist (handle_arpreq)"); return; } uint8_t *arp_pkt = sr_new_arpreq_packet(NULL, iface->addr, req->ip, iface->ip); /* create ARP request packet to re-send */ /* send ARP request packet */ if (sr_send_packet(sr, arp_pkt, sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t), (const char*)(iface->name))==-1) { fprintf(stderr, "Error: sending packet failed."); } /* update arpreq fields */ req->times_sent++; req->sent = now; free(arp_pkt); } } }
/* Sends ICMP messages to all the packets waiting on this request */ void sr_send_icmp_to_waiting(struct sr_instance *sr, struct sr_arpreq *req){ struct sr_packet *packet = req->packets; while(packet){ struct sr_if* node = sr_get_interface(sr, packet->iface); struct sr_ethernet_hdr *eth = (sr_ethernet_hdr_t *)(packet->buf); struct sr_ip_hdr *ip_hdr = (sr_ip_hdr_t *)(eth + 1); sr_send_icmp3(sr, icmp_unreach, icmp_host_unreach, node->ip, ip_hdr->ip_src, (uint8_t*)ip_hdr, (4*(ip_hdr->ip_hl)) + MORSEL); packet = packet->next; } }
int sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *request){ time_t now = get_now(&now); struct sr_packet * packetptr = request->packets; int i; if(difftime(now, request->sent) > 1.0){ if(request->times_sent >= 5){ while(packetptr != NULL){ icmp_send_reply(sr, (uint8_t *)packetptr, packetptr->len, packetptr->iface, 3, 1); /* send unreachable */ packetptr = packetptr->next; } sr_arpreq_destroy(&(sr->cache), request); return -1; }else{ struct sr_rt* entry; struct sr_rt* routing = sr->routing_table; for(entry = routing; entry != NULL; entry = routing->next){ struct sr_if * interface2 = sr_get_interface(sr, entry->interface); /*create arp packet*/ enum sr_arp_opcode opcode = arp_op_request; struct sr_packet *raw = malloc(sizeof(struct sr_arp_hdr) + ETHER_HDR_LEN); /* may need to memset here*/ struct sr_ethernet_hdr *eth = (struct sr_ethernet_hdr *)raw; struct sr_arp_hdr *req = (struct sr_arp_hdr *)(raw + ETHER_HDR_LEN); req->ar_hrd = 0; req->ar_pro = 0; req->ar_hln = 0; req->ar_pln = 0; req->ar_op = opcode; req->ar_sip = sr->sr_addr.sin_addr.s_addr; req->ar_tip = request->ip; for (i = 0; i < ETHER_ADDR_LEN; i++){ req->ar_tha[i] = 0xff; req->ar_sha[i] = interface2->addr[i]; eth->ether_dhost[i] = 0xff; eth->ether_shost[i] = interface2->addr[i]; } /*send packet to the interface on routing_table*/ sr_send_packet(sr, (uint8_t *)raw, sizeof(struct sr_arp_hdr) + ETHER_HDR_LEN, request->packets->iface); free(raw); } request->sent = now; request->times_sent++; } } return 0; }
/* The handle_arpreq() function is a function you should write, and it should handle sending ARP requests if necessary: function handle_arpreq(request): if difftime(now, request->sent) > 1.0 if request->times_sent >= 5: send icmp host unreachable to source addr of all pkts waiting on this request arpreq_destroy(request) else: send arp request request->sent = now request->times_sent++ */ void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *request){ //assert(sr); //assert(request); // If time since last sent is more than 1 second if (difftime(time(NULL), request->sent) >= 1.0) { /* If an ARP request has been sent 5 times with no response, a destination host unreachable should go back to all the sender of packets that were waiting on a reply to this ARP request. */ if (request->times_sent >= 5) { // Iniitalize variables for the loop struct sr_packet *packetPointer = NULL; sr_ethernet_hdr_t *ethernetHeader = NULL; struct sr_if *interface = NULL; // get a pointer to a array of all packets waiting packetPointer = request->packets; // For every xender of packets waiting, send host unreachable while (packetPointer != NULL) { ethernetHeader = (sr_ethernet_hdr_t *)(packetPointer->buf); interface = getAddressInterface(sr, ethernetHeader->ether_dhost); /* do not send an ICMP message for an ICMP message */ // If we got an interface of a waiting sender, send the ICMP host unreachable if (interface) { sendICMP(sr, packetPointer->buf, packetPointer->len, DESTINATION_UNREACHABLE, HOST_UNREACHABLE_CODE); } // Go to the next exisiting packet packetPointer = packetPointer->next; } sr_arpreq_destroy(&(sr->cache), request); } // Otherwise, just send arp request with its sent time = now and increment times sent else { struct sr_if *sendingInterface = sr_get_interface(sr, request->packets->iface); arpRequest(sr, sendingInterface, request->ip); // Set sent time to NOW request->sent = time(NULL); // time(NULL) = NOW // Increment # of times sent request->times_sent = request->times_sent + 1; } } }
/* 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); }
/* prepare arp into ethernet frame and send it */ int boardcast_arpreq(struct sr_instance *sr, struct sr_arpreq *arp_req){ struct sr_if *o_interface; /*first package the arp package header first...*/ o_interface = sr_get_interface(sr, arp_req->packets->iface); struct sr_arp_hdr arp_hdr; uint8_t *arp_package; uint8_t *e_pack; arp_hdr.ar_hrd = sr_arp_hrd_fmt hfmt = arp_hrd_ethernet; /* format of hardware address */ arp_hdr.ar_pro = 0X800; /*from http:/*www.networksorcery.com/enp/protocol/arp.htm#Protocol%20address%20length*/ arp_hdr.ar_hln = ETHER_ADDR_LEN = 8; /*from http:/*www.networksorcery.com/enp/protocol/arp.htm#Protocol%20address%20length*/ arp_hdr.ar_pln = 8; /*from http:/*www.networksorcery.com/enp/protocol/arp.htm#Protocol%20address%20length*/ sr_arp_opcode code = arp_op_request; arp_hdr.ar_op = code; /* ARP opcode (command) */ memcpy(arp_hdr.ar_sha, o_interface->addr, ETHER_ADDR_LEN); /* sender hardware address */ arp_hdr.ar_sip = o_interface.ip; /* sender IP address */ arp_hdr.ar_tip = arp_req.ip; /* target IP address */ /*copy everything into the arp_header*/ arp_package = malloc(sizeof(sr_arp_hdr_t)); print_hdr_arp(arp_package); memcpy(arp_package, &apr_hdr, sizeof(sr_arp_hdr_t)); /*then package the ethernet header along with the arp header...*/ e_pack = eth_hdr_package(uint8_t ether_dhost, sr, o_interface->addr, arp_package, sizeof(struct sr_arp_hdr)); print_hdr_eth(e_pack); /*send it out*/ sr_send_packet(sr, e_pack, sizeof(struct sr_arp_hdr) + sizeof(struct sr_ethernet_hdr), o_interface); /* build the ethernet frame to be broadcast */ int eth_hdr_package(uint8_t ether_dhost, uint8_t ether_shost, uint16_t ether_type, uint8_t *content, int len){ uint8_t *output; int total_length; struct sr_ethernet_hdr e_hdr; /*first step is to create a ethernet header...*/ memcpy(e_hdr.ether_dhost,ether_dhost,ETHER_ADDR_LEN); /* destination ethernet address */ memcpy(e_hdr.ether_shost,ether_shost,ETHER_ADDR_LEN); /* source ethernet address */ e_hdr.ether_type = ether_type; /*calculate the length of the entire thing...*/ total_length = sizeof(sr_ethernet_hdr_t) + len; /*put everything together*/ output = malloc(total_length); /*put the ethernet header in the front*/ memcpy(output, &e_hdr, sizeof(sr_ethernet_hdr_t)); memcpy(output + sizeof(sr_ethernet_hdr_t), content,len); return output; }
void handle_arpreq(struct sr_instance* sr, struct sr_arpreq *cache_req_ptr) { char *iface_name = cache_req_ptr->packets->iface; struct sr_if *interface = sr_get_interface(sr, iface_name); /*Only broadcast if this hasn't been sent out before: *Otherwise, our packet has been added to the end of the * request's linkedlist in the cache: do nothing*/ if (difftime(time(0), cache_req_ptr->sent) > 1.0) { if (cache_req_ptr->times_sent >= 5) { struct sr_packet *req_pkt_ptr = cache_req_ptr->packets; for (; req_pkt_ptr; req_pkt_ptr = req_pkt_ptr->next) { send_icmp(sr, req_pkt_ptr->buf, req_pkt_ptr->len, interface, dest_host_unreach_type, dest_host_unreach_code); } sr_arpreq_destroy(&(sr->cache), cache_req_ptr); } else { /*Create space for the request*/ uint8_t* eth_pkt_buf = (uint8_t *) malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t)); uint8_t* arp_pkt_buf; /*Pointers to where different header structs start in the packet*/ sr_ethernet_hdr_t* req_eth_header = (sr_ethernet_hdr_t*) eth_pkt_buf; /* Allocate mem for reply packet buffer */ /* Copy addresses and type into the ethernet header */ uint8_t broadcast_addr[ETHER_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; memcpy(req_eth_header->ether_dhost, broadcast_addr, ETHER_ADDR_LEN); memcpy(req_eth_header->ether_shost, interface->addr, ETHER_ADDR_LEN); req_eth_header->ether_type = ethertype_arp; /* Convert to network byte ordering */ hton_eth_hdr(&req_eth_header); /* Get the Arp Buffer and Build the Arp packet*/ arp_pkt_buf = eth_pkt_buf + sizeof(sr_ethernet_hdr_t); sr_create_arp_req_packet(arp_pkt_buf, cache_req_ptr, interface); /* Send the ARP request packet */ sr_send_packet(sr, eth_pkt_buf, sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t), interface->name); cache_req_ptr->sent = time(0); cache_req_ptr->times_sent++; free(eth_pkt_buf); } } }
void sr_icmp_ttl_exceeded(struct sr_instance *sr, uint8_t * packet, unsigned int len, char* interface, struct sr_ethernet_hdr *e_hdr, struct ip *ip_hdr) { struct sr_if *iface = sr_get_interface(sr, interface); /* Send ICMP time exceeded message. This is need for traceroute to work. */ uint8_t *new_pkt = (uint8_t *) calloc(1, 70); struct sr_ethernet_hdr *new_e_hdr = (struct sr_ethernet_hdr *) new_pkt; struct ip *new_ip_hdr = (struct ip *) (new_pkt + 14); struct sr_icmphdr *new_icmp_hdr = (struct sr_icmphdr *) (new_pkt + 34); /* ethernet header */ memcpy(new_e_hdr->ether_dhost, e_hdr->ether_shost, 6); memcpy(new_e_hdr->ether_shost, e_hdr->ether_dhost, 6); new_e_hdr->ether_type = htons(0x0800); /* IP header */ new_ip_hdr->ip_hl = 5; new_ip_hdr->ip_v = 4; new_ip_hdr->ip_tos = 0; new_ip_hdr->ip_len = htons(56); new_ip_hdr->ip_id = ip_hdr->ip_id; new_ip_hdr->ip_off = ip_hdr->ip_off; new_ip_hdr->ip_ttl = 64; new_ip_hdr->ip_p = 1; new_ip_hdr->ip_src.s_addr = iface->ip; new_ip_hdr->ip_dst = ip_hdr->ip_src; new_ip_hdr->ip_sum = 0; new_ip_hdr->ip_sum = checksum(new_ip_hdr, 20); /* ICMP ttl exceeded: type: 11, code: 0 */ new_icmp_hdr->icmp_type = 11; new_icmp_hdr->icmp_code = 0; new_icmp_hdr->id = 0; new_icmp_hdr->seqno = 0; memcpy(new_pkt+42, ip_hdr, 28); new_icmp_hdr->icmp_chksum = 0; new_icmp_hdr->icmp_chksum = checksum((uint16_t *)new_icmp_hdr, 36); int success = sr_send_packet(sr, new_pkt, 70, interface); if (success != 0) { fprintf(stderr, "%s: Sending packet failed!\n", __func__); } }
/*--------------------------------------------------------------------- * Method: process_arp(struct sr_instance* sr, * uint8_t * packet, * unsigned int len, * char* interface) * Scope: Internal * * This function processes an arp packe that was received. It handles * two cases, one where it is a request and one where it is a response. * *---------------------------------------------------------------------*/ void process_arp(struct sr_instance* sr, uint8_t * packet, unsigned int len, char* interface) { struct sr_arpentry *arp_entry; struct sr_arpreq *arp_req; struct sr_arp_hdr *arp_hdr; struct sr_if* rec_if; /* Validate the arp packet */ if (!valid_arp(packet, len)) return; /* Is the arp addressed to me? NOTE: I do not follow the RFC recommendation to * update existing cache entries with the received arp packet's ip-mac mapping * before checking whether the packet was addressed me. This is because we do * not have a good way to strictly 'update' cache entries without inserting a new * one and I would like to avoid duplicate valid cache entries for the same ip. */ rec_if = sr_get_interface(sr, interface); arp_hdr = arp_header(packet); if (rec_if->ip != arp_hdr->ar_tip) return; /* Add the sender's protocol address to my table. */ arp_entry = sr_arpcache_lookup(&sr->cache, arp_hdr->ar_sip); /* Arp entry already exists. NOTE: arp_entry is a copy in this case so free it.*/ if (arp_entry != 0) { free(arp_entry); /* Arp entry doesn't exist so add it. */ } else { arp_req = sr_arpcache_insert(&sr->cache, arp_hdr->ar_sha, arp_hdr->ar_sip); /* There are packets waiting on this arp request. Send them. */ if (arp_req != 0) { sr_arpreq_send_packets(sr, arp_req); } } /* Handle a request. */ if (arp_opcode(arp_hdr) == arp_op_request) { process_arp_request(sr, arp_hdr, rec_if); } }
/* * Send an ICMP Error. */ void send_icmp_error(uint8_t type, uint8_t code, struct sr_instance *sr, char *interface, unsigned int len, uint8_t *pkt) { int new_len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t); uint8_t *packet = (uint8_t *) malloc(new_len); struct sr_if *rt_if = (struct sr_if *)malloc(sizeof(struct sr_if)); rt_if = (struct sr_if *)sr_get_interface(sr, interface); /* Prepare ethernet header. */ sr_ethernet_hdr_t *ether_hdr = (sr_ethernet_hdr_t *) pkt; sr_ethernet_hdr_t *ether_newhdr = (sr_ethernet_hdr_t *) packet; ether_newhdr->ether_type = htons(ethertype_ip); memcpy(ether_newhdr->ether_shost, rt_if->addr, ETHER_ADDR_LEN); memcpy(ether_newhdr->ether_dhost, ether_hdr->ether_shost, ETHER_ADDR_LEN); /* Prepare IP header. */ sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(pkt + sizeof(sr_ethernet_hdr_t)); sr_ip_hdr_t *ip_newhdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t)); memcpy(ip_newhdr, ip_hdr, sizeof(sr_ip_hdr_t)); ip_newhdr->ip_src = rt_if->ip; ip_newhdr->ip_dst = ip_hdr->ip_src; ip_newhdr->ip_len = htons(56); ip_newhdr->ip_id = 0; ip_newhdr->ip_hl = 5; ip_newhdr->ip_off = 0; ip_newhdr->ip_ttl = 64; ip_newhdr->ip_p = ip_protocol_icmp; ip_newhdr->ip_sum = 0; ip_newhdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t)); /* Prepare the ICMP t3 header. */ sr_icmp_t3_hdr_t *icmp_t3_hdr = (sr_icmp_t3_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)); icmp_t3_hdr->icmp_type = type; icmp_t3_hdr->icmp_code = code; icmp_t3_hdr->icmp_sum = 0; memcpy(icmp_t3_hdr->data, ip_hdr, 20); memcpy(icmp_t3_hdr->data + 20, pkt + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), 8); icmp_t3_hdr->icmp_sum = cksum(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), sizeof(sr_icmp_t3_hdr_t)); /* Send the ICMP error packet. */ sr_send_packet(sr, packet, new_len, interface); }