示例#1
0
void UDPNetworkSocket::addTarget(const IPv4Address & address) {
	if (address.isValid())
		data->targets.insert(address);
}
示例#2
0
/**
 * main method of the application. Responsible for parsing user args, preparing worker thread configuration, creating the worker threads and activate them.
 * At program termination worker threads are stopped, statistics are collected from them and printed to console
 */
int main(int argc, char* argv[])
{
	std::vector<int> dpdkPortVec;

	bool writePacketsToDisk = false;

	string packetFilePath = "";

	CoreMask coreMaskToUse = getCoreMaskForAllMachineCores();

	int sendPacketsToPort = -1;

	int optionIndex = 0;
	char opt = 0;

	uint32_t mBufPoolSize = DEFAULT_MBUF_POOL_SIZE;

	IPv4Address 	srcIPToMatch = IPv4Address::Zero;
	IPv4Address 	dstIPToMatch = IPv4Address::Zero;
	uint16_t 		srcPortToMatch = 0;
	uint16_t 		dstPortToMatch = 0;
	ProtocolType	protocolToMatch = Unknown;

	while((opt = getopt_long (argc, argv, "d:c:s:f:m:i:I:p:P:r:hl", FilterTrafficOptions, &optionIndex)) != -1)
	{
		switch (opt)
		{
			case 0:
			{
				break;
			}
			case 'd':
			{
				string portListAsString = string(optarg);
				stringstream stream(portListAsString);
				string portAsString;
				int port;
				// break comma-separated string into string list
				while(getline(stream, portAsString, ','))
				{
					char c;
					std::stringstream stream2(portAsString);
					stream2 >> port;
					if (stream2.fail() || stream2.get(c))
					{
						// not an integer
						EXIT_WITH_ERROR_AND_PRINT_USAGE("DPDK ports list is invalid");
					}
					dpdkPortVec.push_back(port);
				}

				// verify list is not empty
				if (dpdkPortVec.empty())
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("DPDK ports list is empty");
				}
				break;
			}
			case 's':
			{
				sendPacketsToPort = atoi(optarg);
				break;
			}
			case 'c':
			{
				coreMaskToUse = atoi(optarg);
				break;
			}
			case 'f':
			{
				packetFilePath = string(optarg);
				writePacketsToDisk = true;
				if (packetFilePath.empty())
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Filename to write packets is empty");
				}
				break;
			}
			case 'm':
			{
				mBufPoolSize = atoi(optarg);
				break;
			}
			case 'i':
			{
				srcIPToMatch = IPv4Address(optarg);
				if (!srcIPToMatch.isValid())
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Source IP to match isn't a valid IP address");
				}
				break;
			}
			case 'I':
			{
				dstIPToMatch = IPv4Address(optarg);
				if (!dstIPToMatch.isValid())
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Destination IP to match isn't a valid IP address");
				}
				break;
			}
			case 'p':
			{
				srcPortToMatch = atoi(optarg);
				if (srcPortToMatch <= 0)
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Source port to match isn't a valid TCP/UDP port");
				}
				break;
			}
			case 'P':
			{
				dstPortToMatch = atoi(optarg);
				if (dstPortToMatch <= 0)
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Destination port to match isn't a valid TCP/UDP port");
				}
				break;
			}
			case 'r':
			{
				string protocol = string(optarg);
				if (protocol == "TCP")
					protocolToMatch = TCP;
				else if (protocol == "UDP")
					protocolToMatch = UDP;
				else
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Protocol to match isn't TCP or UDP");
				}
				break;
			}
			case 'h':
			{
				printUsage();
				exit(0);
			}
			case 'l':
			{
				listDpdkPorts();
				exit(0);
			}
			default:
			{
				printUsage();
				exit(0);
			}
		}
	}

	// verify list is not empty
	if (dpdkPortVec.empty())
	{
		EXIT_WITH_ERROR_AND_PRINT_USAGE("DPDK ports list is empty. Please use the -d switch");
	}

	// initialize DPDK
	if (!DpdkDeviceList::initDpdk(coreMaskToUse, mBufPoolSize))
	{
		EXIT_WITH_ERROR("couldn't initialize DPDK");
	}

	// removing DPDK master core from core mask because DPDK worker threads cannot run on master core
	coreMaskToUse = coreMaskToUse & ~(DpdkDeviceList::getInstance().getDpdkMasterCore().Mask);

	// extract core vector from core mask
	vector<SystemCore> coresToUse;
	createCoreVectorFromCoreMask(coreMaskToUse, coresToUse);

	// collect the list of DPDK devices
	vector<DpdkDevice*> dpdkDevicesToUse;
	for (vector<int>::iterator iter = dpdkPortVec.begin(); iter != dpdkPortVec.end(); iter++)
	{
		DpdkDevice* dev = DpdkDeviceList::getInstance().getDeviceByPort(*iter);
		if (dev == NULL)
		{
			EXIT_WITH_ERROR("DPDK device for port %d doesn't exist", *iter);
		}
		dpdkDevicesToUse.push_back(dev);
	}

	// get DPDK device to send packets to (or NULL if doesn't exist)
	DpdkDevice* sendPacketsTo = DpdkDeviceList::getInstance().getDeviceByPort(sendPacketsToPort);
	if (sendPacketsTo != NULL && !sendPacketsTo->open())
	{
		EXIT_WITH_ERROR("Could not open port#%d for sending matched packets", sendPacketsToPort);
	}

	// go over all devices and open them
	for (vector<DpdkDevice*>::iterator iter = dpdkDevicesToUse.begin(); iter != dpdkDevicesToUse.end(); iter++)
	{
		if (!(*iter)->openMultiQueues((*iter)->getTotalNumOfRxQueues(), (*iter)->getTotalNumOfTxQueues()))
		{
			EXIT_WITH_ERROR("Couldn't open DPDK device #%d, PMD '%s'", (*iter)->getDeviceId(), (*iter)->getPMDName().c_str());
		}
	}

	// prepare configuration for every core
	AppWorkerConfig workerConfigArr[coresToUse.size()];
	prepareCoreConfiguration(dpdkDevicesToUse, coresToUse, writePacketsToDisk, packetFilePath, sendPacketsTo, workerConfigArr, coresToUse.size());

	PacketMatchingEngine matchingEngine(srcIPToMatch, dstIPToMatch, srcPortToMatch, dstPortToMatch, protocolToMatch);

	// create worker thread for every core
	vector<DpdkWorkerThread*> workerThreadVec;
	int i = 0;
	for (vector<SystemCore>::iterator iter = coresToUse.begin(); iter != coresToUse.end(); iter++)
	{
		AppWorkerThread* newWorker = new AppWorkerThread(workerConfigArr[i], matchingEngine);
		workerThreadVec.push_back(newWorker);
		i++;
	}

	// start all worker threads
	if (!DpdkDeviceList::getInstance().startDpdkWorkerThreads(coreMaskToUse, workerThreadVec))
	{
		EXIT_WITH_ERROR("Couldn't start worker threads");
	}

	// register the on app close event to print summary stats on app termination
	FiltetTrafficArgs args;
	args.workerThreadsVector = &workerThreadVec;
	ApplicationEventHandler::getInstance().onApplicationInterrupted(onApplicationInterrupted, &args);

	// infinite loop (until program is terminated)
	while (!args.shouldStop)
	{
		sleep(5);
	}
}
示例#3
0
IPv4Address NetworkUtils::getIPv4Address(std::string hostname, PcapLiveDevice* device, double& dnsResponseTimeMS, uint32_t& dnsTTL,
		int dnsTimeout, IPv4Address dnsServerIP, IPv4Address gatewayIP)
{
	IPv4Address result = IPv4Address::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;
		}
	}

	// first - resolve gateway MAC address

	// if gateway IP wasn't provided - try to find the default gateway
	if (gatewayIP == IPv4Address::Zero)
	{
		gatewayIP = device->getDefaultGateway();
	}

	if (!gatewayIP.isValid() || gatewayIP == IPv4Address::Zero)
	{
		LOG_ERROR("Gateway address isn't valid or couldn't find default gateway");
		return result;
	}

	// send the ARP request to find gateway MAC address
	double arpResTime;
	MacAddress gatewayMacAddress = getMacAddress(gatewayIP, device, arpResTime);

	if (gatewayMacAddress == MacAddress::Zero)
	{
		LOG_ERROR("Coulnd't resolve gateway MAC address");
		return result;
	}

	if (dnsTimeout <= 0)
		dnsTimeout = NetworkUtils::DefaultTimeout;

	// validate DNS server IP. If it wasn't provided - set the system-configured DNS server
	if (dnsServerIP == IPv4Address::Zero && device->getDnsServers().size() > 0)
	{
		dnsServerIP = device->getDnsServers().at(0);
	}

	if (!dnsServerIP.isValid())
	{
		LOG_ERROR("DNS server IP isn't valid");
		return result;
	}

	// create DNS request

	Packet dnsRequest(100);
	MacAddress sourceMac = device->getMacAddress();
	EthLayer ethLayer(sourceMac, gatewayMacAddress, PCPP_ETHERTYPE_IP);
	IPv4Layer ipLayer(device->getIPv4Address(), dnsServerIP);
	ipLayer.getIPv4Header()->timeToLive = 128;

	// randomize source port to a number >= 10000
	int srcPortLowest = 10000;
	int srcPortRange = (2^16) - srcPortLowest;
	uint16_t srcPort = (rand() % srcPortRange) + srcPortLowest;
	UdpLayer udpLayer(srcPort, DNS_PORT);

	// create the DNS request for the hostname
	DnsLayer dnsLayer;

	// randomize transaction ID
	uint16_t transactionID = rand() % (2^16);
	dnsLayer.getDnsHeader()->transactionID = htons(transactionID);
	dnsLayer.addQuery(hostname, DNS_TYPE_A, DNS_CLASS_IN);

	// add all layers to packet
	if (!dnsRequest.addLayer(&ethLayer) || !dnsRequest.addLayer(&ipLayer) || !dnsRequest.addLayer(&udpLayer) || !dnsRequest.addLayer(&dnsLayer))
	{
		LOG_ERROR("Couldn't construct DNS query");
		return result;
	}

	dnsRequest.computeCalculateFields();

	// set a DNS response filter on the device
	PortFilter dnsResponseFilter(53, SRC);
	if (!device->setFilter(dnsResponseFilter))
	{
		LOG_ERROR("Couldn't set DNS respnse filter");
		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 DNS response are 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 DNS 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
	DNSRecievedData data = {
			&mutex,
			&cond,
			hostname,
			transactionID,
			clock(),
			IPv4Address::Zero,
			0,
			0
	};


	struct timeval now;
	gettimeofday(&now,NULL);

	// create the timeout
	timespec timeout = {
			now.tv_sec + dnsTimeout,
			now.tv_usec
	};

	// start capturing. The capture is done on another thread, hence "dnsResponseRecieved" is running on that thread
	device->startCapture(dnsResponseRecieved, &data);

	// send the DNS request
	device->sendPacket(&dnsRequest);

	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("DNS request time out");
		return result;
	}

	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);

	if (closeDeviceAtTheEnd)
		device->close();
	else
		device->clearFilter();

	result = data.result;
	dnsResponseTimeMS = data.dnsResponseTime;
	dnsTTL = data.ttl;

	return result;
}
示例#4
0
int main(int argc, char* argv[])
{
	PfRingDevice* dev = NULL;

	int totalNumOfCores = getNumOfCores();
	int numOfCaptureThreads = totalNumOfCores-1;

	PfRingDevice* sendPacketsToIface = NULL;

	std::string packetFilePath = "";
	bool writePacketsToDisk = true;

	IPv4Address 	srcIPToMatch = IPv4Address::Zero;
	IPv4Address 	dstIPToMatch = IPv4Address::Zero;
	uint16_t 		srcPortToMatch = 0;
	uint16_t 		dstPortToMatch = 0;
	ProtocolType	protocolToMatch = Unknown;

	int optionIndex = 0;
	char opt = 0;

	while((opt = getopt_long (argc, argv, "n:s:t:f:i:I:p:P:r:hl", PfFilterTrafficOptions, &optionIndex)) != -1)
	{
		switch (opt)
		{
			case 0:
			{
				break;
			}
			case 'n':
			{
				std::string ifaceName = std::string(optarg);
				dev = PfRingDeviceList::getInstance().getPfRingDeviceByName(ifaceName);
				if (dev == NULL)
					EXIT_WITH_ERROR("Could not find PF_RING device '%s'", ifaceName.c_str());
				break;
			}
			case 's':
			{
				std::string sendPacketsToIfaceName = std::string(optarg);
				sendPacketsToIface = PfRingDeviceList::getInstance().getPfRingDeviceByName(sendPacketsToIfaceName);
				if (sendPacketsToIface == NULL)
					EXIT_WITH_ERROR("Could not find PF_RING device '%s'", sendPacketsToIfaceName.c_str());

				break;
			}
			case 't':
			{
				numOfCaptureThreads = atoi(optarg);
				if (numOfCaptureThreads < 1 || numOfCaptureThreads > totalNumOfCores-1)
					EXIT_WITH_ERROR("Number of capture threads must be in the range of 1 to %d", totalNumOfCores-1);
				break;
			}
			case 'f':
			{
				packetFilePath = string(optarg);
				// make sure the path ends with '/'
				if (packetFilePath.length() > 1 && (0 != packetFilePath.compare(packetFilePath.length()-1, 1, "/")))
					packetFilePath += "/";

				writePacketsToDisk = true;
				break;
			}
			case 'i':
			{
				srcIPToMatch = IPv4Address(optarg);
				if (!srcIPToMatch.isValid())
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Source IP to match isn't a valid IP address");
				}
				break;
			}
			case 'I':
			{
				dstIPToMatch = IPv4Address(optarg);
				if (!dstIPToMatch.isValid())
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Destination IP to match isn't a valid IP address");
				}
				break;
			}
			case 'p':
			{
				srcPortToMatch = atoi(optarg);
				if (srcPortToMatch <= 0)
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Source port to match isn't a valid TCP/UDP port");
				}
				break;
			}
			case 'P':
			{
				dstPortToMatch = atoi(optarg);
				if (dstPortToMatch <= 0)
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Destination port to match isn't a valid TCP/UDP port");
				}
				break;
			}
			case 'r':
			{
				string protocol = string(optarg);
				if (protocol == "TCP")
					protocolToMatch = TCP;
				else if (protocol == "UDP")
					protocolToMatch = UDP;
				else
				{
					EXIT_WITH_ERROR_AND_PRINT_USAGE("Protocol to match isn't TCP or UDP");
				}
				break;
			}
			case 'h':
			{
				printUsage();
				exit(0);
			}
			case 'l':
			{
				listPfRingDevices();
				exit(0);
			}
			default:
			{
				printUsage();
				exit(0);
			}
		}
	}

	if (dev == NULL)
		EXIT_WITH_ERROR_AND_PRINT_USAGE("Interface name was not provided");

	// open the PF_RING device in multi-thread mode. Distribution of packets between threads will be done per-flow (as opposed to
	// round-robin)
	if (!dev->openMultiRxChannels(numOfCaptureThreads, PfRingDevice::PerFlow))
		EXIT_WITH_ERROR("Couldn't open %d RX channels on interface '%s'", numOfCaptureThreads, dev->getDeviceName().c_str());

	if (sendPacketsToIface != NULL && !sendPacketsToIface->open())
		EXIT_WITH_ERROR("Couldn't open PF_RING device '%s' for sending matched packets", sendPacketsToIface->getDeviceName().c_str());

	CoreMask coreMask = 0;
	int threadId = 0;
	int threadCount = 0;

	// create an array of packet stats with the size of all machine cores
	PacketStats packetStatsArr[totalNumOfCores];

	// init each packet stats instance with an illegal core ID
	for (int coreId = 0; coreId < totalNumOfCores; coreId++)
		packetStatsArr[coreId].ThreadId = MAX_NUM_OF_CORES+1;

	// mark only relevant cores by adding them to core mask
	// mark only relevant packet stats instances by setting their core ID
	while (threadCount < numOfCaptureThreads)
	{
		if (SystemCores::IdToSystemCore[threadId].Id != dev->getCurrentCoreId().Id)
		{
			coreMask |= SystemCores::IdToSystemCore[threadId].Mask;
			packetStatsArr[threadId].ThreadId = SystemCores::IdToSystemCore[threadId].Id;
			threadCount++;
		}

		threadId++;
	}

	// create the matching engine instance
	PacketMatchingEngine matchingEngine(srcIPToMatch, dstIPToMatch, srcPortToMatch, dstPortToMatch, protocolToMatch);

	// create a flow table for each core
	map<uint32_t, bool> flowTables[totalNumOfCores];

	PcapFileWriterDevice** pcapWriters = NULL;

	// if needed, prepare pcap writers for all capturing threads
	if (writePacketsToDisk)
	{
		pcapWriters = new PcapFileWriterDevice*[totalNumOfCores];

		for (int coreId = 0; coreId < totalNumOfCores; coreId++)
		{
			// if core doesn't participate in capturing, skip it
			if ((coreMask & SystemCores::IdToSystemCore[coreId].Mask) == 0)
			{
				pcapWriters[coreId] = NULL;
				continue;
			}

			std::stringstream packetFileName;
			packetFileName << packetFilePath << "Thread" << coreId << ".pcap";
			pcapWriters[coreId] = new PcapFileWriterDevice(packetFileName.str().c_str());
			if (!pcapWriters[coreId]->open())
			{
				EXIT_WITH_ERROR("Couldn't open pcap writer device for core %d", coreId);
			}
		}
	}


	printf("Start capturing on %d threads core mask = 0x%X\n", numOfCaptureThreads, coreMask);

	// prepare packet capture configuration
	CaptureThreadArgs args;
	args.packetStatArr = packetStatsArr;
	args.matchingEngine = &matchingEngine;
	args.flowTables = flowTables;
	args.sendPacketsTo = sendPacketsToIface;
	args.pcapWriters = pcapWriters;

	// start capturing packets on all threads
	if (!dev->startCaptureMultiThread(packetArrived, &args, coreMask))
		EXIT_WITH_ERROR("Couldn't start capturing on core mask %X on interface '%s'", coreMask, dev->getDeviceName().c_str());

	bool shouldStop = false;

	// register the on app close event to print summary stats on app termination
	ApplicationEventHandler::getInstance().onApplicationInterrupted(onApplicationInterrupted, &shouldStop);

	// infinite loop (until program is terminated)
	while (!shouldStop)
	{
		sleep(5);
	}

	// stop capturing packets, close the device
	dev->stopCapture();
	dev->close();

	// close and delete pcap writers
	if (writePacketsToDisk)
	{
		for (int coreId = 0; coreId < totalNumOfCores; coreId++)
		{
			if ((coreMask & SystemCores::IdToSystemCore[coreId].Mask) == 0)
				continue;

			pcapWriters[coreId]->close();
			delete pcapWriters[coreId];
		}
	}

	printf("\n\nApplication stopped\n");

	// print final stats for every capture thread plus sum of all threads and free worker threads memory
	PacketStats aggregatedStats;
	bool printedStatsHeadline = false;
	for (int i = 0; i < totalNumOfCores; i++)
	{
		if (packetStatsArr[i].ThreadId == MAX_NUM_OF_CORES+1)
			continue;

		aggregatedStats.collectStats(packetStatsArr[i]);
		if (!printedStatsHeadline)
		{
			packetStatsArr[i].printStatsHeadline();
			printedStatsHeadline = true;
		}
		packetStatsArr[i].printStats();
	}
	aggregatedStats.printStats();
}