//=========================================================================== // $Name: cflowd-2-1-b1 $ // $Id: flowwatch.cc,v 1.14 2000/10/24 16:18:55 dwm Exp $ //=========================================================================== // CAIDA Copyright Notice // // By accessing this software, cflowd++, you are duly informed // of and agree to be bound by the conditions described below in this // notice: // // This software product, cflowd++, is developed by Daniel W. McRobb, and // copyrighted(C) 1998 by the University of California, San Diego // (UCSD), with all rights reserved. UCSD administers the CAIDA grant, // NCR-9711092, under which part of this code was developed. // // There is no charge for cflowd++ software. You can redistribute it // and/or modify it under the terms of the GNU General Public License, // v. 2 dated June 1991 which is incorporated by reference herein. // cflowd++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use // of it will not infringe on any third party's intellectual property // rights. // // You should have received a copy of the GNU GPL along with cflowd++. // Copies can also be obtained from: // // http://www.gnu.org/copyleft/gpl.html // // or by writing to: // // University of California, San Diego // // SDSC/CAIDA // 9500 Gilman Dr., MS-0505 // La Jolla, CA 92093 - 0505 USA // // Or contact: // // info@caida.org //=========================================================================== extern "C" { #include #include #include #include #include #include #include "caida_t.h" } #include #include "CflowdFlowFilter.hh" #include "CflowdConfig.hh" #include "CflowdConfigLex.hh" #include "CflowdRawFlowConverter.hh" #include "CflowdPacketQueue.hh" #include "CflowdVersion.hh" #include "Signal.hh" extern int errno; static const string rcsid = "@(#) $Name: cflowd-2-1-b1 $ $Id: flowwatch.cc,v 1.14 2000/10/24 16:18:55 dwm Exp $"; static const CflowdVersion g_cflowdVersion(rcsid); static CflowdConfig g_cflowdConfig; static CflowdPacketQueue g_packetQueue; //------------------------------------------------------------------------- // void Usage(const char *argv0) //......................................................................... // //------------------------------------------------------------------------- void Usage(const char *argv0) { cerr << "usage: " << argv0 << " [-v] [-c configFile] [-o outFile] filterExpression" << endl; cerr << " filterExpression is evaluated for a match on each flow entry." << endl << endl; cerr << " Possible flow entry field operands:" << endl << " router srcaddr dstaddr inputif outputif srcport dstport" << " pkts bytes" << endl << " nexthop starttime endtime protocol tos srcas dstas" << " srcmask dstmask" << endl << " tcpflags enginetype engineid all now" << endl << endl; cerr << " Possible operators:" << endl << " < <= == != >= > && || & | ! * / + - % ( )" << endl << endl; cerr << " Example:" << endl << " flowwatch '(protocol == 6) && (dstas == 2056) &&" << " ((tcpflags & 0x02) == 0x02))'" << endl; return; } //------------------------------------------------------------------------- // static void FixFlowAsNumbers(CflowdRawFlow & flow, uint16_t localAS) //......................................................................... // Given a raw flow and the local AS of the Cisco that sent the flow, // try to determin if the flow was sourced from or destined for the // local AS and fix zeros in the corresponding AS fields. //------------------------------------------------------------------------- static void FixFlowAsNumbers(CflowdRawFlow & flow, uint16_t localAS) { if (localAS == 0) return; const CflowdRawFlow::index_type k_srcFields = CflowdRawFlow::k_srcAsMask|CflowdRawFlow::k_srcMaskLenMask; if ((flow.Index() & k_srcFields) == k_srcFields) { if (flow.SrcAs() == 0 && flow.SrcMaskLen() != 0) { flow.SrcAs(localAS); } } const CflowdRawFlow::index_type k_dstFields = CflowdRawFlow::k_dstAsMask|CflowdRawFlow::k_dstMaskLenMask; if ((flow.Index() & k_dstFields) == k_dstFields) { if ((flow.DstAs() == 0) && flow.DstMaskLen() != 0) { flow.DstAs(localAS); } } return; } static int UpdateFlowsWithV8Data(CflowdCiscoMap::iterator ciscoMapIter, CflowdRawFlow *flows, int & flowArrNum, CiscoFlowHeaderV8_t *hdrPtrV8, const char *pktPtr) { CiscoFlowEntryV8AsAggV2_t *entryPtrV8AsAggV2; CiscoFlowEntryV8ProtocolPortAggV2_t *entryPtrV8ProtocolPortAggV2; CiscoFlowEntryV8NetMatrixAggV2_t *entryPtrV8NetMatrixAggV2; int flowNum; uint16_t numFlows = ntohs(hdrPtrV8->count); ipv4addr_t ciscoAddr = (*ciscoMapIter).first; switch (hdrPtrV8->agg_method) { case k_CiscoV8FlowExportASAggType: // AS aggregation if (numFlows > k_maxFlowsPerV8AsAggPacket) { fprintf(stderr, "[E] too many flow in v8 AS agg packet! (%d, max %d) {%s:%d}\n", numFlows,k_maxFlowsPerV8AsAggPacket,__FILE__,__LINE__); return(-1); } entryPtrV8AsAggV2 = (CiscoFlowEntryV8AsAggV2_t *)(&pktPtr[0] + sizeof(CiscoFlowHeaderV8_t)); for (flowNum = 0; flowNum < ntohs(hdrPtrV8->count); flowNum++) { flows[flowArrNum].Init(ciscoAddr,hdrPtrV8,entryPtrV8AsAggV2); entryPtrV8AsAggV2++; flowArrNum++; } break; case k_CiscoV8FlowExportProtocolPortAggType: // protocol/port aggregation if (numFlows > k_maxFlowsPerV8ProtocolPortAggPacket) { fprintf(stderr, "[E] too many flow in protocol/port agg packet!" " (%d, max %d) {%s:%d}\n", numFlows,k_maxFlowsPerV8ProtocolPortAggPacket, __FILE__,__LINE__); return(-1); } entryPtrV8ProtocolPortAggV2 = (CiscoFlowEntryV8ProtocolPortAggV2_t *)(&pktPtr[0] + sizeof(CiscoFlowHeaderV8_t)); for (flowNum = 0; flowNum < ntohs(hdrPtrV8->count); flowNum++) { flows[flowArrNum].Init(ciscoAddr,hdrPtrV8,entryPtrV8ProtocolPortAggV2); entryPtrV8ProtocolPortAggV2++; flowArrNum++; } break; case k_CiscoV8FlowExportNetMatrixAggType: // network prefix matrix aggregation if (numFlows > k_maxFlowsPerV8NetMatrixAggPacket) { fprintf(stderr, "[E] too many flow in net agg packet! (%hu, max %hu) {%s:%d}\n", numFlows,k_maxFlowsPerV8NetMatrixAggPacket,__FILE__,__LINE__); return(-1); } entryPtrV8NetMatrixAggV2 = (CiscoFlowEntryV8NetMatrixAggV2_t *)(&pktPtr[0] + sizeof(CiscoFlowHeaderV8_t)); for (flowNum = 0; flowNum < ntohs(hdrPtrV8->count); flowNum++) { flows[flowArrNum].Init(ciscoAddr,hdrPtrV8,entryPtrV8NetMatrixAggV2); FixFlowAsNumbers(flows[flowArrNum], ((*ciscoMapIter).second)->LocalAS()); entryPtrV8NetMatrixAggV2++; flowArrNum++; } break; default: break; } return(0); } //------------------------------------------------------------------------- // int main(int argc, char *argv[]) //......................................................................... // //------------------------------------------------------------------------- int main(int argc, char *argv[]) { struct sockaddr_un servSockAddr; int servSockAddrLen; int sockFd; char *configFilename = NULL; extern int optind; extern char *optarg; int optChar; CflowdFlowFilter flowFilter; ofstream *outStream = (ofstream *)0; Signal sigQuit(SIGQUIT); if (argc < 2) { Usage(argv[0]); exit(1); } while ((optChar = getopt(argc,argv,"c:o:v")) != EOF) { switch (optChar) { case 'c': configFilename = (char *)strdup(optarg); break; case 'o': outStream = new ofstream(optarg); if (!outStream || !(*outStream)) { cerr << "failed to open output file '" << optarg << "': " << strerror(errno) << " {" << __FILE__ << ":" << __LINE__ << "}" << endl; exit(1); } break; case 'v': cerr << g_cflowdVersion.Name() << " " << g_cflowdVersion.Id() << endl; exit(0); break; case '?': default: Usage(argv[0]); exit(1); break; } } if (configFilename == NULL) { configFilename = (char *)strdup(CflowdConfig::k_defaultCflowdConfigFile.c_str()); } if (LoadConfigFile(configFilename,g_cflowdConfig) < 0) { cerr << "failed to load config file '" << configFilename << "': " << strerror(errno) << endl; Usage(argv[0]); exit(1); } if (g_packetQueue.Open(configFilename,g_cflowdConfig.PacketBufSize()) < 0) { cerr << "[A] failed to open packet queue! Exiting." << endl; exit(1); } if (flowFilter.Compile(argv[argc-1]) < 0) { Usage(argv[0]); exit(1); } g_packetQueue.GetLock(); for (;;) { uint16_t exportVersion; ipv4addr_t ciscoAddr; const char *pktPtr; int pktNum, flowNum, flowArrNum; int numPackets, numFlows; CflowdCiscoMap::iterator ciscoMapIter; CiscoFlowHeaderV1_t *hdrPtrV1; CiscoFlowEntryV1_t *entryPtrV1; CiscoFlowHeaderV5_t *hdrPtrV5; CiscoFlowEntryV5_t *entryPtrV5; CiscoFlowHeaderV6_t *hdrPtrV6; CiscoFlowEntryV6_t *entryPtrV6; CiscoFlowHeaderV8_t *hdrPtrV8; numPackets = g_packetQueue.NumPackets(); CflowdRawFlow flows[numPackets * k_maxFlowsPerAnyPacket]; flowArrNum = 0; for (pktNum = 0; pktNum < numPackets; pktNum++) { // get reference to next packet. pktPtr = g_packetQueue.GetPacket(ciscoAddr); ciscoMapIter = g_cflowdConfig.CiscoMap().find(ciscoAddr); if (ciscoMapIter == g_cflowdConfig.CiscoMap().end()) { struct in_addr addrIn; addrIn.s_addr = ciscoAddr; cerr << "[E] received packet from a source for which" << " we're not configured (" << inet_ntoa(addrIn) << ")" << endl; continue; } // get the flow-export version of the packet exportVersion = ntohs(*(uint16_t *)pktPtr); // and deal with the packet switch (exportVersion) { case 1: hdrPtrV1 = (CiscoFlowHeaderV1_t *)(&pktPtr[0]); entryPtrV1 = (CiscoFlowEntryV1_t *)(&pktPtr[0] + sizeof(CiscoFlowHeaderV1_t)); for (flowNum = 0; flowNum < ntohs(hdrPtrV1->count); flowNum++) { flows[flowArrNum].Init(ciscoAddr,hdrPtrV1,entryPtrV1); entryPtrV5++; flowArrNum++; } break; case 5: hdrPtrV5 = (CiscoFlowHeaderV5_t *)(&pktPtr[0]); entryPtrV5 = (CiscoFlowEntryV5_t *)(&pktPtr[0] + sizeof(CiscoFlowHeaderV5_t)); for (flowNum = 0; flowNum < ntohs(hdrPtrV5->count); flowNum++) { flows[flowArrNum].Init(ciscoAddr,hdrPtrV5,entryPtrV5); FixFlowAsNumbers(flows[flowArrNum], ((*ciscoMapIter).second)->LocalAS()); entryPtrV5++; flowArrNum++; } break; case 6: hdrPtrV6 = (CiscoFlowHeaderV6_t *)(&pktPtr[0]); entryPtrV6 = (CiscoFlowEntryV6_t *)(&pktPtr[0] + sizeof(CiscoFlowHeaderV6_t)); for (flowNum = 0; flowNum < ntohs(hdrPtrV6->count); flowNum++) { flows[flowArrNum].Init(ciscoAddr,hdrPtrV6,entryPtrV6); FixFlowAsNumbers(flows[flowArrNum], ((*ciscoMapIter).second)->LocalAS()); entryPtrV5++; flowArrNum++; } break; case 8: hdrPtrV8 = (CiscoFlowHeaderV8_t *)(&pktPtr[0]); UpdateFlowsWithV8Data(ciscoMapIter,flows,flowArrNum, hdrPtrV8,pktPtr); break; default: break; } } g_packetQueue.ReleaseLock(); numFlows = flowArrNum; for (flowNum = 0; flowNum < numFlows; flowNum++) { if (flowFilter.Matches(&flows[flowNum])) { if (outStream != ((ofstream *)0)) { sigQuit.Block(); flows[flowNum].Write(*outStream); sigQuit.Unblock(); } else { cout << flows[flowNum]; } } } g_packetQueue.ToggleBuffers(false); } }