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; }
/* Send an ICMP packet */ void send_icmp(struct sr_instance* sr, uint8_t* packet, unsigned int len, struct sr_if* in_f, uint8_t type, uint8_t code) { if (type == dest_net_unreach_type && code == dest_net_unreach_code) { send_icmp_error(sr, packet, in_f, type, code); } else if (type == dest_host_unreach_type && code == dest_host_unreach_code) { send_icmp_error(sr, packet, in_f, type, code); } else if (type == port_unreach_type && code == port_unreach_code) { send_icmp_error(sr, packet, in_f, type, code); } else if (type == 11 && code == 0) { send_icmp_error(sr, packet, in_f, type, code); } else { /* Should never reach here, we've put in the wrong type or code */ return; } }
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 */