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++; } } }
int sr_handle_arp_req (struct sr_instance * sr, struct sr_arpreq * arpreq) { assert(arpreq); time_t now; time(&now); int res; if (difftime(now, arpreq->sent) <= 1.0){ return 0; } if (arpreq->times_sent >= 5){ /* send icmp host unreachable to source addr of all pkts waiting on this request type 3 code 1*/ struct sr_packet *packet_walker = arpreq->packets; while (packet_walker){ res = send_icmp_message(sr, packet_walker->buf, 3, 1); if (res == -1){ return -1; } } sr_arpreq_destroy(&(sr->cache), arpreq); } int minlength = sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t); uint8_t arpbuf[minlength]; memset(arpbuf, 0, minlength); struct sr_ethernet_hdr * eth_hdr = (struct sr_ethernet_hdr *) arpbuf; struct sr_arp_hdr * arp_hdr = (struct sr_arp_hdr *) (arpbuf + sizeof(sr_ethernet_hdr_t)); /* make sure its an ARP ethernet packet */ eth_hdr->ether_type = ntohs(ethertype_arp); /* make the dest address FF:FF:FF:FF:FF:FF */ int i; for (i = 0; i < ETHER_ADDR_LEN; i++){ eth_hdr->ether_dhost[i] = 0xff; } struct sr_rt* best_rt = find_best_rt(sr->routing_table, ntohl( arpreq->ip)); if (!best_rt) { /* TODO: didn't find an interface, send an ICMP message type 3 code 0, also if there are any errors above */ return 0; } struct sr_if* best_if = sr_get_interface(sr, best_rt->interface); /* set arp hdr params */ arp_hdr->ar_hrd = ntohs(1); arp_hdr->ar_pro = ntohs(2048); arp_hdr->ar_hln = 6; arp_hdr->ar_pln = 4; arp_hdr->ar_op = ntohs(arp_op_request); /* set eth hdr source mac address */ memcpy(eth_hdr->ether_shost, best_if->addr, ETHER_ADDR_LEN); /* set arp hdr source mac address */ memcpy(arp_hdr->ar_sha, best_if->addr, ETHER_ADDR_LEN); /* set arp hdr dest mac address to FF:FF:FF:FF:FF:FF */ memcpy(arp_hdr->ar_tha, eth_hdr->ether_dhost, ETHER_ADDR_LEN); /* set appropriate IPs */ arp_hdr->ar_sip = best_if->ip; arp_hdr->ar_tip = arpreq->ip; /* send packet using correct interface */ res = 0; res = sr_send_packet(sr, arpbuf, minlength,best_if->name ); if (res != 0) { return -1; } arpreq->sent = now; arpreq->times_sent++; return 0; }
int handle_ip_packet(struct sr_instance * sr, uint8_t * packet, unsigned int len ) { sr_ip_hdr_t *iphdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t)); /* validate checksum. */ uint16_t checksum; checksum = cksum(iphdr, sizeof(*iphdr)); if (checksum != 0xffff) { return -1; } uint8_t * newpacket_for_ip = (uint8_t *) malloc(len); memcpy(newpacket_for_ip, packet, len); sr_ip_hdr_t *new_iphdr = (sr_ip_hdr_t *)(newpacket_for_ip + sizeof(sr_ethernet_hdr_t)); /* Decrement the TTL by 1, and recompute the packet checksum over the modified header. */ /* decrement ttl */ new_iphdr->ip_ttl--; if (new_iphdr->ip_ttl <= 0) { /* check ttl, less than zero */ send_icmp_message(sr,packet, 11, 0); return -1; } /* update checksum. */ new_iphdr->ip_sum = 0; checksum = cksum(new_iphdr, sizeof(*new_iphdr)); new_iphdr->ip_sum = checksum; checksum = cksum(new_iphdr, sizeof(*new_iphdr)); struct sr_if* assoc_iface = validate_ip(sr->if_list, iphdr->ip_dst); if (assoc_iface) { /*it's destined to one of our IPs */ /* ICMP */ uint8_t ip_proto = ip_protocol(packet + sizeof(sr_ethernet_hdr_t)); if (ip_proto == ip_protocol_icmp) { int minlength = sizeof(sr_icmp_hdr_t) + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t); if (len < minlength){ return -1; } struct sr_icmp_hdr * icmp_hdr = (struct sr_icmp_hdr *) (packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)); if(icmp_hdr->icmp_type == 8){ /* is an echo request */ int res; res = make_echo_request(&newpacket_for_ip, len); if (res == -1){ return -1; } } /* end ICMP */ } else { /* got a udp payload to a rounter interface */ int res; res = send_icmp_message(sr, packet, 3, 3); if (res == -1){ return -1; } } } /* Find out which entry in the routing table has the longest prefix match with the destination IP address. */ struct sr_rt* best_rt = find_best_rt(sr->routing_table, ntohl(new_iphdr->ip_dst)); if (!best_rt) { /* didn't find an interface, send an ICMP message type 3 code 0, also if there are any errors above */ int res = send_icmp_message(sr, packet, 3, 0); if (res == -1){ return -1; } return 0; } /* found an interface */ struct sr_if * best_iface = sr_get_interface(sr, best_rt->interface); if (!best_iface){ return -1; } struct sr_arpentry * forward_arp_entry = sr_arpcache_lookup(&(sr->cache), best_rt->gw.s_addr); struct sr_ethernet_hdr * new_ether_hdr = (struct sr_ethernet_hdr * ) newpacket_for_ip; /* ethernet -- update the source address */ memcpy(new_ether_hdr->ether_shost, best_iface->addr, ETHER_ADDR_LEN); if (forward_arp_entry) { /* we have a MAC address */ /* update packet */ /* ethernet -- set the dest address */ memcpy(new_ether_hdr->ether_dhost, forward_arp_entry->mac, ETHER_ADDR_LEN); /* send packet using correct interface */ int res = 0; res = sr_send_packet(sr, newpacket_for_ip, len, best_rt->interface); if (res != 0) { return -1; } free(forward_arp_entry); } else { /* we dont have a MAC address, add to arp queue */ struct sr_arpreq * arpreq; arpreq = sr_arpcache_queuereq(&(sr->cache), best_rt->gw.s_addr, newpacket_for_ip, len, best_rt->interface ); if (!arpreq){ return -1; } uint32_t ip, dest; ip = ntohl(best_iface->ip); dest = ntohl(best_rt->dest.s_addr); sr_handle_arp_req(sr, arpreq); } return 0; }