Esempio n. 1
0
void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req){
    /*Debug("\nsr_handle_arpreq called\n");*/
    time_t     now;
    now = time(NULL);
    
    struct sr_arpcache *cache = &(sr->cache);
    /*if the arp_request has never been sent before or if the last time the 
    arp_request was sent was more than 1 second ago*/

    if ((req->times_sent == 0)||(difftime(now, req->sent)> 1.0)){
        /*Debug("\nARP request not previously sent or have not been sent within the last second\n");*/
        if (req->times_sent >= 5)
		{
            /*Debug("\nARP request was sent 5 times previously; destroy ARP request\n");*/
            /*loop through all of the IP packets waiting for the request,
            call function to send ICMP msg -> host_unreachable*/
            struct sr_packet *packet;
            for(packet = req->packets; packet != NULL; packet = packet->next)
			{
				/*这里的interface是outgoing interface,有问题,send_icmp_message要的是in_interface*/
				send_icmp_message(sr, packet->buf, sizeof(struct sr_packet), sr_get_interface(sr, req->packets->iface), ICMP_DESTINATION_UNREACHABLE_TYPE, ICMP_HOST_UNREACHABLE_CODE);
            }
            sr_arpreq_destroy(cache, req);
        }
        else
		{
            /*Debug("\nSending ARP request\n");*/
			/*这里的interface是outgoing interface,有问题,send_icmp_message要的是in_interface*/
			printf("interface: %s", req->packets->iface);
			send_arp_request(sr, sr_get_interface(sr, req->packets->iface), req->ip);
			req->sent = now;
            req->times_sent++;
		}
    }
}
Esempio n. 2
0
void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) {
	time_t now = time(NULL);
	if (difftime(now, req->sent) >= 0.9) {
		if (req->times_sent >= 5) {
			struct sr_packet *pkt_pending = req->packets;
			struct sr_if *interface = sr_get_interface(sr, pkt_pending->iface);
			while (pkt_pending) {
				icmp_handler(sr, pkt_pending->buf, 0, interface->ip, HOST_UNREACHABLE);
				pkt_pending = pkt_pending->next;
			}
			sr_arpreq_destroy(&(sr->cache), req);
		}
		else {
			int packet_len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t);
			uint8_t *pkt = malloc(packet_len);

			struct sr_ethernet_hdr *eth_hdr = (struct sr_ethernet_hdr *)pkt;
			struct sr_if *interface = sr_get_interface(sr, req->packets->iface);
			uint8_t hrd_addr[ETHER_ADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
			enum sr_ethertype eth_arp = ethertype_arp;
			enum sr_ethertype eth_ip = ethertype_ip;

			memcpy(eth_hdr->ether_dhost, hrd_addr, ETHER_ADDR_LEN);
			memcpy(eth_hdr->ether_shost, interface->addr, ETHER_ADDR_LEN);
			eth_hdr->ether_type = htons(eth_arp);

			struct sr_arp_hdr *arp_hdr = (struct sr_arp_hdr *)(sizeof(sr_ethernet_hdr_t) + pkt);
			enum sr_arp_hrd_fmt hrd_eth = arp_hrd_ethernet;
			enum sr_arp_opcode arp_op_req = arp_op_request;

			arp_hdr->ar_hrd = htons(hrd_eth);
			arp_hdr->ar_pro = htons(eth_ip);
			arp_hdr->ar_hln = ETHER_ADDR_LEN;
			arp_hdr->ar_pln = 4;
			arp_hdr->ar_op = htons(arp_op_req);
			arp_hdr->ar_sip = interface->ip;
			arp_hdr->ar_tip = req->ip;
			memcpy(arp_hdr->ar_sha, interface->addr, ETHER_ADDR_LEN);
			memcpy(arp_hdr->ar_tha, hrd_addr, ETHER_ADDR_LEN);

			printf("Sending Packets.. [3].\n");

			sr_send_packet(sr, pkt, packet_len, interface->name);
			free(pkt);
			req->sent = now;
			req->times_sent++;
		}
	}
}
Esempio n. 3
0
/*---------------------------------------------------------------------
 * Method: handle_arp_request
 * Scope: local
 *
 * Handles an ARP request sent to an interface.
 *
 *---------------------------------------------------------------------*/
static void handle_arp_request(struct sr_instance *sr, struct sr_ethernet_hdr *ethernet_header,
        struct sr_arphdr *arp_header, char *interface) {
    printf("\tIt's an ARP request!\n");

    // Get the interface address
    struct sr_if* iface = sr_get_interface(sr, interface);
    if ( iface == 0 ) {
        fprintf( stderr, "** Error, interface %s, does not exist\n", interface);
    }

    // Create ARP reply :)
    struct sr_arphdr arp_reply;
    memcpy(&arp_reply, arp_header, sizeof(struct sr_arphdr));
    arp_reply.ar_op = htons(ARP_REPLY);
    memcpy(&arp_reply.ar_sha, iface->addr, ETHER_ADDR_LEN);
    memcpy(&arp_reply.ar_tha, arp_header->ar_sha, ETHER_ADDR_LEN);
    memcpy(&arp_reply.ar_sip, &(arp_header->ar_tip), sizeof(uint32_t));
    memcpy(&arp_reply.ar_tip, &(arp_header->ar_sip), sizeof(uint32_t));

    // Send the reply
    uint8_t *buffer = pack_ethernet_packet(ethernet_header->ether_shost, iface->addr,
            ETHERTYPE_ARP, (uint8_t *) &arp_reply, sizeof(struct sr_arphdr));
    sr_send_packet(sr, buffer, sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arphdr),
            interface);
}
Esempio n. 4
0
/*
 * Send ARP request.
 */
void send_arp_request(struct sr_instance *sr, uint32_t dst_ip, char *interface) {
	
	uint8_t *packet = (uint8_t *)malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t));
	unsigned int len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t);
	struct sr_if *rt_if = (struct sr_if *)sr_get_interface(sr, interface);
	uint8_t brdcst_addr[ETHER_ADDR_LEN];
	
	int i = 0;
	for(i; i < ETHER_ADDR_LEN; i++){
		brdcst_addr[i] = 255;
	}
	
	/* Prepare ethernet header. */
	sr_ethernet_hdr_t *ether_hdr = (sr_ethernet_hdr_t *)(packet);
	ether_hdr->ether_type = htons(ethertype_arp);
	memcpy(ether_hdr->ether_shost, rt_if->addr, ETHER_ADDR_LEN);
	memcpy(ether_hdr->ether_dhost, brdcst_addr, ETHER_ADDR_LEN);
	
	/* Prepare ARP header. */
	sr_arp_hdr_t *arp_hdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
	arp_hdr->ar_hrd = htons(arp_hrd_ethernet);
	arp_hdr->ar_pro = htons(ethertype_ip);
	arp_hdr->ar_hln = ETHER_ADDR_LEN;
	arp_hdr->ar_pln = 4;
	arp_hdr->ar_op = htons(arp_op_request);
	memcpy(arp_hdr->ar_sha, rt_if->addr, ETHER_ADDR_LEN);
	arp_hdr->ar_sip = rt_if->ip;
	memcpy(arp_hdr->ar_tha, brdcst_addr, ETHER_ADDR_LEN); 
	arp_hdr->ar_tip = dst_ip;
	
	/* Send the packet. */
	sr_send_packet(sr, packet, len, interface);
}
Esempio n. 5
0
/*-----------------------------------------------------------------------------
 * Method: void checkCachedPackets(struct sr_instance* sr, int cachedArp)
 *
 * searches our packet cache for a matching ip in arpCache[cachedArp]. if we 
 * find a match, we forward the packet. if we do not find a match we need an
 * arp cache entry for it. make sure we have been waiting at least 3 seconds
 * before we send the src icmp unreachable packets. this does not drop the 
 * packet, it just looks every 3rd second to see if we have a response. every
 * time we look, we try to increment the arp counter
 *---------------------------------------------------------------------------*/
void checkCachedPackets(struct sr_instance* sr, int cachedArp)
{
    int i, arpMatch;
    for (i = 0; i < PACKET_CACHE_SIZE; i++) {
        if (packetCache[i].len > 0) {
            // if we have a packet waiting
            if (packetCache[i].arps <= 5) {
                // and we have not sent 5 arps for this packet yet
                if ((arpMatch = arpSearchCache(packetCache[i].tip)) > -1) {
                    // and we have an arp match for our packet's next hop
                    forwardPacket(sr, (uint8_t*)&packetCache[i].packet, packetCache[i].len,
                            // send it along
                            packetCache[i].nexthop->interface, arpReturnEntryMac(arpMatch));
                    packetCache[i].len = 0;
                } else {
                    /* wait three seconds between each arp request */
                    if ((int)(difftime(time(NULL), packetCache[i].timeCached))%3 < 1) {
                        arpSendRequest(sr, sr_get_interface(sr, packetCache[i].nexthop->interface),
                                packetCache[i].nexthop->gw.s_addr);
                        packetCache[i].arps++;
                    }
                }
            } else {
                /* then */
                icmpSendUnreachable(sr, (uint8_t*)&packetCache[i].packet, packetCache[i].len,
                        packetCache[i].nexthop->interface, ICMP_HOST_UNREACHABLE);
                packetCache[i].len = 0;
            }
        }
    }
}
Esempio n. 6
0
/* Insert a new mapping into the nat's mapping table.
   Actually returns a copy to the new mapping, for thread safety.
 */
struct sr_nat_mapping *sr_nat_insert_mapping(struct sr_nat *nat,
  uint32_t ip_int, uint16_t aux_int, sr_nat_mapping_type type ) {

  pthread_mutex_lock(&(nat->lock));

  /* handle insert here, create a mapping, and then return a copy of it */
  struct sr_nat_mapping *mapping = malloc(sizeof(struct sr_nat_mapping));
  mapping->ip_int = ip_int;
  mapping->aux_int = aux_int;
  mapping->type = type;
  mapping->last_updated = time(NULL);
  mapping->conns = NULL;
  
  /* find free port to assign mapping to 1024-2047 */
  uint16_t nxt_prt = 0;
  for(nxt_prt; nxt_prt < NUM_PORTS; nxt_prt++) {
	  if (nat->ports_used[nxt_prt] == 0) {
		  break;
	  }
  } 
  mapping->aux_ext = 1024+nxt_prt;
  nat->ports_used[nxt_prt] == 1;
  
  /* get ext_ip */
  struct sr_if *ext_iface = sr_get_interface(nat->sr, nat->out_if_name);  
  mapping->ip_ext = ext_iface->ip;
  
  mapping->next = nat->mappings; /* add to front of table */
  pthread_mutex_unlock(&(nat->lock));
  
  struct sr_nat_mapping *copy = malloc(sizeof(struct sr_nat_mapping));
  memcpy(copy, mapping, sizeof(struct sr_nat_mapping));
  return copy;
}
Esempio n. 7
0
int send_packet(struct sr_instance* sr, char* iface, uint8_t* dstMAC, uint8_t* payload, unsigned int len, uint16_t type) {
    assert(sr);
    assert(payload);
    assert(iface);
    uint8_t* packet = (uint8_t*)malloc_or_die(len + 14);
    struct sr_ethernet_hdr* tmpHdr = (struct sr_ethernet_hdr*) malloc_or_die(14* sizeof(uint8_t));
    struct sr_vns_if* interface = sr_get_interface(sr, iface);

    mac_copy(dstMAC, tmpHdr->ether_dhost);
    mac_copy(interface->addr, tmpHdr->ether_shost);
    tmpHdr->ether_type = htons(type);
    memcpy(packet, tmpHdr, 14);
    packet = packet + 14;
    memcpy(packet, payload, len);
    packet = packet - 14;
    if((sr_integ_low_level_output(sr, packet, (unsigned int)(len + 14), iface)) == 0) {
        printf("**********         %s   successfully sent a packet reply\n", __func__);
        return 1;
    }
    else {
        printf("\n @@@@@@@@@@@@@@@@@@@@        @@@@@@@@@@@@@@@@     %s  sending packet failed?\n", __func__);
        return 0;
    }
    return -1;
}
Esempio n. 8
0
/* Sends an ARP looking for target IP */
void sr_send_arp(struct sr_instance *sr, enum sr_arp_opcode code, char *iface, unsigned char *target_eth_addr, uint32_t target_ip){

    sr_arp_hdr_t *arp_hdr = malloc(sizeof(sr_arp_hdr_t));
    if(arp_hdr){
        arp_hdr->ar_hrd = htons(arp_hrd_ethernet);
        arp_hdr->ar_pro = htons(ethertype_ip);
        arp_hdr->ar_hln = ETHER_ADDR_LEN;
        arp_hdr->ar_pln = 4;
        arp_hdr->ar_op = htons(code);

        struct sr_if *node = sr_get_interface(sr, iface);

        memcpy(arp_hdr->ar_sha, node->addr, ETHER_ADDR_LEN);
        arp_hdr->ar_sip = node->ip;
        memcpy(arp_hdr->ar_tha, target_eth_addr, ETHER_ADDR_LEN);
        arp_hdr->ar_tip = target_ip;


        sr_send_eth(sr, (uint8_t *)arp_hdr, sizeof(sr_arp_hdr_t), (uint8_t *)target_eth_addr, iface, ethertype_arp);

        free(arp_hdr);

    }
    
}
Esempio n. 9
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);
  /* Error handling */
  if (len < sizeof(sr_ethernet_hdr_t))
  {
    printf("Invalid packet, insufficient length.\n");
    return;
  }

  struct sr_if* iface = sr_get_interface(sr, interface);
  if (iface == 0)
  {
    printf("Invalid interface, interface not found.\n");
  }

  /* Handle ARP packet */
  if (ethertype(packet) == ethertype_arp)
  {
    sr_handle_arp_packet(sr, packet, len, interface, iface);
  }
  /* Handle IP packet */
  else if (ethertype(packet) == ethertype_ip)
  {
    sr_handle_ip_packet(sr, packet, len, interface, iface);
  }
}/* end sr_ForwardPacket */
Esempio n. 10
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);

    /* check length */
    if (len < sizeof(sr_ethernet_hdr_t)) {
        fprintf(stderr, "Failed to process ETHERNET header, insufficient length\n");
        return;
    }
    
    sr_ethernet_hdr_t *eth_hdr = (sr_ethernet_hdr_t *)packet;
    
    uint16_t ether_type = ntohs(eth_hdr->ether_type);
    struct sr_if *iface = sr_get_interface(sr, interface);
    
    if (ether_type == ethertype_ip) {
        sr_handle_ip(sr, packet, len, iface);
    } else if (ether_type == ethertype_arp) {
        sr_handle_arp(sr, packet, len, iface);
    }
}
Esempio n. 11
0
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);
} 
Esempio n. 12
0
void ipForwarding(struct sr_instance *sr, uint8_t *packet, unsigned int len){


    // Construct IP Header
    sr_ip_hdr_t *ipHeader = (sr_ip_hdr_t *)(packet + ethernetHeaderSize);

    /* Forwading Logistics */
    // Decrement TTL
    ipHeader->ip_ttl = ipHeader->ip_ttl - 1;
    // Check if TTL Expried
    if (ipHeader->ip_ttl == 0) {
        sendICMP(sr, packet, len, TIME_EXCEEDED, TTL_CODE);
        return;
    }

    // New Checksum
    ipHeader->ip_sum = 0;       // reset to 0 first
    ipHeader->ip_sum = cksum(ipHeader, ipHeader->ip_hl * 4);

    /// Look for the LPM
    struct sr_rt *matchingEntry = findLPM(sr, ipHeader->ip_dst);

    // No LPM => Send ICMP
    if (matchingEntry == NULL) {
        printf("No LPM Match found... sending ICMP.\n");
        sendICMP(sr, packet, len, DESTINATION_UNREACHABLE, NET_UNREACHABLE_CODE);
        return;
    }

    // Get the outgoing interface to send through
    struct sr_if *sendingInterface = sr_get_interface(sr, matchingEntry->interface);
    sendToInterface(sr, packet, len, sendingInterface, matchingEntry->gw.s_addr);
}
Esempio n. 13
0
void ip_handlepacket(struct sr_instance *sr,
        uint8_t *packet,
        unsigned int len,
        char *interface) {

    printf("** Recieved IP packet\n");

    struct sr_ip_hdr *ip_hdr = ip_header(packet);
    struct sr_if *r_interface = sr_get_interface(sr, interface);

    if (!ip_validpacket(packet, len))
      return;

    /* Check whether NAT is enabled */
    if (!natEnabled(sr)){

      printf("** NO NAT\n");
      
      /* Check interface IP to determine whether this IP packet is for me */
      if (sr_packet_is_for_me(sr, ip_hdr->ip_dst)) {
        ip_handlepacketforme(sr, ip_hdr, interface);
      } else {

          /* Packet is not for me,forward it */
          ip_forwardpacket(sr, ip_hdr, len, interface);
        }
    } else {

        printf("** NAT ENABLED\n");
        sr_nat_handle_ip_packet(sr, ip_hdr, ntohs(ip_hdr->ip_len), r_interface);
    }   
}
Esempio n. 14
0
void arp_handle(struct sr_instance* sr, uint8_t * packet, unsigned int length, char* interface) {
	if(!arp_valid(packet, length)) {
		fprintf(stderr, "ARP packet does not match the recognized format.\n");
		return;
	}
	
	struct sr_if *sr_interface = sr_get_interface(sr, interface);
	if(sr_interface == 0) {
		fprintf(stderr, "Failed to retrieve interface %s.\n", interface);
		return;
	}
	
	struct sr_arphdr *arp_hdr = (struct sr_arphdr *)(packet + sizeof(struct sr_ethernet_hdr));
	
	if(ntohs(arp_hdr->ar_op) == ARP_REQUEST) {
		if(arp_hdr->ar_tip == sr_interface->ip)
			arp_respond(sr, packet, sr_interface);
		else printf("Received ARP packet destined for %d\n", arp_hdr->ar_tip);
	}
	
	else if(ntohs(arp_hdr->ar_op) == ARP_REPLY) {
		struct sr_arp_record *record = cache_add_record(sr, packet);
		if(record == NULL) {
			fprintf(stderr, "Received ARP response that does not match any outstanding ARP requests.\n");
			return;
		}
		cache_send_outstanding(sr, record);
	} 
	
	else {
		fprintf(stderr, "ARP packet opcode must be of type request or reply.\n");
	}
}
Esempio n. 15
0
void sr_handleARPpacket(struct sr_instance *sr, uint8_t* packet, unsigned int len, struct sr_if * iface) {
    assert(packet);
    sr_ethernet_hdr_t* ethHeader = (sr_ethernet_hdr_t*) packet;
    sr_arp_hdr_t * arpHeader = (sr_arp_hdr_t *) (packet+14);

    enum sr_arp_opcode request = arp_op_request;
    enum sr_arp_opcode reply = arp_op_reply;

    struct sr_if *interface = sr_get_interface_from_ip(sr, htonl(arpHeader->ar_tip));

    /* handle an arp request.*/
    if (ntohs(arpHeader->ar_op) == request) {
        /* found an ip->mac mapping. send a reply to the requester's MAC addr */
        if (interface){
          arpHeader->ar_op = ntohs(reply);
          uint32_t temp = arpHeader->ar_sip;
          arpHeader->ar_sip = arpHeader->ar_tip;
          arpHeader->ar_tip = temp;
          memcpy(arpHeader->ar_tha, arpHeader->ar_sha,6);
          memcpy(arpHeader->ar_sha, iface->addr,6);

          /*swapping outgoing and incoming addr*/
          set_addr(ethHeader, iface->addr, ethHeader->ether_shost);
          sr_send_packet(sr,(uint8_t*)ethHeader,len,iface->name);
        }
    }
    /* handle an arp reply */
    else {
      struct sr_packet *req_packet = NULL;
      struct sr_arpreq *req = NULL;
      pthread_mutex_lock(&(sr->cache.lock));   
      
      for (req = sr->cache.requests; req != NULL; req = req->next){
        if(req->ip == arpHeader->ar_sip){
          /* find the interface the packets should be sent out of */
          struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, req->ip);
          if (rt) {
            iface = sr_get_interface(sr, rt->interface);
            /* send all packets waiting on the request that was replied to */
            for (req_packet = req->packets; req_packet != NULL; req_packet = req_packet->next) {
              sr_ethernet_hdr_t * outEther = (sr_ethernet_hdr_t *)req_packet->buf;
              memcpy(outEther->ether_shost, iface->addr,6);
              memcpy(outEther->ether_dhost, ethHeader->ether_shost,6);

              sr_ip_hdr_t * outIP = (sr_ip_hdr_t *)(req_packet->buf+14);
              outIP->ip_ttl = outIP->ip_ttl-1;
              outIP->ip_sum = 0;
              outIP->ip_sum = cksum((uint8_t *)outIP,20);
              
              sr_send_packet(sr,req_packet->buf,req_packet->len,iface->name);
            }
            sr_arpreq_destroy(&(sr->cache), req);
          }
          break;
        }
      }
      pthread_mutex_unlock(&(sr->cache.lock));
      sr_arpcache_insert(&(sr->cache),arpHeader->ar_sha,arpHeader->ar_sip);
    }
}
void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) {
	time_t curtime = time(NULL);
	if (difftime(curtime, req->sent) < 1.0) return;
	if (req->times_sent <= 4) {
		/* Find out which interface it's on */
		char *interface = req->packets->iface;
		struct sr_if* iface = sr_get_interface(sr, interface);

		/* Allocate a new packet */
		size_t out_len = ARP_REPLY_SIZE;
		uint8_t *packet_out = malloc(out_len);

		/* ====== Headers ====== */
		/* Allow easy access to the headers */
		sr_ethernet_hdr_t *eth_header_out = (sr_ethernet_hdr_t*) packet_out;
		sr_arp_hdr_t *arp_header_out = 
				(sr_arp_hdr_t*) (packet_out + ARP_HEAD_OFF);

		/* Create the ethernet header */
		char bcast_addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
		memcpy(eth_header_out->ether_dhost, bcast_addr, 
				ETHER_ADDR_LEN);
		memcpy(eth_header_out->ether_shost, iface->addr, 
				ETHER_ADDR_LEN);
		eth_header_out->ether_type = htons(ethertype_arp);

		/* ====== Body ====== */
		/* Create the ARP packet */
		arp_header_out->ar_hrd = htons(0x1);
		arp_header_out->ar_pro = htons(ethertype_ip);
		arp_header_out->ar_hln = ETHER_ADDR_LEN;
		arp_header_out->ar_pln = IP_ADDR_LEN;
		arp_header_out->ar_op = htons(arp_op_request);
		memcpy(arp_header_out->ar_sha, iface->addr, ETHER_ADDR_LEN);
		arp_header_out->ar_sip = iface->ip;
		char zeroes[] = {0,0,0,0,0,0};
		memcpy(arp_header_out->ar_tha, 
				zeroes, ETHER_ADDR_LEN);
		arp_header_out->ar_tip = req->ip;

		/* Send the packet */
		sr_send_packet(sr, packet_out, out_len, interface);

		free(packet_out);

		return;
	} else {
		struct sr_packet *packet = req->packets;
		while (packet) {
			struct sr_packet *next = packet->next;
			send_icmp_error(sr, packet->buf, packet->len, packet->iface, 3, 1);
			packet = next;
		}
		sr_arpreq_destroy(&(sr->cache), req);
	}

	return;
}
Esempio n. 17
0
sr_if_t *get_external_iface(struct sr_instance *sr) 
{
  sr_if_t *int_iface = sr_get_interface(sr,sr->nat.int_iface_name);
  for (sr_if_t *iface = sr->if_list; iface != NULL; iface = iface->next) {
    if (iface != int_iface)
      return iface;
  }
  return NULL;
}
Esempio n. 18
0
/*******************************************************************
*   Finds interface the ARP Request was received from and constructs ARP Reply to send back out of 
*   the received interface. 
*******************************************************************/
void got_Request(struct packet_state * ps, struct sr_arphdr * arp_hdr, const struct sr_ethernet_hdr* eth)
{
	assert(ps);
	assert(arp_hdr);
	assert(eth);
	
	struct sr_if *iface = sr_get_interface(ps->sr, ps->interface);
	assert(iface);
	construct_reply(ps, arp_hdr, iface->addr, eth);
}
Esempio n. 19
0
/*---------------------------------------------------------------------
 * Method: destined_to_nat_external
 *
 * Scope:  Local
 *
 * returns true if the destination IP address of a packet's  is that
 * of the NAT itself (its external facing IP address)
 *   
 *  parameters:
 *    sr         - a reference to the router structure
 *    ip_dst     - the ip_dst of the received packet.
 *
 *---------------------------------------------------------------------*/
bool destined_to_nat_external(struct sr_instance* sr, uint32_t ip_dst) {
  
  sr_if_t *int_iface = sr_get_interface(sr,sr->nat.int_iface_name);
  for (sr_if_t *iface = sr->if_list; iface != NULL; iface = iface->next) {
    if (iface == int_iface)
      continue;
    if (ip_dst == iface->ip)
      return true;
  }
  return false;
}
Esempio n. 20
0
bool match_interface_etheraddr(struct sr_instance *sr,uint8_t *ethaddr,const char * interface) 
{
	sr_if_t *ifptr = sr_get_interface(sr,interface);
	
	//check if interface exists
	if (ifptr == 0)
		return false;
		
	return ether_addr_equals(ifptr->addr,ethaddr);

}
Esempio n. 21
0
void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) {
        time_t now = time(NULL);
        if(difftime(now, req->sent) > 1.0) {
                /* request timeout */
                if(req->times_sent > 5) {
                        
                        struct sr_packet *packets = req->packets;
                        
                        /* iterate through all packets on queue */
                        while(packets) {
                                uint8_t *reply_packet = 0;
                                sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packets->buf+sizeof(sr_ethernet_hdr_t));
                                reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packets->buf, ip_hdr, sr_get_interface(sr, packets->iface), 3, 1); /* create ICMP type 3, code 1 (host unreachable) */
                                /* if ICMP packet fails to generate */
                                if(reply_packet == 0) {
                                        fprintf(stderr, "Error: failed to generate ICMP packet\n");
                                }
                                
                                
                                /* send ICMP packet to ip of packet in queue */
                                if(sr_send_packet(sr, reply_packet, sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t), (const char*)(packets->iface)) == -1) {
                                        fprintf(stderr, "Error: sending packet failed (handle_arpreq)");
                                }
                                packets = packets->next;
                                free(reply_packet);
                        }
            sr_arpreq_destroy(&(sr->cache), req);
                } else {
                        
                        /* generate ARP packet */
                        struct sr_if *iface = 0;
                        
                        /* if interface is not found */
                        if((iface = sr_get_interface(sr, req->packets->iface)) == 0) {
                                fprintf(stderr, "Error: interface does not exist (handle_arpreq)");
                                return;
                        }
                        
                        uint8_t *arp_pkt = sr_new_arpreq_packet(NULL, iface->addr, req->ip, iface->ip); /* create ARP request packet to re-send */

                        /* send ARP request packet */
                        if (sr_send_packet(sr, arp_pkt, sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t), (const char*)(iface->name))==-1) {
                                fprintf(stderr, "Error: sending packet failed.");
                        }

                        /* update arpreq fields */
                        req->times_sent++;
                        req->sent = now;
                        
                        free(arp_pkt);
                }
        }
}
Esempio n. 22
0
/* Sends ICMP messages to all the packets waiting on this request */
void sr_send_icmp_to_waiting(struct sr_instance *sr, struct sr_arpreq *req){
    struct sr_packet *packet = req->packets;
    while(packet){
        struct sr_if* node = sr_get_interface(sr, packet->iface);

        struct sr_ethernet_hdr *eth = (sr_ethernet_hdr_t *)(packet->buf);
        struct sr_ip_hdr *ip_hdr = (sr_ip_hdr_t *)(eth + 1);
        
        sr_send_icmp3(sr, icmp_unreach, icmp_host_unreach, node->ip, ip_hdr->ip_src, (uint8_t*)ip_hdr, (4*(ip_hdr->ip_hl)) + MORSEL);
        packet = packet->next;
    }
}
Esempio n. 23
0
int sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *request){
   time_t now = get_now(&now);
   struct sr_packet * packetptr = request->packets;
   int i;

   if(difftime(now, request->sent) > 1.0){
      if(request->times_sent >= 5){
         while(packetptr != NULL){
             icmp_send_reply(sr, (uint8_t *)packetptr, packetptr->len, packetptr->iface, 3, 1); /* send unreachable */

             packetptr = packetptr->next;
         }
         sr_arpreq_destroy(&(sr->cache), request);
         return -1;
      }else{
           struct sr_rt* entry;
           struct sr_rt* routing = sr->routing_table;

           for(entry = routing; entry != NULL; entry = routing->next){
             struct sr_if * interface2 = sr_get_interface(sr, entry->interface);
             /*create arp packet*/
             enum sr_arp_opcode opcode = arp_op_request;
             struct sr_packet *raw = malloc(sizeof(struct sr_arp_hdr) + ETHER_HDR_LEN);
             /* may need to memset here*/
             struct sr_ethernet_hdr *eth = (struct sr_ethernet_hdr *)raw;
             struct sr_arp_hdr *req = (struct sr_arp_hdr *)(raw + ETHER_HDR_LEN);

             req->ar_hrd = 0;
             req->ar_pro = 0;
             req->ar_hln = 0;
             req->ar_pln = 0;
             req->ar_op = opcode;
             req->ar_sip = sr->sr_addr.sin_addr.s_addr;
             req->ar_tip = request->ip;

             for (i = 0; i < ETHER_ADDR_LEN; i++){
                 req->ar_tha[i] = 0xff;
                 req->ar_sha[i] = interface2->addr[i];
                 eth->ether_dhost[i] = 0xff;
                 eth->ether_shost[i] = interface2->addr[i];
             }

             /*send packet to the interface on routing_table*/
             sr_send_packet(sr, (uint8_t *)raw, sizeof(struct sr_arp_hdr) + ETHER_HDR_LEN, request->packets->iface);

             free(raw);
            }
         request->sent = now;
         request->times_sent++;
      }
   }
   return 0;
}
Esempio n. 24
0
/*
The handle_arpreq() function is a function you should write, and it should
handle sending ARP requests if necessary:

function handle_arpreq(request):
    if difftime(now, request->sent) > 1.0
        if request->times_sent >= 5:
            send icmp host unreachable to source addr of all pkts waiting
              on this request
            arpreq_destroy(request)
        else:
            send arp request
            request->sent = now
            request->times_sent++

*/
void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *request){
    //assert(sr);
    //assert(request);

	// If time since last sent is more than 1 second
    if (difftime(time(NULL), request->sent) >= 1.0) {

		/* If an ARP request has been sent 5 times with no response,
		a destination host unreachable should go back to all the sender of packets that were waiting on
		a reply to this ARP request. */
        if (request->times_sent >= 5) {

			// Iniitalize variables for the loop
            struct sr_packet *packetPointer = NULL;
            sr_ethernet_hdr_t *ethernetHeader = NULL;
            struct sr_if *interface = NULL;

			// get a pointer to a array of all packets waiting
            packetPointer = request->packets;

			// For every xender of packets waiting, send host unreachable
            while (packetPointer != NULL) {
                ethernetHeader = (sr_ethernet_hdr_t *)(packetPointer->buf);
                interface = getAddressInterface(sr, ethernetHeader->ether_dhost);

                /* do not send an ICMP message for an ICMP message */
				// If we got an interface of a waiting sender, send the ICMP host unreachable
                if (interface) {
                    sendICMP(sr, packetPointer->buf, packetPointer->len, DESTINATION_UNREACHABLE, HOST_UNREACHABLE_CODE);
                }

				// Go to the next exisiting packet
                packetPointer = packetPointer->next;
            }
            sr_arpreq_destroy(&(sr->cache), request);
        }

		// Otherwise, just send arp request with its sent time = now and increment times sent
		else {
            struct sr_if *sendingInterface = sr_get_interface(sr, request->packets->iface);
            arpRequest(sr, sendingInterface, request->ip);

			// Set sent time to NOW
            request->sent = time(NULL); // time(NULL) = NOW

			// Increment # of times sent
            request->times_sent = request->times_sent + 1;
        }
    }
}
Esempio n. 25
0
/*
Expects everything but len in network order
 */
void send_time_exceeded(struct sr_instance *sr, uint8_t *pkt) {

  /* Need to buffer enough space to include the unused 32 bits, the IP
  header length, and 64 bits first bits of original datagrams data  */
  unsigned int packet_size = sizeof(sr_ethernet_hdr_t) +
			      sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t)
			      + UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP + ICMP_DATA_SIZE; 

  uint8_t *outgoing_pkt = malloc(packet_size);
  
  sr_ethernet_hdr_t *outgoing_eth_hdr = get_ethernet_hdr(outgoing_pkt);
  sr_ip_hdr_t *outgoing_ip_hdr = get_ip_hdr(outgoing_pkt);
  sr_icmp_hdr_t *outgoing_icmp_hdr = get_icmp_hdr(outgoing_pkt);

  uint32_t ip_dst = get_ip_hdr(pkt)->ip_src;
  struct sr_rt *outgoing_routing_entry = find_lpm_in_routing_table(sr->routing_table, ntohl(ip_dst));
  if (!outgoing_routing_entry) {
    free(pkt);
    free(outgoing_pkt);
    return;
  }
  struct sr_if *outgoing_inf = sr_get_interface(sr, outgoing_routing_entry->interface);

  /*Ethernet*/
  memcpy(outgoing_eth_hdr->ether_shost, outgoing_inf->addr, ETHER_ADDR_LEN);
  outgoing_eth_hdr->ether_type = htons(ethertype_ip);

  /*IP*/
  populate_ip_hdr_normal(outgoing_ip_hdr);
  outgoing_ip_hdr->ip_len = htons(packet_size - sizeof(sr_ethernet_hdr_t));
  outgoing_ip_hdr->ip_p = ip_protocol_icmp;
  outgoing_ip_hdr->ip_sum = 0;
  outgoing_ip_hdr->ip_src = outgoing_inf->ip;
  outgoing_ip_hdr->ip_dst = ip_dst;
  outgoing_ip_hdr->ip_sum = cksum(outgoing_ip_hdr, sizeof(sr_ip_hdr_t));

  /*ICMP*/
  outgoing_icmp_hdr->icmp_type = ICMP_TYPE_TIME_EXCEEDED;
  outgoing_icmp_hdr->icmp_code = ICMP_CODE_TIME_EXCEEDED;
  outgoing_icmp_hdr->icmp_sum = 0;
  memset((char *)outgoing_icmp_hdr + sizeof(sr_icmp_hdr_t), 0, UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP); 
  memcpy((char *)outgoing_icmp_hdr + sizeof(sr_icmp_hdr_t) + UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP, 
	 get_ip_hdr(pkt), ICMP_DATA_SIZE);
  outgoing_icmp_hdr->icmp_sum = cksum(outgoing_icmp_hdr,
				      sizeof(sr_icmp_hdr_t) + UNUSED_BYTE_LENGTH_TIME_EXCEEDED_ICMP + ICMP_DATA_SIZE);

  send_or_queue_packet_based_on_arp_entry_existence(sr, outgoing_routing_entry,
						    outgoing_pkt, packet_size);
}
Esempio n. 26
0
/* prepare arp into ethernet frame and send it */
int boardcast_arpreq(struct sr_instance *sr, struct sr_arpreq *arp_req){
    struct sr_if *o_interface;
    /*first package the arp package header first...*/
    o_interface = sr_get_interface(sr, arp_req->packets->iface);
    struct sr_arp_hdr arp_hdr;
    uint8_t *arp_package;
    uint8_t *e_pack;
    arp_hdr.ar_hrd = sr_arp_hrd_fmt hfmt = arp_hrd_ethernet;             /* format of hardware address   */
    arp_hdr.ar_pro = 0X800;            /*from http:/*www.networksorcery.com/enp/protocol/arp.htm#Protocol%20address%20length*/
    arp_hdr.ar_hln = ETHER_ADDR_LEN = 8; /*from http:/*www.networksorcery.com/enp/protocol/arp.htm#Protocol%20address%20length*/
    arp_hdr.ar_pln = 8;             /*from http:/*www.networksorcery.com/enp/protocol/arp.htm#Protocol%20address%20length*/
    sr_arp_opcode code = arp_op_request;
    arp_hdr.ar_op = code;              /* ARP opcode (command)         */
    memcpy(arp_hdr.ar_sha, o_interface->addr, ETHER_ADDR_LEN); /* sender hardware address      */
    arp_hdr.ar_sip = o_interface.ip;             /* sender IP address            */
    arp_hdr.ar_tip = arp_req.ip;                 /* target IP address            */
    /*copy everything into the arp_header*/
    arp_package = malloc(sizeof(sr_arp_hdr_t));
    print_hdr_arp(arp_package);
    memcpy(arp_package, &apr_hdr, sizeof(sr_arp_hdr_t));
    /*then package the ethernet header along with the arp header...*/
    e_pack = eth_hdr_package(uint8_t  ether_dhost, sr, o_interface->addr, arp_package, sizeof(struct sr_arp_hdr));
    print_hdr_eth(e_pack);

    /*send it out*/
    sr_send_packet(sr, e_pack, sizeof(struct sr_arp_hdr) + sizeof(struct sr_ethernet_hdr), o_interface);



/* build the ethernet frame to be broadcast */
int eth_hdr_package(uint8_t  ether_dhost, uint8_t  ether_shost, uint16_t ether_type, uint8_t *content, int len){
    uint8_t *output;
    int total_length;
    struct sr_ethernet_hdr e_hdr;
    /*first step is to create a ethernet header...*/
    memcpy(e_hdr.ether_dhost,ether_dhost,ETHER_ADDR_LEN); /* destination ethernet address */
    memcpy(e_hdr.ether_shost,ether_shost,ETHER_ADDR_LEN); /* source ethernet address */
    e_hdr.ether_type = ether_type;
    /*calculate the length of the entire thing...*/
    total_length = sizeof(sr_ethernet_hdr_t) + len;
    /*put everything together*/
    output = malloc(total_length);
    /*put the ethernet header in the front*/
    memcpy(output, &e_hdr, sizeof(sr_ethernet_hdr_t));
    memcpy(output + sizeof(sr_ethernet_hdr_t), content,len);
    return output;
    
}
Esempio n. 27
0
void handle_arpreq(struct sr_instance* sr, struct sr_arpreq *cache_req_ptr) {

  char *iface_name = cache_req_ptr->packets->iface;
  struct sr_if *interface = sr_get_interface(sr, iface_name);

  /*Only broadcast if this hasn't been sent out before: 
   *Otherwise, our packet has been added to the end of the 
  * request's linkedlist in the cache: do nothing*/
  if (difftime(time(0), cache_req_ptr->sent) > 1.0) {
    if (cache_req_ptr->times_sent >= 5) {
      struct sr_packet *req_pkt_ptr = cache_req_ptr->packets;
      for (; req_pkt_ptr; req_pkt_ptr = req_pkt_ptr->next) {
        send_icmp(sr, req_pkt_ptr->buf, req_pkt_ptr->len, interface, dest_host_unreach_type, dest_host_unreach_code);
      }
      sr_arpreq_destroy(&(sr->cache), cache_req_ptr);
    }
    else {
      /*Create space for the request*/
      uint8_t* eth_pkt_buf = (uint8_t *) malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t));
      uint8_t* arp_pkt_buf;
      /*Pointers to where different header structs start in the packet*/
      sr_ethernet_hdr_t* req_eth_header = (sr_ethernet_hdr_t*) eth_pkt_buf; /* Allocate mem for reply packet buffer */
      
      /* Copy addresses and type into the ethernet header */
      uint8_t broadcast_addr[ETHER_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

      memcpy(req_eth_header->ether_dhost, broadcast_addr, ETHER_ADDR_LEN);
      memcpy(req_eth_header->ether_shost, interface->addr, ETHER_ADDR_LEN);
      req_eth_header->ether_type = ethertype_arp;
      
      /* Convert to network byte ordering */
      hton_eth_hdr(&req_eth_header);


      /* Get the Arp Buffer and Build the Arp packet*/
      arp_pkt_buf = eth_pkt_buf + sizeof(sr_ethernet_hdr_t);
      sr_create_arp_req_packet(arp_pkt_buf, cache_req_ptr, interface);

      /* Send the ARP request packet */
      sr_send_packet(sr, eth_pkt_buf, sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t),
        interface->name);
      cache_req_ptr->sent = time(0);
      cache_req_ptr->times_sent++;

      free(eth_pkt_buf);
    }
  }
}
Esempio n. 28
0
void sr_icmp_ttl_exceeded(struct sr_instance *sr, uint8_t * packet,
			  unsigned int len, char* interface,
			  struct sr_ethernet_hdr *e_hdr, struct ip *ip_hdr)
{
  struct sr_if *iface = sr_get_interface(sr, interface);
  
  /* Send ICMP time exceeded message. This is
     need for traceroute to work. */
  uint8_t *new_pkt = (uint8_t *) calloc(1, 70);
  struct sr_ethernet_hdr *new_e_hdr = (struct sr_ethernet_hdr *) new_pkt;
  struct ip *new_ip_hdr = (struct ip *) (new_pkt + 14);
  struct sr_icmphdr *new_icmp_hdr = (struct sr_icmphdr *) (new_pkt + 34);

  /* ethernet header */
  memcpy(new_e_hdr->ether_dhost, e_hdr->ether_shost, 6);
  memcpy(new_e_hdr->ether_shost, e_hdr->ether_dhost, 6);
  new_e_hdr->ether_type = htons(0x0800);

  /* IP header */
  new_ip_hdr->ip_hl = 5;
  new_ip_hdr->ip_v = 4;
  new_ip_hdr->ip_tos = 0;
  new_ip_hdr->ip_len = htons(56);
  new_ip_hdr->ip_id = ip_hdr->ip_id;
  new_ip_hdr->ip_off = ip_hdr->ip_off;
  new_ip_hdr->ip_ttl = 64;
  new_ip_hdr->ip_p = 1;
  new_ip_hdr->ip_src.s_addr = iface->ip;
  new_ip_hdr->ip_dst = ip_hdr->ip_src;
  new_ip_hdr->ip_sum = 0;
  new_ip_hdr->ip_sum = checksum(new_ip_hdr, 20);

  /* ICMP ttl exceeded: type: 11, code: 0 */
  new_icmp_hdr->icmp_type = 11;
  new_icmp_hdr->icmp_code = 0;
  new_icmp_hdr->id = 0;
  new_icmp_hdr->seqno = 0;
  memcpy(new_pkt+42, ip_hdr, 28);
  new_icmp_hdr->icmp_chksum = 0;
  new_icmp_hdr->icmp_chksum = checksum((uint16_t *)new_icmp_hdr, 36);

  int success = sr_send_packet(sr, new_pkt, 70, interface);
  if (success != 0) {
    fprintf(stderr, "%s: Sending packet failed!\n", __func__);
  }
}
Esempio n. 29
0
/*---------------------------------------------------------------------
 * Method: process_arp(struct sr_instance* sr,
 *      			         uint8_t * packet,
 *      				 			 unsigned int len,
 *     			     			 char* interface)
 * Scope:  Internal
 *
 * This function processes an arp packe that was received. It handles 
 * two cases, one where it is a request and one where it is a response.
 *
 *---------------------------------------------------------------------*/
void process_arp(struct sr_instance* sr,
       			     uint8_t * packet,
        				 unsigned int len,
       			     char* interface)
{
	struct sr_arpentry *arp_entry;
	struct sr_arpreq *arp_req;
	struct sr_arp_hdr *arp_hdr;
	struct sr_if* rec_if;
	
	/* Validate the arp packet */
	if (!valid_arp(packet, len))
		return;
	
	/* Is the arp addressed to me? NOTE: I do not follow the RFC recommendation to
	 * update existing cache entries with the received arp packet's ip-mac mapping 
	 * before checking whether the packet was addressed me. This is because we do 
	 * not have a good way to strictly 'update' cache entries without inserting a new 
	 * one and I would like to avoid duplicate valid cache entries for the same ip. */
	rec_if = sr_get_interface(sr, interface);
	arp_hdr = arp_header(packet);
	if (rec_if->ip != arp_hdr->ar_tip)
		return;
		
	/* Add the sender's protocol address to my table. */
	arp_entry = sr_arpcache_lookup(&sr->cache, arp_hdr->ar_sip);
	
	/* Arp entry already exists. NOTE: arp_entry is a copy in this case so free it.*/
	if (arp_entry != 0) {
		free(arp_entry);
	
	/* Arp entry doesn't exist so add it. */
	} else {
		arp_req = sr_arpcache_insert(&sr->cache, arp_hdr->ar_sha, arp_hdr->ar_sip);
		
		/* There are packets waiting on this arp request. Send them. */
		if (arp_req != 0) {
			sr_arpreq_send_packets(sr, arp_req);
		}
	}
		
	/* Handle a request. */
	if (arp_opcode(arp_hdr) == arp_op_request) {
		process_arp_request(sr, arp_hdr, rec_if);
	}
}
Esempio n. 30
0
/*
 * Send an ICMP Error.
 */
void send_icmp_error(uint8_t type, uint8_t code, struct sr_instance *sr, 
					char *interface, unsigned int len, uint8_t *pkt) {
	
	int new_len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t);
	uint8_t *packet = (uint8_t *) malloc(new_len);
	struct sr_if *rt_if = (struct sr_if *)malloc(sizeof(struct sr_if));
	rt_if = (struct sr_if *)sr_get_interface(sr, interface);
	
	/* Prepare ethernet header. */
	sr_ethernet_hdr_t *ether_hdr = (sr_ethernet_hdr_t *) pkt;
	sr_ethernet_hdr_t *ether_newhdr = (sr_ethernet_hdr_t *) packet;
	ether_newhdr->ether_type = htons(ethertype_ip);
	memcpy(ether_newhdr->ether_shost, rt_if->addr, ETHER_ADDR_LEN);
	memcpy(ether_newhdr->ether_dhost, ether_hdr->ether_shost, ETHER_ADDR_LEN); 	
	
	/* Prepare IP header. */
	sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(pkt + sizeof(sr_ethernet_hdr_t));
	sr_ip_hdr_t *ip_newhdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
	memcpy(ip_newhdr, ip_hdr, sizeof(sr_ip_hdr_t));
	ip_newhdr->ip_src = rt_if->ip;
	ip_newhdr->ip_dst = ip_hdr->ip_src;
	ip_newhdr->ip_len = htons(56);
	ip_newhdr->ip_id = 0;
	ip_newhdr->ip_hl = 5;
	ip_newhdr->ip_off = 0;
	ip_newhdr->ip_ttl = 64;
	ip_newhdr->ip_p = ip_protocol_icmp;
	ip_newhdr->ip_sum = 0;
	ip_newhdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t));							
	
	/* Prepare the ICMP t3 header. */
	sr_icmp_t3_hdr_t *icmp_t3_hdr = (sr_icmp_t3_hdr_t *)(packet + 
									sizeof(sr_ethernet_hdr_t) + 
									sizeof(sr_ip_hdr_t));
	icmp_t3_hdr->icmp_type = type;
	icmp_t3_hdr->icmp_code = code;
	icmp_t3_hdr->icmp_sum = 0;
	memcpy(icmp_t3_hdr->data,  ip_hdr, 20);
	memcpy(icmp_t3_hdr->data + 20, pkt + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), 8); 
	icmp_t3_hdr->icmp_sum = cksum(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), 
							sizeof(sr_icmp_t3_hdr_t));
	
	/* Send the ICMP error packet. */
	sr_send_packet(sr, packet, new_len, interface);
}