Beispiel #1
0
static struct frame_t *generate_icmp_error(struct frame_t *incoming, uint16_t icmp_type, uint16_t icmp_code){
    
    assert (incoming);
    
    /* need to get pointers to various things */
    
    /* get some useful info about lengths */
    size_t icmp_data_len = incoming->ip_hl + 2 * sizeof(uint32_t);      //length of echo data, in bytes
    
    if (incoming->ip_len - incoming->ip_hl < 8 )
        icmp_data_len = incoming->ip_len;
    
    /* create and fill out frame_t */
    struct frame_t *outgoing = malloc(sizeof(struct frame_t));
    
    assert(outgoing);
    
    outgoing->len = sizeof(struct sr_ethernet_hdr) + sizeof(struct ip) + sizeof(struct icmp_hdr) + icmp_data_len;
    outgoing->frame = malloc(outgoing->len);
    outgoing->ether_header = (struct sr_ethernet_hdr *)outgoing->frame;
    
    assert(outgoing->frame);
    
    outgoing->ip_header = (struct ip *)(outgoing->frame + sizeof(struct sr_ethernet_hdr));
    outgoing->arp_header = NULL;
    
    assert(outgoing->ip_header);
    
    outgoing->icmp_header = (struct icmp_hdr *)((void *)outgoing->ip_header + incoming->ip_hl);
    
    assert(outgoing->icmp_header);
    
    outgoing->in_or_out = OUT;
    outgoing->MAC_set = 1;
    outgoing->from_ip = incoming->to_ip;
    outgoing->to_ip = incoming->from_ip;
    memcpy(outgoing->from_MAC, incoming->to_MAC, ETHER_ADDR_LEN);
    memcpy(outgoing->to_MAC, incoming->from_MAC, ETHER_ADDR_LEN);
    outgoing->iface = incoming->iface;
    outgoing->ip_len = outgoing->len - sizeof(struct sr_ethernet_hdr);
    outgoing->ip_hl = IP_HDR_LEN;
    
    /* fill out icmp header */
    outgoing->icmp_header->icmp_type = icmp_type;
    outgoing->icmp_header->icmp_code = icmp_code;
    outgoing->icmp_header->icmp_unused = 0;
    outgoing->icmp_header->icmp_sum = 0;
    
    /* copy data into header: packet includes IP header, ICMP header, and beginning of original packet */
    void *icmp_data = (void *)outgoing->icmp_header + sizeof(struct icmp_hdr);
    assert(icmp_data);
    memcpy(icmp_data, incoming->ip_header, icmp_data_len);
    
    compute_icmp_checksum(outgoing);
    ip_header_create(outgoing);
    encapsulate(outgoing);
    return outgoing; 
    
}
Beispiel #2
0
/*--------------------------------------------------------------------- 
 * Method: arp_create;
 *
 *---------------------------------------------------------------------*/
static struct frame_t *arp_create(struct sr_instance *sr, struct frame_t *incoming, struct sr_if *iface, unsigned short op)
{
    assert(incoming);
    
    //create and fill out frame_t
    struct frame_t *outgoing = malloc(sizeof(struct frame_t));
    
    assert(outgoing);
    
    outgoing->len = sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arphdr);
    outgoing->frame = malloc(outgoing->len);
    outgoing->ether_header = (struct sr_ethernet_hdr *)outgoing->frame;
    
    outgoing->arp_header = (struct sr_arphdr *)(outgoing->frame + sizeof(struct sr_ethernet_hdr));
    outgoing->ip_header = NULL;
    outgoing->icmp_header = NULL;
    outgoing->ip_len = 0;
    outgoing->ip_hl = 0;
    outgoing->iface = iface;
    outgoing->MAC_set = 1;
    
    //fill out constant parts of arp_header
    outgoing->arp_header->ar_hrd = htons(1);
    outgoing->arp_header->ar_pro = htons(ETHERTYPE_IP);
    outgoing->arp_header->ar_hln = ETHER_ADDR_LEN;
    outgoing->arp_header->ar_pln = 4;
    
    //fill out MAC and IP addresses
    memcpy(outgoing->arp_header->ar_tha, incoming->from_MAC, ETHER_ADDR_LEN); //this will give nonsense for an arp request which is fine--unless we need a broadcast address, but I don't think so 
    memcpy(outgoing->arp_header->ar_sha, iface->addr, ETHER_ADDR_LEN);
    memcpy(outgoing->from_MAC, iface->addr, ETHER_ADDR_LEN);
    
    if (op == ARP_REQUEST){
        struct sr_rt *route_entry = rt_match(sr, incoming->to_ip);
        outgoing->arp_header->ar_tip = route_entry->gw.s_addr; //incoming is an IP datagram, we want to know MAC of next hop in routing table
        outgoing->to_ip = outgoing->arp_header->ar_tip;
        memset(outgoing->to_MAC, 0xFF, ETHER_ADDR_LEN); //set outgoing MAC to broadcast address 
    }
    else{
        outgoing->arp_header->ar_tip = incoming->from_ip; //incoming is an ARP request, we want to send back to that IP
        outgoing->to_ip = incoming->from_ip;
        memcpy(outgoing->to_MAC, incoming->from_MAC, ETHER_ADDR_LEN);
    }
    
    outgoing->arp_header->ar_sip = outgoing->iface->ip;
    outgoing->from_ip = outgoing->iface->ip;
    
    outgoing->arp_header->ar_op = htons(op);
    
    encapsulate(outgoing);
    assert(outgoing);
    
    return outgoing;
}
Beispiel #3
0
static struct frame_t *generate_icmp_echo(struct frame_t *incoming){
    
    assert(incoming);
    
    
    /* create and fill out frame_t */
    struct frame_t *outgoing = malloc(sizeof(struct frame_t));
    
    assert(outgoing);
    
    outgoing->frame = malloc(incoming->len);
    
    assert(outgoing->frame);
    
    memcpy(outgoing->frame, incoming->frame, incoming->len);
    outgoing->ether_header = (struct sr_ethernet_hdr *)outgoing->frame;
    outgoing->ip_header = (struct ip *)(outgoing->frame + sizeof(struct sr_ethernet_hdr));
    outgoing->arp_header = NULL;
    
    assert(outgoing->ip_header);
    
    outgoing->icmp_header = (struct icmp_hdr *)((void *)outgoing->ip_header + incoming->ip_hl);
    
    assert(outgoing->icmp_header);
    
    outgoing->in_or_out = OUT;
    memcpy(outgoing->from_MAC, incoming->to_MAC, ETHER_ADDR_LEN);
    memcpy(outgoing->to_MAC, incoming->from_MAC, ETHER_ADDR_LEN);
    outgoing->MAC_set = 1;
    outgoing->from_ip = incoming->to_ip;
    outgoing->to_ip = incoming->from_ip;
    outgoing->iface = incoming->iface;
    outgoing->len = incoming->len;
    outgoing->ip_len = incoming->ip_len;
    outgoing->ip_hl = incoming->ip_hl;
    
    
    /* fill out icmp header */
    outgoing->icmp_header->icmp_type = ECHO_REPLY;
    outgoing->icmp_header->icmp_sum = 0;
    
    /* fill out other headers too */
    compute_icmp_checksum(outgoing); //again, this will need updating, ideally it'll only take outgoing as argument
    
    ip_header_create(outgoing); //this function only create headers for ICMP packets 
    encapsulate(outgoing); //memory and such already allocated, just fills in fields appropriately
    
    return outgoing;
    
}
Beispiel #4
0
int *get_fdata(char * data, size_t len, modulation m) {
    frame *frm = encapsulate(data, len);
    char *enc = hm_encode((char *) frm, FRAME_SIZE);
    int * vbuf;
    switch (m) {
    case AM:
        vbuf = modulate_am(enc);
        break;
    case FM:
        vbuf = modulate_fm(enc);
        break;
    }
    free(enc);
    free(frm);
    return vbuf;
}
Beispiel #5
0
    // app data -> SSL -> protocol encapsulation -> reliability layer -> network
    void down_stack_app()
    {
      if (ssl_started_)
	{
	  // push app-layer cleartext through SSL object
	  while (!app_write_queue.empty())
	    {
	      BufferPtr& buf = app_write_queue.front();
	      try {
		const ssize_t size = ssl_->write_cleartext_unbuffered(buf->data(), buf->size());
		if (size == SSLContext::SSL::SHOULD_RETRY)
		  break;
	      }
	      catch (...)
		{
		  if (stats)
		    stats->error(Error::SSL_ERROR);
		  invalidate(Error::SSL_ERROR);
		  throw;
		}
	      app_write_queue.pop_front();
	    }

	  // encapsulate SSL ciphertext packets
	  while (ssl_->read_ciphertext_ready() && rel_send.ready())
	    {
	      typename ReliableSend::Message& m = rel_send.send(*now);
	      m.packet = PACKET(ssl_->read_ciphertext());

	      // encapsulate packet
	      try {
		encapsulate(m.id(), m.packet);
	      }
	      catch (...)
		{
		  if (stats)
		    stats->error(Error::ENCAPSULATION_ERROR);
		  invalidate(Error::ENCAPSULATION_ERROR);
		  throw;
		}

	      // transmit it
	      net_send(m.packet, NET_SEND_SSL);
	    }
	}
    }
Beispiel #6
0
/*--------------------------------------------------------------------- 
 * Method: arpq_entry_clear;
 *
 *---------------------------------------------------------------------*/
static void arpq_entry_clear(struct sr_instance *sr,
                             struct arp_queue *queue,
                             struct arpq_entry *entry,
                             unsigned char *d_ha)
{
    assert(sr);
    assert(queue);
    assert(entry);
    assert(d_ha);
    
    struct queued_packet *qpacket;
    
    while( qpacket = ((entry->arpq_packets).first) )
    {
        struct frame_t *outgoing = qpacket->outgoing;
        memcpy(outgoing->from_MAC, outgoing->iface->addr, ETHER_ADDR_LEN);
        memcpy(outgoing->to_MAC, d_ha, ETHER_ADDR_LEN);
        
        encapsulate(outgoing);
        printf("cleared packet from queue\n");
        sr_send_packet(sr, (uint8_t *)outgoing->frame, outgoing->len, outgoing->iface->name); 
        
        if( !((entry->arpq_packets).first = qpacket->next) ){
            (entry->arpq_packets).first = NULL;
            (entry->arpq_packets).last = NULL; //need to set both so destroy_arpq_entry works right
        }
        
        destroy_frame_t(outgoing);
        free(qpacket);
    }
    
    if (entry->prev) (entry->prev)->next = entry->next;
    else queue->first = entry->next;
    
    if (entry->next) (entry->next)->prev = entry->prev;
    else queue->last = entry->prev;
    
    if (entry->prev) destroy_arpq_entry(entry);
    return;
}
Beispiel #7
0
    // raw app data -> protocol encapsulation -> reliability layer -> network
    void down_stack_raw()
    {
      while (!raw_write_queue.empty() && rel_send.ready())
	{
	  typename ReliableSend::Message& m = rel_send.send(*now);
	  m.packet = raw_write_queue.front();
	  raw_write_queue.pop_front();

	  // encapsulate packet
	  try {
	    encapsulate(m.id(), m.packet);
	  }
	  catch (...)
	    {
	      if (stats)
		stats->error(Error::ENCAPSULATION_ERROR);
	      invalidate(Error::ENCAPSULATION_ERROR);
	      throw;
	    }

	  // transmit it
	  net_send(m.packet, NET_SEND_RAW);
	}
    }
Beispiel #8
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);
    if( len < ETHER_HDR_LEN ) {
        printf("Bogus packet length\n");
        return;
    }
    
    
    struct sr_if *iface;
    
    struct frame_t *incoming = create_frame_t(sr, packet, len, interface);
    struct frame_t *outgoing = NULL;
    
    /* First, deal with ARP cache timeouts */
    arp_cache_flush(&sr_arp_cache);
    arp_queue_flush(sr, &sr_arp_queue);
    
    /* Do we only need to cache ARP replies, or src MAC/IP on regular IP packets too, etc? */
    /* Also, do we need to worry about fragmentation? */
    
    /* Then actually handle the packet */
    /* Start by determining protocol */
    if (incoming->ip_header){
        
        /* sanity checks */
        if ( incoming->ip_header->ip_v != 4 ){
            printf("IP packet not IPv4\n");
            return;
        }
        
        compute_ip_checksum(incoming);
        /* Check the checksum */
        if( incoming->ip_header->ip_sum != 0 ) { 
            fprintf(stderr, "IP checksum incorrect, packet was dropped\n");
            return;
        }
        //set checksum back to what it was
        compute_ip_checksum(incoming);
        

        /* Are we the destination? */
        if (iface = if_dst_check(sr, incoming->to_ip)){  //we could change this to just take incoming and then get to_ip

            /* Is this an ICMP packet? */
            if (incoming->icmp_header){
                printf("received ICMP datagram\n");
                compute_icmp_checksum(incoming);
                if(incoming->icmp_header->icmp_type == ECHO_REQUEST && incoming->icmp_header->icmp_sum == 0){
                    outgoing = generate_icmp_echo(incoming); 
                    printf("received ICMP echo request\n");
                }
                else
                    printf("Dropped packet--we don't deal with that code, or invalid checksum\n");
            }
            else{
                outgoing = generate_icmp_error(incoming, DEST_UNREACH, PORT_UNREACH);
                printf("A packet for me! Flattering, but wrong.\n");
            }
        }
        else {
            /* Has it timed out? */
            if (incoming->ip_header->ip_ttl <= 0){
                int err = 0;
                //make sure it's not an ICMP error packet alrady
                if (incoming->ip_header->ip_p == IPPROTO_ICMP){
                    incoming->icmp_header = ((void *) incoming->ip_header + 
                                                             incoming->ip_hl);
                    uint8_t code = incoming->icmp_header->icmp_type;
                    //don't send ICMP error messages about ICMP error messages
                    if (code == DEST_UNREACH || code == TIME_EXCEEDED || code == 12 || code == 31)
                        //12 and 31 indicate bad IP header and datagram conversion error, respectively
                        err = 1;
                }
                if (!err){
                    outgoing = generate_icmp_error(incoming, TIME_EXCEEDED, TIME_INTRANSIT);
                    printf("Slowpoke. TTL exceeded.\n");
                }
            }
            else {

                /* update and forward packet; if necessary, add it to queue */
                struct arpc_entry *incache;
                uint32_t arpc_ip;
                outgoing = update_ip_hdr(sr, incoming, &arpc_ip);

                
                
                
                incache = arp_cache_lookup(sr_arp_cache.first, arpc_ip);
                
                
                if (!incache){
                    struct arpq_entry *entry = arp_queue_lookup(sr_arp_queue.first, outgoing->to_ip);
                    struct arpq_entry *temp_entry = NULL;
                    if ( entry ){ //if we've already sent an ARP request about this IP
                        if( time(NULL) - 1 > entry->arpq_last_req ) {
                            if(entry->arpq_num_reqs >= ARP_MAX_REQ)
                            {
                                printf("Too many ARP requests\n");
                                arpq_packets_icmpsend(sr, &entry->arpq_packets);
                                destroy_arpq_entry(entry);
                                return;
                            }
                            else if (entry->arpq_packets.first)
                            {
                                struct frame_t *arp_req;
                                struct queued_packet *old_packet = entry->arpq_packets.first;
                                entry->arpq_last_req = time(NULL);
                                entry->arpq_num_reqs++;
                            }
                        }
                        assert( (entry->arpq_packets).first );
                        if (!arpq_add_packet(entry, outgoing, len, incoming->from_MAC, incoming->iface))
                            printf("ARP queue packet add failed\n");
                        else printf("added packet to queue\n");
                    }
                    /* else, there are no outstanding ARP requests for this particular IP */
                    else {
                        printf("outgoing ip is %d\n", ntohl(outgoing->to_ip));
                        temp_entry = arpq_add_entry(&sr_arp_queue, outgoing->iface, outgoing, outgoing->to_ip, outgoing->ip_len, incoming->from_MAC, incoming->iface);
                    }
                    free(outgoing->frame);
                    
                    /* make ARP request */
                    outgoing = arp_create(sr, outgoing, outgoing->iface, ARP_REQUEST); //send datagram will now point to an ARP packet, not to the IP datagram 
                    if (temp_entry){
                        temp_entry->arpq_next_hop = outgoing->to_ip;
                    }
                    printf("sending ARP request\n");
                }
                else{
                    printf("got the MAC, can actually send this packet\n");
                    memcpy(outgoing->to_MAC, incache->arpc_mac, ETHER_ADDR_LEN);
                    encapsulate(outgoing);
                }
            }
        }
    }
    else if ( incoming->arp_header )
    {
        printf("received ARP packet\n");
        
        struct sr_arphdr *arp_header = incoming->arp_header;
        
        
        uint8_t in_cache = 0;
        
        struct arpc_entry *arpc_ent = arp_cache_lookup(sr_arp_cache.first, arp_header->ar_sip);
        printf("checking the cache\n");
        if( arpc_ent )
        {
            arp_cache_update(arpc_ent, arp_header->ar_sha);
            printf("updated cache\n");
            in_cache = 1;
        }
        
        struct sr_if *target_if = if_dst_check(sr, arp_header->ar_tip);
        printf("checking the target\n");
        if( target_if )
        {
            printf("It's for us\n");
            if( !in_cache ) {
                if( arp_cache_add(&sr_arp_cache, arp_header->ar_sha, arp_header->ar_sip) ) {
                    printf("added to cache\n");
                    printf("ip is %d\n", ntohl(arp_header->ar_sip));
                    struct arpq_entry *new_ent;
                    if( new_ent = arpq_next_hop_lookup(sr_arp_queue.first, arp_header->ar_sip) )
                        arpq_entry_clear(sr, &sr_arp_queue, new_ent, arp_header->ar_sha);
                }
                else perror("ARP request not added to cache");
            }
            if( ntohs(arp_header->ar_op) == ARP_REQUEST ){
                outgoing = arp_create(sr, incoming, incoming->iface, ARP_REPLY);
                printf("created ARP reply\n");
                
                assert(outgoing);
            }
        }
    }
    else perror("Unknown protocol");
        
    //send datagram, if appropriate
    if (outgoing != NULL){ 
        sr_send_packet(sr, (uint8_t *)outgoing->frame, outgoing->len, outgoing->iface->name);
        printf("sent packet of length %d on iface %s\n", outgoing->len, outgoing->iface->name);
    }
    
    if (outgoing != NULL) destroy_frame_t(outgoing);
    
}/* end sr_handlepacket */