void print_packet(const struct sniff_ethernet *eth, const struct sniff_ip *ip, const struct sniff_tcp *tcp) { /* Ethernet */ printf("DADDR:"); print_ethernet_addr(eth->dest_host); printf("SADDR:"); print_ethernet_addr(eth->src_host); printf("TYPE:%u\n", eth->ether_type); /* IP */ printf( "\tVERSION: %u\n" "\tHEADER LENGTH: %u\n" "\tTOTAL LENGTH: %u\n" "\tTOS: %u\n" "\tTTL: %u\n", IP_VER(ip), IP_HL(ip), ip->ip_len, ip->ip_tos, ip->ip_ttl); /* TCP */ printf( "\t\tSPORT: %u\n" "\t\tDPORT: %u\n" "\t\tSEQ: %u\n" "\t\tACK: %u\n", ntohs(tcp->th_sport), ntohs(tcp->th_dport), tcp->th_seq, tcp->th_ack); }
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 on interface \"%s\"\n", len, interface); // Deconstruct the packet's ethernet header struct sr_ethernet_hdr *header = malloc(sizeof(struct sr_ethernet_hdr)); memcpy(header, packet, sizeof(struct sr_ethernet_hdr)); header->ether_type = htons(header->ether_type); // Determine proper routing behavior based on ether_type switch(header->ether_type) { case ETHERTYPE_ARP: { // Unpack the ARP header struct sr_arphdr *arp_header = malloc(sizeof(struct sr_arphdr)); memcpy(arp_header, packet + 14, sizeof(struct sr_arphdr)); arp_header->ar_op = ntohs(arp_header->ar_op); // Check the ARP opcode switch(arp_header->ar_op) { case ARP_REQUEST: handle_arp_request(sr, header, arp_header, interface); break; case ARP_REPLY: printf("\tIt's an ARP reply!\n"); add_arp_cache_entry(cache, arp_header->ar_sip, arp_header->ar_sha); struct in_addr addr = {arp_header->ar_sip}; printf("\tMapping %s to ", inet_ntoa(addr)); print_ethernet_addr(arp_header->ar_sha, stdout); printf("\n"); // Scan for packets we can retransmit struct ip_cache_entry *cache_entry = next_packet_with_dest(ip_cache, addr); struct sr_if *iface = sr_get_interface(sr, interface); while(cache_entry) { // Wrap the IP packet in an ethernet header uint8_t *wrapped_packet = pack_ethernet_packet(arp_header->ar_sha, iface->addr, ETHERTYPE_IP, cache_entry->packet, cache_entry->len); // Send the newly wrapped packet sr_send_packet(sr, wrapped_packet, sizeof(struct sr_ethernet_hdr) + cache_entry->len, iface->name); // TODO: We're dumb are forgot this cache_entry = next_packet_with_dest(ip_cache, addr); } break; } break; } case ETHERTYPE_IP: { // TODO printf("\tIt's an IP packet!\n"); route_ip_packet(sr, packet, len, interface); break; } default: { printf("\tIt's an unknown packet type (ether_type = 0x%X)\n", header->ether_type); break; } } } /* end sr_ForwardPacket */
static void route_ip_packet(struct sr_instance *sr, uint8_t *packet, size_t len, char *interface) { // Copy the IP header struct ip *ip_header = calloc(1, sizeof(struct ip)); memcpy(ip_header, packet + sizeof(struct sr_ethernet_hdr), sizeof(struct ip)); // The IP header is a dirty liar int actual_header_length = ip_header->ip_hl * 4; int ip_packet_len = len - sizeof(struct sr_ethernet_hdr); // Decrement the TTL and check if it's 0 ip_header->ip_ttl -= 1; if(ip_header->ip_ttl <= 0) { return; } // Zero out the old checksum ip_header->ip_sum = 0; // Create a buffer to calculate the checksum uint16_t *header_buffer; // Create a chunk of memory aligned to 16 bits posix_memalign((void **) &header_buffer, CHECKSUM_ALIGNMENT, actual_header_length); bzero(header_buffer, actual_header_length); // Copy required IP header fields memcpy(header_buffer, ip_header, sizeof(struct ip)); // Copy the original IP header flags memcpy(header_buffer, packet + sizeof(struct sr_ethernet_hdr) + sizeof(struct ip), actual_header_length - sizeof(struct ip)); // Calculate the new checksum ip_header->ip_sum = header_checksum(header_buffer, actual_header_length / 2); free(header_buffer); // Get the IP packet's destination struct in_addr destination_addr = ip_header->ip_dst; uint32_t destination_ip = destination_addr.s_addr; // Check if we're the destination struct sr_if *iface = sr_get_interface(sr, interface); if(destination_ip == iface->ip) { printf("Dropping packet bound for router on %s\n", interface); return; } // Check the routing table for the correct gateway to forward the packet through struct sr_rt *table_entry = search_routing_table(sr, destination_ip); printf("\tThe nexthop is %s\n", inet_ntoa(table_entry->gw)); if(table_entry) { // Get the interface for the gateway struct sr_if *gw_iface = sr_get_interface(sr, table_entry->interface); // Determine the IP to forward to struct in_addr nexthop; // Determine if the IP to forward to is in our network if(table_entry->gw.s_addr == 0) { nexthop = destination_addr; } else { nexthop = table_entry->gw; } // Create an updated IP packet with the correct headers/data uint8_t *updated_packet = calloc(ip_packet_len, sizeof(uint8_t)); memcpy(updated_packet, ip_header, actual_header_length); memcpy(updated_packet + actual_header_length, packet + sizeof(struct sr_ethernet_hdr ) + actual_header_length, len - sizeof(struct sr_ethernet_hdr ) - actual_header_length); // Search the ARP cache for the nexthop uint8_t *gw_addr = search_arp_cache(cache, nexthop.s_addr); if(gw_addr) { printf("\tForwarding packet bound for %s through next hop @ ", inet_ntoa(destination_addr)); printf("%s (", inet_ntoa(table_entry->gw)); print_ethernet_addr(gw_addr, stdout); printf(")\n"); uint8_t *buffer = pack_ethernet_packet(gw_addr, gw_iface->addr, ETHERTYPE_IP, updated_packet, ip_packet_len); sr_send_packet(sr, buffer, len, gw_iface->name); } else { // Otherwise we cache the IP packet and make an ARP request printf("\tSending ARP request to %s (%s), to forward packet bound for ", inet_ntoa(nexthop), gw_iface->name); printf("%s\n", inet_ntoa(destination_addr)); add_ip_cache_entry(ip_cache, updated_packet, nexthop, ip_packet_len); send_arp_request(sr, gw_iface, nexthop); } } else { // TODO: What do we do here? } }