From 60e2375e6c9dbc7589653019b0aafa0dad8f08b2 Mon Sep 17 00:00:00 2001 From: cpomz Date: Sun, 16 Mar 2014 14:38:13 -0700 Subject: [PATCH] My changes --- sr_arpcache.c | 123 ++++++++ sr_arpcache.h | 5 + sr_if.c | 27 ++ sr_if.h | 2 +- sr_protocol.h | 4 +- sr_router.c | 826 ++++++++++++++++++++++++++++++++++++-------------- sr_router.h | 1 + sr_rt.c | 41 +++ sr_rt.h | 2 +- 9 files changed, 799 insertions(+), 232 deletions(-) diff --git a/sr_arpcache.c b/sr_arpcache.c index 194a6fb..ab171c8 100644 --- a/sr_arpcache.c +++ b/sr_arpcache.c @@ -10,14 +10,137 @@ #include "sr_router.h" #include "sr_if.h" #include "sr_protocol.h" +#include "sr_utils.h" /* This function gets called every second. For each request sent out, we keep checking whether we should resend an request or destroy the arp request. See the comments in the header file for an idea of what it should look like. */ + + +void handle_arpreq(struct sr_instance* sr,struct sr_arpreq* request) +{ + time_t now = time(0); /*get system time*/ + 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*/ + struct sr_packet* iter = request->packets; + + while(iter) /*for each packet in the packet list*/ + { + + /*initialize ICMP packet*/ + unsigned int packet_len = sizeof(sr_ethernet_hdr_t)+sizeof(sr_ip_hdr_t)+sizeof(sr_icmp_hdr_t); + uint8_t *packet_buf = (uint8_t*)malloc(packet_len); + + + /*find the ethernet header field of the packet to extract the source address*/ + sr_ethernet_hdr_t* ether_header = (sr_ethernet_hdr_t*) (iter->buf); + unsigned char srcAddr[ETHER_ADDR_LEN]; + memcpy(srcAddr,ether_header->ether_shost,ETHER_ADDR_LEN); + char iname[sr_IFACE_NAMELEN]; /*name of the destination interface*/ + strcpy(iname,find_interface(sr,srcAddr)); + + /*source address becomes destination address of ICMP packet*/ + sr_ethernet_hdr_t* icmp_ether_header = (sr_ethernet_hdr_t*) packet_buf; + /*struct sr_if* src_interface = sr_get_interface(sr,sr->host);*/ /*find source host interface*/ + memcpy(icmp_ether_header->ether_dhost,ether_header->ether_shost,ETHER_ADDR_LEN); /*copy destination address*/ + memcpy(icmp_ether_header->ether_shost,ether_header->ether_dhost,ETHER_ADDR_LEN); /*source of icmp packet is destination of packet*/ + icmp_ether_header->ether_type |= ethertype_ip; /*ICMP is carried via ip*/ + + /*find ip_header field of the packet*/ + sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*) (iter->buf+sizeof(sr_ethernet_hdr_t)); + + /*initialize ip_header field of icmp packet*/ + sr_ip_hdr_t* icmp_ip_header = (sr_ip_hdr_t*) (packet_buf+sizeof(sr_ethernet_hdr_t)); + icmp_ip_header->ip_len = sizeof(sr_ip_hdr_t)+sizeof(sr_icmp_t3_hdr_t); /*the only data will be icmp type3 header packet;*/ + icmp_ip_header->ip_p |= ip_protocol_icmp; /*upper layer protocol is icmp protocol*/ + icmp_ip_header->ip_src = ip_header->ip_dst; + icmp_ip_header->ip_dst = ip_header->ip_src; + icmp_ip_header->ip_ttl = 255; /*maximum allowed TTL value for IPv4*/ + icmp_ip_header->ip_sum = 0; /*initially 0 before computing checksum*/ + icmp_ip_header->ip_sum = cksum(icmp_ip_header,sizeof(sr_ip_hdr_t)); /*then calculate checksum*/ + + /*now initialize icmp type3 header field of the icmp packet*/ + sr_icmp_hdr_t* icmp3_header = (sr_icmp_hdr_t*) (packet_buf+sizeof(sr_ethernet_hdr_t)+sizeof(sr_ip_hdr_t)); + icmp3_header->icmp_type = 3; /*icmp type3*/ + icmp3_header->icmp_code = 1; /*destination host unreachable*/ + icmp3_header->icmp_sum = 0; /*checksum field initially 0*/ + icmp3_header->icmp_sum = cksum(icmp3_header,sizeof(sr_icmp_hdr_t)); /*then calculate checksum*/ + + sr_send_packet(sr,packet_buf,packet_len,iname); + + iter = iter->next; + } + /*destroy the request*/ + sr_arpreq_destroy(&(sr->cache),request); + } + + else + { + /*send arp request*/ + + /*build an arp packet*/ + unsigned int packet_len = sizeof(sr_ethernet_hdr_t)+sizeof(sr_arp_hdr_t); + uint8_t* packet_buf = (uint8_t*) malloc(packet_len); + sr_ethernet_hdr_t* arp_ether_header = (sr_ethernet_hdr_t*) (packet_buf); + int i; + for (i = 0; i < ETHER_ADDR_LEN; i++) + { + /*destination address is broadcast address*/ + arp_ether_header->ether_dhost[i] = 0xff; + } + + /*finding source hardware / ip address of arp packet*/ + struct sr_if* iface = sr_get_interface(sr,sr->host); + /*source hardware address*/ + memcpy(arp_ether_header->ether_shost,iface->addr,ETHER_ADDR_LEN); + arp_ether_header->ether_type |= ethertype_arp; /*ARP type*/ + + /*build arp header of the arp packet*/ + sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*) (packet_buf+sizeof(sr_ethernet_hdr_t)); + arp_header->ar_tip = request->ip; /*next hop ip address*/ + memcpy(arp_header->ar_tha,arp_ether_header->ether_dhost,ETHER_ADDR_LEN); /*target hardware address (should be ff-ff-ff-ff-ff-ff)*/ + arp_header->ar_sip = iface->ip; /*sender ip address*/ + memcpy(arp_header->ar_sha,iface->addr,ETHER_ADDR_LEN); /*sender hardware address*/ + arp_header->ar_tip = request->ip; /*arp request ip address is stored as target ip address*/ + arp_header->ar_op |= arp_op_request; /*operation is request*/ + arp_header->ar_hrd = 1; /*ethernet*/ + arp_header->ar_pro |= 0x0800; /*IPv4*/ + arp_header->ar_hln = 6; /*length of ethernet address*/ + arp_header->ar_pln = 4; /*length of IPv4 address*/ + + /*send the ARP request to all the available interfaces, since arp is broadcasting*/ + struct sr_if* if_walker = sr->if_list; + + while (if_walker) + { + sr_send_packet(sr,packet_buf,packet_len,if_walker->name); + if_walker = if_walker->next; + } + request->sent = now; /*reset time*/ + request->times_sent++; /*increment # times sent*/ + + } + } +} + + + void sr_arpcache_sweepreqs(struct sr_instance *sr) { /* Fill this in */ + struct sr_arpreq *iter = sr->cache.requests; + /*for each request on static router cache, invoke handle_arpreq()*/ + while (iter) + { + handle_arpreq(sr,iter); + iter = iter->next; + } + } /* You should not need to touch the rest of this code. */ diff --git a/sr_arpcache.h b/sr_arpcache.h index 370e062..2e189c4 100644 --- a/sr_arpcache.h +++ b/sr_arpcache.h @@ -96,6 +96,7 @@ struct sr_arpreq { uint32_t times_sent; /* Number of times this request was sent. You should update this. */ struct sr_packet *packets; /* List of pkts waiting on this req to finish */ + char* interface; /*added a new field in order to get request handling to work*/ struct sr_arpreq *next; }; @@ -106,6 +107,10 @@ struct sr_arpcache { pthread_mutexattr_t attr; }; + +/*helper function for sr_arpcache_lookup*/ +void handle_arpreq(struct sr_instance* sr,struct sr_arpreq* request); + /* Checks if an IP->MAC mapping is in the cache. IP is in network byte order. You must free the returned structure if it is not NULL. */ struct sr_arpentry *sr_arpcache_lookup(struct sr_arpcache *cache, uint32_t ip); diff --git a/sr_if.c b/sr_if.c index 152f796..9e597c9 100644 --- a/sr_if.c +++ b/sr_if.c @@ -192,3 +192,30 @@ void sr_print_if(struct sr_if* iface) Debug("\n"); Debug("\tinet addr %s\n",inet_ntoa(ip_addr)); } /* -- sr_print_if -- */ +/*--------------------------------------------------------------------- + * Method: sr_find_interface + * + * Finds interface by ip + *---------------------------------------------------------------------*/ + +struct sr_if* sr_find_interface(struct sr_instance* sr, uint32_t ip_dst) { + /* Requires */ + assert(sr); + + if (sr->if_list == 0) { + printf(" Interface list empty\n"); + return NULL; + } + + struct sr_if* if_entry = sr->if_list; + + while (if_entry) { + /* Check for matching IP */ + if (ip_dst == if_entry->ip) { + /* Interface found */ + return if_entry; + } + if_entry = if_entry->next; + } + return NULL; +} /* -- sr_find_interface -- */ diff --git a/sr_if.h b/sr_if.h index 1f21d9a..f98873f 100644 --- a/sr_if.h +++ b/sr_if.h @@ -50,5 +50,5 @@ void sr_set_ether_addr(struct sr_instance*, const unsigned char*); void sr_set_ether_ip(struct sr_instance*, uint32_t ip_nbo); void sr_print_if_list(struct sr_instance*); void sr_print_if(struct sr_if*); - +struct sr_if* sr_find_interface(struct sr_instance* sr, uint32_t ip_dst); #endif /* -- sr_INTERFACE_H -- */ diff --git a/sr_protocol.h b/sr_protocol.h index cba9338..4adbccd 100644 --- a/sr_protocol.h +++ b/sr_protocol.h @@ -103,7 +103,9 @@ typedef struct sr_icmp_t3_hdr sr_icmp_t3_hdr_t; - +#ifndef IP_ADDR_LEN +#define IP_ADDR_LEN 4 +#endif /* * Structure of an internet header, naked of options. */ diff --git a/sr_router.c b/sr_router.c index 750b34b..91f0d1c 100644 --- a/sr_router.c +++ b/sr_router.c @@ -12,6 +12,8 @@ **********************************************************************/ #include +#include +#include #include #include @@ -23,195 +25,593 @@ #include "sr_utils.h" -//**********************************************************// -//*** helper function set to obtain longest prefix match ***// -//**********************************************************// - -//declaring a new struct to contain destination addresses in the router -//that matches packet's destination ip address - -struct addr_in -{ - uint32_t maskedAddr; - uint32_t destAddr; - struct addr_in* next; - int common_len; -}; - -//build a linked-list of destination address and corresponding masked address -void addr_in_set(struct addr_in ** in,uint32_t addr_mask,uint32_t dest_addr) +/*forwarding logic : obtain the routing table entry with the longest prefix matching to the input ip address */ +struct sr_rt* entry_with_longest_prefix(struct sr_instance* sr,uint32_t ip) { - if (*in == NULL) + assert(sr); + + struct sr_rt* iter = sr->routing_table; + struct sr_rt* res = NULL; + uint16_t max = 0; + uint32_t masked =0; + + /*iterate through the routing table*/ + while (iter) { - *in = (struct addr_in*)malloc(sizeof(struct addr_in)); - (*in)->maskedAddr = addr_mask; - (*in)->destAddr = dest_addr; - (*in)->next == NULL; + /*if masked input address = masked routing table address */ + if ((ip & iter->mask.s_addr) == (iter->dest.s_addr & iter->mask.s_addr)) + { + /*network long to host long byte order*/ + masked = ntohl((iter->mask).s_addr); + if (masked > max) /*compare with longest masked address*/ + { + max = masked; + res = iter; + } + + } + iter = iter->next; } - - else - { - struct addr_in* naddr = (struct addr_in*)malloc(sizeof(struct addr_in)); - naddr->maskedAddr = addr_mask; - naddr->destAddr = dest_addr; - naddr->next = *in; - *in = naddr; + return res; - } +} +/*--------------------------------------------------------------------- + * Method: send_icmp_packet( + struct sr_instance* sr, + uint8_t type, uint8_t code, + uint32_t ip, + uint8_t* payload, + char* interface) + // ip should be in network byte order + * Scope: Global + * + * function to send the icmp_packet + * + *---------------------------------------------------------------------*/ +int send_icmp_packet( + struct sr_instance* sr, + uint8_t type, uint8_t code, + uint32_t ip, + uint8_t* payload, + char* interface) { + + assert(sr); + assert(payload); + assert(interface); + int etherLen = sizeof(sr_ethernet_hdr_t); //ethernet header size + int ipLen = sizeof(sr_ip_hdr_t); //ip header length + int arpLen = sizeof(sr_arp_hdr_t); //arp header length + if (type != 3 && type != 11) { + printf("ICMP wasn't type 3 or 11. Stopping send\n"); + return -1; + } + + unsigned int icmp_start = etherLen + ipLen; + unsigned int response_length = icmp_start + sizeof(sr_icmp_t3_hdr_t); + + // Create ethernet packet with ICMP Type 3 + uint8_t* response_packet = (uint8_t *)malloc(response_length); + + // Populate ICMP Message + sr_icmp_t3_hdr_t* response_icmp = (sr_icmp_t3_hdr_t *)(response_packet +icmp_start); + response_icmp->icmp_type = type; + response_icmp->icmp_code = code; + + response_icmp->unused = 0; + response_icmp->next_mtu = 0; + + // Copy over IP Header + 8 bytes + memcpy(response_icmp->data, payload, ICMP_DATA_SIZE); + + // Generate ICMP checksum + response_icmp->icmp_sum = 0; // Clear just in case + response_icmp->icmp_sum = cksum(response_packet + icmp_start,sizeof(sr_icmp_t3_hdr_t)); + + // Populate respone IP Packet + sr_ip_hdr_t* response_ip = (sr_ip_hdr_t *)(response_packet +etherLen); + + //Get interface + struct sr_if* sender = sr_get_interface(sr, interface); + + // Set src and dst addresses + response_ip->ip_dst = ip; + response_ip->ip_src = sender->ip; + + // Set IP Headers + response_ip->ip_v = 4; + response_ip->ip_hl = 5; + response_ip->ip_tos = 0; + response_ip->ip_len = htons(response_length - etherLen); + response_ip->ip_id = htons(0); + response_ip->ip_off = htons(IP_DF); + response_ip->ip_ttl = 100; + response_ip->ip_p = ip_protocol_icmp; + + // Generate IP checksum + response_ip->ip_sum = 0; + response_ip->ip_sum = cksum(response_packet + etherLen,ipLen); + + // Generate ethernet packet + sr_ethernet_hdr_t* response_eth = (sr_ethernet_hdr_t *)(response_packet); + response_eth->ether_type = htons(ethertype_ip); + + // Find a route to destination IP address + struct sr_rt* route = sr_find_rt_entry(sr, ip); + if (route == NULL) { + fprintf(stderr, "(Unreachable) Could not find route to original sender\n"); + return -1; + } + + if (send_packet_to_ip_addr( + sr, response_packet, response_length, ip, route->interface) == -1) { + fprintf(stderr, "Error sending packet\n"); + return -1; + } + printf("Packet sent (%d)\n", response_length); + + free(response_packet); + + return 0; } +/*--------------------------------------------------------------------- + * Method: process_ip_packet( + struct sr_instance* sr, + uint8_t* packet_buffer, + unsigned int len, + char* interface) + * Scope: Global + * + * function to process the arp packet + * + *---------------------------------------------------------------------*/ +int process_ip_packet( + struct sr_instance* sr, + uint8_t* packet_buffer, + unsigned int len, + char* interface) { -//function to determine address with the longest prefix -uint32_t longest_prefix_dest_addr(struct addr_in** in,uint32_t ip_dest) -{ + assert(sr); + assert(packet_buffer); + assert(interface); - struct addr_in* iter = *in; - int i,snum; - while (iter) - { - snum = 0; //number of matching bits - //compare each bit in the ip destination address and the router's masked - //destination address, starting from the highest bit - for (i = 0; i < 32; i++) - { - uint32_t addr_bit1 = (ip_dest >> 31-i) & 0x0001; - uint32_t addr_bit2 = (iter->maskedAddr >> 31-i) & 0x0001; - if (addr_bit1 == addr_bit2) - { snum++;} - } - iter->common_len = snum; - iter = iter->next; - } - - struct addr_in *iter2 = *in; - uint32_t longest_addr; - uint32_t max = 0; - - //find the destination address with the longest prefix match - while (iter2) - { - if (snum > max) - { - max = snum; - longest_addr = iter2->destAddr; - } - iter2 = iter2->next; + // Start of next header: add to packet head + unsigned int etherLen = sizeof(sr_ethernet_hdr_t); + int ipLen = sizeof(sr_ip_hdr_t); //ip header length + int arpLen = sizeof(sr_arp_hdr_t); //arp header length + if (len < etherLen + ipLen) { + fprintf(stderr, "IP header: insufficient length\n"); + return -1; + } + + printf("Processing IP Packet\n"); + // DEBUG only print_hdr_ip(packet + etherLen); + + // Create request IP Packet + sr_ip_hdr_t *ip_header = (sr_ip_hdr_t *)(packet_buffer + etherLen); + + uint16_t req_cksum = ip_header->ip_sum; + ip_header->ip_sum = 0; + + if (cksum(packet_buffer + etherLen, ipLen) != req_cksum) { + fprintf(stderr, "Error: IP header - invalid checksum\n"); + return -1; + } + + // Check if in router's interfaces + struct sr_if* my_interface = sr_find_interface(sr, ip_header->ip_dst); + + if (my_interface) { + //Interface exists + + etherLen += ipLen; + + if (ip_header->ip_p == ip_protocol_icmp) { // ICMP + if (len < etherLen + sizeof(sr_icmp_hdr_t)) { + fprintf(stderr, "Error: ICMP header - insufficient length\n"); + return -1; + } + printf("Processing ICMP Packet\n"); + + // Create ICMP Packet + sr_icmp_hdr_t* req_icmp = (sr_icmp_hdr_t *)(packet_buffer + etherLen); + + uint16_t req_icmp_cksum = req_icmp->icmp_sum; + req_icmp->icmp_sum = 0; + + if (cksum(packet_buffer + etherLen, len - etherLen) != req_icmp_cksum) { + fprintf(stderr, "Error: ICMP header - invalid checksum\n"); + return -1; + } + + // Process ICMP message + if (req_icmp->icmp_type != 8 || req_icmp->icmp_code != 0) { + // Drop packet if not echo request + printf("ICMP wasn't type echo. Dropping packet\n"); + return -1; + } + + // Set response length equal to request's + uint16_t reply_pkt_len = len; + + // TODO(Tim): This code looks redundant. We should probably use + // send_icmp_packet to send the ping so we don't do all of + // this repeated work. DRY DRY DRY + + //construct icmp echo reply packet + uint8_t* reply_buf = (uint8_t *)malloc(reply_pkt_len); + + // copy icmp data + icmp header + memcpy(reply_buf + etherLen, packet_buffer + etherLen,reply_pkt_len - etherLen); + + + // Populate ICMP Message + + sr_icmp_hdr_t* response_icmp = (sr_icmp_hdr_t *)(reply_buf +etherLen); + + // Format echo reply + response_icmp->icmp_type = 0; + response_icmp->icmp_code = 0; + + // Generate ICMP checksum + response_icmp->icmp_sum = 0; //initially 0 + response_icmp->icmp_sum = cksum(reply_buf + etherLen,reply_pkt_len - etherLen); + + // construct icmp echo reply ip header + sr_ip_hdr_t* reply_ip_hdr = (sr_ip_hdr_t *)(reply_buf + etherLen); + + // simply swap src and dst addresses + reply_ip_hdr->ip_dst = ip_header->ip_src; + reply_ip_hdr->ip_src = ip_header->ip_dst; + + // Set IP Headers + reply_ip_hdr->ip_v = 4; + reply_ip_hdr->ip_hl = 5; + reply_ip_hdr->ip_tos = 0; + reply_ip_hdr->ip_len = htons(reply_pkt_len -etherLen); //header + icmp header + reply_ip_hdr->ip_id = htons(0); + reply_ip_hdr->ip_off = htons(IP_DF); + reply_ip_hdr->ip_ttl = 100; + reply_ip_hdr->ip_p = ip_protocol_icmp; + + // Generate IP checksum + reply_ip_hdr->ip_sum = 0; + reply_ip_hdr->ip_sum = cksum(reply_buf + etherLen,ipLen); + + // Modify Ethernet packet + sr_ethernet_hdr_t* response_eth = (sr_ethernet_hdr_t *)(reply_buf); + response_eth->ether_type = htons(ethertype_ip); + + printf("Sending ICMP ping reply\n"); + if (send_packet_to_ip_addr(sr, reply_buf, reply_pkt_len, + reply_ip_hdr->ip_dst, interface) == -1) { + fprintf(stderr, "Error sending packet\n"); + return -1; + } + printf("Packet sent (%d)\n", reply_pkt_len); + + free(reply_buf); + + } else if (ip_header->ip_p == 6 || ip_header->ip_p == 17) { + // TCP or UDP + printf("TCP or UDP found. Sending back ICMP type 3, code 3\n"); + + if (send_icmp_packet( + sr, 3, 3, ip_header->ip_src, (uint8_t *)ip_header, interface) == -1) { + fprintf(stderr, "Error: Failure sending ICMP message (3,3)\n"); + return -1; + } + + } else { + // Drop packet if other protocol + printf("Protocol not found. Dropping packet\n"); + return -1; + } + + } else { + // Forward the Packet + printf("Forwarding Process Initiated\n"); + + // Routing Table lookup + struct sr_rt* route = sr_find_rt_entry(sr, ip_header->ip_dst); + + // Make sure there is a next route. + if (route == NULL) { + printf("Route does not exist. Forwarding terminated\n"); + + if (send_icmp_packet( + sr, 3, 0, ip_header->ip_src, (uint8_t *)ip_header, interface) == -1) { + fprintf(stderr, "Error: Failure sending ICMP message (3,0)\n"); + return -1; + } + + return -2; + } + + // Decrement the TTL + ip_header->ip_ttl--; + if (ip_header->ip_ttl == 0) { + // Send back ICMP time exceeded + printf("Packet TTL expired.\n"); + if (send_icmp_packet( + sr, 11, 0, ip_header->ip_src, (uint8_t *)ip_header, interface) == -1) { + fprintf(stderr, "Error: Failure sending ICMP message (11,0)\n"); + return -1; + } + return 0; + } + + // Update the checksum + ip_header->ip_sum = 0; + ip_header->ip_sum = cksum((uint8_t*) ip_header, ipLen); + + // Send the packet to the correct IP + if (send_packet_to_ip_addr(sr, packet_buffer, len, route->gw.s_addr, + route->interface) != 0) { + fprintf(stderr, "Error: Failure from send_packet_to_ip_addr\n"); + return -1; + } + printf("Packet forwarded\n"); + } - } - return longest_addr; - + return 0; +} +/*--------------------------------------------------------------------- + * Method: process_arp_packet(struct sr_instance* sr, + uint8_t *packet_buffer, + unsigned int len, + char* interface) + * Scope: Global + * + * function to process the arp packet + * + *---------------------------------------------------------------------*/ +int process_arp_packet( + struct sr_instance* sr, + uint8_t *packet_buffer, + unsigned int len, + char* interface) { + + assert(sr); + assert(packet_buffer); + assert(interface); + int etherLen = sizeof(sr_ethernet_hdr_t); //ethernet header size + int ipLen = sizeof(sr_ip_hdr_t); //ip header length + int arpLen = sizeof(sr_arp_hdr_t); //arp header length + if (len < etherLen + arpLen) { + fprintf(stderr, "Error: ARP header - insufficient length\n"); + return -1; + } + printf("ARP Packet Processing Initiated\n"); + // print_hdr_arp(packet + sizeof(sr_ethernet_hdr_t)); + + // Create ARP Header and find interface + sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)(packet_buffer + etherLen); + struct sr_if* my_interface = sr_find_interface(sr, arp_header->ar_tip); + + if (my_interface) { + printf("Found Interface: "); + sr_print_if(my_interface); + + if (strcmp(my_interface->name, interface) == 0) { + printf("Interface name's match up\n"); + unsigned short op_code = ntohs(arp_header->ar_op); + + if (op_code == arp_op_reply) { // Process ARP Reply + printf("Processing ARP Reply\n"); + + // See if there's an ARP request in the queue. + struct sr_arpreq* req = sr_arpcache_insert( + &(sr->cache), arp_header->ar_sha, arp_header->ar_sip); + + // Forward all packets waiting on req if req exists. + struct sr_packet* pckt = req ? req->packets : NULL; + for (; pckt != NULL; pckt = pckt->next) { + eth_frame_send_with_mac( + sr, pckt->buf, pckt->len, arp_header->ar_sha, pckt->iface); + } + } else if (op_code == arp_op_request) { // Process ARP Request + printf("Processing ARP Request\n"); + + // Set the target to the incoming ARP source. + memcpy(arp_header->ar_tha, arp_header->ar_sha, ETHER_ADDR_LEN); + arp_header->ar_tip = arp_header->ar_sip; + + // Set the source to this interface. + memcpy(arp_header->ar_sha, my_interface->addr, ETHER_ADDR_LEN); + arp_header->ar_sip = my_interface->ip; + + // Set ethernet frame MAC information + sr_ethernet_hdr_t* ethernet_hdr = (sr_ethernet_hdr_t*)(packet_buffer); + memcpy(ethernet_hdr->ether_dhost, arp_header->ar_tha, ETHER_ADDR_LEN); + memcpy(ethernet_hdr->ether_shost, arp_header->ar_sha, ETHER_ADDR_LEN); + + // Send the packet back on it's way. + arp_header->ar_op = htons(arp_op_reply); + printf("Sending out ARP Reply\n"); + sr_send_packet(sr, packet_buffer, len, interface); + } else { + fprintf(stderr, "ARP Op Code Unknown: (%d)\n", arp_header->ar_op); + return -1; + } + } else { + fprintf(stderr, "ARP interface names didn't match: %s, %s\n", + my_interface->name, interface); + return -1; + } + } else { + printf("ARP interface not found\n"); + } + return 0; } -//helper function to find the name of the interface given its MAC address -const char* find_interface(struct sr_instance* sr,char addr[ETHER_ADDR_LEN]) +/*--------------------------------------------------------------------- + * Method: eth_frame_send_with_mac(struct sr_instance* sr, + uint8_t* packet, + unsigned int len, + unsigned char* mac, + char* iface) + * Scope: Global + * + * send the ethernet frame + * + *---------------------------------------------------------------------*/ +int eth_frame_send_with_mac( + struct sr_instance* sr, + uint8_t* packet, + unsigned int len, + unsigned char* mac, + char* iface) { + + printf("Sending Packet\n"); + + // Cast the packet in order to update fields. + sr_ethernet_hdr_t* e_packet = (sr_ethernet_hdr_t *)(packet); + struct sr_if* interface = sr_get_interface(sr, iface); + + // Set fields + memcpy(e_packet->ether_dhost, mac, ETHER_ADDR_LEN); + memcpy(e_packet->ether_shost, interface->addr, ETHER_ADDR_LEN); + + // Send the packet + print_hdrs(packet, len); + sr_send_packet(sr, packet, len, iface); + return 0; +} +/*--------------------------------------------------------------------- + * Method: send_packet_to_ip_addr(struct sr_instance* sr, + uint8_t* packet, + unsigned int len, + uint32_t dest_ip, + char* iface) + * Scope: Global + * + * send the packet to the ip address. First consult the cache if not. + * + *---------------------------------------------------------------------*/ +int send_packet_to_ip_addr(struct sr_instance* sr, + uint8_t* packet, + unsigned int len, + uint32_t dest_ip, + char* iface) { + struct sr_arpentry* arp_entry = sr_arpcache_lookup(&(sr->cache), dest_ip); + + if (arp_entry) { + printf("ARP Cache Hit\n"); + // Forward the packet + eth_frame_send_with_mac(sr, packet, len, arp_entry->mac, iface); + + // Free ARP entry + free(arp_entry); + } else { + printf("ARP Cache Miss\n"); + struct sr_arpreq* req = sr_arpcache_queuereq( + &(sr->cache), dest_ip, packet, len, iface); + req->interface = iface; + handle_arpreq(sr, req); + } + + return 0; +} + + +/*helper function to find the name of the interface given its MAC address*/ +const char* find_interface(struct sr_instance* sr,unsigned char addr[ETHER_ADDR_LEN]) { struct sr_if* iter = sr->if_list; while (iter) { - //found the address - if (strcmp(addr,iter->addr) == 0) + /*found the address*/ + if (memcmp(addr,iter->addr,ETHER_ADDR_LEN) == 0) { return iter->name;} iter = iter->next; } - return 0; //interface not found + return 0; /*interface not found*/ } -void handle_arpreq(struct sr_instance* sr,struct sr_arpreq* request) +void icmp_handler(struct sr_instance* sr,uint8_t* pkt,char* interface,uint8_t type,uint8_t code) { - time_t now = time(0); //get system time - 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 - struct sr_packet* iter = request->packets; - - while(iter) //for each packet in the packet list - { + int ipLen,etherLen,icmpLen3,totalLen; + ipLen = sizeof(sr_ip_hdr_t); + etherLen = sizeof(sr_ethernet_hdr_t); + icmpLen3 = sizeof(sr_icmp_t3_hdr_t); + totalLen = ipLen+etherLen+icmpLen3; + + /*extract information from input packet*/ + /*sr_ethernet_hdr_t* ether_header = (sr_ethernet_hdr_t*) pkt;*/ + sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*) (pkt+etherLen); - //find the ethernet header field of the packet to extract the source address - sr_ethernet_hdr_t* ether_header = (sr_ethernet_hdr_t*) (iter->buf); - char srcAddr[ETHER_ADDR_LEN]; - memcpy(srcAddr,ether_header->ether_shost,ETHER_ADDR_LEN); - char iname[sr_IFACE_NAMELEN]; - strcpy(iname,find_interface(sr,srcAddr)); - - //find ip_header field of the packet - sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*) (iter->buf+sizeof(sr_ethernet_hdr_t)); - ip_header->ip_p |= ip_protocol_icmp; //set protocol type to icmp - int headerLen = sizeof(sr_ip_hdr_t); - ip_header->ip_ttl--; //decrement ttl value - ip_header->ip_sum = cksum(ip_header,headerLen); //recompute checksum - - sr_icmp_t3_hdr_t* icmp3 = (sr_icmp_t3_hdr_t*) (iter->buf+sizeof(sr_ethernet_hdr_t)+sizeof(sr_ip_hdr_t)); - icmp3->icmp_type = 3; //icmp type3 - icmp3->icmp_code = 1; //destination host unreachable - int icmp_len = sizeof(sr_icmp_t3_hdr_t); - //also check the checksum of icmp protocol to see - //that data has not been corrupted - int checksum = cksum(icmp3->icmp_sum,icmp_len); - if ((checksum & 0xffff) != 0xffff) - { perror("Error: data has been corrupted");} - //now send packet to the source address - sr_send_packet(sr,iter->buf,iter->len,iname); - - iter = iter->next; - } - //destroy the request - sr_arpreq_destroy(&(sr->cache),request); - } - - else - { - //send arp request - - //build a packet - unsigned int packet_len = sizeof(sr_ethernet_hdr_t)+sizeof(sr_arp_hdr_t); - uint8_t* packet_buf = (uint8_t*) malloc(packet_len); - sr_ethernet_hdr_t* ether_header = (sr_ethernet_hdr_t*) (packet_buf); - int i; - for (i = 0; i < ETHER_ADDR_LEN; i++) - { - //broadcast address - ether_header->ether_dhost[i] = 0xff; - } - - //finding source hardware / ip address - struct sr_if* iface = sr_get_interface(sr,sr->host); - //source hardware address - memcpy(ether_header->ether_shost,iface->addr,ETHER_ADDR_LEN); - ether_header->ether_type |= ethertype_arp; //arp type + /*construct icmp reply packet*/ + unsigned int reply_pkt_len = etherLen+ipLen+icmpLen3; + uint8_t* reply_buf = (uint8_t*)malloc(reply_pkt_len); + + struct sr_if* riface = sr_get_interface(sr,interface); + /*construct icmp port unreachable ip header*/ + sr_ip_hdr_t* reply_ip_hdr = (sr_ip_hdr_t*) (reply_buf+etherLen); + reply_ip_hdr->ip_len = htons(ipLen+icmpLen3); /*ip header + data*/ + reply_ip_hdr->ip_v = 4; + reply_ip_hdr->ip_hl = 5; + reply_ip_hdr->ip_ttl = 100; + /*don't fragement. id = 0*/ + reply_ip_hdr->ip_off = htons(IP_DF); + reply_ip_hdr->ip_id = htons(0); + reply_ip_hdr->ip_p = ip_protocol_icmp; + reply_ip_hdr->ip_src = riface->ip; + reply_ip_hdr->ip_dst = ip_header->ip_src; + reply_ip_hdr->ip_sum = 0; /*initially 0*/ + reply_ip_hdr->ip_sum = cksum(reply_buf+etherLen,ipLen); /*recompute checksum*/ - sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*) (packet_buf+sizeof(sr_ethernet_hdr_t)); - arp_header->ar_tip = request->ip; //next hop ip address - memcpy(arp_header->ar_tha,ether_header->ether_dhost,ETHER_ADDR_LEN); //destination hardware address (should be ff-ff-ff-ff-ff-ff) - arp_header->ar_sip = iface->ip; - memcpy(arp_header->ar_sha,ether_header->ether_shost,ETHER_ADDR_LEN); //source hardware address - arp_header->ar_op |= arp_op_request; //operation is request - arp_header->ar_hrd = 1; //ethernet - arp_header->ar_pro |= 0x0800; //IPv4 - arp_header->ar_hln = 6; //length of ethernet address - arp_header->ar_pln = 4; //length of IPv4 address - - //send the ARP request to all the available interfaces - struct sr_if* if_walker = sr->if_list; - while (if_walker) - { - sr_send_packet(sr,packet_buf,packet_len,if_walker->name); - if_walker = if_walker->next; - } - request->sent = now; //reset time - request->times_sent++; //increment # times sent - - } - } - - + /*construct icmp port unreachable icmp header*/ + sr_icmp_t3_hdr_t* reply_icmp_hdr = (sr_icmp_t3_hdr_t*) (reply_buf+etherLen+ipLen); + reply_icmp_hdr->icmp_type = type; + reply_icmp_hdr->icmp_code = code; + /*unused and mtu values are irrelevant. can be set to 0*/ + reply_icmp_hdr->unused = 0; + reply_icmp_hdr->next_mtu = 0; + memcpy(reply_icmp_hdr->data,pkt+etherLen,ICMP_DATA_SIZE); + reply_icmp_hdr->icmp_sum = 0; /*initially 0*/ + reply_icmp_hdr->icmp_sum = cksum(reply_buf+etherLen+ipLen,icmpLen3); + + /*find routing table entry with longest prefix matching to destination ip address*/ struct sr_rt* lentry = entry_with_longest_prefix(sr,reply_ip_hdr->ip_dst); + if (!lentry) + { + perror("Error: cannot route to the receiver\n"); + exit(1); + } + /*find interface corresponding to the routing table entry*/ + struct sr_if* src_iface = sr_get_interface(sr,lentry->interface); + /*find ip to mac mapping*/ + struct sr_arpentry* arpentry = sr_arpcache_lookup(&(sr->cache),reply_ip_hdr->ip_dst); + if (arpentry) + { + /*build ethernet header*/ + sr_ethernet_hdr_t* reply_ether_hdr = (sr_ethernet_hdr_t*) reply_buf; + /*source interface*/ + memcpy(reply_ether_hdr->ether_shost,src_iface->addr,ETHER_ADDR_LEN); + /*using longest prefix matching ip to mac mapping*/ + memcpy(reply_ether_hdr->ether_dhost,arpentry->mac,ETHER_ADDR_LEN); + /*host byte to network byte conversion*/ + reply_ether_hdr->ether_type = htons(ethertype_ip); + /*send packet*/ + sr_send_packet(sr,reply_buf,reply_pkt_len,lentry->interface); + /*free arpentry*/ + free(arpentry); + + } + else + { + /*build ethernet header*/ + sr_ethernet_hdr_t* reply_ether_hdr = (sr_ethernet_hdr_t*) reply_buf; + reply_ether_hdr->ether_type = htons(ethertype_ip); + struct sr_arpreq* request = sr_arpcache_queuereq(&(sr->cache),reply_ip_hdr->ip_dst,reply_buf,totalLen,lentry->interface); + request->interface = lentry->interface; + handle_arpreq(sr,request); + } + return; } /*--------------------------------------------------------------------- @@ -242,15 +642,15 @@ void sr_init(struct sr_instance* sr) /* Add initialization code here! */ - //adding interfaces in the routing table to sr instance. - struct sr_rt* rt_walker = sr->routing_table; + /*adding interfaces in the routing table to sr instance. */ +/* struct sr_rt* rt_walker = sr->routing_table; while (rt_walker) { sr_add_interface(sr,rt_walker->interface); rt_walker = rt_walker->next; - } - //everything else in sr_instance struct is initialized in main.c + }*/ + /*everything else in sr_instance struct is initialized in main.c */ } /* -- sr_init -- */ @@ -280,91 +680,59 @@ void sr_handlepacket(struct sr_instance* sr, assert(packet); assert(interface); - printf("*** -> Received packet of length %d \n",len); + printf("Received packet of length %d \n",len); /* fill in code here */ - //initializing key variables - uint8_t* packet_buffer; //packet buffer - struct sr_if* iface; //interface struct - uint16_t checksum,ether_type; //checksum bit - unsigned int packet_len,minlength; //packet length - uint32_t maskedAddr,dest_longest; - int ip_headerLen; - + /*initializing key variables*/ + uint8_t* packet_buffer; /*packet buffer*/ + /*struct sr_if* iface;*/ /*interface struct*/ + uint16_t checksum,ether_type; /*checksum bit*/ + unsigned int packet_len,minlength; /*packet length*/ + int ipLen,etherLen,arpLen; + packet_buffer = packet; packet_len = len; minlength = sizeof(sr_ethernet_hdr_t); + etherLen = sizeof(sr_ethernet_hdr_t); /*ethernet header size*/ + ipLen = sizeof(sr_ip_hdr_t); /*ip header length*/ + arpLen = sizeof(sr_arp_hdr_t); /*arp header length*/ + if (len > IP_MAXPACKET) { perror("Error: invalid packet size"); + exit(1); } if (len < minlength) { perror("Error: packet size too small"); + exit(1); } - //obtain interface information - iface = sr_get_interface(sr,interface); + /*obtain interface information*/ + /*iface = sr_get_interface(sr,interface);*/ - //performing checksum on the packet - checksum = cksum(packet_buffer,packet_len); - if ((checksum & 0xffff) != 0xffff) //data has been corrupted - { - perror("Error: data has been corrupted"); - } - //examining each layer of header// + /*examining each layer of header*/ - //examine ethernet header + /*examine ethernet header*/ sr_ethernet_hdr_t* ether_header = (sr_ethernet_hdr_t*) packet_buffer; - ether_type = ethertype(packet_buffer); //examine ethernet subheader type - - if (ether_type == ethertype_ip) //ip + ether_type = ethertype(packet_buffer); + + if (ether_type == ethertype_ip) /*IP*/ { - sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*) (packet_buffer+sizeof(sr_ethernet_hdr_t)); //obtain ip_header - ip_header->ip_ttl--; //decrement TTL field - ip_headerLen = sizeof(sr_ip_hdr_t); //find ip header length - ip_header->ip_sum = cksum(ip_header,ip_headerLen); //recompute checksum over ip header - - //now performing longest-prefix-matching - - struct sr_rt* rt_walker = sr->routing_table; - struct addr_in* destAddrSet = NULL; - //obtaining list of destination addresses and their corresponding subnet masked addresses in the routing table - while (rt_walker) - { - //maskedAddr - maskedAddr = rt_walker->dest.s_addr & rt_walker->mask.s_addr; - addr_in_set(&destAddrSet,maskedAddr,rt_walker->dest.s_addr); - rt_walker = rt_walker->next; - - } - //find destination address with the longest prefix match - dest_longest = longest_prefix_dest_addr(&destAddrSet,ip_header->ip_dst); - - //look up an IP->MAC mapping in the cache - struct sr_arpentry * mapping_entry = sr_arpcache_lookup(&(sr->cache),dest_longest); - if (mapping_entry) //if there is a mapping - { - - char* out_iface = find_interface(sr,mapping_entry->mac); - sr_send_packet(sr,packet_buffer,len,out_iface); - - } - - else - { - struct sr_arpreq* request = sr_arpcache_queuereq(&(sr->cache),dest_longest,packet,len,interface); - - } - + if (process_ip_packet(sr, packet, len, interface) < 0) { + fprintf(stderr, "Error processing IP datagram\n"); + } } - else if (ether_type == ethertype_arp) //arp + else if (ether_type == ethertype_arp) /*ARP*/ { - sr_arp_hdr_t *arp_header = (sr_arp_hdr_t*) (packet_buffer + sizeof(sr_ethernet_hdr_t)); - - + if (process_arp_packet(sr, packet, len, interface) <0) { + fprintf(stderr, "Error processing ARP packet\n"); + } + } + else { + fprintf(stderr, "Error: Unrecognized Ethernet Type: %d\n", ether_type); } }/* end sr_ForwardPacket */ diff --git a/sr_router.h b/sr_router.h index e7e8bd4..5fc17bc 100644 --- a/sr_router.h +++ b/sr_router.h @@ -65,6 +65,7 @@ int sr_connect_to_server(struct sr_instance* ,unsigned short , char* ); int sr_read_from_server(struct sr_instance* ); /* -- sr_router.c -- */ +const char* find_interface(struct sr_instance* sr,unsigned char addr[ETHER_ADDR_LEN]); void sr_init(struct sr_instance* ); void sr_handlepacket(struct sr_instance* , uint8_t * , unsigned int , char* ); diff --git a/sr_rt.c b/sr_rt.c index 35f172f..21cc7ed 100644 --- a/sr_rt.c +++ b/sr_rt.c @@ -176,3 +176,44 @@ void sr_print_routing_entry(struct sr_rt* entry) printf("%s\n",entry->interface); } /* -- sr_print_routing_entry -- */ + +/*--------------------------------------------------------------------- + * Method: sr_find_rt_entry + * + * Finds LPM routing table entry by ip + *---------------------------------------------------------------------*/ + +struct sr_rt* sr_find_rt_entry(struct sr_instance* sr, uint32_t ip_dst) { + /* Requires */ + assert(sr); + + if (sr->routing_table == 0) { + printf(" Routing table empty\n"); + return 0; + } + + struct sr_rt* rt_entry = 0; + struct sr_rt* rt_walker = sr->routing_table; + uint16_t longest_mask = 0; + uint16_t mask = 0; + + while (rt_walker) { + /* Check masked destination to routing table entry */ + if ((ip_dst & (rt_walker->mask).s_addr) == + ((rt_walker->dest).s_addr & (rt_walker->mask).s_addr)) { + /* Get mask in integer form */ + mask = ntohl((rt_walker->mask).s_addr); + + /* Compare to determine longest prefix match */ + if (mask > longest_mask) { + /* Save route*/ + rt_entry = rt_walker; + + longest_mask = mask; + } + } + rt_walker = rt_walker->next; + } + return rt_entry; + +} /* -- sr_find_rt_entry -- */ diff --git a/sr_rt.h b/sr_rt.h index 05adba6..c637a2b 100644 --- a/sr_rt.h +++ b/sr_rt.h @@ -42,6 +42,6 @@ void sr_add_rt_entry(struct sr_instance*, struct in_addr,struct in_addr, struct in_addr, char*); void sr_print_routing_table(struct sr_instance* sr); void sr_print_routing_entry(struct sr_rt* entry); - +struct sr_rt* sr_find_rt_entry(struct sr_instance* sr, uint32_t ip_dst); #endif /* -- sr_RT_H -- */