Beispiel #1
0
/* Tries to find ip address in arp cache. If found, sends ethernet frame. If not found,
adds packet to arp queue */
void sr_attempt_send(struct sr_instance *sr, uint32_t ip_dest, 
                                        uint8_t *frame,           
                                       unsigned int frame_len,
                                       char *iface){


   struct sr_arpentry *entry = sr_arpcache_lookup(&(sr->cache), ip_dest);

   if (entry){

        unsigned char *mac_address = entry->mac;
        memcpy( ((sr_ethernet_hdr_t *)frame)->ether_dhost, mac_address, ETHER_ADDR_LEN);
        //free packet??
        sr_send_packet(sr, frame, frame_len, iface);

        free(entry);


   }else{
        fprintf(stderr, "Couldn't find entry for: ");
        print_addr_ip_int(ntohl(ip_dest));

       struct sr_arpreq *req = sr_arpcache_queuereq(&(sr->cache), ip_dest, frame, frame_len, iface);
       sr_handle_arpreq(sr, req);
   }
}
/*
 * When we want to send an ip packet, we need to firstly check arp acache.
 */
void sr_check_and_send_arp(struct sr_instance* sr, uint8_t* packet, uint32_t next_hop_ip, struct sr_if* out_iface, unsigned int len)
{
        Debug("\ncheck_and_send_arp called\n");
        struct sr_arpentry* entry = sr_arpcache_lookup(&(sr->cache), next_hop_ip); 

        if(entry) 
		{ 
            Debug("\narp_cache hit!\n");
            next_hop_ip = entry->ip;

            int i;
            for (i = 0; i < ETHER_ADDR_LEN; i++)
			{
                packet[i] = entry->mac[i];
            }

            sr_send_packet(sr, packet, len, out_iface->name);

            free(packet);
            free(entry);
        }
        else
		{
            Debug("\narp_cache miss; call handle_arppreq\n");
			struct sr_arpreq* req = sr_arpcache_queuereq(&(sr->cache), next_hop_ip, packet, len, out_iface->name);
			free(packet);
            sr_handle_arpreq(sr, req);
        }
}
Beispiel #3
0
/*Does all handling of incoming ARP packets, returns 1 if successful*/
int handle_ARP_packet(struct sr_instance* sr, 
		      uint8_t* packet,
		      int len, 
		      char* interface){
  int minLenARP = sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arp_hdr); 
  if (len < minLenARP){
      fprintf(stderr, "Failed to access ARP header, too small\n");
      drop_packet = 1;
      //return;
    }
    if (drop_packet == 0){
      if (destinedToRouter(dest_ip)){
	sr_ethernet_hdr_t* ethernet_hdr = (sr_ethernet_hdr_t*)packet;
	sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)(packet + (uint8_t) eth_size);

	if (ntohl(arp_header->ar_op) == arp_op_reply){//We have a ARP reply
	  //process reply
	  //move entries from ARP request queue to ARP cache
	  struct sr_arpreq* req;
	  req = sr_arpcache_insert(&(sr->cache), arp_header->ar_sha,
				   ntohl(arp_header->ar_sip));
	  if (req!=NULL){
	     struct sr_packet* traverser = req->packets;
	     while(traverser != NULL){
	       //normal IP forward, no errors detected
	       //change old contents
	       struct sr_arpentry *arp_entry;
	       arp_entry = sr_arpcache_lookup(&(sr->cache),dest_ip);
	       sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)(packet + (uint8_t) eth_size);
	       sr_ethernet_hdr_t* out_eth = (sr_ethernet_hdr_t*)packet;
	       uint16_t modCksum = cksum(ip_header, sizeof(struct sr_ip_hdr));
	       int ret = ip_forward(sr,packet,len,out_eth,arp_entry->mac,
				    dest_ip, modCksum,interface);
	       if (ret!= 0){
		 fprintf(stderr, "Didn't send ip packet properly\n");

	       }

	       traverser = traverser->next;
	     }
	     sr_arpreq_destroy(&(sr->cache), req);
	  }
	}else{
	  //process ARP request and send reply 
	  //(they want our MAC address) so sends reply packet
	  int ret =  arp_send(sr,packet,len,
			      ethernet_hdr,arp_header,dest_ip);
	  if (ret!= 0){
	    fprintf(stderr, "Didn't send arp packet properly\n");

	  }
	}
      }else{
	//pass
	//forward packet
      }
    }
    return 1;
}
Beispiel #4
0
void test_arp_cache(struct sr_instance *sr){
    in_addr_t x;

    char *y = (char *)&x; /* so that we can address the individual bytes */

    y[0] = 107;
    y[1] = 23;
    y[2] = 53;
    y[3] = 142;

    struct in_addr ip = *(struct in_addr *)&x;

    //char interface[sr_IFACE_NAMELEN];
    //bool found = longest_prefix_match(sr, ip, interface);
    struct sr_arpentry *entry = sr_arpcache_lookup(&(sr->cache), ip.s_addr);
}
Beispiel #5
0
/*---------------------------------------------------------------------
 * 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);
	}
}
Beispiel #6
0
/*Expects outgoing packet length in host order*/
void send_or_queue_packet_based_on_arp_entry_existence(struct sr_instance
						       *sr, struct sr_rt
						       *outgoing_routing_entry,
						       uint8_t *pkt, unsigned
						       int len) {
  if (!outgoing_routing_entry) {
    /*Router has no way of sending this packet, so drop it.
     This is expected behavior for packets we construct and create, not
     for forwarding. For IP forwarding, if there is no outgoing entry, a
     different function is called (sending a destination network
     unreachable) instead of this function.*/
    free(pkt);
    return;
  }

  struct sr_arpentry *arp_entry = sr_arpcache_lookup(&(sr->cache), outgoing_routing_entry->gw.s_addr);
  
  struct sr_if *outgoing_interface = sr_get_interface(sr, outgoing_routing_entry->interface);

  /*Src mac changed here before added to queue*/
  sr_ethernet_hdr_t *eth_hdr = get_ethernet_hdr(pkt);
  memcpy(eth_hdr->ether_shost, outgoing_interface->addr, ETHER_ADDR_LEN);

  if (arp_entry) {
    /*Copy the destination MAC inside, and send*/
    memcpy(eth_hdr->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
    sr_send_packet(sr, (uint8_t *)pkt, len, outgoing_interface->name);

    /*No reliability guarantee, so free the packet*/
    free(pkt);

    /*Needs to be freed according to API*/
    free(arp_entry);
  } else {
    /*Queue for later sending*/
    struct sr_arpreq *req = sr_arpcache_queuereq(&(sr->cache), outgoing_routing_entry->gw.s_addr, (uint8_t*)pkt, len, outgoing_routing_entry->interface);
    free(pkt); /*specified in comments*/
    sr_handle_arpreq(sr, req);
  }
}
Beispiel #7
0
int handle_arp_reply(struct sr_instance * sr, uint8_t * packet, unsigned int len){

      struct sr_arp_hdr *arp_hdr = (struct sr_arp_hdr *)(packet + sizeof(sr_ethernet_hdr_t));
      struct sr_arpentry *arpentry = sr_arpcache_lookup(&(sr->cache),arp_hdr->ar_sip);

      /* if entry isn't already in cache */
      if (arpentry) {

            return 0;
      }
      struct sr_arpreq *req = sr_arpcache_insert(&(sr->cache), arp_hdr->ar_sha, arp_hdr->ar_sip);

      /* if there were requests pending on this IP */
      if(!req){
           
            return 0;
      }

      struct sr_packet * to_send = req->packets;
      struct sr_ethernet_hdr * ethr_to_send;
      int res;

      /* send all packets waiting on this IP */
      while (to_send){

            /* update the mac address of each ethernet frame */
            ethr_to_send = (struct sr_ethernet_hdr *) to_send->buf;
            memcpy(ethr_to_send->ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);

            res = sr_send_packet(sr, to_send->buf, to_send->len, to_send->iface);

            if (res != 0){
                
                  continue;
            }
            to_send = to_send->next;
      }
      return 0;
}
void sr_lookup_and_send(struct sr_instance *sr, uint8_t *packet, unsigned int len, struct sr_if *oiface, uint32_t ip)
{
    assert(sr);
    assert(packet);
    assert(oiface);
    
    struct sr_arpentry *entry = sr_arpcache_lookup(&(sr->cache), ip);
    
    if (entry) {
        sr_ethernet_hdr_t *eth_hdr = (sr_ethernet_hdr_t *)packet;
        
        memcpy(eth_hdr->ether_dhost, entry->mac, ETHER_ADDR_LEN);
        memcpy(eth_hdr->ether_shost, oiface->addr, ETHER_ADDR_LEN);
        
        sr_send_packet(sr, packet, len, oiface->name);
        
        free(entry);
    } else {
        struct sr_arpreq *req = sr_arpcache_queuereq(&(sr->cache), ip, packet, len, oiface->name);
        
        sr_handle_arpreq(sr, req);
    }
} /* -- sr_lookup_and_send -- */
Beispiel #9
0
void processForward(struct sr_instance* sr,
        uint8_t * packet,
        unsigned int len,
        char* interface) {

	struct sr_ip_hdr *ipHeader = (struct sr_ip_hdr *) (packet + sizeof(struct sr_ethernet_hdr));

	/* Reply with timeout if TTL exceeded */
	ipHeader->ip_ttl = ipHeader->ip_ttl - 1;
	if (ipHeader->ip_ttl == 0) {
		icmp_send_time_exceeded(sr, packet, len, interface);
		return;
	}

	/* At this point, all checks passed, check routing table */
	struct sr_rt *closestMatch = findLongestMatchPrefix(sr->routing_table, ipHeader->ip_dst);

	if (closestMatch == NULL) {
		/* No match found. Send net unreachable */
		icmp_send_net_unreachable(sr, packet, len, interface);

	} else {
		/* Match found. Lookup MAC address in ARP cache */
		struct sr_arpentry *arpEntry = sr_arpcache_lookup(&(sr->cache), ntohl(closestMatch->gw.s_addr));

		if (arpEntry != NULL) {
			/* Found MAC address. Send the packet */
			struct sr_rt *arpClosestMatch = findLongestMatchPrefix(sr->routing_table, ntohl(arpEntry->ip));
			send_packet_to_dest(sr, packet, len, arpClosestMatch->interface, arpEntry->mac, ntohl(arpEntry->ip));

		} else {
			/* Could not find MAC address. Queue request for ARP  */
			sr_arpcache_queuereq(&(sr->cache), ntohl(closestMatch->gw.s_addr), packet, len, interface);
		}
	}
}
Beispiel #10
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;
}
Beispiel #11
0
void sr_send_ip(struct sr_instance* sr, uint8_t* packet,
                unsigned int len, char* iface)
{
  printf("Forwarding IP packet...\n");

  struct sr_if* interface = sr_get_interface(sr, iface);
  struct sr_ip_hdr* ipHeader = (struct sr_ip_hdr*)(packet + sizeof(sr_ethernet_hdr_t));

  /* Fetch the outgoing MAC from the ARP table */
  struct sr_arpentry * arpCacheEntry = sr_arpcache_lookup(&(sr->cache), ipHeader->ip_dst);

  /* Build the ethernet header */
  struct sr_ethernet_hdr* ethHeader = (struct sr_ethernet_hdr*)packet;

  memcpy(ethHeader->ether_shost, (char*)interface->addr, ETHER_ADDR_LEN);
  memcpy(ethHeader->ether_dhost, (char*)arpCacheEntry->mac, ETHER_ADDR_LEN);
  ethHeader->ether_type = htons(ethertype_ip);
  
  print_hdrs(packet, len);
  sr_send_packet(sr, packet, len, iface);
  printf("Sent on interface...%s\n", iface);
  free(arpCacheEntry);

}/* -- sr_send_ip -- */
Beispiel #12
0
int handle_ip_packet(struct sr_instance * sr, uint8_t * packet, unsigned int len ) {


      sr_ip_hdr_t *iphdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));

      /* validate checksum. */
      uint16_t checksum;

      checksum = cksum(iphdr, sizeof(*iphdr));
      if (checksum != 0xffff) {

            return -1;
      } 


      
      uint8_t * newpacket_for_ip = (uint8_t *) malloc(len);
      memcpy(newpacket_for_ip, packet, len);
      sr_ip_hdr_t *new_iphdr = (sr_ip_hdr_t *)(newpacket_for_ip + sizeof(sr_ethernet_hdr_t));

      /* Decrement the TTL by 1, and recompute the packet 
      checksum over the modified header. */

      /* decrement ttl */
      new_iphdr->ip_ttl--;

      if (new_iphdr->ip_ttl <= 0) {
          /* check ttl, less than zero */
            send_icmp_message(sr,packet, 11, 0);
            return -1;
      }

      /* update checksum. */
      new_iphdr->ip_sum = 0;
      checksum = cksum(new_iphdr, sizeof(*new_iphdr));
      new_iphdr->ip_sum = checksum;
      checksum = cksum(new_iphdr, sizeof(*new_iphdr));

      struct sr_if* assoc_iface = validate_ip(sr->if_list, iphdr->ip_dst);
      if (assoc_iface) {
            /*it's destined to one of our IPs */
            /* ICMP */
            uint8_t ip_proto = ip_protocol(packet + sizeof(sr_ethernet_hdr_t));
            if (ip_proto == ip_protocol_icmp) { 

                
                  int minlength = sizeof(sr_icmp_hdr_t) + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t);
                  if (len < minlength){
                  
                        return -1;
                  }

                  struct sr_icmp_hdr * icmp_hdr =  (struct sr_icmp_hdr *) (packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

                  if(icmp_hdr->icmp_type == 8){
                        /* is an echo request */

                        int res;
                        res = make_echo_request(&newpacket_for_ip, len);

                        if (res == -1){
                              
                              return -1;
                        }
                  }
                  /* end ICMP */
            } else {
                  /* got a udp payload to a rounter interface */
                  int res;
                  res = send_icmp_message(sr, packet, 3,  3);
                  if (res == -1){
                        
                        return -1;
                  }
            }
      }


      /* Find out which entry in the routing table has 
      the longest prefix match with the 
      destination IP address. */
      struct sr_rt* best_rt = find_best_rt(sr->routing_table,  ntohl(new_iphdr->ip_dst));         
      if (!best_rt) {
            /* didn't find an interface, send an ICMP message type 3 
            code 0, also if there are any errors above */
            int res = send_icmp_message(sr, packet, 3,  0);
            if (res == -1){
                 
                  return -1;
            }
            
            return 0;
      }

      /* found an interface */

      struct sr_if * best_iface = sr_get_interface(sr, best_rt->interface);
      if (!best_iface){
           
            return -1;
      }
      struct sr_arpentry * forward_arp_entry = sr_arpcache_lookup(&(sr->cache), best_rt->gw.s_addr);
      
      struct sr_ethernet_hdr * new_ether_hdr = (struct sr_ethernet_hdr * ) newpacket_for_ip; 

      /* ethernet -- update the source address */
      memcpy(new_ether_hdr->ether_shost, best_iface->addr,  ETHER_ADDR_LEN);

      if (forward_arp_entry) {
            /* we have a MAC address */
           

            /* update packet */
            /* ethernet -- set the dest address */
            memcpy(new_ether_hdr->ether_dhost, forward_arp_entry->mac, ETHER_ADDR_LEN);

            /* send packet using correct interface */
            int res = 0; 

            
            res = sr_send_packet(sr, newpacket_for_ip, len, best_rt->interface);

            if (res != 0) {
                 
                  return -1;
            }

            free(forward_arp_entry);
      } else {
            /* we dont have a MAC address, add to arp queue */
            
            struct sr_arpreq * arpreq;
            arpreq = sr_arpcache_queuereq(&(sr->cache), best_rt->gw.s_addr, newpacket_for_ip, 
                  len, best_rt->interface );
            if (!arpreq){
                 
                  return -1;
            }
            uint32_t ip, dest;
           
            ip = ntohl(best_iface->ip);

            dest = ntohl(best_rt->dest.s_addr);
            sr_handle_arp_req(sr, arpreq); 
      } 
      return 0;      
}
Beispiel #13
0
/*Returns 0 on success and error code on fail*/
int sr_handleip(struct sr_instance* sr, 
                uint8_t* packet,
                unsigned int len, 
                struct sr_if* in_f, 
                uint8_t** ethernet_data_addr){
  sr_ip_hdr_t* ip_header_buffer = (sr_ip_hdr_t*) *ethernet_data_addr;

  /* Get headers from packet */
  /*sr_ethernet_hdr_t* eth_hdr = (sr_ethernet_hdr_t*) packet;
  uint8_t * ip_pkt_buf = packet + sizeof(sr_ethernet_hdr_t);
  sr_ip_hdr_t* ip_hdr = (sr_ip_hdr_t*) (packet + sizeof(sr_ethernet_hdr_t)); */
  uint8_t * icmp_pkt_buf = packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t);
  sr_icmp_hdr_t* icmp_hdr = (sr_icmp_hdr_t*) icmp_pkt_buf;
  struct sr_if* ret_if; /* return interface */

  if (check_ip_sum(ip_header_buffer) == 0) { /*Pass Checksum*/
    printf("Checksum Pass\n");
  }
  else { /*Fail Checksum*/
    printf("Checksum Fail\n");
    return -1;
  }

  /*If the TTL went to 0*/
  if (decrement_ttl(ip_header_buffer) == -1) {
    /*Send ICMP with the proper TTL decrease type and icmp code*/
    printf("TTL reached 0\n"); 
    send_icmp(sr, packet, len, in_f, time_exceed_type, time_exceed_code);
    return -1;
  }

  /*Check if the IP packet is for us and not a echo request*/
  ret_if = sr_get_interface_from_ip(sr, ip_header_buffer->ip_dst);
  if(ret_if &&  !(ip_header_buffer->ip_p == ip_protocol_icmp && 
      icmp_hdr->icmp_type == echo_req_type && icmp_hdr->icmp_code == echo_req_code)) {
    /* The IP packet is FOR US */    
    printf("FOR US, NOT ECHO REQ");

    /* Check if it is an echo request */
    if (ip_header_buffer->ip_p == ip_protocol_tcp || 
               ip_header_buffer->ip_p == ip_protocol_udp) {
      /* It is TCP/UDP send ICMP port unreachable 
         SEND: an ICMP port unreachable to sending host*/
      send_icmp(sr, packet, len, in_f, port_unreach_type, port_unreach_code);
    } else {
      ;
      /* According to the Assignment: IGNORE THE PACKET*/
    }

  } else {
    
    /*If it's not in the routing table, send ICMP net unreachable*/
    struct sr_rt * routing_node;

    uint32_t ip_dest;

    /*If it's for us, we want to send back to the source, so check for the source in the routing table*/
    if (ret_if) {
      /* The IP packet is FOR US */
      printf("FOR US\n");
      ip_dest = ip_header_buffer->ip_src;
    }
    /*If not for us, we want to keep forwarding to the destination so check for that in the routing table*/
    else {
      /* The IP packet is NOT FOR US */
      printf("NOT FOR US\n");
      ip_dest = ip_header_buffer->ip_dst;
    }

    if ((routing_node = check_routing_table(sr, ip_dest)) == NULL) { 
      printf("NOT in routing table\n");
      send_icmp(sr, packet, len, in_f, dest_net_unreach_type, dest_net_unreach_code);
    }
    else {
      printf("In routing table\n");
      /*Got the routing table node in routing_node */

      /*Next hop IP address is in gateway
       *Look it up in arpcache_lookup to see if we know the MAC address
      */
      uint32_t nexthopIP = routing_node->gw.s_addr;
      struct sr_arpentry *arp_dest = sr_arpcache_lookup(&(sr->cache), nexthopIP);
      struct sr_if* nexthopInterface = sr_get_interface(sr, routing_node->interface);


      /*Create an ethernet header in front of the packet to forward regardless of
        whether or not we've found the next hop IP: need it in both cases*/

      /*Allocate space for ethernet header and packet, copy in contents of packet*/
      uint8_t* eth_header_packet = malloc(len);

      uint8_t* ip_header = eth_header_packet + sizeof(sr_ethernet_hdr_t);

      uint8_t* only_packet = eth_header_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t);

      memcpy(ip_header, ip_header_buffer, sizeof(sr_ip_hdr_t));

      memcpy(only_packet, (packet+sizeof(sr_ethernet_hdr_t)+sizeof(sr_ip_hdr_t)), len-sizeof(sr_ethernet_hdr_t)-sizeof(sr_ip_hdr_t));

      /*Save it in struct form*/
      sr_ethernet_hdr_t* packet_to_forward = (sr_ethernet_hdr_t*)eth_header_packet;

      /*Now set the actual ethernet header for the packet*/
      packet_to_forward->ether_type = htons(ethertype_ip);
      memcpy(packet_to_forward->ether_shost, nexthopInterface->addr, ETHER_ADDR_LEN);




      /*If NULL, send out the arp request*/
      if(arp_dest == NULL){
        printf("Not in arp cache: need to send an ARP request!\n");
        broadcast_arp_req(sr, nexthopIP, packet_to_forward, len, routing_node, nexthopInterface);

      }

      /*Otherwise just forward the packet to arp_dest's MAC address*/
      else {

        /*It's for us, it must be an echo request*/
        if (ret_if) {
          /*Doesn't have a code so just passing 0 as code*/
          struct sr_if *interface = sr_get_interface(sr, routing_node->interface);
          send_icmp_echo_reply(sr, packet, len, interface, arp_dest->mac, echo_reply_type, 0);
        }
        else {

          printf("In arp cache: just forwarding the packet\n");

          memcpy(packet_to_forward->ether_dhost, arp_dest->mac, ETHER_ADDR_LEN);
          sr_send_packet(sr, (uint8_t*)packet_to_forward, len, routing_node->interface);
          
          /*Free the arp_dest that sr_arpcache_lookup created*/
          free(arp_dest);
        }
      }


    }

  }

  return 0;
}
Beispiel #14
0
/*
  Find route and send out inet packet.
*/
void sr_send_inetpkt(struct sr_instance* sr,
        uint8_t * pkt/* lent */,
        unsigned int len,
        struct sr_if* src_iface/* lent */,
        int inited_by_router) {

  sr_ip_hdr_t *iphdr = (sr_ip_hdr_t *)(pkt + sizeof(sr_ethernet_hdr_t));

  /* Find route */
  struct sr_rt* nexthop = sr_findroute(sr, iphdr->ip_dst);

  if (nexthop == NULL) {
    /* No route found */
    fprintf(stderr, "sr_send_inetpkt: No route found!\n");
    if (inited_by_router)
      return;

    sr_send_icmp(sr, pkt, len, src_iface, 
      ICMP_TYPE_UNREACHABLE, ICMP_UNREACHABLE_NET);
    return;
  }

  /* Next hop is immediate host */
  uint32_t nexthop_ip = (nexthop->gw.s_addr ? nexthop->gw.s_addr : iphdr->ip_dst);
  
  /* ARP Lookup */
  struct sr_arpentry *arpentry = sr_arpcache_lookup(&sr->cache, nexthop_ip);

  if (arpentry == NULL) {
    /* No ARP entry found in cache, request one & queue packet */
    fprintf(stderr, "sr_send_inetpkt: No ARP entry found in cache, queuing packet.\n");

    struct sr_arpreq *arpreq = sr_arpcache_queuereq(
      &sr->cache, 
      nexthop_ip, 
      pkt, len, nexthop->interface);

    /* Send ARP request if not already sent */
    if (arpreq->sent == 0) {
      sr_send_arpreq(sr, arpreq->ip, sr_get_interface(sr, nexthop->interface));
      arpreq->sent = time(NULL);
      ++arpreq->times_sent;
    }

    return;
  }

  struct sr_if* iface_nexthop = sr_get_interface(sr, nexthop->interface);
  assert(iface_nexthop);

  sr_fill_eth(pkt, (uint8_t *)arpentry->mac, 
    (uint8_t *)iface_nexthop->addr, ethertype_ip);

  free(arpentry);

  /* Send frame to next hop */
  fprintf(stderr, "sr_send_inetpkt: Ready to send frame.\n");
  
  /* Send INet Packet */
  sr_send_packet(sr, pkt, len, iface_nexthop->name);
}
Beispiel #15
0
/*
 * Send an IP packet by linking its phyical address using 
 * the ARP cache. If the address is not found in the ARP cache
 * mapping, we send a ARP request, where the outstanding packets 
 * will resume sending once the ARP reply is received.
 */
void sr_send_ip_packet(struct sr_instance* sr, sr_ethernet_hdr_t* packet,
   unsigned int len, char* interface, struct sr_rt* route)
{
  uint32_t next_hop_ip_addr;
  struct sr_arpentry* arp_entry;

  /* Set ethernet source addr */
  struct sr_if* request_iface = sr_get_interface(sr, interface);
  struct sr_if* route_iface = sr_get_interface(sr, route->interface);
  memcpy(packet->ether_shost, route_iface->addr, ETHER_ADDR_LEN);
  packet->ether_type = ntohs(ethertype_ip);

  /* Find gateway IP for arp cahce lookup */
  next_hop_ip_addr = ntohl(route->gw.s_addr);
  arp_entry = sr_arpcache_lookup(&sr->cache, next_hop_ip_addr);

  if (arp_entry != NULL)
  {
    /* Arp cache found, send packet */
    memcpy(packet->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
    sr_send_packet(sr, (uint8_t*)packet, len, route_iface->name);
    free(arp_entry);
  }
  else
  {
    /* Arp cache not found */
    struct sr_arpreq* arp_request_entry = sr_arpcache_queuereq(
      &sr->cache, next_hop_ip_addr, (uint8_t*)packet, len, route->interface);

    if (arp_request_entry->times_sent == -1)
    {
      /* Contruct and send a new ARP request */
      uint8_t* request_arp_packet = (uint8_t *) malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t));
      sr_ethernet_hdr_t* request_ethernet_hdr = (sr_ethernet_hdr_t*)request_arp_packet;
      sr_arp_hdr_t* request_arp_hdr = (sr_arp_hdr_t*)(request_arp_packet + sizeof(sr_ethernet_hdr_t));

      /* Ethernet header */
      /* Destination addr is set to FF:FF:FF:FF:FF:FF */
      memcpy(request_ethernet_hdr->ether_dhost, ethernet_broadcast_addr, ETHER_ADDR_LEN);
      memcpy(request_ethernet_hdr->ether_shost, request_iface->addr, ETHER_ADDR_LEN);
      request_ethernet_hdr->ether_type = htons(ethertype_arp);

      /* ARP Header */
      request_arp_hdr->ar_hrd = htons(arp_hrd_ethernet);
      request_arp_hdr->ar_pro = htons(ethertype_ip);
      request_arp_hdr->ar_hln = ETHER_ADDR_LEN;
      request_arp_hdr->ar_pln = IP_ADDR_LEN;
      request_arp_hdr->ar_op = htons(arp_op_request);
      memcpy(request_arp_hdr->ar_sha, route_iface->addr, ETHER_ADDR_LEN);
      request_arp_hdr->ar_sip = route_iface->ip;

      /* Target addr set to 00:00:00:00:00:00 */
      memcpy(request_arp_hdr->ar_tha, blank_addr, ETHER_ADDR_LEN);
      request_arp_hdr->ar_tip = htonl(arp_request_entry->ip);

      printf("Sending ARP request for %u.%u.%u.%u on %s\n", 
        (arp_request_entry->ip >> 24) & 0xFF,
        (arp_request_entry->ip >> 16) & 0xFF,
        (arp_request_entry->ip >> 8) & 0xFF,
        arp_request_entry->ip & 0xFF,
        route_iface->name);
      sr_send_packet(sr, request_arp_packet, sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t), route_iface->name);
      free(request_arp_packet);

      arp_request_entry->times_sent = 1;
      arp_request_entry->sent = time(NULL);
    }
  }
Beispiel #16
0
void sr_handlepacket(struct sr_instance* sr, uint8_t * packet/* lent */,
					unsigned int len, char* interface/* lent */) {
	/* Function implemented by g1izzyw and gustan50404 */
	/* REQUIRES */
	assert(sr);
	assert(packet);
	assert(interface);
	
	struct sr_if *ether_interface = (struct sr_if *) sr_get_interface(sr, interface); 
	
	/* Check if it an ethernet interface. */
	if (ether_interface) {
		/* Now we deal with the ethernet header */
		struct sr_ethernet_hdr *ether_hdr = (struct sr_ethernet_hdr *) packet;
	    
		/* Check to see if we are dealing with an ARP request/reply */
		if (ether_hdr->ether_type == htons(ethertype_arp)) {
			
			fprintf(stderr, "We Got an ARP Packet\n");
			/* Handle ARP for ethernet */ 
			struct sr_arp_hdr * arp_hdr = (struct sr_arp_hdr *)(packet + sizeof(struct sr_ethernet_hdr));
			if (arp_hdr->ar_hrd == htons(arp_hrd_ethernet)) {

				if (arp_hdr->ar_op == htons(arp_op_request)) {
				/* arp request */
					struct sr_if *interface_for_ip = get_interface_for_ip(sr, arp_hdr->ar_tip);	
					if (interface_for_ip) {
  			
						/* Target ip is one of the router interfaces */
						fprintf(stderr, "ARP req for one of our interfaces\n");

						/* Now we want to make an arp reply and send it back */
						uint8_t *buf = (uint8_t *) malloc(len);
						memcpy(buf, packet, len);
    			
						/*Make Arp Header*/
						make_arprply_hdr(interface_for_ip->addr, arp_hdr->ar_sha, interface_for_ip->ip,
														arp_hdr->ar_sip, buf);
														
						/*Make Ethernet Header*/
						make_ether_hdr(interface_for_ip->addr, ether_hdr->ether_shost, ethertype_arp, buf);

						/* Now we send the packet */
						sr_send_packet(sr, buf, len, interface_for_ip->name);
						free(buf);
						fprintf(stderr, "ARP reply sent\n");
					}
				} else if (arp_hdr->ar_op == htons(arp_op_reply)) {

					fprintf(stderr, "We got an ARP Reply, need to check for intfc tho \n");
					/* arp reply */
					struct sr_if *interface_for_ip = get_interface_for_ip(sr, arp_hdr->ar_tip);	
					if (interface_for_ip) {
			
						fprintf(stderr, "We got an ARP Reply for one of our interfaces\n");
						/*We first want to insert into Arp cache*/
						struct sr_arpreq *request = sr_arpcache_insert(&(sr->cache), 
																		arp_hdr->ar_sha, 
																		arp_hdr->ar_sip);
						fprintf(stderr, "Signalling all waiting packets\n");
						if (request) {
							struct sr_packet *cur_packet = request->packets;
							while(cur_packet) {
								fprintf(stderr, "About to forward \n");
								print_hdrs(cur_packet->buf, cur_packet->len);
								forward_packet(sr, cur_packet->iface, arp_hdr->ar_sha, 
															cur_packet->len, cur_packet->buf); 
								fprintf(stderr, "Packet Forwarded\n");							
								cur_packet = cur_packet->next;
							}
						}
					}
				}		
			}      
    	} else if (ether_hdr->ether_type == htons(ethertype_ip)) {
					
			/* Get the ip header from the ethernet header*/
			sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
			/*IP Checksum Stuff*/
			uint16_t temp_ip_sum = ip_hdr->ip_sum;
			ip_hdr->ip_sum = 0;
			ip_hdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t));																	
			if (temp_ip_sum == ip_hdr->ip_sum) {
			
				/*We got here means IP Cheksum is alright, so we extract the interface*/
				struct sr_if *interface_for_ip = get_interface_for_ip(sr, ip_hdr->ip_dst);
				
				/*Check to make sure interface is one of ours*/
				if (interface_for_ip) {
					
					fprintf(stderr, "IP Packet destined towards our interface\n");
					/*Check if our IP packet is UDP or TCP*/
					if (ip_hdr->ip_p == 6 || ip_hdr->ip_p == 17) {
						fprintf(stderr, "We Got TCP or UDP, sending ICMP error msg\n");
						send_icmp_error(3, 3, sr, interface, len, packet);
					
					} else {
						
						/* Get the ICMP header */
						sr_icmp_hdr_t *icmp_hdr = (struct sr_icmp_hdr *) (packet + 
																		sizeof(sr_ethernet_hdr_t) + 
																		sizeof(sr_ip_hdr_t));
						
						/*Now we do the ICMP checksum chek*/
						/*This covers the ICMP echo case*/
						uint16_t temp_icmp_sum = icmp_hdr->icmp_sum;
						temp_icmp_sum = icmp_hdr->icmp_sum;
						icmp_hdr->icmp_sum = 0;
						if (temp_icmp_sum == cksum(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), 
												len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t))) {
							/*Everything is fine so we send an ICMP echo back*/
							fprintf(stderr, "Sending ICMP echo reply\n");
	    					send_icmp_echo(sr, interface, len, packet);
	    				}
	    			}
				} else {
					/*IP Packet not destined towards one of our interfaces*/
					
					fprintf(stderr, "IP packet not destined to our interface\n");
					/*Decremenrt TTL by 1*/
					
					fprintf(stderr, "TTL modified \n");
					print_hdrs(packet, len);
					if (ip_hdr->ip_ttl <= 1) {
						fprintf(stderr, "Packte with TTL < 0 found, sending ICMP error \n");
						/*TTL is less than 0 so send an ICMP ERROR*/
						send_icmp_error(11, 0, sr, interface, len, packet);
						
					} else {
						
						/*Recompute Checksum over new header TTL is fine*/
						/*Check if it exists in the routing table*/
						ip_hdr->ip_ttl = ip_hdr->ip_ttl - 1;
						fprintf(stderr, "Recomputing Checksum after modifying TTl\n");
						ip_hdr->ip_sum = 0;																			
						ip_hdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t));
						struct sr_if *dst_if = (struct sr_if *)malloc(sizeof(struct sr_if));
						dst_if = next_hop(sr, interface, ip_hdr->ip_dst);
						
						if (!(dst_if)) {
						
							fprintf(stderr, "IP packet has no longest matching prefix sending ICMP error\n");
							/*dst ip has no longest macthing prefix*/
							/*So we send a type 3 code 0 ICMP error*/
							send_icmp_error(3, 0, sr, interface, len, packet);
							
						} else {
							
							/*This is the case where we do have a longest macthing prefix*/
							fprintf(stderr, "Found Longest mathcing prefix in RT\n");
							struct sr_arpcache *cache = &(sr->cache);
							struct sr_arpentry *in_cache = sr_arpcache_lookup(cache, ip_hdr->ip_dst);
							if (in_cache) {
							
								fprintf(stderr, "Found IP->MAC mapping in ARP cache forwarding packet \n");
								/*this is the case where ip->mac maping is already in cache*/
								forward_packet(sr, dst_if->name, in_cache->mac, len, packet);
								free(in_cache);
								
							} else {
							
								fprintf(stderr, "IP->MAC mapping not in ARP cache %u \n", ip_hdr->ip_dst);
								/*Case where ip->mapping is not in cache*/
								sr_arpcache_queuereq(cache, ip_hdr->ip_dst, packet, len, dst_if->name);
								fprintf(stderr, "Added Arp Req to queu \n"); 						
							}
						}					
					}
				}
			}
		}
	} 
	
} /* end sr_ForwardPacket */
Beispiel #17
0
/*---------------------------------------------------------------------
 * Method: sr_encap_and_send_pkt(struct sr_instance* sr, 
 *						  							uint8_t *packet, 
 *						 		  					unsigned int len, 
 *						  	  					uint32_t dip,
 *						  							int send_icmp,
 *						  							sr_ethertype type)
 * Scope:  Global
 *
 * Sends a packet of length len and destination ip address dip, by 
 * looking up the shortest prefix match of the dip (net byte order). 
 * If the destination is not found, it sends an ICMP host unreachable. 
 * If it finds a match, it then checks the arp cache to find the 
 * associated hardware address. If the hardware address is found it 
 * sends it, otherwise it queues the packet and sends an ARP request. 
 *
 *---------------------------------------------------------------------*/
void sr_encap_and_send_pkt(struct sr_instance* sr,
						 	 					uint8_t *packet, 
						 						unsigned int len, 
						  					uint32_t dip,
						  					int send_icmp,
						  					enum sr_ethertype type)
{
	struct sr_arpentry *arp_entry;
	struct sr_arpreq *arp_req;
	struct sr_ethernet_hdr eth_hdr;
	uint8_t *eth_pkt;
	struct sr_if *interface;
	struct sr_rt *rt;
	unsigned int eth_pkt_len;
	
	/* Look up shortest prefix match in your routing table. */
	rt = sr_longest_prefix_match(sr, ip_in_addr(dip));
	
	/* If the entry doesn't exist, send ICMP host unreachable and return if necessary. */
	if (rt == 0) {
		if (send_icmp)
			sr_send_icmp(sr, packet, len, ICMP_UNREACHABLE_TYPE, ICMP_NET_CODE);
		return;
	}
	
	/* Fetch the appropriate outgoing interface. */
	interface = sr_get_interface(sr, rt->interface);
	
	/* If there is already an arp entry in the cache, send now. */
	arp_entry = sr_arpcache_lookup(&sr->cache, rt->gw.s_addr);
	if (arp_entry || type == ethertype_arp) {
		
		/* Create the ethernet packet. */
		eth_pkt_len = len + sizeof(eth_hdr);
		eth_hdr.ether_type = htons(type);
		
		/* Destination is broadcast if it is an arp request. */
		if (type == ethertype_arp && ((struct sr_arp_hdr *)packet)->ar_op == htons(arp_op_request))
			memset(eth_hdr.ether_dhost, 255, ETHER_ADDR_LEN);
		
		/* Destination is the arp entry mac if it is an ip packet or and are reply. */
		else
			memcpy(eth_hdr.ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
		memcpy(eth_hdr.ether_shost, interface->addr, ETHER_ADDR_LEN);
		eth_pkt = malloc(eth_pkt_len);
		memcpy(eth_pkt, &eth_hdr, sizeof(eth_hdr));
		memcpy(eth_pkt + sizeof(eth_hdr), packet, len);
		sr_send_packet(sr, eth_pkt, eth_pkt_len, rt->interface);
		free(eth_pkt);
		if (arp_entry)
			free(arp_entry);
	
	/* Otherwise add it to the arp request queue. */
	} else {
		eth_pkt = malloc(len);
		memcpy(eth_pkt, packet, len);
		arp_req = sr_arpcache_queuereq(&sr->cache, rt->gw.s_addr, eth_pkt, len, rt->interface);
		sr_arpreq_handle(sr, arp_req);
		free(eth_pkt);
	}
}
Beispiel #18
0
/*Handles all incoming IP packets, returns 1 if successful*/
int handle_IP_packet(struct sr_instance* sr, 
		      uint8_t* packet,
		      int len, 
		      char* interface){
  int normal_ip_forward = 0;
  int icmp_send = 0;
  struct sr_ethernet_hdr* ethernet_hdr =  (sr_ethernet_hdr_t*)packet;
  sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)(packet + (uint8_t) eth_size);
  int minLenIP = eth_size + sizeof(struct sr_ip_hdr);
  
  //1. Basic Standards: Make  sure it meets min len of packet,
  //   check checksum correct; set drop_packet if necessary
  if (len < minLenIP){
    fprintf(stderr, "Failed to access IP header, too small\n");
    drop_packet = 1;
    //return;
  }
  uint16_t initCksum = cksum(ip_header, sizeof(struct sr_ip_hdr));
  if (ntohl(ip_header->ip_sum) != initCksum){
    drop_packet = 1;
    icmp_type_code = -1;
  }

  //2. Figure out if either drop packet, or ICMP neccessary, 
  //   or just IP forward
  if (drop_packet == 0){
    dest_ip = ntohl(ip_header->ip_dst);
    if (destinedToRouter(dest_ip)){
      //destined for us
      icmp_type_code = icmp(sr,packet);
      if (icmp_type_code == -1){
	//unknown
	drop_packet = 1;
      }else{
	icmp_send = 1;
      }
    }else{//not destined to us
      icmp_type_code = icmp(sr,packet);
      if (icmp_type_code == -1){
	normal_ip_forward = 1;//good to forward
      }else{
	icmp_send = 1;
      }
    }
  }
   
  //if going to ip forward -> recompute ttl
  if (normal_ip_forward == 1){
    //ttl--, recompute checksum over modifified header
    ip_header->ip_ttl = htonl(ntohs(ip_header->ip_ttl) - 1);
    modCksum = cksum(ip_header, sizeof(struct sr_ip_hdr));
  }

  //if not dropping
  if (drop_packet == 0){
    //check arp cache for mac address
    struct sr_arpentry *arp_entry;
    arp_entry = sr_arpcache_lookup(&(sr->cache),
				   htonl(ip_header->ip_dst));

    //Means we found the ARP entry
    if (arp_entry != NULL){
      uint8_t dest_mac[ETHER_ADDR_LEN];
      convertMAC(dest_mac, arp_entry->mac);

      //use this to send to next hop ip, free entry
      free(arp_entry);
	
      //ICMP
      if (icmp_send == 1){
	//send back to source IP
	//Create Ethernet header, IP header and ICMP header
	int buff_size = minLenIP 
	  + sizeof(struct sr_icmp_t3_hdr) + ICMP_DATA_SIZE;//plus more?
	uint8_t* buf = (uint8_t*)malloc(buff_size);
	  
	setIcmpHeaders(buf, icmp_type_code, sr);
	sendPacket(sr,buf, interface, buff_size); //????????

      }else{
	if (normal_ip_forward == 1){
	  //means no errors detected; thus send packet
	  int ret = ip_forward(sr,packet,len,ethernet_hdr,
			       dest_mac,dest_ip,modCksum,interface);
	  if (ret!= 0){
	    fprintf(stderr, "Didn't send ip packet properly\n");
	    //return;
	  }
	}
      }
    }else{
      //entry not found ARP cache
      struct sr_arpreq* req1;
      req1 = (struct sr_arpreq*)(arpcache_queuereq(htonl(dest_ip),packet,len));
      free(req1);
      //rest done by arp_cahce. functions
      //ARP reply process code handles this
    }
  }//else packets are ignored (drop packet)
  return 1;
}
Beispiel #19
0
void ip_handlepacketforme(struct sr_instance *sr,
        sr_ip_hdr_t *ip_hdr,
        char *interface) {
 
    struct sr_arpreq *req;
    struct sr_arpentry *arp_entry;
    uint8_t *cache_packet;
    uint16_t total_len;
    uint16_t icmp_len;
    uint32_t dst;
    uint8_t icmp_type;
    uint8_t icmp_code;

    /* Check whether ICMP echo request or TCP/UDP */
    if (ip_hdr->ip_p == ip_protocol_icmp){

      dst = ip_hdr->ip_src;
      ip_hdr->ip_src = ip_hdr->ip_dst;
      ip_hdr->ip_dst = dst;

      /* Modify the ICMP reply packet */
      sr_icmp_hdr_t *icmp_hdr_ptr = icmp_header(ip_hdr);

      icmp_hdr_ptr->icmp_sum = 0;
      icmp_hdr_ptr->icmp_type = type_echo_reply;
      icmp_hdr_ptr->icmp_code = code_echo_reply;
      icmp_len = ntohs(ip_hdr->ip_len)-ip_hdr->ip_hl * 4;
              
      /* Copy the packet over */
      total_len = ip_hdr->ip_len;
      cache_packet = malloc(total_len);
      memcpy(cache_packet, ip_hdr, total_len);

      icmp_hdr_ptr = icmp_header((struct sr_ip_hdr *)cache_packet);
      icmp_hdr_ptr->icmp_sum = cksum(icmp_hdr_ptr, icmp_len);

      struct sr_ip_hdr *ip_hdr_csum = (struct sr_ip_hdr *)cache_packet;
      ip_hdr_csum->ip_sum = cksum(ip_hdr_csum, sizeof(sr_ip_hdr_t));

      /* Check if we should send immediately or wait */
      arp_entry = sr_arpcache_lookup(&sr->cache, dst);

      if (arp_entry != 0){

        /* Entry Exists, we can send it out right now */
        sr_add_ethernet_send(sr, cache_packet, total_len, dst, ethertype_ip);

        printf("** ARP entry exists, Echo reply sent\n");

      } else {
          req = sr_arpcache_queuereq(&sr->cache, dst, cache_packet, 
                                    total_len, interface);

          printf("** ARP entry doesn't exist, Echo reply queued\n");

          sr_handle_arpreq(sr, req);
        }
    } else if (ip_hdr->ip_p == ip_protocol_tcp||ip_hdr->ip_p == ip_protocol_udp) {

        /* Send ICMP port unreachable */            
        icmp_type = 3;
        icmp_code = 3;             
        sr_icmp_with_payload(sr, ip_hdr, interface, icmp_type, icmp_code);
      }
}
Beispiel #20
0
void sr_handlepacket(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
  uint8_t buf[len];
  int cksumtemp = 0;
  int cksumcalculated = 0;
  struct sr_arpentry *entry;
  struct sr_arpreq *req;
  struct sr_arpcache *arp_cache = &(sr->cache);
  struct sr_if *sr_interface;
  struct sr_rt *rt_walker = 0;
  char *temp_if;

  /* REQUIRES */
  assert(sr);
  assert(packet);
  assert(interface);

  printf("\n*** -> Received packet of length %d \n",len);

  /* fill in code here */
  sr_ethernet_hdr_t *ethhdr = (sr_ethernet_hdr_t *)packet;
  sr_arp_hdr_t *arphdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  sr_ip_hdr_t *iphdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  sr_icmp_hdr_t *icmphdr = (sr_icmp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

  sr_ethernet_hdr_t *arpreply_ethhdr = (sr_ethernet_hdr_t *)buf;
  sr_arp_hdr_t *arpreply_arphdr = (sr_arp_hdr_t *)(buf + sizeof(sr_ethernet_hdr_t));

  sr_ethernet_hdr_t *tempreq;

  if (len < sizeof(sr_ethernet_hdr_t)) {
    fprintf(stderr, "ETHERNET header is insufficient length\n");
    return;
  }

  if(ethertype(packet) == ethertype_arp) { /* ARP */
    if (len < (sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t))) {
      /* todo: call sr_arp_req_not_for_us, maybe later */
      fprintf(stderr, "ARP header is insufficient length\n");
      return;
    }
    else {
      printf("ARP packet received\n");
      if(ntohs(arphdr->ar_op) == arp_op_request) { /* ARP request */
	printf("\tARP request\n");
	/* send ARP reply */
	sr_interface = sr_get_interface(sr,interface);
	memcpy(buf,packet,len);

	memset(arpreply_ethhdr->ether_dhost,0xff,6);
	memcpy(arpreply_ethhdr->ether_shost,sr_interface->addr,6);
	arpreply_ethhdr->ether_type = htons(ethertype_arp);

	arpreply_arphdr->ar_op = htons(arp_op_reply);
	memcpy(arpreply_arphdr->ar_sha,sr_interface->addr,6);
	arpreply_arphdr->ar_sip = arphdr->ar_tip;
	memcpy(arpreply_arphdr->ar_tha,arphdr->ar_sha,6);
	arpreply_arphdr->ar_tip = arphdr->ar_sip;
	sr_send_packet(sr,buf,len,interface);

	printf("\tARP reply sent\n");
		/* sr_arpcache_dump(arp_cache); */
      }
      else if(ntohs(arphdr->ar_op) == arp_op_reply) { /* ARP reply */
	printf("\tARP reply\n");
	/* cache IP->MAC mapping and check if arp req in queue */
	req = sr_arpcache_insert(arp_cache,arphdr->ar_sha,ntohs(arphdr->ar_sip));
	tempreq = (sr_ethernet_hdr_t *)req->packets->buf;
	memcpy(tempreq->ether_dhost,ethhdr->ether_shost,6);
	if(req != NULL) {
	  /* send outstanding packets by call */
	  printf("\tARP req in queue\n");
	  sr_send_packet(sr,req->packets->buf,req->packets->len,interface);
	  sr_arpreq_destroy(arp_cache,req);
	}
	else
	  printf("\tARP req not in queue\n");
      }
      else /* not ARP request or reply */
	fprintf(stderr, "Unknown ARP opcode\n");
    }
  }

  else if(ethertype(packet) == ethertype_ip) { /* IP */
    if (len < (sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t))) {
      fprintf(stderr, "IP header is insufficient length\n");
      return;
    }
    else {
      printf("IP packet received\n");
      /* check checksum */
      cksumtemp = iphdr->ip_sum;
      iphdr->ip_sum = 0;
      cksumcalculated = cksum((void *)iphdr,4*iphdr->ip_hl);

      if(cksumtemp == cksumcalculated) {
	printf("\tChecksum good!\n");

	/* this part should not be here, it should be called though */
	if(iphdr->ip_ttl <= 1) {
	  fprintf(stderr, "ICMP time exceeded\n"); /* ICMP time exceeded */
	  return;
	}
	else
	  iphdr->ip_ttl -= 1; 
	
	/* update checksum */
	iphdr->ip_sum = cksum((void *)iphdr,4*iphdr->ip_hl);

	/* todo: LPM and find next hop ip, if no match ICMP net unreachable  */

	/* check routing table, save interface */
	rt_walker = sr->routing_table;
	while(rt_walker != NULL) {
	  if(iphdr->ip_dst == (uint32_t)rt_walker->dest.s_addr) { /* checks for dest IP addr, should be LPM ip not ip_dst */
	    temp_if = rt_walker->interface;
	  }
	  rt_walker = rt_walker->next;
	}
	sr_interface = sr_get_interface(sr,temp_if);

	/* check cache to avoid unnecessary arp req */
	entry = sr_arpcache_lookup(arp_cache,ntohs(iphdr->ip_dst)); /* should be LPM ip not ip_dst, but since next hop is destination... */

	if(entry != NULL) { /* cache hit, just send ip packet to next hop*/
	  printf("\tIP->MAC hit\n");
	  sr_send_packet(sr,packet,len,sr_interface);
	  free(entry);
	}
	else { /* cache miss, send ARP req and wait for reply */
	  printf("\tIP->MAC miss\n");
	  if(sr_interface == 0) { /* no match in routing table */
	    fprintf(stderr, "ICMP host unreachable\n");
	    return;
	  }
	  else { /* match in routing table */
	    /* construct arp req with new interface */
	    memset(arpreply_ethhdr->ether_dhost,0xff,6);
	    memcpy(arpreply_ethhdr->ether_shost,sr_interface->addr,6);
	    arpreply_ethhdr->ether_type = htons(ethertype_arp);

	    arpreply_arphdr->ar_hrd = htons(arp_hrd_ethernet);
	    arpreply_arphdr->ar_pro = htons(ethertype_ip);
	    arpreply_arphdr->ar_hln = 0x6;
	    arpreply_arphdr->ar_pln = 0x4;
	    arpreply_arphdr->ar_op = htons(arp_op_request);
	    memcpy(arpreply_arphdr->ar_sha,sr_interface->addr,6);
	    arpreply_arphdr->ar_sip = sr_interface->ip;
	    memset(arpreply_arphdr->ar_tha,0x00,6);
	    arpreply_arphdr->ar_tip = iphdr->ip_dst;

	    memcpy(ethhdr->ether_shost,sr_interface->addr,6);

	    printf("\tARP request sent\n");
	    /* add packet to queue list */
	    req = sr_arpcache_queuereq(arp_cache,ntohs(iphdr->ip_dst),packet,len,sr_interface);
	    handle_arpreq(arp_cache,sr,req,buf,sr_interface);
	  }
	}
      }
      else {
	/* drop packet */
	fprintf(stderr, "\tChecksum bad!\n");
	return;
      }
    }
  }

  else /* not IP or ARP */
    printf("Unrecognized Ethernet Type 0x%X\n",ethertype(packet));
}
Beispiel #21
0
void sr_handle_ip(struct sr_instance* sr, uint8_t* packet,
                  unsigned int len, char* iface)
{
  struct sr_if* interface = sr_get_interface(sr, iface);
  struct sr_ip_hdr* ipHeader = (struct sr_ip_hdr*)(packet + sizeof(sr_ethernet_hdr_t));

  /* Verify the checksum */
  uint16_t check = cksum(ipHeader, sizeof(sr_ip_hdr_t));
  if(check != 0xFFFF)
  {
    printf("Packet Corrupted!\n");  
    return;
  }

  /* Check destination */
  if(ipHeader->ip_dst == interface->ip)
  {
    /* Check protocol */
    if(ipHeader->ip_p == ip_protocol_icmp)
    {
      /* Process ICMP message */
      struct sr_icmp_hdr* icmpHeader = (struct sr_icmp_hdr*)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
      if(icmpHeader->icmp_type == icmp_type_echorequest)
      {
        printf("Echo Request...\n");  
        sr_send_icmp(sr, packet, len, icmp_type_echoreply, 0);
      }
    }
    else
    {
      /* Send port unreachable ICMP message  */
      printf("Port Unreachable\n");  
      sr_send_icmp(sr, packet, len, icmp_type_destunreachable, icmp_code_portunreachable);
    }

  }
  else
  {
    printf("Processing Packet for forwarding...\n");
    /* Forward the packet accordingly */
    /* Decrement TTL */
    ipHeader->ip_ttl = ipHeader->ip_ttl-1;

    if(ipHeader->ip_ttl == 0)
    {
      /* Send ICMP time exceeded */
      printf("TTL expired! Returning ICMP timeexceeded\n");
      sr_send_icmp(sr, packet, len, icmp_type_timeexceeded, 0);
      return;
    }

    /* Check if the destination is in our routing table */
    char * iface = sr_get_routing_entry_interface(sr, ipHeader->ip_dst);
    if(iface == NULL)
    {
      /* Send a network unreachable message */
      printf("No route! Returning ICMP netUnreachable\n");
      sr_send_icmp(sr, packet, len, icmp_type_destunreachable, icmp_code_netunreachable);
      return;
    }

    /* Recalculate the  checksum */
    ipHeader->ip_sum = 0x0000;
    ipHeader->ip_sum = cksum(ipHeader, sizeof(sr_ip_hdr_t));

    /* Look up in the ARP table */
    struct sr_arpentry * arpCacheEntry = sr_arpcache_lookup(&(sr->cache), ipHeader->ip_dst);

    /* At this point we know we're going to send it, so make a copy */
    uint8_t* copy = (uint8_t*)malloc(len);
    memcpy(copy, packet, len);
    struct sr_ip_hdr* copyIPHeader = (struct sr_ip_hdr*)(copy + sizeof(sr_ethernet_hdr_t));

    /* See if there was an entry */
    if(arpCacheEntry == NULL)
    {
      /* No entry, so queue up for ARP request */
      printf("ARP MISS!\n");
      sr_arpcache_queuereq(&(sr->cache), copyIPHeader->ip_dst, copy, len, iface);
      printf("Added ARP req for ");
      print_addr_ip_int(htonl(copyIPHeader->ip_dst));
      printf(" to queue\n");
      return;
    }
    printf("ARP HIT!\n");
    /* Forward the IP message using the ARP Cache info */
    sr_send_ip(sr, copy, len, iface);

    free(arpCacheEntry);

  }
}/* -- sr_handle_ip -- */
Beispiel #22
0
void arp_handlepacket(struct sr_instance *sr,
        uint8_t *packet,
        unsigned int len,
        char *interface) 
{
    printf("** Recieved ARP packet\n");

    /* Initalize ARP header from the Packet */
    struct sr_arp_hdr *arp_hdr = arp_header(packet);
    /* Interface the packet arrived in */
    struct sr_if *r_iface = sr_get_interface(sr,interface);

    /* Check if interface->ip = arp header->ip */
    if (r_iface->ip != arp_hdr->ar_tip){
      return;
    }

    /* validate ARP packet */
    if (!arp_validpacket(packet, len))
      return;

    if (ntohs(arp_hdr->ar_op) == arp_op_request){

      if(sr_arp_req_not_for_us(sr, packet, len, interface))
        return;

      printf("** ARP packet request to me \n");   
      
      /* Build and send ARP packet  */
      build_arp_reply(sr, arp_hdr, r_iface);
      
    } else if (ntohs(arp_hdr->ar_op) == arp_op_reply) {
        printf("** ARP packet reply to me\n");

        struct sr_arpentry *arp_entry;
        struct sr_arpreq *arp_req;
        struct sr_if *s_interface;
        struct sr_packet *pkt_wait;
        struct sr_packet *temp;
        uint8_t *send_packet;
        unsigned int eth_pkt_len;

        /* Check ARP cache  */
        arp_entry = sr_arpcache_lookup(&sr->cache, arp_hdr->ar_sip);

        if (arp_entry != 0){
          free(arp_entry);
        } else {
            arp_req = sr_arpcache_insert(&sr->cache, arp_hdr->ar_sha, arp_hdr->ar_sip);

            printf("** ARP entry created\n");

            /* Check ARP request queue, if not empty send out packets on it*/
            if (arp_req != 0) {
              pkt_wait = arp_req->packets;

              while (pkt_wait != 0) {

                printf("** ARP resolved, sending queued packets\n");
                /* Send the packets out */
                s_interface = sr_get_interface(sr, pkt_wait->iface);
                struct sr_ethernet_hdr sr_ether_hdr;

                /* Construct the ethernet packet */
                sr_ether_hdr.ether_type = htons(ethertype_ip);
                memcpy(sr_ether_hdr.ether_shost, s_interface->addr, ETHER_ADDR_LEN);
                memcpy(sr_ether_hdr.ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);

                /* Copy the packet into the sender buf */
                eth_pkt_len = pkt_wait->len + sizeof(struct sr_ethernet_hdr);
                send_packet = malloc(eth_pkt_len);
                memcpy(send_packet, &sr_ether_hdr, sizeof(struct sr_ethernet_hdr));
                memcpy(send_packet + sizeof(struct sr_ethernet_hdr), 
                      pkt_wait->buf, pkt_wait->len);

                sr_send_packet(sr, send_packet, eth_pkt_len, s_interface->name);

                temp = pkt_wait;
                pkt_wait = pkt_wait->next;
                free(temp);
              }

	    printf("** All queued packets sent\n");

            } 
          }   
      }
}
Beispiel #23
0
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);

  print_hdrs(packet, len);

  sr_arp_hdr_t* arpHdr = (sr_arp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
  sr_ethernet_hdr_t* ethHdr = (sr_ethernet_hdr_t*)packet;
  sr_ip_hdr_t* ipHdr = (sr_ip_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
  sr_icmp_hdr_t* icmpHdr = (sr_icmp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
 

  struct sr_rt* route = sr->routing_table;
  struct sr_arpentry* ent;
  char ifBuf[INET_ADDRSTRLEN];
  char ipBuf[INET_ADDRSTRLEN];



  if(strcmp(arpHdr->ar_tha, "\0") == 0){
    sr_arpcache_queuereq(&(sr->cache), arpHdr->ar_tip, packet, len, interface);
    printf("added arpreq to queue.\n\n");
    return;
  }
  printf("arp rep: %d\n", ntohs(arpHdr->ar_op));
  printf("opcode: %d\n", arp_op_reply);
  if(ntohs(arpHdr->ar_op) == arp_op_reply){
    ent = sr_arpcache_lookup(&sr->cache, arpHdr->ar_sip);
    if( ent == NULL){
      //      printf("Added %s to cache\n", ntohl(arpHdr->ar_sip));
      printf("Incoming arp response\n");
      //      sleep(2);
      

      struct sr_arpreq* req = sr->cache.requests;
      printf("%p, %p\n", req, sr->cache.requests);
      while(req != NULL){
	if(req->ip == arpHdr->ar_sip){
	  struct sr_packet* pkt = req->packets;
	  while(pkt != NULL){
	    if(route != NULL){
	      do{
		sr_ip_hdr_t* reqIpHdr = (sr_ip_hdr_t*)(pkt->buf + sizeof(sr_ethernet_hdr_t));
		sr_ethernet_hdr_t* reqEthHdr = (sr_ethernet_hdr_t*)(pkt->buf);
		//      sr_print_routing_entry(route);
		inet_ntop(AF_INET, &route->dest, ifBuf, sizeof(char) * INET_ADDRSTRLEN);
		convert_addr_ip_int(ntohl(reqIpHdr->ip_dst), ipBuf);
		printf("%s dest: %s\n",route->interface, ifBuf);
		printf("ip dest: %s\n", ipBuf);
		if(strcmp(ifBuf, ipBuf) == 0){
		  
		  memcpy(reqEthHdr->ether_shost, (uint8_t*)(sr_get_interface(sr, route->interface)->addr), sizeof(uint8_t) * ETHER_ADDR_LEN);
		  memcpy(reqEthHdr->ether_dhost, (uint8_t*)arpHdr->ar_sha, sizeof(uint8_t) * ETHER_ADDR_LEN);
		  print_hdrs(pkt->buf, pkt->len);
		  sr_send_packet(sr, pkt->buf, pkt->len, &(route->interface));
		  printf("pkt sent down %s\n\n", route->interface);
		  //	  free(ent);
		  //return;
		  break;
		}
		route = route->next;
	      } while(route != NULL);
	      pkt = pkt->next;
	    }

	  }
	  free(ent);
	  sr_arpreq_destroy(&sr->cache, req);
	  break;
	}
	req = req->next;
      }

    }
    sr_arpcache_insert(&(sr->cache), arpHdr->ar_sha, arpHdr->ar_sip);  




    //sr_arpcache_dump(&sr->cache);
    free(ent);
    return;
  }

  ent = sr_arpcache_lookup(&sr->cache, ipHdr->ip_dst);
  route = sr->routing_table;
  //Make and queue requests if dest isn't in arpcache
  if( ent == NULL ){
    if(route != NULL){
      do{
	inet_ntop(AF_INET, &route->dest, ifBuf, 100);
	convert_addr_ip_int(ntohl(ipHdr->ip_dst), ipBuf);
	if(strcmp(ifBuf, ipBuf) == 0){
	  sr_arpcache_queuereq(&sr->cache, ipHdr->ip_dst, packet, len, route->interface);
	  free(ent);
	  return;
	}
	route = route->next;
      } while(route != NULL);
      sr_arpcache_queuereq(&sr->cache, ipHdr->ip_dst, packet, len, "eth1");

    }
  }

  //Forwards packet to interface
  if(route != NULL){
    do{
      //      sr_print_routing_entry(route);
      inet_ntop(AF_INET, &route->dest, ifBuf, sizeof(char) * INET_ADDRSTRLEN);
      convert_addr_ip_int(ntohl(ipHdr->ip_dst), ipBuf);
      printf("%s dest: %s\n",route->interface, ifBuf);
      printf("ip dest: %s\n", ipBuf);
      if(strcmp(ifBuf, ipBuf) == 0){
	
	memcpy(ethHdr->ether_shost, (uint8_t*)(sr_get_interface(sr, route->interface)->addr), sizeof(uint8_t) * ETHER_ADDR_LEN);
	memcpy(ethHdr->ether_dhost, (uint8_t*)ent->mac, sizeof(uint8_t) * ETHER_ADDR_LEN);
	print_hdrs(packet, len);
	sr_send_packet(sr, packet, len, &(route->interface));
	printf("pkt sent down %s\n\n", route->interface);
	free(ent);
	return;
      }
      route = route->next;
    } while(route != NULL);
  }

  free(ent);
  


}/* end sr_ForwardPacket */
Beispiel #24
0
void sr_icmp_with_payload(struct sr_instance *sr,
        sr_ip_hdr_t *ip_hdr, char *interface,
        uint8_t icmp_type, uint8_t icmp_code) {

    struct sr_if *r_interface = sr_get_interface(sr, interface);
    struct sr_arpreq *req;
    struct sr_arpentry *arp_entry;
    uint8_t *cache_packet;
    uint16_t total_len;
    uint16_t icmp_len;
    uint32_t dst;

    if (icmp_type == 11 && icmp_code == 0){
      if (natEnabled(sr)){
        sr_nat_undo_mapping(sr, ip_hdr, ip_hdr->ip_len, r_interface);
      }
    }

    /* Create a new IP packet for ICMP message */
    struct sr_ip_hdr send_ip_hdr;

    send_ip_hdr.ip_hl = 5;
    send_ip_hdr.ip_v = ip_hdr->ip_v;
    send_ip_hdr.ip_tos = 0;
    send_ip_hdr.ip_id = 0;
    send_ip_hdr.ip_off = htons(IP_DF);
    send_ip_hdr.ip_ttl = DEFAULT_TTL;
    send_ip_hdr.ip_p = ip_protocol_icmp;
    send_ip_hdr.ip_sum = 0;
    send_ip_hdr.ip_dst = ip_hdr->ip_src;

    if (icmp_type == 3 && icmp_code == 3){
      ip_hdr->ip_sum = cksum(ip_hdr, ip_hdr->ip_hl * 4);
      send_ip_hdr.ip_src = ip_hdr->ip_dst;
    } else {
        send_ip_hdr.ip_src = r_interface->ip;
    }
    dst = ip_hdr->ip_src;

    struct sr_icmp_t3_hdr error_packet;

    error_packet.icmp_type = icmp_type;
    error_packet.icmp_code = icmp_code;
    error_packet.icmp_sum = 0;
    error_packet.unused = 0;
    error_packet.next_mtu = htons(MTU);

    icmp_len = sizeof(struct sr_icmp_t3_hdr);
    total_len = ICMP_IP_HDR_LEN_BYTE + icmp_len;
    send_ip_hdr.ip_len = htons(total_len);
    send_ip_hdr.ip_sum = cksum(&send_ip_hdr, ICMP_IP_HDR_LEN_BYTE);

    cache_packet = malloc(total_len);

    memcpy(error_packet.data, ip_hdr, ICMP_DATA_SIZE);
    memcpy(cache_packet, &(send_ip_hdr), ICMP_IP_HDR_LEN_BYTE);
    memcpy(cache_packet + ICMP_IP_HDR_LEN_BYTE, &(error_packet), 
          sizeof(struct sr_icmp_t3_hdr));

    struct sr_icmp_hdr *icmp_hdr_ptr = icmp_header((struct sr_ip_hdr *)cache_packet);

    icmp_hdr_ptr->icmp_sum = cksum(icmp_hdr_ptr, icmp_len);

    /*Check if we should send immediately or wait */
    arp_entry = sr_arpcache_lookup(&sr->cache, dst);
    
    if (arp_entry != 0){

    /* Entry exists, we can send it out right now */
    sr_add_ethernet_send(sr, cache_packet, total_len, dst, ethertype_ip);
    } else {
        req = sr_arpcache_queuereq(&sr->cache, dst, 
                                  cache_packet, total_len, interface);
        sr_handle_arpreq(sr, req);
      }  
}
Beispiel #25
0
void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) 
{
    if (difftime(time(0), req->sent) > 0.9) {

      /* Host is not reachable */
      if (req->times_sent >= 5) {

        printf("** Host Unreachable\n");
        
        /* Send ICMP host unreachable*/
        struct sr_packet *ip_packet, *next;
        ip_packet = req->packets;

        if(ip_packet != 0){
          next = ip_packet->next;
        }
        while(ip_packet != 0){
          sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(ip_packet->buf);
          struct sr_if *s_interface = sr_get_interface(sr, ip_packet->iface);
          uint32_t dst;
          
          /* Send ICMP host unreachable */
          struct sr_ip_hdr send_ip_hdr;
          
          send_ip_hdr.ip_hl = 5;
          send_ip_hdr.ip_v = ip_hdr->ip_v;
          send_ip_hdr.ip_tos = 0;
          send_ip_hdr.ip_id = 0;
          send_ip_hdr.ip_off = htons(IP_DF);
          send_ip_hdr.ip_ttl = 100;
          send_ip_hdr.ip_p = ip_protocol_icmp;
          send_ip_hdr.ip_sum = 0;
          send_ip_hdr.ip_dst = ip_hdr->ip_src;
          send_ip_hdr.ip_src = s_interface->ip;
          dst = ip_hdr->ip_src;
            
          /* Copy the packet over */
          uint8_t *cache_packet;
          uint16_t total_len;
          uint16_t icmp_len;

          icmp_len = sizeof(struct sr_icmp_t3_hdr);
          total_len = ICMP_IP_HDR_LEN_BYTE + icmp_len;
          send_ip_hdr.ip_len = htons(total_len);
          send_ip_hdr.ip_sum = cksum(&send_ip_hdr, ICMP_IP_HDR_LEN_BYTE);

          cache_packet = malloc(total_len);
          struct sr_icmp_t3_hdr icmp_error_packet = icmp_send_error_packet(ip_hdr, code_host_unreach);

          memcpy(cache_packet, &(send_ip_hdr), ICMP_IP_HDR_LEN_BYTE);
          memcpy(cache_packet + ICMP_IP_HDR_LEN_BYTE, &(icmp_error_packet), 
                sizeof(struct sr_icmp_t3_hdr));

          print_hdr_ip(cache_packet);

          struct sr_arpreq *icmp_req;
          struct sr_arpentry *arp_entry;

          /* Check ARP cache  */
          arp_entry = sr_arpcache_lookup(&sr->cache, dst);

          if (arp_entry != 0){
                
            /* Entry exists, we can send it out right now */
            sr_add_ethernet_send(sr, cache_packet, total_len, dst, ethertype_ip);
          } else {

              /* Get the interface at which the original packet arrived */
              struct sr_rt *lpmatch;
              struct sr_if *r_iface;

              lpmatch = longest_prefix_matching(sr, dst);
              r_iface = sr_get_interface(sr, lpmatch->interface);           
              icmp_req = sr_arpcache_queuereq(&sr->cache, dst, 
                                        cache_packet, total_len, r_iface->name);
              sr_handle_arpreq(sr, icmp_req);
            }
          ip_packet = next;
          if(ip_packet != 0){
            next = ip_packet->next;
          } else {
              sr_arpreq_destroy(&sr->cache, req);
          }
        }  
      } else {
          arp_boardcast(sr, req);

	  printf("** APR boardcasted\n");

          req->sent = time(0);
          req->times_sent ++;
        }
    }
}
Beispiel #26
0
void ip_forwardpacket(struct sr_instance *sr,
        sr_ip_hdr_t *ip_hdr,
        unsigned int len,
        char *interface) {

        printf("** FORWARDING\n");

        struct sr_arpreq *req;
        struct sr_arpentry *arp_entry;
        uint8_t icmp_type;
        uint8_t icmp_code;

        ip_hdr->ip_ttl --;
 	
        /* Update checksum */
        ip_hdr->ip_sum = 0;
        ip_hdr->ip_sum = cksum(ip_hdr, ip_hdr->ip_hl * 4);

        uint8_t *ip_pkt;

        ip_pkt = malloc(len);
        memcpy(ip_pkt, ip_hdr, len);

        /* Find longest prefix match in routing table */
        struct sr_rt* lpmatch = longest_prefix_matching(sr, ip_hdr->ip_dst);
        
        /* If cannot find destination IP in routing table, send ICMP net unreachable */
        /* OR TTL = 0 */
        if (lpmatch == 0) {
          icmp_type = 3;
          icmp_code = 0;
          sr_icmp_with_payload(sr, ip_hdr, interface, icmp_type, icmp_code);
          return;
        } else if (ip_hdr->ip_ttl == 0){
          icmp_type = 11;
          icmp_code = 0;
          sr_icmp_with_payload(sr, (sr_ip_hdr_t *)(ip_pkt), interface, icmp_type, icmp_code);
          return;
        }

        /* Ready to forward packet */  
        /* Get the corresponding interface of the destination IP. */
        struct sr_if* s_interface = sr_get_interface(sr, lpmatch->interface);
      
        /* Check ARP cache */
        arp_entry = sr_arpcache_lookup(&sr->cache, lpmatch->gw.s_addr);

        if (arp_entry == 0){

            /* If miss APR cache, add the packet to ARP request queue */
            req = sr_arpcache_queuereq(&sr->cache, lpmatch->gw.s_addr, ip_pkt, 
                                      len, s_interface->name);
            sr_handle_arpreq(sr, req);
        } else {

            /* Hit ARP cache, send out the packet right away using next-hop */
            /* Encap the ARP request into ethernet frame and then send it */
            sr_ethernet_hdr_t sr_ether_pkt;

            memcpy(sr_ether_pkt.ether_dhost, arp_entry->mac, ETHER_ADDR_LEN); /* Address from routing table */
            memcpy(sr_ether_pkt.ether_shost, s_interface->addr, ETHER_ADDR_LEN); /* Hardware address of the outgoing interface */
            sr_ether_pkt.ether_type = htons(ethertype_ip);

            uint8_t *packet_rqt;
            unsigned int total_len = len + sizeof(struct sr_ethernet_hdr);
            packet_rqt = malloc(total_len);
            memcpy(packet_rqt, &(sr_ether_pkt), sizeof(sr_ether_pkt));
            memcpy(packet_rqt + sizeof(sr_ether_pkt), ip_pkt, len);

            /* Forward the IP packet*/
            sr_send_packet(sr, packet_rqt, total_len, s_interface->name);
            free(packet_rqt);
          }
}
void process_ether_type_ip(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
  assert(sr);
  assert(packet);
  assert(interface);

  /* Create IP header struct for further processing */
  sr_ip_hdr_t *ip_header = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  sr_ethernet_hdr_t *eth_header = (sr_ethernet_hdr_t *)(packet);

  printf("IP Packet Received...\n");
  fprintf(stderr, "\tsource IP: ");
  print_addr_ip_int(ntohl(ip_header->ip_src));
  fprintf(stderr, "\tsource MAC: ");
  print_addr_eth(eth_header->ether_shost);
  fprintf(stderr, "\tdestination IP: ");
  print_addr_ip_int(ntohl(ip_header->ip_dst));
  fprintf(stderr, "\tdestination MAC: ");
  print_addr_eth(eth_header->ether_dhost);

  /* Decrement TTL and recompute checksum */
  ip_header->ip_sum = 0;
  ip_header->ip_sum = cksum((const void*)ip_header, sizeof(sr_ip_hdr_t));  

  struct sr_if* pkt_interface = 0;
  struct sr_if* interface_list_iterator = sr->if_list;

  /* If destination address belongs to Router's if_list */
  while (interface_list_iterator!=NULL) 
  {
    if (ip_header->ip_dst == interface_list_iterator->ip) 
        pkt_interface = interface_list_iterator;
    interface_list_iterator = interface_list_iterator->next;
  }

  /* IP packet destined for router's interface - NO GO */
  /* Processing only for ICMP echo request-reply otherwise no go */
  
  if (pkt_interface!=0) /* Interface record exists */
  { 
    printf("IP Packet meant for Router...\n");
    if (ip_header->ip_p == ip_protocol_icmp) /* echo req/reply */
    {
      printf("IP Packet contains ICMP...\n");
      sr_icmp_hdr_t* icmp_header = (sr_icmp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
      if (icmp_header->icmp_type == 8) /* PING */
      {
          printf("ICMP Echo request to Router...\n");

          uint8_t* send_packet = (uint8_t *)malloc(len);
          /* Same content as packet */
          memcpy(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t),len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t));
          /* ICMP header */
          sr_icmp_hdr_t* new_icmp = (sr_icmp_hdr_t *)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
          new_icmp->icmp_type = 0;
          new_icmp->icmp_code = 0;
          new_icmp->icmp_sum = cksum(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), len - sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
          /* Ethernet header */
          sr_ethernet_hdr_t *new_ethhdr = (sr_ethernet_hdr_t *) send_packet;
          new_ethhdr->ether_type = ntohs(0x0800);
          /* IP header */
          sr_ip_hdr_t *new_iphdr = (sr_ip_hdr_t *)(send_packet + sizeof(sr_ethernet_hdr_t));
          new_iphdr->ip_len = ntohs(len - sizeof(sr_ethernet_hdr_t));
          new_iphdr->ip_ttl = 64; /* 64 */
          new_iphdr->ip_v = 4;
          new_iphdr->ip_hl = 5;
          new_iphdr->ip_dst = ip_header->ip_src;
          new_iphdr->ip_src = ip_header->ip_dst;
          new_iphdr->ip_p = 0x0001;
          new_iphdr->ip_sum = 0;
          new_iphdr->ip_sum = cksum(send_packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t));

          printf("ICMP Echo response prepared...\n");
          struct sr_arpentry* entry = sr_arpcache_lookup(&(sr->cache), new_iphdr->ip_dst);
          if (entry)
          {
            memcpy(new_ethhdr->ether_dhost, entry->mac, 6);
            struct sr_if* sending_interface = sr_get_interface(sr, interface);
            memcpy(new_ethhdr->ether_shost, sending_interface->addr, 6);
            sr_send_packet(sr, send_packet, len, interface);
            printf("ICMP Echo response sent (Cache lookup successful)...\n");
            free(entry);
          }
          else
          {
            printf("Entry not found in Cache for ICMP Echo response (Preparing ARP Request)...\n");
            struct sr_arpreq* req = sr_arpcache_queuereq(&(sr->cache), new_iphdr->ip_dst, send_packet, len, interface);
            req->iface = interface;
            handle_arpreq(sr, req);
          }
          free (send_packet);
          return;
      }
      else 
      {
        /* Drop DA packet*/
        printf("Non-PING ICMP to Router. Packet will be dropped...\n");
      }
    } 

    /*receive a TCP/UDP packet, send ICMP port unreachable back*/

    else if(ip_header->ip_p == 0x06 || ip_header->ip_p == 0x11)
    {
        printf("TCP/UDP packet to Router...\n");

        size_t tulen = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t);
        uint8_t* send_packet = malloc(tulen);
        sr_ethernet_hdr_t* new_ether_header = (sr_ethernet_hdr_t*)send_packet;
        sr_ip_hdr_t* new_ip_header = (sr_ip_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t));
        sr_icmp_t3_hdr_t* new_icmp_header = (sr_icmp_t3_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

        /*write ethernet header*/
        struct sr_if* sending_interface = sr_get_interface(sr, interface);
        memcpy(new_ether_header->ether_dhost, eth_header->ether_shost, 6);
        memcpy(new_ether_header->ether_shost, sending_interface->addr, 6);
        new_ether_header->ether_type = htons(0x0800);

        /*write ip header*/
        new_ip_header->ip_hl = 5;
        new_ip_header->ip_v = 4;
        new_ip_header->ip_tos = ip_header->ip_tos;
        new_ip_header->ip_len = htons( sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t));
        new_ip_header->ip_id = ip_header->ip_id;
        new_ip_header->ip_off = htons(0x4000);
        new_ip_header->ip_ttl = 64;
        new_ip_header->ip_p = ip_protocol_icmp;
        new_ip_header->ip_sum = 0;
        new_ip_header->ip_src = sending_interface->ip;
        new_ip_header->ip_dst = ip_header->ip_src;
        new_ip_header->ip_sum = cksum(new_ip_header, sizeof(sr_ip_hdr_t));

        /*write icmp header*/
        new_icmp_header->icmp_type = 3;
        new_icmp_header->icmp_code = 3;
        new_icmp_header->icmp_sum = 0;
        new_icmp_header->next_mtu = htons(512);
        memcpy(new_icmp_header->data, (uint8_t *)ip_header, 28);
        /*memcpy(new_icmp_header->data + sizeof(sr_ip_hdr_t), send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), 8);*/
        new_icmp_header->icmp_sum = cksum(send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), sizeof(sr_icmp_t3_hdr_t));

        printf("Port Unreachable: Sending ICMP (3,3)...\n");
        /*send packet*/
        sr_send_packet(sr, send_packet, tulen, interface);
        free(send_packet);
        return;
    } 
    else
    {
      printf("Unknown IP protocol number to Router. Packet will be dropeed...\n");
    }
  } 


  else 
  {
     printf("IP Packet not meant for router...\n");
    /* Forward the Packet  */
    printf("Preparing to forward...\n");

    struct sr_rt* next_hop = NULL;
    struct sr_rt* table_iterator = sr->routing_table;
    while (table_iterator) 
    {
      if ((ip_header->ip_dst & (table_iterator->mask).s_addr) == ((table_iterator->dest).s_addr & (table_iterator->mask).s_addr)) 
        next_hop = table_iterator;
      table_iterator = table_iterator->next;
    }

    /* If no matching entry in Routing Table. Send Destination Net Unreachable */

    if (next_hop == NULL)
    {
        printf("Non existent route to destination IP...\n");

        size_t tulen = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t);
        uint8_t* send_packet = malloc(tulen);
        sr_ethernet_hdr_t* new_ether_header = (sr_ethernet_hdr_t*)send_packet;
        sr_ip_hdr_t* new_ip_header = (sr_ip_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t));
        sr_icmp_t3_hdr_t* new_icmp_header = (sr_icmp_t3_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

        /*write ethernet header*/
        struct sr_if* sending_interface = sr_get_interface(sr, interface);
        memcpy(new_ether_header->ether_dhost, eth_header->ether_shost, 6);
        memcpy(new_ether_header->ether_shost, sending_interface->addr, 6);
        new_ether_header->ether_type = htons(0x0800);

        /*write ip header*/
        new_ip_header->ip_hl = 5;
        new_ip_header->ip_v = 4;
        new_ip_header->ip_tos = ip_header->ip_tos;
        new_ip_header->ip_len = htons( sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t));
        new_ip_header->ip_id = ip_header->ip_id;
        new_ip_header->ip_off = 0;
        new_ip_header->ip_ttl = 64;
        new_ip_header->ip_p = ip_protocol_icmp;
        new_ip_header->ip_sum = 0;
        new_ip_header->ip_src = sending_interface->ip;
        new_ip_header->ip_dst = ip_header->ip_src;
        new_ip_header->ip_sum = cksum(new_ip_header, sizeof(sr_ip_hdr_t));

        /*write icmp header*/
        new_icmp_header->icmp_type = 3;
        new_icmp_header->icmp_code = 0;
        new_icmp_header->icmp_sum = 0;
        new_icmp_header->next_mtu = htons(512);
        memcpy(new_icmp_header->data, (uint8_t *)ip_header, 28);
        /*memcpy(new_icmp_header->data + sizeof(sr_ip_hdr_t), send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), 8);*/
        new_icmp_header->icmp_sum = cksum(send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), sizeof(sr_icmp_t3_hdr_t));

        printf("Net Unreachable: Sending ICMP (3,0)...\n");
        /*send packet*/
        sr_send_packet(sr, send_packet, tulen, interface);
        free(send_packet);
        return;
    }

    /* Continue Forwarding otherwise */
    ip_header->ip_ttl--;

    if (ip_header->ip_ttl == 0) 
    {
        printf("Timed out (TTL = 0). IP packet will be discarded MUAHAHAHAH! ...\n");

        size_t tulen = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t);
        uint8_t* send_packet = malloc(tulen);
        sr_ethernet_hdr_t* new_ether_header = (sr_ethernet_hdr_t*)send_packet;
        sr_ip_hdr_t* new_ip_header = (sr_ip_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t));
        sr_icmp_hdr_t* new_icmp_header = (sr_icmp_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

        /*write ethernet header*/
        struct sr_if* sending_interface = sr_get_interface(sr, interface);
        memcpy(new_ether_header->ether_dhost, eth_header->ether_shost, 6);
        memcpy(new_ether_header->ether_shost, sending_interface->addr, 6);
        new_ether_header->ether_type = htons(0x0800);

        /*write ip header*/
        new_ip_header->ip_hl = 5;
        new_ip_header->ip_v = 4;
        new_ip_header->ip_tos = ip_header->ip_tos;
        new_ip_header->ip_len = htons( sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t));
        new_ip_header->ip_id = ip_header->ip_id;
        new_ip_header->ip_off = 0;
        new_ip_header->ip_ttl = 64;
        new_ip_header->ip_p = ip_protocol_icmp;
        new_ip_header->ip_sum = 0;
        new_ip_header->ip_src = sending_interface->ip;
        new_ip_header->ip_dst = ip_header->ip_src;
        new_ip_header->ip_sum = cksum(new_ip_header, sizeof(sr_ip_hdr_t));

        /*write icmp header*/
        new_icmp_header->icmp_type = 11;
        new_icmp_header->icmp_code = 0;
        new_icmp_header->icmp_sum = 0;
        new_icmp_header->icmp_sum = cksum(send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), sizeof(sr_icmp_t3_hdr_t));

        printf("Time Exceeded: Sending ICMP (11,0)...\n");
        /*send packet*/
        sr_send_packet(sr, send_packet, tulen, interface);
        free(send_packet);
        return;      
    }

    ip_header->ip_sum = 0;
    ip_header->ip_sum = cksum((uint8_t*) ip_header, sizeof(sr_ip_hdr_t));

    struct sr_arpentry* entry = sr_arpcache_lookup(&(sr->cache), next_hop->gw.s_addr);
    if (entry) 
    {
      sr_ethernet_hdr_t* new_etheader = (sr_ethernet_hdr_t *)(packet);
      struct sr_if* interface = sr_get_interface(sr, next_hop->interface);
      memcpy(new_etheader->ether_dhost, entry->mac, 6);
      memcpy(new_etheader->ether_shost, interface->addr, 6);
      printf("Packet forwarded (Cache lookup successful)...\n");
      sr_send_packet(sr, packet, len, next_hop->interface);
      free(entry);
    }
    else 
    {
      printf("Forwarding Entry not found in Cache (Preparing ARP Request)...\n");
      struct sr_arpreq* req = sr_arpcache_queuereq(&(sr->cache), next_hop->gw.s_addr, packet, len, next_hop->interface);
      req->iface = next_hop->interface;
      handle_arpreq(sr, req);
    }
  }              
}
Beispiel #28
0
void sr_natHandleIP(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;
  uint8_t* ip_packet = packet+sizeof(sr_ethernet_hdr_t);
  sr_ip_hdr_t * ipHeader = (sr_ip_hdr_t *) (ip_packet);  

  uint16_t incm_cksum = ipHeader->ip_sum;
  ipHeader->ip_sum = 0;
  uint16_t currentChecksum = cksum(ip_packet,20);
  ipHeader->ip_sum = incm_cksum;
  uint8_t* icmp_packet;

  /* if the destination address is one of my interfaces */
  if (currentChecksum==incm_cksum && sr_get_interface_from_ip(sr,ntohl(ipHeader->ip_dst)) != NULL){
    /* check cache for ip->mac mapping for next hop */
    /*struct sr_arpentry *entry;
    entry = sr_arpcache_lookup(&sr->cache, ipHeader->ip_dst);
    struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, ipHeader->ip_dst);
*/
    /* found next hop. send packet */
    if (ipHeader->ip_ttl <= 1){   /* IP TTL died. send ICMP type 11, code 0 */
      icmp_packet = createICMP(11, 0, ip_packet,len-14);
      memcpy(ip_packet+20,icmp_packet,sizeof(sr_icmp_t3_hdr_t));
      ipHeader->ip_p = 1;
      ipHeader->ip_len = htons(20+8+(len-34<28?len-34:28));
      free(icmp_packet);      
    } else if(ipHeader->ip_p==6){  /* IP TCP */
      icmp_packet = createICMP(3,3,ip_packet,len-14);
      memcpy(ip_packet+20,icmp_packet,sizeof(sr_icmp_t3_hdr_t));
      
      ipHeader->ip_p = 1;
      ipHeader->ip_len = htons(20+8+(len-34<28?len-34:28));
      free(icmp_packet);
    }else if(ipHeader->ip_tos==0 && ipHeader->ip_p==1){ /* IP ping */
	    sr_icmp_hdr_t * icmp_header = (sr_icmp_hdr_t *) (packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
      incm_cksum = icmp_header->icmp_sum;
      icmp_header->icmp_sum = 0;
	    currentChecksum = cksum(icmp_header,len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t));
	    
      if(currentChecksum == incm_cksum && icmp_header->icmp_type == 8 && icmp_header->icmp_code == 0) {
	      icmp_header->icmp_type = 0;
        ipHeader->ip_sum = 0;
	      icmp_header->icmp_sum = cksum(icmp_header,len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t));
	    }
      else{
        printf("ICMP INVALID\n");
        printf("%d != %d OR %d != %d\n",currentChecksum,incm_cksum, icmp_header->icmp_type, 8);
      }
    } else {
      printf("IP Bad\n");
      ip_packet = NULL;
    }
  }
  else{
      printf("IP INVALID\n");
      ip_packet = NULL;
  }
  if(ip_packet){  /* send ICMP packet */
    ipHeader->ip_dst = ipHeader->ip_src;
    ipHeader->ip_src = iface->ip;
    ipHeader->ip_ttl = 64;
    ipHeader->ip_sum = 0;
    ipHeader->ip_sum = cksum(ip_packet,20);

    struct sr_arpentry *entry;
    entry = sr_arpcache_lookup(&sr->cache, ipHeader->ip_dst);
    struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, ipHeader->ip_dst);

    if (entry && rt) {    /* found next hop. send packet */
      iface = sr_get_interface(sr, rt->interface);
      set_addr(ethHeader, iface->addr, entry->mac);
      sr_send_packet(sr,packet,len,iface->name);
      free(entry);
      ip_packet = NULL;
    } else if (rt) { /* send an arp request to find out what the next hop should be */
      struct sr_arpreq *req;
      sr_arpcache_insert(&(sr->cache), ethHeader->ether_shost, ipHeader->ip_src);
      req = sr_arpcache_queuereq(&(sr->cache), ipHeader->ip_dst, packet, len, iface->name);
      /*handle_arpreq(sr, req);*/
      ip_packet = NULL;
    }
  }
}
Beispiel #29
0
/* This will foreward the given IP packet 
It checks for the Destination IP address and finds appropriate interface (LPM) and sends out! */
int forward_packet(struct sr_instance* sr,uint8_t* packet,int len,int packet_src_iface)
{
	uint32_t ip;
	sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)packet;
	/* Get Dest IP */
	ip = ip_header->ip_dst;

	/* This target variable stores the next hop */
	struct sr_rt* target = NULL;
	/* Perform LPM and get the target routing table entry which has the interface to pass and next hop IP */
	target = LPM(sr->routing_table,ip);
	/* Now the next hop ip (dest->gw)  is known and the interface also */
	if( target == NULL )
	{
		/* ICMP Destination Unreachable */
		/* There is no routing table entry for this destination IP address
		Now we have to send this packet encapsulated in ICMP packet with 3,0( Destiantion Network Unreachable )
		with src address of the incoming interface address and destination address as the source */
		
		/* We have IP packet, Now encapsulate in the ICMP */
		sr_icmp_hdr_t* ih = (sr_icmp_hdr_t*)(packet+sizeof(sr_ip_hdr_t));
		if( (ip_header->ip_p == ICMP_PROTOCOL) && (ih->icmp_type != 8) )
		{
			/* Dont send an ICMP for ICMP */
			return;
		}
		print_hdr_ip(packet);
		int size = sizeof(sr_ip_hdr_t)+sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8;

		uint8_t* complete_packet = (uint8_t*) malloc(sizeof(uint8_t)*size);

		uint8_t* icmp_start = make_ICMP(sr,packet,len,3,0);
		
		
		struct sr_if* src_if = sr_get_interface(sr,packet_src_iface);
		

		uint8_t* ip_start = make_IP_packet(*((uint8_t*)ip_header),(0x0000), htons(size), 0x0000, 0x0000,64,0x01, \
								src_if->ip,ip_header->ip_src);
		
		/* Foreward the ICMP packet with 3,0 to the src host */
		/* If the entry is again wrong, then dont send the ICMP for ICMP */
		
		memcpy(complete_packet,ip_start,sizeof(sr_ip_hdr_t));
		memcpy(complete_packet+sizeof(sr_ip_hdr_t),icmp_start,sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8);
		
		forward_packet(sr,complete_packet,size,packet_src_iface);
		return;
	}

	/* Now query for the Ethernet details */
	/* Get the router interface from where the packet should leave */
	struct sr_if* src_interface = sr_get_interface(sr,target->interface);
	/* Get the ARP entry for the next hop IP */
	struct sr_arpentry* entry = sr_arpcache_lookup(&sr->cache,(target->gw.s_addr));
	/* Now build the ethernet header */	
	
	uint8_t* complete_packet = (uint8_t*)malloc(sizeof(sr_ethernet_hdr_t)+len);

	memcpy(complete_packet+sizeof(sr_ethernet_hdr_t),packet,len);	
	
	/* Fill in all the details of the ethernet */

	sr_ethernet_hdr_t* eth_hdr = (sr_ethernet_hdr_t*)complete_packet;
	memcpy(eth_hdr->ether_shost,src_interface->addr,sizeof(uint8_t)*6);
	eth_hdr->ether_type = htons(IP_PROTOCOL);

	/* If entry is NULL, It means that there is no cache entry in ARP Table */
	/* If not NULL, Then use the entry for next hop MAC address */

	/*assert(entry!=NULL);*/
	
	if( entry == NULL )
	{
		/* Destination MAC is not known ! */
		memset(eth_hdr->ether_dhost,0,sizeof(uint8_t)*6);
		/* Cache doesnt have this entry, So request it */
		struct sr_arpreq* req = sr_arpcache_queuereq(&sr->cache,target->gw.s_addr,complete_packet,len+sizeof(sr_ethernet_hdr_t) \
								,target->interface);
		assert(req!=NULL);
		/* Free the packet, as we dont need it. It has been copied to other buffer in the request queue */
		handle_ARP_req(sr, &sr->cache,req);
	}
	else
	{
		/* Destination MAC is known, So use it! */	
		memcpy(eth_hdr->ether_dhost,entry->mac,sizeof(uint8_t)*6);
		/* Now send the packet to the target interface */
		sr_send_packet(sr,complete_packet,sizeof(sr_ethernet_hdr_t)+len,target->interface);
		free(entry);
	}
}
Beispiel #30
0
void sr_add_ethernet_send(struct sr_instance *sr,
        uint8_t *packet,
        unsigned int len,
        uint32_t dip,
        enum sr_ethertype type) 
{
    struct sr_rt *lpmatch;
    struct sr_if *r_iface;
    struct sr_ethernet_hdr sr_ether_pkt;
    struct sr_arp_hdr * arp_pkt;
    uint8_t *send_packet;
    unsigned int eth_pkt_len;
    struct sr_arpentry *arp_entry;

    lpmatch = longest_prefix_matching(sr, dip);
    r_iface = sr_get_interface(sr, lpmatch->interface);

    if (type == ethertype_arp) { 
      arp_pkt = (struct sr_arp_hdr *)packet;

      /* Broadcast request */
      if (arp_pkt->ar_op == htons(arp_op_request)){
        memset(sr_ether_pkt.ether_dhost, 255, ETHER_ADDR_LEN);
      }
                   
      /* Build reply packet */
      else if (arp_pkt->ar_op == htons(arp_op_reply))
        memcpy(sr_ether_pkt.ether_dhost, arp_pkt->ar_tha, ETHER_ADDR_LEN);
        memcpy(sr_ether_pkt.ether_shost, r_iface->addr, ETHER_ADDR_LEN);
              sr_ether_pkt.ether_type = htons(type);

        /* Copy the packet into the sender buf */
        eth_pkt_len = sizeof(struct sr_arp_hdr) + sizeof(struct sr_ethernet_hdr);
        send_packet = malloc(eth_pkt_len);
        memcpy(send_packet, &sr_ether_pkt, sizeof(struct sr_ethernet_hdr));
        memcpy(send_packet + sizeof(struct sr_ethernet_hdr), 
              packet, sizeof(struct sr_arp_hdr));

        /* Send the reply*/
        sr_send_packet(sr, send_packet, eth_pkt_len, r_iface->name);
        free(send_packet);

    } else {
        arp_entry = sr_arpcache_lookup(&sr->cache, dip);

        /* Set the ethernet header */
        memcpy(sr_ether_pkt.ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
        memcpy(sr_ether_pkt.ether_shost, r_iface->addr, ETHER_ADDR_LEN);
              sr_ether_pkt.ether_type = htons(type);

        /* Copy the packet into the sender buf */
        eth_pkt_len = len + sizeof(struct sr_ethernet_hdr);
        send_packet = malloc(eth_pkt_len);
        memcpy(send_packet, &sr_ether_pkt, sizeof(struct sr_ethernet_hdr));
        memcpy(send_packet + sizeof(struct sr_ethernet_hdr), packet, len);

        /* Send the reply*/
        sr_send_packet(sr, send_packet, eth_pkt_len, r_iface->name);
        free(send_packet);
    }

}