NetSend::Result NetSend::initialize() { DEBUG(""); for (HashIterator<String, Argument *> it(m_arguments.getFlags()); it.hasCurrent(); it++) { printf("key = '%s' value = '%s'\n", *it.key(), *it.current()->getName()); } for (Size i = 0; i < m_arguments.getPositionals().count(); i++) { printf("pos[%d]: %s = %s\n", i, *m_arguments.getPositionals()[i]->getName(), *m_arguments.getPositionals()[i]->getValue()); } //const String *dev = m_arguments.get("device"); //if (dev) // DEBUG("sending on device: " << **dev); IPV4::Address ipAddr = (192 << 24) | (168 << 16) | (1 << 8) | (123); Ethernet::Address etherAddr; arpRequest(ipAddr, ðerAddr); return Success; }
/* The handle_arpreq() function is a function you should write, and it should handle sending ARP requests if necessary: function handle_arpreq(request): if difftime(now, request->sent) > 1.0 if request->times_sent >= 5: send icmp host unreachable to source addr of all pkts waiting on this request arpreq_destroy(request) else: send arp request request->sent = now request->times_sent++ */ void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *request){ //assert(sr); //assert(request); // If time since last sent is more than 1 second if (difftime(time(NULL), request->sent) >= 1.0) { /* If an ARP request has been sent 5 times with no response, a destination host unreachable should go back to all the sender of packets that were waiting on a reply to this ARP request. */ if (request->times_sent >= 5) { // Iniitalize variables for the loop struct sr_packet *packetPointer = NULL; sr_ethernet_hdr_t *ethernetHeader = NULL; struct sr_if *interface = NULL; // get a pointer to a array of all packets waiting packetPointer = request->packets; // For every xender of packets waiting, send host unreachable while (packetPointer != NULL) { ethernetHeader = (sr_ethernet_hdr_t *)(packetPointer->buf); interface = getAddressInterface(sr, ethernetHeader->ether_dhost); /* do not send an ICMP message for an ICMP message */ // If we got an interface of a waiting sender, send the ICMP host unreachable if (interface) { sendICMP(sr, packetPointer->buf, packetPointer->len, DESTINATION_UNREACHABLE, HOST_UNREACHABLE_CODE); } // Go to the next exisiting packet packetPointer = packetPointer->next; } sr_arpreq_destroy(&(sr->cache), request); } // Otherwise, just send arp request with its sent time = now and increment times sent else { struct sr_if *sendingInterface = sr_get_interface(sr, request->packets->iface); arpRequest(sr, sendingInterface, request->ip); // Set sent time to NOW request->sent = time(NULL); // time(NULL) = NOW // Increment # of times sent request->times_sent = request->times_sent + 1; } } }
MacAddress NetworkUtils::getMacAddress(IPv4Address ipAddr, PcapLiveDevice* device, double& arpResponseTimeMS, MacAddress sourceMac, IPv4Address sourceIP, int arpTimeout) { MacAddress result = MacAddress::Zero; // open the device if not already opened bool closeDeviceAtTheEnd = false; if (!device->isOpened()) { closeDeviceAtTheEnd = true; if (!device->open()) { LOG_ERROR("Cannot open device"); return result; } } if (sourceMac == MacAddress::Zero) sourceMac = device->getMacAddress(); if (sourceIP == IPv4Address::Zero) sourceIP = device->getIPv4Address(); if (arpTimeout <= 0) arpTimeout = NetworkUtils::DefaultTimeout; // create an ARP request from sourceMac and sourceIP and ask for target IP Packet arpRequest(100); MacAddress destMac(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); EthLayer ethLayer(sourceMac, destMac); ArpLayer arpLayer(ARP_REQUEST, sourceMac, destMac, sourceIP, ipAddr); if (!arpRequest.addLayer(ðLayer)) { LOG_ERROR("Couldn't build Eth layer for ARP request"); return result; } if (!arpRequest.addLayer(&arpLayer)) { LOG_ERROR("Couldn't build ARP layer for ARP request"); return result; } arpRequest.computeCalculateFields(); // set a filter for the interface to intercept only ARP response packets ArpFilter arpFilter(ARP_REPLY); if (!device->setFilter(arpFilter)) { LOG_ERROR("Couldn't set ARP filter for device"); return result; } // since packet capture is done on another thread, I use a conditional mutex with timeout to synchronize between the capture // thread and the main thread. When the capture thread starts running the main thread is blocking on the conditional mutex. // When the ARP response is captured the capture thread signals the main thread and the main thread stops capturing and continues // to the next iteration. If a timeout passes and no ARP response is captured, the main thread stops capturing pthread_mutex_t mutex; pthread_cond_t cond; // init the conditonal mutex pthread_mutex_init(&mutex, 0); pthread_cond_init(&cond, 0); // this is the token that passes between the 2 threads. It contains pointers to the conditional mutex, the target IP for identifying // the ARP response, the iteration index and a timestamp to calculate the response time ArpingRecievedData data = { &mutex, &cond, ipAddr, clock(), MacAddress::Zero, 0 }; struct timeval now; gettimeofday(&now,NULL); // create the timeout timespec timeout = { now.tv_sec + arpTimeout, now.tv_usec }; // start capturing. The capture is done on another thread, hence "arpPacketRecieved" is running on that thread device->startCapture(arpPacketRecieved, &data); // send the ARP request device->sendPacket(&arpRequest); pthread_mutex_lock(&mutex); // block on the conditional mutex until capture thread signals or until timeout expires int res = pthread_cond_timedwait(&cond, &mutex, &timeout); // stop the capturing thread device->stopCapture(); pthread_mutex_unlock(&mutex); // check if timeout expired if (res == ETIMEDOUT) { LOG_ERROR("ARP request time out"); return result; } pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); if (closeDeviceAtTheEnd) device->close(); else device->clearFilter(); result = data.result; arpResponseTimeMS = data.arpResponseTime; return result; }