void sr_forward_ip(struct sr_instance *sr, uint8_t *packet, unsigned int len)
{
    assert(sr);
    assert(packet);
    
    sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
    
   
    ip_hdr->ip_ttl--;
    
    if (ip_hdr->ip_ttl == 0) {
        sr_send_icmp(sr, packet, len, 11, 0);
        return;
    }
    

    ip_hdr->ip_sum = 0;
    ip_hdr->ip_sum = cksum(ip_hdr, ip_hdr->ip_hl * 4);
    
    
    struct sr_rt *rt = sr_longest_prefix_match_lookup(sr, ip_hdr->ip_dst);
    
    if (!rt) {
        sr_send_icmp(sr, packet, len, 3, 0);
        return;
    }
    
    
    struct sr_if *oiface = sr_get_interface(sr, rt->interface);
    
    sr_lookup_and_send(sr, packet, len, oiface, rt->gw.s_addr);
} 
Exemple #2
0
void sr_handleicmp(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        struct sr_if* iface/* lent */) {

  if (len < ( sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t) )) {
    fprintf(stderr, "Failed to process ICMP header, insufficient length\n");
    return;
  }

  sr_icmp_hdr_t *icmp_hdr = (sr_icmp_hdr_t *)(
    packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

  /* Sanity Check */
  if (cksum(icmp_hdr, packet + len - (uint8_t*)icmp_hdr) != CKSUM_CORRECT) {
    fprintf(stderr, "sr_handleicmp: Corrupted ICMP Header, dropping packet.\n");
    return;
  }

  /* Ignore anything other than ICMP Echo Request */
  if (icmp_hdr->icmp_type != 8) {
    fprintf(stderr, "sr_handleicmp: ICMP Reply dropped.\n");
    return;
  }

  sr_send_icmp(sr, packet, len, iface, ICMP_TYPE_ECHO_REPLY, 0);
}
Exemple #3
0
/*---------------------------------------------------------------------
 * Method: forward_ip_pkt(struct sr_instance* sr, sr_ip_hdr *ip_hdr)
 * Scope:  Internal
 *
 * Forwards an IP packet to its next hop.
 *
 *---------------------------------------------------------------------*/
void forward_ip_pkt(struct sr_instance* sr, struct sr_ip_hdr *ip_hdr)
{
	uint8_t *fwd_ip_pkt;
	unsigned int len;

	/* Update the ip header ttl. */
	ip_hdr->ip_ttl--;
	
	/* If the ttl is equal to 0, send an ICMP Time exceeded response and return. */
	len = ip_len(ip_hdr);
	if (ip_hdr->ip_ttl == 0) {
		sr_send_icmp(sr, (uint8_t *)ip_hdr, len, ICMP_TIME_EXCEEDED_TYPE, 0);
		return;
	}
	
	/* Update the checksum. */
	ip_hdr->ip_sum = 0;
	ip_hdr->ip_sum = cksum(ip_hdr, ip_ihl(ip_hdr));
	
	/* Make a copy, encapsulate and send it on. */
	fwd_ip_pkt = malloc(len);
	memcpy(fwd_ip_pkt, ip_hdr, len);
	sr_encap_and_send_pkt(sr, fwd_ip_pkt, len, ip_hdr->ip_dst, 1, ethertype_ip);
	free(fwd_ip_pkt);
}
Exemple #4
0
/*---------------------------------------------------------------------
 * Method: process_ip(struct sr_instance* sr,
 *      			    		uint8_t * packet,
 *       							unsigned int len,
 *      			   			char* interface)
 * Scope:  Internal
 *
 * Processes a received IP packet. Takes in a raw ethernet packet.
 *
 *---------------------------------------------------------------------*/
void process_ip(struct sr_instance* sr,
       			    uint8_t * packet,
        				unsigned int len,
       			    char* interface)
{
	struct sr_ip_hdr *ip_hdr;

	/* Return if it is not a valid ip packet */
	if (!valid_ip(packet, len))
		return;
	
	/* Is it destined for me?! */
	ip_hdr = ip_header(packet);
	if (sr_interface_ip_match(sr, ip_hdr->ip_dst)) {
	
		/* Process ICMP. */
		if (ip_hdr->ip_p == ip_protocol_icmp) {
			process_icmp(sr, ip_hdr);
		
		/* If it's TCP/UDP, send ICMP port unreachable. */
		} else {
			sr_send_icmp(sr, 
								   (uint8_t *)ip_hdr, 
								   ip_len(ip_hdr), 
								   ICMP_UNREACHABLE_TYPE, 
								   ICMP_PORT_CODE);
		}
	
	/* Forward it. */
	} else {
		forward_ip_pkt(sr, ip_hdr);
	}
}
void sr_handle_icmp(struct sr_instance *sr, uint8_t *packet, unsigned int len)
{
    assert(sr);
    assert(packet);
    
    sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
    
    
    if (len < sizeof(sr_ethernet_hdr_t) + (ip_hdr->ip_hl * 4) + sizeof(sr_icmp_hdr_t)) {
        fprintf(stderr, "Failed to process ICMP header, insufficient length\n");
        return;
    }
    
    sr_icmp_hdr_t *icmp_hdr = (sr_icmp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t) + (ip_hdr->ip_hl * 4));

    uint16_t received_cksum = icmp_hdr->icmp_sum;
    icmp_hdr->icmp_sum = 0;
    
    uint16_t computed_cksum = cksum(icmp_hdr, ntohs(ip_hdr->ip_len) - (ip_hdr->ip_hl * 4));
    icmp_hdr->icmp_sum = received_cksum;
    
    if (received_cksum != computed_cksum) {
        fprintf(stderr, "Failed to process ICMP header, incorrect checksum\n");
        return;
    }
    
    if (icmp_hdr->icmp_type == 8 && icmp_hdr->icmp_code == 0) {
        sr_send_icmp(sr, packet, len, 0, 0);
    }
} 
Exemple #6
0
void sr_handleincoming(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        struct sr_if* iface/* lent */) {

  /* Reply everything with 0x3 = Port unreachable */
  sr_send_icmp(sr, packet, len, iface, 
    ICMP_TYPE_UNREACHABLE, ICMP_UNREACHABLE_PORT);
}
Exemple #7
0
/*---------------------------------------------------------------------
 * Method: process_icmp(struct sr_instance* sr, sr_ip_hdr *ip_hdr)
 * Scope:  Internal
 *
 * This function processes an ICMP packet that was destined for the 
 * router.
 *
 *---------------------------------------------------------------------*/
void process_icmp(struct sr_instance* sr, struct sr_ip_hdr *ip_hdr)
{
	/* Validate icmp. Drop if it not an echo request or bad checksum. */
	if (!valid_icmp(ip_hdr))
		return;
	
	/* Send icmp echo reply. */
	sr_send_icmp(sr, (uint8_t *)ip_hdr, ip_len(ip_hdr), ICMP_ECHO_REPLY_CODE, 0);
}
void sr_handle_ip(struct sr_instance *sr, uint8_t *packet, unsigned int len, struct sr_if *iface)
{
    assert(sr);
    assert(packet);
    assert(iface);
    
    
    if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)) {
        fprintf(stderr, "Failed to process IP header, insufficient length\n");
        return;
    }
    
    sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
    
    
    if (len < sizeof(sr_ethernet_hdr_t) + (ip_hdr->ip_hl * 4)) {
        fprintf(stderr, "Failed to process IP header, insufficient length\n");
        return;
    }
    
    /* verify checksum */
    uint16_t received_cksum = ip_hdr->ip_sum;
    ip_hdr->ip_sum = 0;
    
    uint16_t computed_cksum = cksum(ip_hdr, ip_hdr->ip_hl * 4);
    ip_hdr->ip_sum = received_cksum;
    
    if (received_cksum != computed_cksum) {
        fprintf(stderr, "Failed to process IP header, incorrect checksum\n");
        return;
    }
     
    struct sr_if *diface = sr_get_interface_from_ip(sr, ip_hdr->ip_dst);
    
    if (!diface) {
        sr_forward_ip(sr, packet, len);
    } else {
        if (ip_hdr->ip_p == ip_protocol_icmp) {
            sr_handle_icmp(sr, packet, len);
        } else if (ip_hdr->ip_p == 0x0006 || ip_hdr->ip_p == 0x0011) {
            sr_send_icmp(sr, packet, len, 3, 3);
        }
    }
}
Exemple #9
0
void sr_forwardpkt(struct sr_instance* sr,
        uint8_t * pkt/* lent */,
        unsigned int len,
        struct sr_if* iface/* lent */) {

  assert(sr);
  assert(pkt);
  assert(iface);

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

  /* Check TTL */
  if (iphdr->ip_ttl <= 1) {
    /* TTL Exceeded */
    fprintf(stderr, "sr_forwardpkt: TTL Exceeded!\n");
    sr_send_icmp(sr, pkt, len, iface, ICMP_TYPE_TTLEXCEED, 0);
    /* ICMP Type 11 0x0: Time exceeded */

    return;
  }


  /* Make a copy */
  uint8_t *outpkt = malloc(len);
  memcpy(outpkt, pkt, len);

  /* Decrement TTL */
  iphdr = (sr_ip_hdr_t *)(outpkt + sizeof(sr_ethernet_hdr_t));
  --iphdr->ip_ttl;
  /* Recalculate checksum */
  iphdr->ip_sum = 0x0;
  iphdr->ip_sum = cksum((void*)iphdr, sizeof(sr_ip_hdr_t));

  sr_send_inetpkt(sr, outpkt, len, iface, 0);

  free(outpkt);
}
void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req)
{
    assert(sr);
    assert(req);
    
    if (difftime(time(NULL), req->sent) >= 1.0) {
        if (req->times_sent >= 5) {
            struct sr_packet *pkt = NULL;
            sr_ethernet_hdr_t *eth_hdr = NULL;
            struct sr_if *iface = NULL;
            
            pkt = req->packets;
            
            while (pkt) {
                eth_hdr = (sr_ethernet_hdr_t *)(pkt->buf);
                iface = sr_get_interface_from_addr(sr, eth_hdr->ether_dhost);
                
                /* do not send an ICMP message for an ICMP message */
                if (iface) {
                    sr_send_icmp(sr, pkt->buf, pkt->len, 3, 1);
                }
                
                pkt = pkt->next;
            }
            
            sr_arpreq_destroy(&(sr->cache), req);
        } else {
            struct sr_if *oiface = sr_get_interface(sr, req->packets->iface);
            
            sr_send_arp_request(sr, oiface, req->ip);
            
            req->sent = time(NULL);
            req->times_sent++;
        }
    }
} /* -- sr_handle_arpreq -- */
Exemple #11
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 -- */
Exemple #12
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);
}
Exemple #13
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);
	}
}