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++; } } }
static enum ofp_return_code ofp_ip_output_add_eth(odp_packet_t pkt, struct ip_out *odata) { uint8_t l2_size = 0; void *l2_addr; if (!odata->gw) /* link local */ odata->gw = odata->ip->ip_dst.s_addr; if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port)) l2_size = sizeof(struct ofp_ether_header); else l2_size = sizeof(struct ofp_ether_vlan_header); if (odp_packet_l2_offset(pkt) + l2_size == odp_packet_l3_offset(pkt)) { l2_addr = odp_packet_l2_ptr(pkt, NULL); } else if (odp_packet_l3_offset(pkt) >= l2_size) { odp_packet_l2_offset_set(pkt, odp_packet_l3_offset(pkt) - l2_size); l2_addr = odp_packet_l2_ptr(pkt, NULL); } else { l2_addr = odp_packet_push_head(pkt, l2_size - odp_packet_l3_offset(pkt)); odp_packet_l2_offset_set(pkt, 0); odp_packet_l3_offset_set(pkt, l2_size); odp_packet_l4_offset_set(pkt, l2_size + (odata->ip->ip_hl<<2)); } if (odp_unlikely(l2_addr == NULL)) { OFP_DBG("l2_addr == NULL"); return OFP_PKT_DROP; } if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port)) { struct ofp_ether_header *eth = (struct ofp_ether_header *)l2_addr; uint32_t addr = odp_be_to_cpu_32(odata->ip->ip_dst.s_addr); if (OFP_IN_MULTICAST(addr)) { eth->ether_dhost[0] = 0x01; eth->ether_dhost[1] = 0x00; eth->ether_dhost[2] = 0x5e; eth->ether_dhost[3] = (addr >> 16) & 0x7f; eth->ether_dhost[4] = (addr >> 8) & 0xff; eth->ether_dhost[5] = addr & 0xff; } else if (odata->dev_out->ip_addr == odata->ip->ip_dst.s_addr) { odata->is_local_address = 1; ofp_copy_mac(eth->ether_dhost, &(odata->dev_out->mac[0])); } else if (ofp_get_mac(odata->dev_out, odata->gw, eth->ether_dhost) < 0) { send_arp_request(odata->dev_out, odata->gw); return ofp_arp_save_ipv4_pkt(pkt, odata->nh, odata->gw, odata->dev_out); } ofp_copy_mac(eth->ether_shost, odata->dev_out->mac); eth->ether_type = odp_cpu_to_be_16(OFP_ETHERTYPE_IP); } else {
void arp_queue_add(struct sr_instance* sr, uint8_t* packet, unsigned int len, const char* out_iface_name, struct in_addr *next_hop) { assert(sr); assert(packet); assert(out_iface_name); assert(next_hop); router_state *rs = get_router_state(sr); /* Is there an existing queue entry for this IP? */ arp_queue_entry* aqe = get_from_arp_queue(sr, next_hop); if (!aqe) { /* create a new queue entry */ aqe = (arp_queue_entry*)malloc(sizeof(arp_queue_entry)); bzero(aqe, sizeof(arp_queue_entry)); memcpy(aqe->out_iface_name, out_iface_name, IF_LEN); aqe->next_hop = *next_hop; /* send a request */ time(&(aqe->last_req_time)); aqe->requests = 1; send_arp_request(sr, next_hop->s_addr, out_iface_name); arp_queue_entry_add_packet(aqe, packet, len); /* create a node, add this entry to the node, and push it into our linked list */ node* n = node_create(); n->data = aqe; if (rs->arp_queue == NULL) { rs->arp_queue = n; } else { node_push_back(rs->arp_queue, n); } } else { /* entry exists, just add the packet */ arp_queue_entry_add_packet(aqe, packet, len); } }
void handle_arpreq(struct sr_instance* sr, struct sr_arpreq* req) { time_t curtime = time(NULL); if (difftime(curtime,req->sent) > 1.0) { if (req->times_sent >= 5) { struct sr_packet* sr_pckt = req->packets; while (sr_pckt != NULL) { send_icmp_destination_host_unreachable(sr, sr_pckt->buf, sr_pckt->len); sr_pckt = sr_pckt->next; } sr_arpreq_destroy(&sr->cache, req); } else { send_arp_request(sr, req); req->sent = curtime; req->times_sent = req->times_sent + 1; } } }
int zcip_main(int argc UNUSED_PARAM, char **argv) { char *r_opt; const char *l_opt = "169.254.0.0"; int state; int nsent; unsigned opts; // Ugly trick, but I want these zeroed in one go struct { const struct ether_addr null_ethaddr; struct ifreq ifr; uint32_t chosen_nip; int conflicts; int timeout_ms; // must be signed int verbose; } L; #define null_ethaddr (L.null_ethaddr) #define ifr (L.ifr ) #define chosen_nip (L.chosen_nip ) #define conflicts (L.conflicts ) #define timeout_ms (L.timeout_ms ) #define verbose (L.verbose ) memset(&L, 0, sizeof(L)); INIT_G(); #define FOREGROUND (opts & 1) #define QUIT (opts & 2) // Parse commandline: prog [options] ifname script // exactly 2 args; -v accumulates and implies -f opt_complementary = "=2:vv:vf"; opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose); #if !BB_MMU // on NOMMU reexec early (or else we will rerun things twice) if (!FOREGROUND) bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv); #endif // Open an ARP socket // (need to do it before openlog to prevent openlog from taking // fd 3 (sock_fd==3)) xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd); if (!FOREGROUND) { // do it before all bb_xx_msg calls openlog(applet_name, 0, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } bb_logenv_override(); { // -l n.n.n.n struct in_addr net; if (inet_aton(l_opt, &net) == 0 || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr ) { bb_error_msg_and_die("invalid network address"); } G.localnet_ip = ntohl(net.s_addr); } if (opts & 4) { // -r n.n.n.n struct in_addr ip; if (inet_aton(r_opt, &ip) == 0 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip ) { bb_error_msg_and_die("invalid link address"); } chosen_nip = ip.s_addr; } argv += optind - 1; /* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */ /* We need to make space for script argument: */ argv[0] = argv[1]; argv[1] = argv[2]; /* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */ #define argv_intf (argv[0]) xsetenv("interface", argv_intf); // Initialize the interface (modprobe, ifup, etc) if (run(argv, "init", 0)) return EXIT_FAILURE; // Initialize G.iface_sockaddr // G.iface_sockaddr is: { u16 sa_family; u8 sa_data[14]; } //memset(&G.iface_sockaddr, 0, sizeof(G.iface_sockaddr)); //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?! safe_strncpy(G.iface_sockaddr.sa_data, argv_intf, sizeof(G.iface_sockaddr.sa_data)); // Bind to the interface's ARP socket xbind(sock_fd, &G.iface_sockaddr, sizeof(G.iface_sockaddr)); // Get the interface's ethernet address //memset(&ifr, 0, sizeof(ifr)); strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf); xioctl(sock_fd, SIOCGIFHWADDR, &ifr); memcpy(&G.our_ethaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); // Start with some stable ip address, either a function of // the hardware address or else the last address we used. // we are taking low-order four bytes, as top-order ones // aren't random enough. // NOTE: the sequence of addresses we try changes only // depending on when we detect conflicts. { uint32_t t; move_from_unaligned32(t, ((char *)&G.our_ethaddr + 2)); t += getpid(); srand(t); } // FIXME cases to handle: // - zcip already running! // - link already has local address... just defend/update // Daemonize now; don't delay system startup if (!FOREGROUND) { #if BB_MMU bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); #endif bb_info_msg("start, interface %s", argv_intf); } // Run the dynamic address negotiation protocol, // restarting after address conflicts: // - start with some address we want to try // - short random delay // - arp probes to see if another host uses it // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 tell 0.0.0.0 // - arp announcements that we're claiming it // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 (00:04:e2:64:23:c2) tell 169.254.194.171 // - use it // - defend it, within limits // exit if: // - address is successfully obtained and -q was given: // run "<script> config", then exit with exitcode 0 // - poll error (when does this happen?) // - read error (when does this happen?) // - sendto error (in send_arp_request()) (when does this happen?) // - revents & POLLERR (link down). run "<script> deconfig" first if (chosen_nip == 0) { new_nip_and_PROBE: chosen_nip = pick_nip(); } nsent = 0; state = PROBE; while (1) { struct pollfd fds[1]; unsigned deadline_us; struct arp_packet p; int ip_conflict; int n; fds[0].fd = sock_fd; fds[0].events = POLLIN; fds[0].revents = 0; // Poll, being ready to adjust current timeout if (!timeout_ms) { timeout_ms = random_delay_ms(PROBE_WAIT); // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to // make the kernel filter out all packets except // ones we'd care about. } // Set deadline_us to the point in time when we timeout deadline_us = MONOTONIC_US() + timeout_ms * 1000; VDBG("...wait %d %s nsent=%u\n", timeout_ms, argv_intf, nsent); n = safe_poll(fds, 1, timeout_ms); if (n < 0) { //bb_perror_msg("poll"); - done in safe_poll return EXIT_FAILURE; } if (n == 0) { // timed out? VDBG("state:%d\n", state); switch (state) { case PROBE: // No conflicting ARP packets were seen: // we can progress through the states if (nsent < PROBE_NUM) { nsent++; VDBG("probe/%u %s@%s\n", nsent, argv_intf, nip_to_a(chosen_nip)); timeout_ms = PROBE_MIN * 1000; timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); send_arp_request(0, &null_ethaddr, chosen_nip); continue; } // Switch to announce state nsent = 0; state = ANNOUNCE; goto send_announce; case ANNOUNCE: // No conflicting ARP packets were seen: // we can progress through the states if (nsent < ANNOUNCE_NUM) { send_announce: nsent++; VDBG("announce/%u %s@%s\n", nsent, argv_intf, nip_to_a(chosen_nip)); timeout_ms = ANNOUNCE_INTERVAL * 1000; send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip); continue; } // Switch to monitor state // FIXME update filters run(argv, "config", chosen_nip); // NOTE: all other exit paths should deconfig... if (QUIT) return EXIT_SUCCESS; // fall through: switch to MONITOR default: // case DEFEND: // case MONITOR: (shouldn't happen, MONITOR timeout is infinite) // Defend period ended with no ARP replies - we won timeout_ms = -1; // never timeout in monitor state state = MONITOR; continue; } } // Packet arrived, or link went down. // We need to adjust the timeout in case we didn't receive // a conflicting packet. if (timeout_ms > 0) { unsigned diff = deadline_us - MONOTONIC_US(); if ((int)(diff) < 0) { // Current time is greater than the expected timeout time. diff = 0; } VDBG("adjusting timeout\n"); timeout_ms = (diff / 1000) | 1; // never 0 } if ((fds[0].revents & POLLIN) == 0) { if (fds[0].revents & POLLERR) { // FIXME: links routinely go down; // this shouldn't necessarily exit. bb_error_msg("iface %s is down", argv_intf); if (state >= MONITOR) { // Only if we are in MONITOR or DEFEND run(argv, "deconfig", chosen_nip); } return EXIT_FAILURE; } continue; } // Read ARP packet if (safe_read(sock_fd, &p, sizeof(p)) < 0) { bb_perror_msg_and_die(bb_msg_read_error); } if (p.eth.ether_type != htons(ETHERTYPE_ARP)) continue; if (p.arp.arp_op != htons(ARPOP_REQUEST) && p.arp.arp_op != htons(ARPOP_REPLY) ) { continue; } #ifdef DEBUG { struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha; struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha; struct in_addr *spa = (struct in_addr *) p.arp.arp_spa; struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa; VDBG("source=%s %s\n", ether_ntoa(sha), inet_ntoa(*spa)); VDBG("target=%s %s\n", ether_ntoa(tha), inet_ntoa(*tpa)); } #endif ip_conflict = 0; if (memcmp(&p.arp.arp_sha, &G.our_ethaddr, ETH_ALEN) != 0) { if (memcmp(p.arp.arp_spa, &chosen_nip, 4) == 0) { // A probe or reply with source_ip == chosen ip ip_conflict = 1; } if (p.arp.arp_op == htons(ARPOP_REQUEST) && memcmp(p.arp.arp_spa, &const_int_0, 4) == 0 && memcmp(p.arp.arp_tpa, &chosen_nip, 4) == 0 ) { // A probe with source_ip == 0.0.0.0, target_ip == chosen ip: // another host trying to claim this ip! ip_conflict |= 2; } } VDBG("state:%d ip_conflict:%d\n", state, ip_conflict); if (!ip_conflict) continue; // Either src or target IP conflict exists if (state <= ANNOUNCE) { // PROBE or ANNOUNCE conflicts++; timeout_ms = PROBE_MIN * 1000 + CONFLICT_MULTIPLIER * random_delay_ms(conflicts); goto new_nip_and_PROBE; } // MONITOR or DEFEND: only src IP conflict is a problem if (ip_conflict & 1) { if (state == MONITOR) { // Src IP conflict, defend with a single ARP probe VDBG("monitor conflict - defending\n"); timeout_ms = DEFEND_INTERVAL * 1000; state = DEFEND; send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip); continue; } // state == DEFEND // Another src IP conflict, start over VDBG("defend conflict - starting over\n"); run(argv, "deconfig", chosen_nip); conflicts = 0; timeout_ms = 0; goto new_nip_and_PROBE; } // Note: if we only have a target IP conflict here (ip_conflict & 2), // IOW: if we just saw this sort of ARP packet: // aa:bb:cc:dd:ee:ff > xx:xx:xx:xx:xx:xx arp who-has <chosen_nip> tell 0.0.0.0 // we expect _kernel_ to respond to that, because <chosen_nip> // is (expected to be) configured on this iface. } // while (1) #undef argv_intf }
void main() { struct hw_ip_pair *hi_pair; char IP_str[20], cache_hw_addr[6]; fd_set rset; int cache_ifindex, cache_hatype; struct hw_addr HWaddr; hi_pair = malloc(sizeof(struct hw_ip_pair)); get_hw_ip_pair(hi_pair); printf("My IP :%s,\t HW addr", hi_pair->ip_addr); print_mac_to_string(hi_pair->hw_addr); printf("\n"); int pf_pack_sockfd = create_pf_pack_socket(); void* buffer = (void*)malloc(ETH_FRAME_LEN); int listen_sockfd, conn_sockfd, clilen, n; struct sockaddr_un servaddr, cliaddr; char sendline[MAXLINE], recvline[MAXLINE]; struct sockaddr_in *destIP = malloc(sizeof(struct sockaddr_in)); char ip_addr[20]; struct arp_packet *arp_req = malloc(sizeof(struct arp_packet)); struct arp_packet *arp_rep = malloc(sizeof(struct arp_packet)); struct arp_packet *arp_recv = malloc(sizeof(struct arp_packet)); struct sockaddr_ll socket_address; int ll_len = sizeof(struct sockaddr_ll); int i=0; listen_sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0); unlink(SUN_PATH_ARP); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, SUN_PATH_ARP); Bind(listen_sockfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listen_sockfd, LISTENQ); int lookup_flag=0; clilen = sizeof(struct sockaddr_un); while(1) { FD_ZERO(&rset); FD_SET(listen_sockfd, &rset); FD_SET(pf_pack_sockfd, &rset); FD_SET(conn_sockfd, &rset); int max; if(conn_sockfd != 0) max = max(max(listen_sockfd, conn_sockfd),pf_pack_sockfd); else max = max(listen_sockfd,pf_pack_sockfd); int ret = select(max+1, &rset, NULL, NULL, NULL); if(FD_ISSET(listen_sockfd, &rset)) { conn_sockfd = Accept(listen_sockfd, (SA *) &cliaddr, &clilen); /* n = read(conn_sockfd, destIP, sizeof(struct sockaddr_in)); Inet_ntop(AF_INET, &(destIP->sin_addr), ip_addr, 20); // Lookup for the <HW,IP> pair in the ARP cache lookup_arp_cache(ip_addr, cache_hw_addr, &cache_ifindex, &cache_hatype,&lookup_flag); if(lookup_flag == 0) { printf("Entry not found from cache\n"); create_arp_request_packet(arp_req, ip_addr, hi_pair); send_arp_request(pf_pack_sockfd, arp_req, hi_pair, conn_sockfd); } else{ printf("Entry found from cache\n"); // Send from cache HWaddr.sll_ifindex = cache_ifindex; HWaddr.sll_hatype = cache_hatype; HWaddr.sll_halen = sizeof(cache_hatype); memcpy(HWaddr.mac_addr, cache_hw_addr,6); print_mac_to_string(HWaddr.mac_addr); Write(conn_sockfd, (void *)&HWaddr, sizeof(HWaddr)); close(conn_sockfd); } printf("Sent ARP request\n"); */ } else if(ret!= -1 && FD_ISSET(conn_sockfd, &rset)) { n = read(conn_sockfd, destIP, sizeof(struct sockaddr_in)); Inet_ntop(AF_INET, &(destIP->sin_addr), ip_addr, 20); // Lookup for the <HW,IP> pair in the ARP cache lookup_arp_cache(ip_addr, cache_hw_addr, &cache_ifindex, &cache_hatype,&lookup_flag); if(lookup_flag == 0) { create_arp_request_packet(arp_req, ip_addr, hi_pair); printf("send 1\n"); send_arp_request(pf_pack_sockfd, arp_req, hi_pair, conn_sockfd); } else{ // Send from cache HWaddr.sll_ifindex = cache_ifindex; HWaddr.sll_hatype = cache_hatype; HWaddr.sll_halen = sizeof(cache_hatype); memcpy(HWaddr.mac_addr, cache_hw_addr,6); // print_mac_to_string(HWaddr.mac_addr); Write(conn_sockfd, (void *)&HWaddr, sizeof(HWaddr)); close(conn_sockfd); conn_sockfd = 0; } } else if(FD_ISSET(pf_pack_sockfd, &rset)) { Recvfrom(pf_pack_sockfd, buffer, ETH_FRAME_LEN, 0, (SA *)&socket_address, &ll_len); void *data = buffer + 14; arp_rep = (struct arp_packet *)data; if (arp_rep->id == ARP_ID){ if(arp_rep->op == ARP_REQ) { if(strcmp(arp_rep->dest_IP, hi_pair->ip_addr) == 0) { printf("Printing Ethernet Header and ARP Request Packet Received\n"); print_ethernet_and_arp(arp_rep->src_mac, arp_rep->dest_mac, arp_rep); add_to_arp_cache_list(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, socket_address.sll_hatype, conn_sockfd, 1); // print_arp_cache_list(); create_arp_reply_packet(arp_recv, arp_rep->src_IP, hi_pair, arp_rep->src_mac, arp_rep->id); send_arp_reply(pf_pack_sockfd, arp_recv, hi_pair, socket_address.sll_ifindex); } else { update_arp_cache(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, 0, conn_sockfd); } continue; } else if(arp_rep->op == ARP_REP) { if(ret == -1) { delete_from_arp_cache(arp_rep->src_IP); // print_arp_cache_list(); continue; } printf("Printing Ethernet Header and ARP Reply Packet Received\n"); print_ethernet_and_arp(arp_rep->src_mac, arp_rep->dest_mac, arp_rep); update_arp_cache(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, 0, conn_sockfd); // print_arp_cache_list(); HWaddr.sll_ifindex = socket_address.sll_ifindex; HWaddr.sll_hatype = socket_address.sll_hatype; HWaddr.sll_halen = socket_address.sll_halen; memcpy(HWaddr.mac_addr, arp_rep->src_mac,6); // print_mac_to_string(HWaddr.mac_addr); Write(conn_sockfd, (void *)&HWaddr, sizeof(HWaddr)); close(conn_sockfd); conn_sockfd = 0; update_arp_cache(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, 0, -1); // print_arp_cache_list(); } } } } }
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? } }
/** * \brief detect and resolve IP conflict * \param the ethernet interface entry in the MIB for which we change the IP * \param interface the name of this interface (eth0/enp2s0/lo...) * \return TRUE if conflict could be resolved, FALSE otherwise */ gboolean ip_conflict_detection( struct ethernetIfTableEntry *if_entry, gchar *interface ){ g_debug ("ip_conflict_detection()" ); /* select a random time to wait between 0 en PROBE_WAIT */ srand(time(NULL)); /* PROBE_WAIT is given in second, if we want a integer value for microsecond , we should multiply it by 1000000 */ gdouble probe_wait = ((gdouble) rand()/ (gdouble)(RAND_MAX)) * PROBE_WAIT; /* send PROB_NUM ARP PROBE messages between space randomly between PROBE_MIN and PROBE_MAX number*/ gdouble space = (((gdouble) rand()/ (gdouble)(RAND_MAX)) / (gdouble) ((PROBE_MAX - PROBE_MIN) * PROBE_NUM)); gdouble time_passed = 0 ; gboolean conflict = TRUE ; in_addr_t max_ip_value = inet_addr ( DEFAULT_STATIC_IP ) ; GTimer *timer = g_timer_new(); /* wait probe_wait */ g_debug ("waiting %G second(s)", probe_wait); g_timer_start( timer ); while(time_passed < probe_wait){ time_passed = g_timer_elapsed ( timer, NULL ); } int sending_socket_fd; struct sockaddr_ll sa; if ( !prepare_arp_request_socket (if_entry , &sending_socket_fd , &sa )){ g_critical("cannot prepare socket for ARP request"); return FALSE; } /* variable for the ethernet frame to build */ struct arp_packet pkt; int ethernet_frame_length; uint8_t *ethernet_frame; while ( conflict ){ /* build the ethernet frame */ ethernet_frame = init_ethernet_frame (if_entry , &pkt, ðernet_frame_length, TRUE ); if ( !ethernet_frame ){ g_critical("cannot build ethernet frame for ARP request"); return FALSE; } /* wait PROBE_MIN */ g_debug ("waiting %d second(s)", PROBE_MIN); g_timer_reset( timer ); time_passed = g_timer_elapsed ( timer, NULL ); while( time_passed < (PROBE_MIN) ){ time_passed = g_timer_elapsed ( timer, NULL ); } /* send ARP PROBE message PROBE_NUM times with an interval probe_wait */ g_debug("send ARP Probe message %d times every %G second(s)", PROBE_NUM, space); for( int i = 1 ; i <= PROBE_NUM ; i ++){ g_timer_reset( timer ); time_passed = g_timer_elapsed ( timer, NULL ); while( time_passed < space ){ time_passed = g_timer_elapsed ( timer, NULL ); } send_arp_request( sending_socket_fd , ethernet_frame, ethernet_frame_length, sa ); } conflict = receive_arp_reply( ) ; /* if receive_arp_reply return FALSE there is a conflict, else, we are fine with this IP */ if ( conflict ){ struct in_addr device_ip; device_ip.s_addr = if_entry->ethernetIfIpAddress ; g_debug("IP address %s already in use", inet_ntoa ( device_ip )); /* pick up a new random IP */ if_entry->ethernetIfIpAddressConflict = if_entry->ethernetIfIpAddress ; if_entry->ethernetIfIpAddress = random_ip_for_conflict(interface); if ( if_entry->ethernetIfIpAddress == max_ip_value ) return TRUE; /* send trap */ send_ipAddressConflict_trap(); } } /* build and send probe message */ ethernet_frame = init_ethernet_frame (if_entry , &pkt, ðernet_frame_length, FALSE ); send_arp_request( sending_socket_fd , ethernet_frame, ethernet_frame_length, sa ); /* close sockets */ close ( sending_socket_fd ); /* free the ethernet frame build */ free(ethernet_frame); return FALSE; }
/* * HELPER function called from arp_thread */ void process_arp_queue(struct sr_instance* sr) { router_state* rs = get_router_state(sr); node* n = get_router_state(sr)->arp_queue; node* next = NULL; time_t now; double diff; while (n) { next = n->next; arp_queue_entry* aqe = (arp_queue_entry*)n->data; /* has it been over a second since the last arp request was sent? */ time(&now); diff = difftime(now, aqe->last_req_time); if (diff > 1) { /* have we sent less than 5 arp requests? */ if (aqe->requests < 5) { /* send another */ time(&(aqe->last_req_time)); ++(aqe->requests); send_arp_request(sr, aqe->next_hop.s_addr, aqe->out_iface_name); } else { /* we have exceeded the max arp requests, return packets to sender */ node* cur_packet_node = aqe->head; node* next_packet_node = NULL; while (cur_packet_node) { /* send icmp for the packet, free it, and its encasing entry */ arp_queue_packet_entry* aqpe = (arp_queue_packet_entry*)cur_packet_node->data; /* only send an icmp error if the packet is not icmp, or if it is, its an echo request or reply * also ensure we don't send an icmp error back to one of our interfaces */ if ((get_ip_hdr(aqpe->packet, aqpe->len)->ip_p != IP_PROTO_ICMP) || (get_icmp_hdr(aqpe->packet, aqpe->len)->icmp_type == ICMP_TYPE_ECHO_REPLY) || (get_icmp_hdr(aqpe->packet, aqpe->len)->icmp_type == ICMP_TYPE_ECHO_REQUEST)) { /* also ensure we don't send an icmp error back to one of our interfaces */ if (!iface_match_ip(rs, get_ip_hdr(aqpe->packet, aqpe->len)->ip_src.s_addr)) { /* Total hack here to increment the TTL since we already decremented it earlier in the pipeline * and the ICMP error should return the original packet. * TODO: Don't decrement the TTL until the packet is ready to be put on the wire * and we have the next hop ARP address, although checking should be done * where it is currently being decremented to minimize effort on a doomed packet */ ip_hdr *ip = get_ip_hdr(aqpe->packet, aqpe->len); if (ip->ip_ttl < 255) { ip->ip_ttl++; /* recalculate checksum */ bzero(&ip->ip_sum, sizeof(uint16_t)); uint16_t checksum = htons(compute_ip_checksum(ip)); ip->ip_sum = checksum; } send_icmp_packet(sr, aqpe->packet, aqpe->len, ICMP_TYPE_DESTINATION_UNREACHABLE, ICMP_CODE_HOST_UNREACHABLE); } } free(aqpe->packet); next_packet_node = cur_packet_node->next; //free(cur_packet_node); /* IS THIS CORRECT TO FREE IT ? */ node_remove(&(aqe->head), cur_packet_node); cur_packet_node = next_packet_node; } /* free the arp queue entry for this destination ip, and patch the list */ node_remove(&(get_router_state(sr)->arp_queue), n); } } n = next; } }