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 handle_arp_reply(struct sr_instance *sr, uint8_t* ethernet_data_addr, struct sr_if* in_f){ printf("in handle arp reply\n"); /* The ARP reply processing code should move entries from the ARP request queue to the ARP cache: # When servicing an arp reply that gives us an IP->MAC mapping req = arpcache_insert(ip, mac) if req: send all packets on the req->packets linked list arpreq_destroy(req) */ /*Loop through sr_cache requests and look for an IP match to the ARP header source IP*/ sr_arp_hdr_t *arp_header = (sr_arp_hdr_t *) ethernet_data_addr; struct sr_arpreq *req_ptr = sr_arpcache_insert(&(sr->cache), arp_header->ar_sha, arp_header->ar_sip); /*If the IP in the reply matched something in our request queue*/ if (req_ptr) { struct sr_packet *req_pkts = req_ptr->packets; struct sr_packet *req_pkt_ptr = req_pkts; for (; req_pkt_ptr; req_pkt_ptr = req_pkt_ptr->next) { sr_ethernet_hdr_t *packet_eth_hdr = (sr_ethernet_hdr_t *) req_pkts->buf; sr_ip_hdr_t *packet_ip_hdr = (sr_ip_hdr_t *) (req_pkts->buf + sizeof(sr_ethernet_hdr_t)); /*ret_if will be populated if this was originally an echo request, else 0*/ struct sr_if* ret_if = sr_get_interface_from_ip(sr, packet_ip_hdr->ip_dst); if (ret_if) { /*Doesn't have a code so just passing 0 as code*/ send_icmp_echo_reply(sr, (uint8_t *) packet_eth_hdr, req_pkt_ptr->len, in_f, arp_header->ar_sha, echo_reply_type, 0); } else { memcpy(packet_eth_hdr->ether_dhost, arp_header->ar_sha, ETHER_ADDR_LEN); sr_send_packet(sr, (uint8_t *) packet_eth_hdr, req_pkt_ptr->len, in_f->name); } } sr_arpreq_destroy(&(sr->cache), req_ptr); } /*Otherwise do nothing, the reply wasn't about anything in our queue*/ }
/*Returns 0 on success and error code on fail*/ int sr_handlearp(struct sr_instance** sr, uint8_t** ethernet_data_addr, struct sr_if* in_f, unsigned int len){ uint8_t *eth_pkt_buf; uint8_t *arp_pkt_buf; /* ARP packet buffer */ struct sr_if* ret_if; /* return interface */ printf("sr_handlearp"); sr_arp_hdr_t* arp_header_buffer = (sr_arp_hdr_t*)*ethernet_data_addr; ntoh_arp_hdr(&arp_header_buffer); /* converts header members into host byte order where appropriate */ /* Recieved ARP request! Reply to request. */ if(arp_header_buffer->ar_op == arp_op_request) { if ((ret_if = sr_get_interface_from_ip(*sr, arp_header_buffer->ar_tip))) { /* Target IP is IP of a Router Interface*/ /* Send an ARP reply (uint8_t*) */ /* Create reply frame */ eth_pkt_buf = (uint8_t *) malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t)); /* Allocate mem for reply packet buffer */ sr_ethernet_hdr_t *req_reply_eth_header = (sr_ethernet_hdr_t *) eth_pkt_buf; /* Build Ethernet Header */ memcpy(req_reply_eth_header->ether_dhost, arp_header_buffer->ar_sha, ETHER_ADDR_LEN); memcpy(req_reply_eth_header->ether_shost, in_f->addr, ETHER_ADDR_LEN); req_reply_eth_header->ether_type = ethertype_arp; /* Convert to network byte ordering */ hton_eth_hdr(&req_reply_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_packet(&arp_pkt_buf, arp_header_buffer, ret_if); /* Create arp packet to be sent as ARP reply, fill arp_pkt_buf with ARP reply header data */ /* Send the ARP reply packet */ sr_send_packet(*sr, eth_pkt_buf, sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t), in_f->name); free(eth_pkt_buf); } else { /* Target IP is *NOT* IP of a Router Interface */ /* I'm not sure what to do here yet MAYBE NOTHING?!*/ } } else if (arp_header_buffer->ar_op == arp_op_reply) { handle_arp_reply(*sr, *ethernet_data_addr, in_f); } return 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); } } }
void sr_natHandleIP(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; uint8_t* ip_packet = packet+sizeof(sr_ethernet_hdr_t); sr_ip_hdr_t * ipHeader = (sr_ip_hdr_t *) (ip_packet); uint16_t incm_cksum = ipHeader->ip_sum; ipHeader->ip_sum = 0; uint16_t currentChecksum = cksum(ip_packet,20); ipHeader->ip_sum = incm_cksum; uint8_t* icmp_packet; /* if the destination address is one of my interfaces */ if (currentChecksum==incm_cksum && sr_get_interface_from_ip(sr,ntohl(ipHeader->ip_dst)) != NULL){ /* check cache for ip->mac mapping for next hop */ /*struct sr_arpentry *entry; entry = sr_arpcache_lookup(&sr->cache, ipHeader->ip_dst); struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, ipHeader->ip_dst); */ /* found next hop. send packet */ if (ipHeader->ip_ttl <= 1){ /* IP TTL died. send ICMP type 11, code 0 */ icmp_packet = createICMP(11, 0, ip_packet,len-14); memcpy(ip_packet+20,icmp_packet,sizeof(sr_icmp_t3_hdr_t)); ipHeader->ip_p = 1; ipHeader->ip_len = htons(20+8+(len-34<28?len-34:28)); free(icmp_packet); } else if(ipHeader->ip_p==6){ /* IP TCP */ icmp_packet = createICMP(3,3,ip_packet,len-14); memcpy(ip_packet+20,icmp_packet,sizeof(sr_icmp_t3_hdr_t)); ipHeader->ip_p = 1; ipHeader->ip_len = htons(20+8+(len-34<28?len-34:28)); free(icmp_packet); }else if(ipHeader->ip_tos==0 && ipHeader->ip_p==1){ /* IP ping */ sr_icmp_hdr_t * icmp_header = (sr_icmp_hdr_t *) (packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)); incm_cksum = icmp_header->icmp_sum; icmp_header->icmp_sum = 0; currentChecksum = cksum(icmp_header,len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t)); if(currentChecksum == incm_cksum && icmp_header->icmp_type == 8 && icmp_header->icmp_code == 0) { icmp_header->icmp_type = 0; ipHeader->ip_sum = 0; icmp_header->icmp_sum = cksum(icmp_header,len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t)); } else{ printf("ICMP INVALID\n"); printf("%d != %d OR %d != %d\n",currentChecksum,incm_cksum, icmp_header->icmp_type, 8); } } else { printf("IP Bad\n"); ip_packet = NULL; } } else{ printf("IP INVALID\n"); ip_packet = NULL; } if(ip_packet){ /* send ICMP packet */ ipHeader->ip_dst = ipHeader->ip_src; ipHeader->ip_src = iface->ip; ipHeader->ip_ttl = 64; ipHeader->ip_sum = 0; ipHeader->ip_sum = cksum(ip_packet,20); struct sr_arpentry *entry; entry = sr_arpcache_lookup(&sr->cache, ipHeader->ip_dst); struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, ipHeader->ip_dst); if (entry && rt) { /* found next hop. send packet */ iface = sr_get_interface(sr, rt->interface); set_addr(ethHeader, iface->addr, entry->mac); sr_send_packet(sr,packet,len,iface->name); free(entry); ip_packet = NULL; } else if (rt) { /* send an arp request to find out what the next hop should be */ struct sr_arpreq *req; sr_arpcache_insert(&(sr->cache), ethHeader->ether_shost, ipHeader->ip_src); req = sr_arpcache_queuereq(&(sr->cache), ipHeader->ip_dst, packet, len, iface->name); /*handle_arpreq(sr, req);*/ ip_packet = NULL; } } }
/*Returns 0 on success and error code on fail*/ int sr_handleip(struct sr_instance* sr, uint8_t* packet, unsigned int len, struct sr_if* in_f, uint8_t** ethernet_data_addr){ sr_ip_hdr_t* ip_header_buffer = (sr_ip_hdr_t*) *ethernet_data_addr; /* Get headers from packet */ /*sr_ethernet_hdr_t* eth_hdr = (sr_ethernet_hdr_t*) packet; uint8_t * ip_pkt_buf = packet + sizeof(sr_ethernet_hdr_t); sr_ip_hdr_t* ip_hdr = (sr_ip_hdr_t*) (packet + sizeof(sr_ethernet_hdr_t)); */ uint8_t * icmp_pkt_buf = packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t); sr_icmp_hdr_t* icmp_hdr = (sr_icmp_hdr_t*) icmp_pkt_buf; struct sr_if* ret_if; /* return interface */ if (check_ip_sum(ip_header_buffer) == 0) { /*Pass Checksum*/ printf("Checksum Pass\n"); } else { /*Fail Checksum*/ printf("Checksum Fail\n"); return -1; } /*If the TTL went to 0*/ if (decrement_ttl(ip_header_buffer) == -1) { /*Send ICMP with the proper TTL decrease type and icmp code*/ printf("TTL reached 0\n"); send_icmp(sr, packet, len, in_f, time_exceed_type, time_exceed_code); return -1; } /*Check if the IP packet is for us and not a echo request*/ ret_if = sr_get_interface_from_ip(sr, ip_header_buffer->ip_dst); if(ret_if && !(ip_header_buffer->ip_p == ip_protocol_icmp && icmp_hdr->icmp_type == echo_req_type && icmp_hdr->icmp_code == echo_req_code)) { /* The IP packet is FOR US */ printf("FOR US, NOT ECHO REQ"); /* Check if it is an echo request */ if (ip_header_buffer->ip_p == ip_protocol_tcp || ip_header_buffer->ip_p == ip_protocol_udp) { /* It is TCP/UDP send ICMP port unreachable SEND: an ICMP port unreachable to sending host*/ send_icmp(sr, packet, len, in_f, port_unreach_type, port_unreach_code); } else { ; /* According to the Assignment: IGNORE THE PACKET*/ } } else { /*If it's not in the routing table, send ICMP net unreachable*/ struct sr_rt * routing_node; uint32_t ip_dest; /*If it's for us, we want to send back to the source, so check for the source in the routing table*/ if (ret_if) { /* The IP packet is FOR US */ printf("FOR US\n"); ip_dest = ip_header_buffer->ip_src; } /*If not for us, we want to keep forwarding to the destination so check for that in the routing table*/ else { /* The IP packet is NOT FOR US */ printf("NOT FOR US\n"); ip_dest = ip_header_buffer->ip_dst; } if ((routing_node = check_routing_table(sr, ip_dest)) == NULL) { printf("NOT in routing table\n"); send_icmp(sr, packet, len, in_f, dest_net_unreach_type, dest_net_unreach_code); } else { printf("In routing table\n"); /*Got the routing table node in routing_node */ /*Next hop IP address is in gateway *Look it up in arpcache_lookup to see if we know the MAC address */ uint32_t nexthopIP = routing_node->gw.s_addr; struct sr_arpentry *arp_dest = sr_arpcache_lookup(&(sr->cache), nexthopIP); struct sr_if* nexthopInterface = sr_get_interface(sr, routing_node->interface); /*Create an ethernet header in front of the packet to forward regardless of whether or not we've found the next hop IP: need it in both cases*/ /*Allocate space for ethernet header and packet, copy in contents of packet*/ uint8_t* eth_header_packet = malloc(len); uint8_t* ip_header = eth_header_packet + sizeof(sr_ethernet_hdr_t); uint8_t* only_packet = eth_header_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t); memcpy(ip_header, ip_header_buffer, sizeof(sr_ip_hdr_t)); memcpy(only_packet, (packet+sizeof(sr_ethernet_hdr_t)+sizeof(sr_ip_hdr_t)), len-sizeof(sr_ethernet_hdr_t)-sizeof(sr_ip_hdr_t)); /*Save it in struct form*/ sr_ethernet_hdr_t* packet_to_forward = (sr_ethernet_hdr_t*)eth_header_packet; /*Now set the actual ethernet header for the packet*/ packet_to_forward->ether_type = htons(ethertype_ip); memcpy(packet_to_forward->ether_shost, nexthopInterface->addr, ETHER_ADDR_LEN); /*If NULL, send out the arp request*/ if(arp_dest == NULL){ printf("Not in arp cache: need to send an ARP request!\n"); broadcast_arp_req(sr, nexthopIP, packet_to_forward, len, routing_node, nexthopInterface); } /*Otherwise just forward the packet to arp_dest's MAC address*/ else { /*It's for us, it must be an echo request*/ if (ret_if) { /*Doesn't have a code so just passing 0 as code*/ struct sr_if *interface = sr_get_interface(sr, routing_node->interface); send_icmp_echo_reply(sr, packet, len, interface, arp_dest->mac, echo_reply_type, 0); } else { printf("In arp cache: just forwarding the packet\n"); memcpy(packet_to_forward->ether_dhost, arp_dest->mac, ETHER_ADDR_LEN); sr_send_packet(sr, (uint8_t*)packet_to_forward, len, routing_node->interface); /*Free the arp_dest that sr_arpcache_lookup created*/ free(arp_dest); } } } } return 0; }
void sr_handle_arp(struct sr_instance *sr, uint8_t *packet, unsigned int len, struct sr_if *iface) { assert(sr); assert(packet); assert(iface); /* check length */ if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t)) { fprintf(stderr, "Failed to process ARP header, insufficient length\n"); return; } sr_arp_hdr_t *arp_hdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t)); /* print_hdr_arp((uint8_t *)arp_hdr); */ /* check hardware type */ if (ntohs(arp_hdr->ar_hrd) != arp_hrd_ethernet) { return; } /* check protocol */ if (ntohs(arp_hdr->ar_pro) != ethertype_ip) { return; } /* is it for me? */ struct sr_if *tiface = sr_get_interface_from_ip(sr, arp_hdr->ar_tip); if (!tiface) { return; } unsigned short arp_op = ntohs(arp_hdr->ar_op); if (arp_op == arp_op_request) { sr_send_arp_reply(sr, packet, iface, tiface); } else if (arp_op == arp_op_reply) { struct sr_arpreq *req = sr_arpcache_insert(&(sr->cache), arp_hdr->ar_sha, arp_hdr->ar_sip); if (req) { struct sr_packet *pkt = NULL; struct sr_if *oiface = NULL; sr_ethernet_hdr_t *eth_hdr = NULL; pkt = req->packets; while (pkt) { oiface = sr_get_interface(sr, pkt->iface); eth_hdr = (sr_ethernet_hdr_t *)(pkt->buf); memcpy(eth_hdr->ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN); memcpy(eth_hdr->ether_shost, oiface->addr, ETHER_ADDR_LEN); sr_send_packet(sr, pkt->buf, pkt->len, pkt->iface); pkt = pkt->next; } sr_arpreq_destroy(&(sr->cache), req); } } } /* -- sr_handle_arp -- */