Beispiel #1
0
/*Broadcasts an arp request because the destination IP isn't in our cache*/
void broadcast_arp_req(struct sr_instance* sr, uint32_t nexthopIP, sr_ethernet_hdr_t* packet_to_forward, unsigned int len, struct sr_rt * routing_node, struct sr_if* nexthopInterface){
  
  /*Insert the request into the arpcache with pre-made sr_arpcache_queuereq: cache pointer is returned*/
  struct sr_arpreq *cache_req_ptr = sr_arpcache_queuereq(&(sr->cache), nexthopIP, (uint8_t*) packet_to_forward, len, routing_node->interface);
  
  handle_arpreq(sr, cache_req_ptr);
}
/*
 * 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
/* 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);
   }
}
Beispiel #4
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);
  }
}
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 #6
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 #7
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 #8
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 #9
0
/* Handle IP packet */
void sr_handle_ippacket(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */) 
{
    assert(sr);
    assert(packet);
    assert(interface);

    /* Get ethernet header */
    sr_ethernet_hdr_t *eth_hdr = get_eth_hdr(packet);
	if (eth_hdr == NULL) {
		printf("ethernet header NULL!!!\n");
		return;
	}

    /* Get ip header */
    sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet);
	if (ip_hdr == NULL) {
		printf("ip header NULL!!!\n");
		return;
	}

	/* Before doing ttl decrement, check checksum */
	uint16_t old_ip_sum = ip_hdr->ip_sum;
	ip_hdr->ip_sum = 0;

	if (!verify_checksum(ip_hdr, sizeof(sr_ip_hdr_t), old_ip_sum)) {
		fprintf(stderr, "CHECKSUM FAILED!!\n");
		return;
	}
	ip_hdr->ip_sum = old_ip_sum;

    /* Get the arp cache */
    struct sr_arpcache *sr_arp_cache = &sr->cache;

    /* Get the destination interface on the router */
	struct sr_if *sr_iface = sr_get_router_if(sr, ip_hdr->ip_dst);
	/* Get the connected interface on the router */
	struct sr_if *sr_con_if = sr_get_interface(sr, interface);

    /* Check the time exceeded condition, if ttl==0, we need to form icmp 11 and send back */
    if (ip_hdr->ip_ttl <= 1) {
        /* time exceeded message and icmp type 11 */
        printf("TTL time exceeded\n");
        int packet_len = ICMP_T3_PACKET_LEN;
        uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

        create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_con_if);
        /* Create ip header */
        create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_con_if);

        /* Send icmp type 11 time exceeded */
        /* icmp_t3 type=11, code=0 */
        create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 11, 0);

        /* Send icmp type 11 packet */
		struct sr_arpentry *arp_entry = sr_arpcache_lookup(sr_arp_cache, ip_hdr->ip_src);
		if (arp_entry != NULL) {
			sr_send_packet(sr, icmp_t3_hdr, packet_len, sr_con_if->name);
			free(icmp_t3_hdr);
		} else {
			struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, sr_con_if->name);
			handle_arpreq(arp_req, sr);
		}
        return;
    }

    /* Get the protocol from IP */
    uint8_t ip_p = ip_hdr->ip_p;

    /* If the packet is sent to self, meaning the ip is sent to the router */
    if (sr_iface) {
        /* Check the protocol if it is icmp */
        if (ip_p == ip_protocol_icmp) {
            /* Get the icmp header */
            sr_icmp_hdr_t *icmp_hdr = get_icmp_hdr(packet);

            /* Check if it is ICMP echo request */
            /* icmp_echo_req = 8 */
            if (icmp_hdr->icmp_type == 8) {
				/* Do LPM on the routing table */
        		/* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
        		struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src);

				if (longest_pref_match) {
					/* check ARP cache */
					struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr);
					struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);

					/* If hit, meaning the arp mapping has been cached */
					if (arp_entry != NULL) {
						/* We need to send the icmp echo reply */
				        /* Modify ethernet header */
						memcpy(eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
						memcpy(eth_hdr->ether_shost, out_iface->addr, ETHER_ADDR_LEN);

				        /* Modify ip header */
						ip_hdr->ip_off = htons(0b0100000000000000);        /* fragment offset field */
						ip_hdr->ip_ttl = 100;                    			/* time to live */
						uint32_t temp = ip_hdr->ip_src;
						ip_hdr->ip_src = ip_hdr->ip_dst;        /* source address */
						ip_hdr->ip_dst = temp;        			/* dest address */
						ip_hdr->ip_sum = 0;
						ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));			/* checksum */

				        /* Modify icmp header */
						unsigned int icmp_whole_size = len - IP_PACKET_LEN;
						icmp_hdr->icmp_type = 0;
						icmp_hdr->icmp_code = 0;
						icmp_hdr->icmp_sum = 0;
						icmp_hdr->icmp_sum = cksum(icmp_hdr, icmp_whole_size);

				        /* Send icmp echo reply */
				        sr_send_packet(sr, packet, len, out_iface->name);
				        return;
					}
					/* Else no hit, we cache it to the queue and send arp request */ 
					else {
						/* Add reply to the ARP queue */
						/* We need to send the icmp echo reply */
				        /* Modify ethernet header */
						memcpy(eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
						memcpy(eth_hdr->ether_shost, sr_con_if->addr, ETHER_ADDR_LEN);

				        /* Modify ip header */
						ip_hdr->ip_off = htons(0b0100000000000000);        /* fragment offset field */
						ip_hdr->ip_ttl = 100;                    			/* time to live */
						uint32_t temp = ip_hdr->ip_src;
						ip_hdr->ip_src = ip_hdr->ip_dst;        /* source address */
						ip_hdr->ip_dst = temp;        			/* dest address */
						ip_hdr->ip_sum = 0;
						ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));			/* checksum */

				        /* Modify icmp header */
						unsigned int icmp_whole_size = len - IP_PACKET_LEN;
						icmp_hdr->icmp_type = 0;
						icmp_hdr->icmp_code = 0;
						icmp_hdr->icmp_sum = 0;
						icmp_hdr->icmp_sum = cksum(icmp_hdr, icmp_whole_size);
						struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_dst, packet, len, out_iface->name);
						/* Send ARP request, which is a broadcast */
						handle_arpreq(arp_req, sr);
						return;
					}
				} else {
					fprintf(stderr, "Longest prefix doesnt match!!\n");
                	return;
				}

            } else {
                fprintf(stderr, "Not an ICMP request!\n");
                return;
            }
        }
        /* Else it is TCP/UDP request */
        else {
            fprintf(stderr, "*** -> Received TCP/UDP!\n");

			/* Do LPM on the routing table */
    		/* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
    		struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src);

			if (longest_pref_match) {
				/* check ARP cache */
				struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr);
				struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);
				
				/* Send ICMP port unreachable */
				if (arp_entry != NULL) {

					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_iface);
					/*memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
					memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN);*/

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_iface);
					/*sr_ip_hdr_t *icmp_t3_hdr_ip = (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN);
					icmp_t3_hdr_ip->ip_src = ip_hdr->ip_dst;
					icmp_t3_hdr_ip->ip_sum = 0;
					icmp_t3_hdr_ip->ip_sum = cksum(icmp_t3_hdr_ip, sizeof(sr_ip_hdr_t));*/
					

					/* Should update source address to be interface address */

				    /* Send icmp type 3 port unreachable */
				    /* Create icmp port unreachable packet */
				    /* icmp_t3 type=3, code=3 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 3);

				    /* Send icmp type 3 packet */
				    sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name);

				    free(icmp_t3_hdr);
				    return;
				} else {
				
					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_iface);
					/*memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
					memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN);*/

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_iface);
					/*sr_ip_hdr_t *icmp_t3_hdr_ip = (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN);
					icmp_t3_hdr_ip->ip_src = ip_hdr->ip_dst;
					icmp_t3_hdr_ip->ip_sum = 0;
					icmp_t3_hdr_ip->ip_sum = cksum(icmp_t3_hdr_ip, sizeof(sr_ip_hdr_t));*/

				    /* Send icmp type 3 port unreachable */
				    /* Create icmp port unreachable packet */
				    /* icmp_t3 type=3, code=3 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 3);

					struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, out_iface->name);
					/* Send ARP request, which is a broadcast */
					handle_arpreq(arp_req, sr);
					return;
				}
			} else {
				fprintf(stderr, "Longest prefix doesnt match!!\n");
                return;
			}            
            
        }
    }
    /* Else Check the routing table, perfomr LPM */
    else {
        /* Sanity-check the packet */
        /* minimum length */
        if (!check_min_length(len, IP_PACKET_LEN)) {
            fprintf(stderr, "The packet length is not enough:(\n");
            return;
        }
		
        /* Do LPM on the routing table */
        /* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
        struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_dst);
        if (longest_pref_match) {
            /* check ARP cache */
			struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);

            struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr); /* ip_hdr->ip_dst */
         
			/* If hit, meaning the arp_entry is found */
            if (arp_entry) {

				/*fprintf(stderr, "************ found the lpm router entry ***********\n");*/
                /* Send frame to next hop */
                /* update the eth_hdr source and destination ethernet address */
                /* use next_hop_ip->mac mapping in the entry to send the packet */

                ip_hdr->ip_ttl--;

                /* recompute the packet checksum over the modified header */
                ip_hdr->ip_sum = 0;
                uint16_t new_ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));
                ip_hdr->ip_sum = new_ip_sum;

                memcpy(eth_hdr->ether_shost, out_iface->addr, ETHER_ADDR_LEN);
                memcpy(eth_hdr->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
                sr_send_packet(sr, packet, len, out_iface->name);
				print_hdr_ip((uint8_t*)ip_hdr);
                /* free the entry */
                free(arp_entry);
                return;
            } else/* No Hit */ {
                /* send an ARP request for the next-hop IP */
                /* add the packet to the queue of packets waiting on this ARP request */
                /* Add request to ARP queue*/

                ip_hdr->ip_ttl--;

                /* recompute the packet checksum over the modified header */
                ip_hdr->ip_sum = 0;
                uint16_t new_ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));
                ip_hdr->ip_sum = new_ip_sum;

                struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_dst, packet, len, out_iface->name);
                /* send ARP request, this is a broadcast */
                handle_arpreq(arp_req, sr);
                return;
            }
        } else /* if not matched */ {
            /* Send ICMP net unreachable */
			printf("--------------- Net Unreachable ---------------\n");

			/* Do LPM on the routing table */
    		/* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
    		struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src);

			if (longest_pref_match) {
				/* check ARP cache */
				struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr);
				struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);

				if (arp_entry) {
					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, out_iface);

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), out_iface);

				    /* Create icmp net unreachable */
				    /* icmp_t3 type=3, code=0 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 0);

				    /* Send icmp type 3 packet */
				    sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name);

				    free(icmp_t3_hdr);
				    return;
				} else {

					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, out_iface);

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), out_iface);
					/*	((sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN))->ip_ttl += 1; */

				    /* Send icmp type 3 net unreachable */
				    /* Create icmp net unreachable packet */
				    /* icmp_t3 type=3, code=0 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 0);

					struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, out_iface->name);
					/* Send ARP request, which is a broadcast */
					handle_arpreq(arp_req, sr);
					return;
				}
			} else {
				fprintf(stderr, "Longest prefix doesnt match!!\n");
                return;
			}
        }
    }

    return;
}
Beispiel #10
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 #11
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;
    }
  }
}
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 #13
0
void sr_handleip(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
	sr_ip_hdr_t *ip_hdr = 0;
	struct sr_if *iface = 0;
	sr_icmp_hdr_t *icmp_hdr = 0;
	uint8_t *reply_packet = 0;
	struct sr_rt *rt = 0;
	uint32_t nexthop_ip, longest_mask = 0;
	struct sr_arpentry *arp_entry = 0;
	struct sr_arpreq *arp_req = 0;
	sr_ethernet_hdr_t *ether_hdr = 0;
	int matched = 0;
	
	/* check if header has the correct size */
	if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)) {
		fprintf(stderr, "Error: invalid IP header length\n");
		return;
	}
	
	ip_hdr = (sr_ip_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
	
	/* perform ip header checksum */
	if (cksum(ip_hdr, ip_hdr->ip_hl) != 0xffff) {
		fprintf(stderr, "Error: IP checksum failed\n");
		return;
	}
	
	/* grab the receiving interface */
	if ((iface = sr_get_interface(sr, interface)) == 0) {
		fprintf(stderr, "Error: interface does not exist (sr_handleip)\n");
		return;
	}
	
	/* if the packet is destined to our ip */
	if (ip_hdr->ip_dst == htonl(iface->ip)) {
	
		/* if it is an ICMP */
		if (ip_hdr->ip_p == htons(ip_protocol_icmp)) {
			
			/* check if header has the correct size */
			if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t)) {
				fprintf(stderr, "Error: invalid ICMP header length\n");
				return;
			}
			
			icmp_hdr = (sr_icmp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
			
			/* if it is an ICMP echo request, send an ICMP echo reply */
			if (icmp_hdr->icmp_type == htons(8) && icmp_hdr->icmp_code == htons(0)) {
				
				/* perform ICMP header checksum */
				if (cksum(icmp_hdr, sizeof(icmp_hdr)) != 0xffff) {
					fprintf(stderr, "Error: ICMP checksum failed\n");
					return;
				}
				
				/* generate an echo reply packet */
				if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 0, 0)) == 0) {
					fprintf(stderr, "Error: failed to generate ICMP echo reply packet\n");
					return;
				}
				
				/* send an ICMP echo reply */
				if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
					fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
				}
				
				free(reply_packet);				
			}
		}
		/* if it contains a TCP or UDP payload */
		else {
		
			/* generate Destination net unreachable (type 3, code 0) reply packet */
			if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 3, 3)) == 0) {
				fprintf(stderr, "Error: failed to generate ICMP packet\n");
				return;
			}
			
			/* send an ICMP */
			if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
				fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
			}
			
			free(reply_packet);		
		}
	}
	/* packet not for us, forward it */
	else {
		
		/* if TTL reaches 0 */
		if (ip_hdr->ip_ttl <= htons(1)) {
		
			/* generate Time exceeded (type 11, code 0) reply packet */
			if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 11, 0)) == 0) {
				fprintf(stderr, "Error: failed to generate ICMP packet\n");
				return;
			}
			
			/* send an ICMP */
			if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
				fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
			}
			
			free(reply_packet);
		}
		/* if packet has enough TTL */
		else {
			
			/* decrement the TTL by 1 */
			ip_hdr->ip_ttl --;
			
			/* recompute the packet checksum */
			ip_hdr->ip_sum = htons(0);
			ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));
			
			/* Find entry in the routing table with the longest prefix match */
			rt = sr->routing_table;
			while (rt != NULL) {
				
				/* update the gateway ip and the longest mask so far */
				if ((rt->dest.s_addr & rt->mask.s_addr) == (ntohl(ip_hdr->ip_dst) & rt->mask.s_addr) &&
					rt->mask.s_addr > longest_mask) {
					nexthop_ip = rt->gw.s_addr;
					longest_mask = rt->mask.s_addr;
					matched = 1;
				}
				
				rt = rt->next;
			}
			
			/* if a matching routing table entry was NOT found */
			if (matched == 0) {
				
				/* generate Destination net unreachable (type 3, code 0) reply packet */
				if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 3, 0)) == 0) {
					fprintf(stderr, "Error: failed to generate ICMP packet\n");
					return;
				}
				
				/* send an ICMP */
				if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
					fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
				}
				
				free(reply_packet);
			}
			/* if a matching routing table entry was found */
			else {
				/* if the next hop is 0.0.0.0 */
				if(nexthop_ip == 0) {
					nexthop_ip = ip_hdr->ip_dst;
				}
				
				/* set the source MAC of ethernet header */
				ether_hdr = (sr_ethernet_hdr_t*)packet;
				memcpy(ether_hdr->ether_shost, iface->addr, ETHER_ADDR_LEN);
				
				/* if the next-hop IP CANNOT be found in ARP cache */
				if ((arp_entry = sr_arpcache_lookup(&(sr->cache), htonl(nexthop_ip))) == NULL) {
					
					/* send an ARP request */
					arp_req = sr_arpcache_queuereq(&(sr->cache), nexthop_ip, packet, len, iface);
					handle_arpreq(sr, arp_req);
				}
				/* if the next-hop IP can be found in ARP cache */
				else {
					
					/* set the destination MAC of ethernet header */
					memcpy(ether_hdr->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
					
					/* send the packet */
					if (sr_send_packet(sr, packet, sizeof(packet), (const char*)interface) == -1) {
						fprintf(stderr, "Error: sending packet failed (sr_handlearp)\n");
					}
					
					free(arp_entry);
				}
			}
		}
	}
}
Beispiel #14
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 #15
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 #16
0
void sr_try_send_ip_packet(struct sr_instance* sr,
        uint32_t ip_dst, /* network order */
        uint32_t ip_src, /* optional value - 0 to deactivate */
        sr_constructed_packet_t *payload,
        sr_ip_hdr_t *ip_hdr)
{
    /* Check for longest match in routing table */

    struct sr_rt* rt_dst = sr_rt_longest_match(sr,ip_dst);

    /* If we found any matches, forward the packet */

    if (rt_dst != 0) {

        char* temp_ip = ip_to_str(rt_dst->gw.s_addr);
        printf("Forwarding IP packet to %s\n",temp_ip);
        free(temp_ip);

        /* Grab the interface we'll be sending the packet out through */

        struct sr_if* gw_if = sr_get_interface(sr, rt_dst->interface);

        /* Lookups in the ARP cache keep IP addresses in network byte order, so we need to convert. */

        struct sr_arpentry *entry = sr_arpcache_lookup(&(sr->cache), rt_dst->gw.s_addr);

        /* Check whether or not we're overriding the source of the packet */

        temp_ip = ip_to_str(ip_src);
        /*printf("Overriding src IP: %s\n",temp_ip);*/
        free(temp_ip);

        if (ip_src == 0) {
            ip_src = gw_if->ip;
        }

        if (entry) {

            /* puts("ARP cache entry exists."); */

            /* use next_hop_ip->mac mapping in entry to send the packet */
            
            sr_constructed_packet_t *ip_packet = sr_build_eth_packet(
                gw_if->addr, /* src */
                entry->mac, /* dst */
                ethertype_ip,

                sr_build_ip_packet(
                    ip_src, /* src */
                    ip_dst, /* dst */
                    ip_protocol_icmp,

                    payload
                )
            );

            /* If they pass in an ip header, lets copy it over */

            if (ip_hdr != NULL) {
                /* puts("Copying passed in IP header\n"); */

                /* Now let's copy it over */

                sr_ip_hdr_t* ip_hdr_buf = (sr_ip_hdr_t*)(ip_packet->buf + sizeof(sr_ethernet_hdr_t));
                memcpy(ip_hdr_buf, ip_hdr, sizeof(sr_ip_hdr_t));
            }

            /* Send out the packet we just built */

            sr_send_packet(sr, (uint8_t*)ip_packet->buf, ip_packet->len, rt_dst->interface);

            /* Cleanup */

            free(entry);
            sr_free_packet(ip_packet);
        }
        else {

            /* puts("ARP cache entry doesn't exist. Queuing the packet contents."); */

            /* We don't free the payload, because it gets put directly into the queue */

            struct sr_arpreq *req = sr_arpcache_queuereq(&sr->cache, rt_dst->gw.s_addr, ip_dst, ip_src, payload, ip_hdr, rt_dst->interface);
            sr_handle_arpreq(sr,req);
        }

        return;
    }

    /* If we get here, it means that it's not for us, and there's noone to forward it to.
     * Thus, it's time for some ICMP, if we were trying to send an IP request.
     */

    /* puts("Nothing in the forwarding table for the destination IP."); */

    /* If ip_hdr == NULL, then we were sending this packet out, and there's no reason to
     * respond to ourselves with an ICMP host unreachable error.
     */

    if (ip_hdr != NULL) {
        /* puts("Was an IP packet (as expected). Checking if its an ICMP error, which we'll drop."); */

        /* Free the payload we won't be using */

        sr_free_packet(payload);

        if (ip_hdr->ip_p == ip_protocol_icmp) {
            sr_icmp_hdr_t* icmp_hdr = (sr_icmp_hdr_t*)(((uint8_t*)ip_hdr)+sizeof(sr_ip_hdr_t));
            if (icmp_hdr->icmp_type == 3) { /* Don't foward anything with type 3 */
                /* puts("Was an ICMP error. Dropping."); */
                return;
            }
        }
        else {
            /* puts("Wasn't ICMP."); */
        }

        /* puts("Wasn't an ICMP error."); */

        /* Recurse to send this packet back */

        sr_try_send_ip_packet(sr, ip_hdr->ip_src, ip_hdr->ip_dst,
            sr_build_icmp_t3_packet(
                ICMP_TYPE_NET_UNREACHABLE,
                ICMP_CODE_NET_UNREACHABLE,

                /* reconstruct the original IP packet */

                (uint8_t*)ip_hdr
            ),
            NULL
        );
    }
}
Beispiel #17
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 #18
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);
          }
}
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
/*
 * 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 #21
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 #22
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 #23
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 #24
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 #25
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 */