/* * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * http://www.ntop.org * * Copyright (C) 1998-2007 Luca Deri * * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ntop.h" static void processFcPkt(const u_char *bp, const struct pcap_pkthdr *h, u_int16_t ethertype, int actualDeviceId); static char *fcProtocolStrings[] = { "", "SW_ILS", "IP", "SCSI", "BLS", "ELS", "FCCT", "LinkData", "Video", "LinkCtl", "SWILS_RSP", "FICON", "Undefined" }; /* PPPoE - Courtesy of Andreas Pfaller Feb2003 */ #ifdef HAVE_LINUX_IF_PPPOX_H #include #else /* Extracted and modified from the Linux header for other systems - BMS Mar2003 */ /* And for Linux systems without if_pppox.h - BMS Apr2003 */ struct pppoe_tag { u_int16_t tag_type; u_int16_t tag_len; char tag_data; }; struct pppoe_hdr { #ifdef CFG_LITTLE_ENDIAN u_int8_t ver : 4; u_int8_t type : 4; #else u_int8_t type : 4; u_int8_t ver : 4; #endif u_int8_t code; u_int16_t sid; u_int16_t length; struct pppoe_tag tag; }; #endif static const struct pcap_pkthdr *h_save; static const u_char *p_save; static u_char ethBroadcast[] = { 255, 255, 255, 255, 255, 255 }; static u_char lowMemoryMsgShown = 0; static void updateASTraffic(int actualDeviceId, u_int16_t src_as_id, u_int16_t dst_as_id, u_int octets); /* ******************************* */ static u_int32_t getFcProtocol (u_int8_t r_ctl, u_int8_t type) { switch (r_ctl & 0xF0) { case FC_RCTL_DEV_DATA: switch (type) { case FC_TYPE_SWILS: if ((r_ctl == 0x2) || (r_ctl == 0x3)) return FC_FTYPE_SWILS; else return FC_FTYPE_UNDEF; case FC_TYPE_IP: return FC_FTYPE_IP; case FC_TYPE_SCSI: return FC_FTYPE_SCSI; case FC_TYPE_FCCT: return FC_FTYPE_FCCT; case FC_TYPE_SB_FROM_CU: case FC_TYPE_SB_TO_CU: return FC_FTYPE_SBCCS; default: return FC_FTYPE_UNDEF; } break; case FC_RCTL_ELS: if (((r_ctl & 0x0F) == 0x2) || ((r_ctl & 0x0F) == 0x3)) return FC_FTYPE_ELS; else return FC_FTYPE_UNDEF; break; case FC_RCTL_LINK_DATA: return FC_FTYPE_LINKDATA; break; case FC_RCTL_VIDEO: return FC_FTYPE_VDO; break; case FC_RCTL_BLS: if (type == 0) return FC_FTYPE_BLS; else return FC_FTYPE_UNDEF; break; case FC_RCTL_LINK_CTL: return FC_FTYPE_LINKCTL; break; default: return FC_FTYPE_UNDEF; break; } } /* ******************************* */ void allocateSecurityHostPkts(HostTraffic *srcHost) { if(srcHost->secHostPkts == NULL) { if((srcHost->secHostPkts = (SecurityHostProbes*)malloc(sizeof(SecurityHostProbes))) == NULL) return; resetSecurityHostTraffic(srcHost); } } /* ************************************ */ static void updateRoutedTraffic(HostTraffic *router) { if(router != NULL) { if(router->routedTraffic == NULL) { int mallocLen = sizeof(RoutingCounter); router->routedTraffic = (RoutingCounter*)malloc(mallocLen); if(router->routedTraffic == NULL) return; memset(router->routedTraffic, 0, mallocLen); } if(router->routedTraffic != NULL) { /* malloc() didn't fail */ incrementTrafficCounter(&router->routedTraffic->routedPkts, 1); incrementTrafficCounter(&router->routedTraffic->routedBytes, (Counter)(h_save->len - sizeof(struct ether_header))); } } } /* ************************************ */ int handleIP(u_short port, HostTraffic *srcHost, HostTraffic *dstHost, const u_int _length, u_short isPassiveSess, u_short isVoipSess, u_short p2pSessionIdx, int actualDeviceId, u_short newSession) { int idx; Counter length = (Counter)_length; if((srcHost == NULL) || (dstHost == NULL)) { if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (4) [Low memory?]"); lowMemoryMsgShown = 1; return(-1); } if(isPassiveSess) { /* Emulate non passive session */ idx = myGlobals.FTPIdx; } else if(isVoipSess || (port == 54045 /* Skype default port */)) { /* Emulate VoIP session */ idx = myGlobals.VoipIdx; } else { if(p2pSessionIdx) { switch(p2pSessionIdx) { case FLAG_P2P_EDONKEY: idx = myGlobals.EdonkeyIdx; break; case FLAG_P2P_GNUTELLA: idx = myGlobals.GnutellaIdx; break; case FLAG_P2P_KAZAA: idx = myGlobals.KazaaIdx; break; case FLAG_P2P_WINMX: idx = myGlobals.WinMXIdx; break; case FLAG_P2P_DIRECTCONNECT: idx = myGlobals.DirectConnectIdx; break; case FLAG_P2P_BITTORRENT: idx = myGlobals.BitTorrentIdx; break; default: idx = -1; break; } } else idx = mapGlobalToLocalIdx(port); } if(idx == -1) { return(-1); /* Unable to locate requested index */ } else if(idx >= myGlobals.numIpProtosToMonitor) { traceEvent(CONST_TRACE_ERROR, "Discarding idx=%d for port=%d", idx, port); return(-1); } #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "port=%d - isPassiveSess=%d - isVoipSess=%d - p2pSessionIdx=%d - idx=%d", port, isPassiveSess, isVoipSess, p2pSessionIdx, idx); #endif if(idx != FLAG_NO_PEER) { if(newSession) incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipProtoStats[idx].totalFlows, 1); if(subnetPseudoLocalHost(srcHost)) { if(subnetPseudoLocalHost(dstHost)) { if((!broadcastHost(srcHost)) && (srcHost->protoIPTrafficInfos != NULL)) { if(srcHost->protoIPTrafficInfos[idx] == NULL) { srcHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(srcHost->protoIPTrafficInfos[idx] == NULL) return(-1); } incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->sentLoc, length); if(newSession) incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->totalFlows, 1); } if((!broadcastHost(dstHost)) && (dstHost->protoIPTrafficInfos != NULL)) { if(dstHost->protoIPTrafficInfos[idx] == NULL) { dstHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(dstHost->protoIPTrafficInfos[idx] == NULL) return(-1); } incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->rcvdLoc, length); if(newSession) incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->totalFlows, 1); } incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipProtoStats[idx].local, length); } else { if((!broadcastHost(srcHost)) && (srcHost->protoIPTrafficInfos != NULL)) { if(srcHost->protoIPTrafficInfos[idx] == NULL) { srcHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(srcHost->protoIPTrafficInfos[idx] == NULL) return(-1); } incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->sentRem, length); if(newSession) incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->totalFlows, 1); } if((!broadcastHost(dstHost)) && (dstHost->protoIPTrafficInfos != NULL)) { if(dstHost->protoIPTrafficInfos[idx] == NULL) { dstHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(dstHost->protoIPTrafficInfos[idx] == NULL) return(-1); } incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->rcvdLoc, length); if(newSession) incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->totalFlows, 1); } incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipProtoStats[idx].local2remote, length); } } else { /* srcHost is remote */ if(subnetPseudoLocalHost(dstHost)) { if((!broadcastHost(srcHost)) && (srcHost->protoIPTrafficInfos != NULL)) { if(srcHost->protoIPTrafficInfos[idx] == NULL) { srcHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(srcHost->protoIPTrafficInfos[idx] == NULL) return(-1); } if(newSession) incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->totalFlows, 1); incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->sentLoc, length); } if((!broadcastHost(dstHost)) && (dstHost->protoIPTrafficInfos != NULL)) { if(dstHost->protoIPTrafficInfos[idx] == NULL) { dstHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(dstHost->protoIPTrafficInfos[idx] == NULL) return(-1); } if(newSession) incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->totalFlows, 1); incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->rcvdFromRem, length); } incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipProtoStats[idx].remote2local, length); } else { if((!broadcastHost(srcHost)) && (srcHost->protoIPTrafficInfos != NULL)) { if(srcHost->protoIPTrafficInfos[idx] == NULL) { srcHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(srcHost->protoIPTrafficInfos[idx] == NULL) return(-1); } if(newSession) incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->totalFlows, 1); incrementTrafficCounter(&srcHost->protoIPTrafficInfos[idx]->sentRem, length); } if((!broadcastHost(dstHost)) && (dstHost->protoIPTrafficInfos != NULL)) { if(dstHost->protoIPTrafficInfos[idx] == NULL) { dstHost->protoIPTrafficInfos[idx] = calloc(sizeof(ProtoTrafficInfo), 1); if(dstHost->protoIPTrafficInfos[idx] == NULL) return(-1); } if(newSession) incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->totalFlows, 1); incrementTrafficCounter(&dstHost->protoIPTrafficInfos[idx]->rcvdFromRem, length); } incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipProtoStats[idx].remote, length); } } } return(idx); } /* ************************************ */ static void addContactedPeers(HostTraffic *sender, HostAddr *srcAddr, HostTraffic *receiver, HostAddr *dstAddr, int actualDeviceId) { if((sender == NULL) || (receiver == NULL) || (sender == receiver)) { if ((sender != NULL) && (sender->l2Family == FLAG_HOST_TRAFFIC_AF_FC) && (strncasecmp (sender->fcCounters->hostNumFcAddress, FC_FAB_CTLR_ADDR, strlen (FC_FAB_CTLR_ADDR)) == 0)) { /* This is normal. Return without warning */ return; } traceEvent(CONST_TRACE_ERROR, "Sanity check failed @ addContactedPeers (%p, %p)", sender, receiver); return; } if((sender != myGlobals.otherHostEntry) && (receiver != myGlobals.otherHostEntry)) { /* The statements below have no effect if the serial has been already computed */ setHostSerial(sender); setHostSerial(receiver); sender->totContactedSentPeers += incrementUsageCounter(&sender->contactedSentPeers, receiver, actualDeviceId); receiver->totContactedRcvdPeers += incrementUsageCounter(&receiver->contactedRcvdPeers, sender, actualDeviceId); } } /* ***************************************** * * Fragment handling code courtesy of * Andreas Pfaller * * NOTE: * the code below has a small (neglictable) limitation * as described below. * * Subject: ntop 1.3.2: Fragment handling * Date: Mon, 7 Aug 2000 16:05:45 +0200 * From: a.pfaller@pop.gun.de (Andreas Pfaller) * To: l.deri@tecsiel.it (Luca Deri) * * I have also had a look at the code you added to handle * overlapping fragments. It again assumes specific package * ordering (either 1,2,..,n or n,n-1,..,1) which the IP protocol * does not guarantee. The above assumptions are probably true * for most users but in some setups they are nearly never true. * Consider two host connected by multiple network cards * * e.g.: * +--------+ eth0 eth0 +--------+ * | |-------------------| | * | HOST A | | HOST B | * | |-------------------| | * +--------+ eth1 eth1 +--------+ * * which distribute traffic on this interfaces to achive better * throughput (Called bonding in Linux, Etherchannel by Cisco or * trunking by Sun). A simple algorithm simple uses the interfaces * in a cyclic way. Since packets are not always the same length * or the interfaces my have different speeds more complicated * ones use other methods to try to achive maximum throughput. * In such an environment you have very high probability for * out of order packets. * * ***************************************** */ #ifdef FRAGMENT_DEBUG static void dumpFragmentData(IpFragment *fragment) { printf("FRAGMENT_DEBUG: IPFragment: (%p)\n", fragment); printf(" %s:%d->%s:%d\n", fragment->src->hostResolvedName, fragment->sport, fragment->dest->hostResolvedName, fragment->dport); printf(" FragmentId=%d\n", fragment->fragmentId); printf(" lastOffset=%d, totalPacketLength=%d\n", fragment->lastOffset, fragment->totalPacketLength); printf(" totalDataLength=%d, expectedDataLength=%d\n", fragment->totalDataLength, fragment->expectedDataLength); fflush(stdout); } #endif /* ************************************ */ static IpFragment *searchFragment(HostTraffic *srcHost, HostTraffic *dstHost, u_int fragmentId, int actualDeviceId) { IpFragment *fragment = myGlobals.device[actualDeviceId].fragmentList; while ((fragment != NULL) && ((fragment->src != srcHost) || (fragment->dest != dstHost) || (fragment->fragmentId != fragmentId))) fragment = fragment->next; return(fragment); } /* ************************************ */ void deleteFragment(IpFragment *fragment, int actualDeviceId) { if(fragment->prev == NULL) myGlobals.device[actualDeviceId].fragmentList = fragment->next; else fragment->prev->next = fragment->next; free(fragment); } /* ************************************ */ /* Courtesy of Andreas Pfaller */ static void checkFragmentOverlap(HostTraffic *srcHost, HostTraffic *dstHost, IpFragment *fragment, u_int fragmentOffset, u_int dataLength, int actualDeviceId) { if(fragment->fragmentOrder == FLAG_UNKNOWN_FRAGMENT_ORDER) { if(fragment->lastOffset > fragmentOffset) fragment->fragmentOrder = FLAG_DECREASING_FRAGMENT_ORDER; else fragment->fragmentOrder = FLAG_INCREASING_FRAGMENT_ORDER; } if((fragment->fragmentOrder == FLAG_INCREASING_FRAGMENT_ORDER && fragment->lastOffset+fragment->lastDataLength > fragmentOffset) || (fragment->fragmentOrder == FLAG_DECREASING_FRAGMENT_ORDER && fragment->lastOffset < fragmentOffset+dataLength)) { if(myGlobals.runningPref.enableSuspiciousPacketDump) { char buf[LEN_GENERAL_WORK_BUFFER]; safe_snprintf(__FILE__, __LINE__, buf, LEN_GENERAL_WORK_BUFFER, "Detected overlapping packet fragment [%s->%s]: " "fragment id=%d, actual offset=%d, previous offset=%d\n", fragment->src->hostResolvedName, fragment->dest->hostResolvedName, fragment->fragmentId, fragmentOffset, fragment->lastOffset); dumpSuspiciousPacket(actualDeviceId); } allocateSecurityHostPkts(fragment->src); allocateSecurityHostPkts(fragment->dest); incrementUsageCounter(&fragment->src->secHostPkts->overlappingFragmentSent, dstHost, actualDeviceId); incrementUsageCounter(&fragment->dest->secHostPkts->overlappingFragmentRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.overlappingFragment, 1); } } /* ************************************ */ static u_int handleFragment(HostTraffic *srcHost, HostTraffic *dstHost, u_short *sport, u_short *dport, u_int fragmentId, u_int off, u_int packetLength, u_int dataLength, int actualDeviceId) { IpFragment *fragment; u_int fragmentOffset, length; if(!myGlobals.enableFragmentHandling) return(0); fragmentOffset = (off & 0x1FFF)*8; fragment = searchFragment(srcHost, dstHost, fragmentId, actualDeviceId); if(fragment == NULL) { /* new fragment */ fragment = (IpFragment*) malloc(sizeof(IpFragment)); if(fragment == NULL) return(0); /* out of memory, not much we can do */ memset(fragment, 0, sizeof(IpFragment)); fragment->src = srcHost; fragment->dest = dstHost; fragment->fragmentId = fragmentId; fragment->firstSeen = myGlobals.actTime; fragment->fragmentOrder = FLAG_UNKNOWN_FRAGMENT_ORDER; fragment->next = myGlobals.device[actualDeviceId].fragmentList; fragment->prev = NULL; myGlobals.device[actualDeviceId].fragmentList = fragment; } else checkFragmentOverlap(srcHost, dstHost, fragment, fragmentOffset, dataLength, actualDeviceId); fragment->lastOffset = fragmentOffset; fragment->totalPacketLength += packetLength; fragment->totalDataLength += dataLength; fragment->lastDataLength = dataLength; if(fragmentOffset == 0) { /* first fragment contains port numbers */ fragment->sport = *sport; fragment->dport = *dport; } else if(!(off & IP_MF)) /* last fragment->we know the total data size */ fragment->expectedDataLength = fragmentOffset+dataLength; #ifdef FRAGMENT_DEBUG dumpFragmentData(fragment); #endif /* Now check if we have all the data needed for the statistics */ if((fragment->sport != 0) && (fragment->dport != 0) /* first fragment rcvd */ /* last fragment rcvd */ && (fragment->expectedDataLength != 0) /* probably all fragments rcvd */ && (fragment->totalDataLength >= fragment->expectedDataLength)) { *sport = fragment->sport; *dport = fragment->dport; length = fragment->totalPacketLength; deleteFragment(fragment, actualDeviceId); } else { *sport = 0; *dport = 0; length = 0; } return length; } /* ************************************ */ void purgeOldFragmentEntries(int actualDeviceId) { IpFragment *fragment, *next; u_int fragcnt=0, expcnt=0; fragment = myGlobals.device[actualDeviceId].fragmentList; while(fragment != NULL) { fragcnt++; next = fragment->next; if((fragment->firstSeen + CONST_DOUBLE_TWO_MSL_TIMEOUT) < myGlobals.actTime) { expcnt++; #ifdef FRAGMENT_DEBUG dumpFragmentData(fragment); #endif deleteFragment(fragment, actualDeviceId); } fragment=next; } #ifdef FRAGMENT_DEBUG if(fragcnt) { printf("FRAGMENT_DEBUG: fragcnt=%d, expcnt=%d\n", fragcnt, expcnt); fflush(stdout); } #endif } /* ************************************ */ static void checkNetworkRouter(HostTraffic *srcHost, HostTraffic *dstHost, u_char *ether_dst, int actualDeviceId) { if((subnetLocalHost(srcHost) && (!subnetLocalHost(dstHost)) && (!broadcastHost(dstHost)) && (!multicastHost(dstHost))) || (subnetLocalHost(dstHost) && (!subnetLocalHost(srcHost)) && (!broadcastHost(srcHost)) && (!multicastHost(srcHost)))) { HostTraffic *router = lookupHost(NULL, ether_dst, srcHost->vlanId, 0, 0, actualDeviceId); if(router == NULL) return; if(((router->hostNumIpAddress[0] != '\0') && (broadcastHost(router) || multicastHost(router) || (!subnetLocalHost(router)) /* No IP: is this a special Multicast address ? */)) || (addrcmp(&router->hostIpAddress,&dstHost->hostIpAddress) == 0) || (memcmp(router->ethAddress, dstHost->ethAddress, LEN_ETHERNET_ADDRESS) == 0) ) return; incrementUsageCounter(&srcHost->contactedRouters, router, actualDeviceId); #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "(%s/%s/%s) -> (%s/%s/%s) routed by [%s/%s/%s]", srcHost->ethAddressString, srcHost->hostNumIpAddress, srcHost->hostResolvedName, dstHost->ethAddressString, dstHost->hostNumIpAddress, dstHost->hostResolvedName, router->ethAddressString, router->hostNumIpAddress, router->hostResolvedName); #endif FD_SET(FLAG_GATEWAY_HOST, &router->flags); updateRoutedTraffic(router); } } /* ************************************ */ /* Reset the traffic at every hour */ static void resetHourTraffic(u_short hourId) { int i; for(i=0; itrafficDistribution != NULL) { resetTrafficCounter(&el->trafficDistribution->last24HoursBytesSent[hourId]); resetTrafficCounter(&el->trafficDistribution->last24HoursBytesRcvd[hourId]); } } } } /* ************************************ */ void updatePacketCount(HostTraffic *srcHost, HostAddr *srcAddr, HostTraffic *dstHost, HostAddr *dstAddr, TrafficCounter length, Counter numPkts, int actualDeviceId) { static u_short lastHourId=0; u_short hourId; struct tm t, *thisTime; if((srcHost == NULL) || (dstHost == NULL)) { traceEvent(CONST_TRACE_ERROR, "NULL host detected"); return; } updateASTraffic(actualDeviceId, srcHost->hostAS, dstHost->hostAS, length.value); if (!myGlobals.runningPref.printIpOnly) { if (srcHost == dstHost) { /* Fabric controllers exchange link messages where the S_ID & D_ID * are equal. A lot of control traffic is exchanged using these * addresses and so we must track this as an exception to the case of * S_ID == D_ID. */ if (srcHost->l2Family == FLAG_HOST_TRAFFIC_AF_FC) { if (strncasecmp (srcHost->fcCounters->hostNumFcAddress, FC_FAB_CTLR_ADDR, strlen (FC_FAB_CTLR_ADDR)) != 0) { return; } } else { return; } } else if ((srcHost == myGlobals.otherHostEntry) && (dstHost == myGlobals.otherHostEntry)) { return; } } else if (srcHost == dstHost) return; thisTime = localtime_r(&myGlobals.actTime, &t); hourId = thisTime->tm_hour % 24 /* just in case... */;; if(lastHourId != hourId) { resetHourTraffic(hourId); lastHourId = hourId; } if(srcHost != myGlobals.otherHostEntry) { incrementTrafficCounter(&srcHost->pktSent, numPkts); incrementTrafficCounter(&srcHost->pktSentSession, numPkts); if(srcHost->trafficDistribution == NULL) { srcHost->trafficDistribution = calloc(1, sizeof(TrafficDistribution)); if(srcHost->trafficDistribution == NULL) return; } incrementTrafficCounter(&srcHost->trafficDistribution->last24HoursBytesSent[hourId], length.value); incrementTrafficCounter(&srcHost->bytesSent, length.value); incrementTrafficCounter(&srcHost->bytesSentSession, length.value); } if(dstHost != myGlobals.otherHostEntry) { if(dstHost->trafficDistribution == NULL) { dstHost->trafficDistribution = calloc(1, sizeof(TrafficDistribution)); if(dstHost->trafficDistribution == NULL) return; } incrementTrafficCounter(&dstHost->trafficDistribution->last24HoursBytesRcvd[hourId], length.value); incrementTrafficCounter(&dstHost->bytesRcvd, length.value); incrementTrafficCounter(&dstHost->bytesRcvdSession, length.value); incrementTrafficCounter(&dstHost->pktRcvd, numPkts); incrementTrafficCounter(&dstHost->pktRcvdSession, numPkts); } if(broadcastHost(dstHost)) { if(srcHost != myGlobals.otherHostEntry) { incrementTrafficCounter(&srcHost->pktBroadcastSent, numPkts); incrementTrafficCounter(&srcHost->bytesBroadcastSent, length.value); } incrementTrafficCounter(&myGlobals.device[actualDeviceId].broadcastPkts, numPkts); } else if(isMulticastAddress(&(dstHost->hostIpAddress), NULL, NULL)) { #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "%s->%s", srcHost->hostResolvedName, dstHost->hostResolvedName); #endif if(srcHost != myGlobals.otherHostEntry) { incrementTrafficCounter(&srcHost->pktMulticastSent, numPkts); incrementTrafficCounter(&srcHost->bytesMulticastSent, length.value); } if(dstHost != myGlobals.otherHostEntry) { incrementTrafficCounter(&dstHost->pktMulticastRcvd, numPkts); incrementTrafficCounter(&dstHost->bytesMulticastRcvd, length.value); } incrementTrafficCounter(&myGlobals.device[actualDeviceId].multicastPkts, numPkts); } if((dstHost != NULL) /*&& (!broadcastHost(dstHost))*/) addContactedPeers(srcHost, srcAddr, dstHost, dstAddr, actualDeviceId); } /* ************************************ */ void updateHostName(HostTraffic *el) { if((el->hostNumIpAddress[0] == '\0') || (el->hostResolvedName == NULL) || (el->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_NONE) || strcmp(el->hostResolvedName, el->hostNumIpAddress) == 0) { int i; if(el->nonIPTraffic == NULL) { el->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(el->nonIPTraffic == NULL) return; /* Not enough memory */ } if(el->nonIPTraffic->nbHostName != NULL) { /* Use NetBIOS name (when available) if the IP address has not been resolved. */ memset(el->hostResolvedName, 0, sizeof(el->hostResolvedName)); setResolvedName(el, el->nonIPTraffic->nbHostName, FLAG_HOST_SYM_ADDR_TYPE_NETBIOS); } else if(el->nonIPTraffic->ipxHostName != NULL) { setResolvedName(el, el->nonIPTraffic->ipxHostName, FLAG_HOST_SYM_ADDR_TYPE_IPX); } else if(el->nonIPTraffic->atNodeName != NULL) { setResolvedName(el, el->nonIPTraffic->atNodeName, FLAG_HOST_SYM_ADDR_TYPE_ATALK); } if(el->hostResolvedName[0] != '\0') for(i=0; el->hostResolvedName[i] != '\0'; i++) el->hostResolvedName[i] = (char)tolower(el->hostResolvedName[i]); } } /* ************************************ */ static void updateDevicePacketTTLStats(u_int ttl, int actualDeviceId) { if(ttl <= 32) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo32, 1); else if(ttl <= 64) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo64, 1); else if(ttl <= 96) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo96, 1); else if(ttl <= 128) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo128, 1); else if(ttl <= 160) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo160, 1); else if(ttl <= 192) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo192, 1); else if(ttl <= 224) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo224, 1); else incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktTTLStats.upTo255, 1); } /* ************************************ */ void updateInterfacePorts(int actualDeviceId, u_short sport, u_short dport, u_int length) { if((sport >= MAX_IP_PORT) || (dport >= MAX_IP_PORT)) return; accessMutex(&myGlobals.purgePortsMutex, "updateInterfacePorts"); if(myGlobals.device[actualDeviceId].ipPorts == NULL) allocDeviceMemory(actualDeviceId); if(myGlobals.device[actualDeviceId].ipPorts[sport] == NULL) { myGlobals.device[actualDeviceId].ipPorts[sport] = (PortCounter*)malloc(sizeof(PortCounter)); if(myGlobals.device[actualDeviceId].ipPorts[sport] == NULL) return; myGlobals.device[actualDeviceId].ipPorts[sport]->port = sport; myGlobals.device[actualDeviceId].ipPorts[sport]->sent = 0; myGlobals.device[actualDeviceId].ipPorts[sport]->rcvd = 0; } if(myGlobals.device[actualDeviceId].ipPorts[dport] == NULL) { myGlobals.device[actualDeviceId].ipPorts[dport] = (PortCounter*)malloc(sizeof(PortCounter)); if(myGlobals.device[actualDeviceId].ipPorts[dport] == NULL) return; myGlobals.device[actualDeviceId].ipPorts[dport]->port = dport; myGlobals.device[actualDeviceId].ipPorts[dport]->sent = 0; myGlobals.device[actualDeviceId].ipPorts[dport]->rcvd = 0; } myGlobals.device[actualDeviceId].ipPorts[sport]->sent += length; myGlobals.device[actualDeviceId].ipPorts[dport]->rcvd += length; releaseMutex(&myGlobals.purgePortsMutex); } /* ************************************ */ /* Fingerprint code courtesy of ettercap http://ettercap.sourceforge.net */ static u_char TTL_PREDICTOR(u_char x) /* coded by awgn */ { /* round the TTL to the nearest power of 2 (ceiling) */ register u_char i = x; register u_char j = 1; register u_char c = 0; do { c += i & 1; j <<= 1; } while ( i >>= 1 ); if( c == 1 ) return x; else return ( j ? j : 0xff ); } /* ************************************ */ void incrementUnknownProto(HostTraffic *host, int direction, u_int16_t eth_type, u_int16_t dsap, u_int16_t ssap, u_int16_t ipProto) { int i; if(host->nonIPTraffic == NULL) { host->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(host->nonIPTraffic == NULL) return; } if(direction == 0) { /* Sent */ if(host->nonIPTraffic->unknownProtoSent == NULL) { host->nonIPTraffic->unknownProtoSent = (UnknownProto*)malloc(sizeof(UnknownProto)* MAX_NUM_UNKNOWN_PROTOS); if(host->nonIPTraffic->unknownProtoSent == NULL) return; memset(host->nonIPTraffic->unknownProtoSent, 0, sizeof(UnknownProto)*MAX_NUM_UNKNOWN_PROTOS); } for(i=0; inonIPTraffic->unknownProtoSent[i].protoType == 0) break; if((host->nonIPTraffic->unknownProtoSent[i].protoType == 1) && eth_type) { if(host->nonIPTraffic->unknownProtoSent[i].proto.ethType == eth_type) { return; } } else if((host->nonIPTraffic->unknownProtoSent[i].protoType == 2) && (dsap || ssap)) { if((host->nonIPTraffic->unknownProtoSent[i].proto.sapType.dsap == dsap) && (host->nonIPTraffic->unknownProtoSent[i].proto.sapType.ssap == ssap)) { return; } } else if((host->nonIPTraffic->unknownProtoSent[i].protoType == 3) && ipProto) { if(host->nonIPTraffic->unknownProtoSent[i].proto.ipType == ipProto) { return; } } } if(inonIPTraffic->unknownProtoSent[i].protoType = 1; host->nonIPTraffic->unknownProtoSent[i].proto.ethType = eth_type; } else if(dsap || ssap) { host->nonIPTraffic->unknownProtoSent[i].protoType = 2; host->nonIPTraffic->unknownProtoSent[i].proto.sapType.dsap = dsap; host->nonIPTraffic->unknownProtoSent[i].proto.sapType.ssap = ssap; } else { host->nonIPTraffic->unknownProtoSent[i].protoType = 3; host->nonIPTraffic->unknownProtoSent[i].proto.ipType = ipProto; } } } else { /* Rcvd */ if(host->nonIPTraffic->unknownProtoRcvd == NULL) { host->nonIPTraffic->unknownProtoRcvd = (UnknownProto*)malloc(sizeof(UnknownProto)* MAX_NUM_UNKNOWN_PROTOS); if(host->nonIPTraffic->unknownProtoRcvd == NULL) return; memset(host->nonIPTraffic->unknownProtoRcvd, 0, sizeof(UnknownProto)*MAX_NUM_UNKNOWN_PROTOS); } for(i=0; inonIPTraffic->unknownProtoRcvd[i].protoType == 0) break; if((host->nonIPTraffic->unknownProtoRcvd[i].protoType == 1) && eth_type) { if(host->nonIPTraffic->unknownProtoRcvd[i].proto.ethType == eth_type) { return; } } else if((host->nonIPTraffic->unknownProtoRcvd[i].protoType == 2) && (dsap || ssap)) { if((host->nonIPTraffic->unknownProtoRcvd[i].proto.sapType.dsap == dsap) && (host->nonIPTraffic->unknownProtoRcvd[i].proto.sapType.ssap == ssap)) { return; } } else if((host->nonIPTraffic->unknownProtoRcvd[i].protoType == 3) && ipProto) { if(host->nonIPTraffic->unknownProtoRcvd[i].proto.ipType == ipProto) { return; } } } if(inonIPTraffic->unknownProtoRcvd[i].protoType = 1; host->nonIPTraffic->unknownProtoRcvd[i].proto.ethType = eth_type; } else if(dsap || ssap) { host->nonIPTraffic->unknownProtoRcvd[i].protoType = 2; host->nonIPTraffic->unknownProtoRcvd[i].proto.sapType.dsap = dsap; host->nonIPTraffic->unknownProtoRcvd[i].proto.sapType.ssap = ssap; } else { host->nonIPTraffic->unknownProtoRcvd[i].protoType = 3; host->nonIPTraffic->unknownProtoRcvd[i].proto.ipType = ipProto; } } } } /* ************************************ */ static AsStats* allocASStats(u_int16_t as_id) { AsStats *asStats = (AsStats*)malloc(sizeof(AsStats)); if(0) traceEvent(CONST_TRACE_WARNING, "Allocating stats for AS %d", as_id); if(asStats != NULL) { memset(asStats, 0, sizeof(AsStats)); asStats->as_id = as_id; resetTrafficCounter(&asStats->outBytes); resetTrafficCounter(&asStats->outPkts); resetTrafficCounter(&asStats->inBytes); resetTrafficCounter(&asStats->inPkts); resetTrafficCounter(&asStats->selfBytes); resetTrafficCounter(&asStats->selfPkts); } return(asStats); } /* ************************************ */ static void updateASTraffic(int actualDeviceId, u_int16_t src_as_id, u_int16_t dst_as_id, u_int octets) { AsStats *stats, *prev_stats = NULL; u_char found_src = 0, found_dst = 0; if(0) traceEvent(CONST_TRACE_INFO, "updateASTraffic(actualDeviceId=%d, src_as_id=%d, dst_as_id=%d, octets=%d)", actualDeviceId, src_as_id, dst_as_id, octets); if((src_as_id == 0) && (dst_as_id == 0)) return; accessMutex(&myGlobals.device[actualDeviceId].asMutex, "updateASTraffic"); stats = myGlobals.device[actualDeviceId].asStats; while(stats) { if(stats->as_id == src_as_id) { stats->lastUpdate = myGlobals.actTime; incrementTrafficCounter(&stats->outBytes, octets), incrementTrafficCounter(&stats->outPkts, 1), stats->totPktsSinceLastRRDDump++; if(src_as_id == dst_as_id) { incrementTrafficCounter(&stats->selfBytes, octets), incrementTrafficCounter(&stats->selfPkts, 1); releaseMutex(&myGlobals.device[actualDeviceId].asMutex); return; } if(dst_as_id == 0) { releaseMutex(&myGlobals.device[actualDeviceId].asMutex); return; } else found_src = 1; } else if(stats->as_id == dst_as_id) { stats->lastUpdate = myGlobals.actTime; incrementTrafficCounter(&stats->inBytes, octets), incrementTrafficCounter(&stats->inPkts, 1), stats->totPktsSinceLastRRDDump++; if(src_as_id == dst_as_id) { incrementTrafficCounter(&stats->selfBytes, octets), incrementTrafficCounter(&stats->selfPkts, 1); releaseMutex(&myGlobals.device[actualDeviceId].asMutex); return; } if(src_as_id == 0) { releaseMutex(&myGlobals.device[actualDeviceId].asMutex); return; } else found_dst = 1; } if(found_src && found_dst) { releaseMutex(&myGlobals.device[actualDeviceId].asMutex); return; } if((myGlobals.actTime-stats->lastUpdate) > PARM_AS_MAXIMUM_IDLE) { AsStats *next = stats->next; if(0) traceEvent(CONST_TRACE_INFO, "Purging stats about AS %d", stats->as_id); if(prev_stats == NULL) myGlobals.device[actualDeviceId].asStats = next; else prev_stats->next = next; free(stats); stats = next; } else { prev_stats = stats; stats = stats->next; } } /* while */ /* One (or both) ASs are missing */ if((src_as_id != 0) && (!found_src)) { stats = allocASStats(src_as_id); stats->next = myGlobals.device[actualDeviceId].asStats; stats->lastUpdate = myGlobals.actTime; myGlobals.device[actualDeviceId].asStats = stats; } if((dst_as_id != 0) && (dst_as_id != src_as_id) && (!found_dst)) { stats = allocASStats(dst_as_id); stats->next = myGlobals.device[actualDeviceId].asStats; stats->lastUpdate = myGlobals.actTime; myGlobals.device[actualDeviceId].asStats = stats; } releaseMutex(&myGlobals.device[actualDeviceId].asMutex); updateASTraffic(actualDeviceId, src_as_id, dst_as_id, octets); } /* ************************************ */ static void processIpPkt(const u_char *bp, const struct pcap_pkthdr *h, u_int length, u_char *ether_src, u_char *ether_dst, int actualDeviceId, int vlanId) { u_short sport=0, dport=0; int sportIdx, dportIdx; struct ip ip; #ifdef INET6 struct ip6_hdr *ip6; struct icmp6_hdr icmp6Pkt; u_int advance; u_char *cp; u_char *snapend; u_int icmp6len; #endif u_int nh; int fragmented = 0; struct tcphdr tp; struct udphdr up; struct icmp icmpPkt; u_int hlen, ip_len,tcpDataLength, udpDataLength, off, tcpUdpLen, idx; char *proto; HostTraffic *srcHost=NULL, *dstHost=NULL; HostAddr srcAddr, dstAddr; /* Protocol Independent addresses */ u_char forceUsingIPaddress = 0; struct timeval tvstrct; u_char *theData, found = 0; TrafficCounter ctr; ProtocolsList *protoList; u_short newSession = 0; IPSession *theSession = NULL; u_short isPassiveSess = 0, nonFullyRemoteSession = 1, isVoipSess = 0; /* Need to copy this over in case bp isn't properly aligned. * This occurs on SunOS 4.x at least. * Paul D. Smith */ memcpy(&ip, bp, sizeof(struct ip)); #ifdef INET6 /* TODO: isipv6 = (ip.ip_v == 6)?1:0; */ if(ip.ip_v == 6) { /* handle IPv6 packets */ ip6 = (struct ip6_hdr *)bp; } else ip6 = NULL; #endif #ifdef INET6 if(ip6) hlen = sizeof(struct ip6_hdr); else #endif hlen = (u_int)ip.ip_hl * 4; incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipPkts, 1); #ifdef INET6 if(ip6 == NULL) #endif if((bp != NULL) && (myGlobals.device[actualDeviceId].datalink != DLT_NULL) && (in_cksum((const u_short *)bp, hlen, 0) != 0) ) { incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.badChecksum, 1); return; } /* Fix below courtesy of Christian Hammers */ #ifdef INET6 if(ip6) incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipv6Bytes, length /* ntohs(ip.ip_len) */); else #endif incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipBytes, length /* ntohs(ip.ip_len) */); #ifdef INET6 if(ip6 == NULL) { #endif if(ip.ip_p == CONST_GRE_PROTOCOL_TYPE) { /* Cisco GRE (Generic Routing Encapsulation) Tunnels (RFC 1701, 1702) */ GreTunnel tunnel; PPPTunnelHeader pppTHeader; memcpy(&tunnel, bp+hlen, sizeof(GreTunnel)); switch(ntohs(tunnel.protocol)) { case CONST_PPP_PROTOCOL_TYPE: memcpy(&pppTHeader, bp+hlen+sizeof(GreTunnel), sizeof(PPPTunnelHeader)); if(ntohs(pppTHeader.protocol) == 0x21 /* IP */) { memcpy(&ip, bp+hlen+sizeof(GreTunnel)+sizeof(PPPTunnelHeader), sizeof(struct ip)); hlen = (u_int)ip.ip_hl * 4; ether_src = NULL, ether_dst = NULL; } break; case ETHERTYPE_IP: memcpy(&ip, bp+hlen+4 /* 4 is the size of the GRE header */, sizeof(struct ip)); hlen = (u_int)ip.ip_hl * 4; ether_src = NULL, ether_dst = NULL; break; } } #ifdef INET6 } #endif if((ether_src == NULL) && (ether_dst == NULL)) { /* Ethernet-less protocols (e.g. PPP/RAW IP) */ forceUsingIPaddress = 1; } #ifdef INET6 if(ip6) { addrput(AF_INET6, &srcAddr, &ip6->ip6_src); addrput(AF_INET6, &dstAddr, &ip6->ip6_dst); } else #endif { NTOHL(ip.ip_dst.s_addr); NTOHL(ip.ip_src.s_addr); addrput(AF_INET, &srcAddr,&ip.ip_src.s_addr); addrput(AF_INET, &dstAddr,&ip.ip_dst.s_addr); } #ifdef INET6 if(ip6 == NULL) { #endif if((!myGlobals.runningPref.dontTrustMACaddr) && isBroadcastAddress(&dstAddr, NULL, NULL) && (ether_src != NULL) && (ether_dst != NULL) /* PPP has no ethernet */ && (memcmp(ether_dst, ethBroadcast, 6) != 0)) { /* forceUsingIPaddress = 1; */ srcHost = lookupHost(NULL, ether_src, vlanId, 0, 0, actualDeviceId); if(srcHost != NULL) { if(vlanId != NO_VLAN) srcHost->vlanId = vlanId; if(myGlobals.runningPref.enableSuspiciousPacketDump && (!hasWrongNetmask(srcHost))) { /* Dump the first packet only */ char etherbuf[LEN_ETHERNET_ADDRESS_DISPLAY]; traceEvent(CONST_TRACE_WARNING, "Host %s has a wrong netmask", etheraddr_string(ether_src, etherbuf)); dumpSuspiciousPacket(actualDeviceId); } FD_SET(FLAG_HOST_WRONG_NETMASK, &srcHost->flags); } } #ifdef INET6 } #endif /* IMPORTANT: do NOT change the order of the lines below (see isBroadcastAddress call) */ dstHost = lookupHost(&dstAddr, ether_dst, vlanId, 1 , 0 ,actualDeviceId); if(dstHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (2) [Low memory?]"); lowMemoryMsgShown = 1; return; } srcHost = lookupHost(&srcAddr, ether_src, vlanId, /* Don't check for multihoming when the destination address is a broadcast address */ (!isBroadcastAddress(&dstAddr, NULL, NULL)), forceUsingIPaddress, actualDeviceId); if(srcHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (1) [Low memory?]"); lowMemoryMsgShown = 1; return; /* It might be that there's not enough memory that that dstHost = lookupHost(&ip.ip_dst, ether_dst) caused srcHost to be freed */ } if(vlanId != NO_VLAN) { srcHost->vlanId = vlanId; dstHost->vlanId = vlanId; } #ifdef DEBUG if(myGlobals.runningPref.rFileName != NULL) { static int numPkt=1; traceEvent(CONST_TRACE_INFO, "%d) %s -> %s", numPkt++, srcHost->hostNumIpAddress, dstHost->hostNumIpAddress); fflush(stdout); } #endif /* ****************** */ #ifdef INET6 if(ip6) { updateDevicePacketTTLStats(ip6->ip6_hlim, actualDeviceId); if(ip6->ip6_hlim != 255) { if((srcHost->minTTL == 0) || (ip6->ip6_hlim < srcHost->minTTL)) srcHost->minTTL = ip6->ip6_hlim; if((ip6->ip6_hlim > srcHost->maxTTL)) srcHost->maxTTL = ip6->ip6_hlim; } } else #endif { updateDevicePacketTTLStats(ip.ip_ttl, actualDeviceId); if(ip.ip_ttl != 255) { /* TTL can be calculated only when the packet is originated by the sender */ if((srcHost->minTTL == 0) || (ip.ip_ttl < srcHost->minTTL)) srcHost->minTTL = ip.ip_ttl; if((ip.ip_ttl > srcHost->maxTTL)) srcHost->maxTTL = ip.ip_ttl; } } ctr.value = h->len; updatePacketCount(srcHost, &srcAddr, dstHost, &dstAddr, ctr, 1, actualDeviceId); if((!myGlobals.runningPref.dontTrustMACaddr) && (!myGlobals.device[actualDeviceId].dummyDevice)) { checkNetworkRouter(srcHost, dstHost, ether_dst, actualDeviceId); ctr.value = length; updateTrafficMatrix(srcHost, dstHost, ctr, actualDeviceId); } #ifdef INET6 if(ip6) { incrementTrafficCounter(&srcHost->ipv6Sent, length), incrementTrafficCounter(&dstHost->ipv6Rcvd, length); } else #endif { incrementTrafficCounter(&srcHost->ipBytesSent, length), incrementTrafficCounter(&dstHost->ipBytesRcvd, length); } if(subnetPseudoLocalHost(srcHost)) { if(subnetPseudoLocalHost(dstHost)) { incrementTrafficCounter(&srcHost->bytesSentLoc, length); incrementTrafficCounter(&dstHost->bytesRcvdLoc, length); } else { incrementTrafficCounter(&srcHost->bytesSentRem, length); incrementTrafficCounter(&dstHost->bytesRcvdLoc, length); } } else { /* srcHost is remote */ if(subnetPseudoLocalHost(dstHost)) { incrementTrafficCounter(&srcHost->bytesSentLoc, length); incrementTrafficCounter(&dstHost->bytesRcvdFromRem, length); } else { incrementTrafficCounter(&srcHost->bytesSentRem, length); incrementTrafficCounter(&dstHost->bytesRcvdFromRem, length); } } #ifdef INET6 if(ip6) { if(ip6->ip6_nxt == IPPROTO_FRAGMENT) { fragmented = 1; nh = ip6->ip6_nxt; } } else #endif { off = ntohs(ip.ip_off); if(off & 0x3fff) { fragmented = 1; nh = ip.ip_p; } } /* This is a fragment: fragment handling is handled by handleFragment() called below. Courtesy of Andreas Pfaller */ if(fragmented) { incrementTrafficCounter(&myGlobals.device[actualDeviceId].fragmentedIpBytes, length); switch(nh) { case IPPROTO_TCP: incrementTrafficCounter(&srcHost->tcpFragmentsSent, length), incrementTrafficCounter(&dstHost->tcpFragmentsRcvd, length); break; case IPPROTO_UDP: incrementTrafficCounter(&srcHost->udpFragmentsSent, length), incrementTrafficCounter(&dstHost->udpFragmentsRcvd, length); break; case IPPROTO_ICMP: incrementTrafficCounter(&srcHost->icmpFragmentsSent, length), incrementTrafficCounter(&dstHost->icmpFragmentsRcvd, length); break; #ifdef INET6 case IPPROTO_ICMPV6: incrementTrafficCounter(&srcHost->icmp6FragmentsSent, length), incrementTrafficCounter(&dstHost->icmp6FragmentsRcvd, length); break; #endif } } #ifdef INET6 if(ip6) { advance = sizeof(struct ip6_hdr); cp = (unsigned char *) ip6; snapend = (unsigned char *)(bp+length); nh = ip6->ip6_nxt; ip_len = ntohs(ip6->ip6_plen); tcpUdpLen = ip_len; } else #endif { nh = ip.ip_p; ip_len = ntohs(ip.ip_len); tcpUdpLen = ip_len - hlen; } #ifdef INET6 loop: if(ip6) cp +=advance; #endif switch(nh) { #ifdef INET6 case IPPROTO_FRAGMENT: if(ip6) { advance = sizeof(struct ip6_frag); if(snapend <= cp+advance) goto end; nh = *cp; goto loop; } /* If it's no IPv6 we continue */ #endif case IPPROTO_TCP: incrementTrafficCounter(&myGlobals.device[actualDeviceId].tcpBytes, length); if(tcpUdpLen < sizeof(struct tcphdr)) { if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, "Malformed TCP pkt %s->%s detected (packet too short)", srcHost->hostResolvedName, dstHost->hostResolvedName); dumpSuspiciousPacket(actualDeviceId); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->malformedPktsSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->malformedPktsRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.malformedPkts, 1); } } else { proto = "TCP"; memcpy(&tp, bp+hlen, sizeof(struct tcphdr)); /* Sanity check */ if(tcpUdpLen >= (tp.th_off * 4)) { int diff; /* Real lenght if we captured the full packet */ tcpDataLength = tcpUdpLen - (tp.th_off * 4); /* Actual lenght scaled with caplen */ diff = h->caplen - (h->len - tcpDataLength); if(diff > 0) { tcpDataLength = diff; theData = (u_char*)(bp+hlen+(tp.th_off * 4)); } else { tcpDataLength = 0; theData = NULL; } } else { tcpDataLength = 0; theData = NULL; } sport = ntohs(tp.th_sport); dport = ntohs(tp.th_dport); /* Don't move this code on top as it is supposed to stay here as it modifies sport/sport Courtesy of Andreas Pfaller */ if(myGlobals.enableFragmentHandling && (fragmented)) { /* Handle fragmented packets */ #ifdef INET6 if(ip6) length = handleFragment(srcHost, dstHost, &sport,&dport, (u_short)(ip6->ip6_flow & 0xffff),fragmented, length,ntohs(ip6->ip6_plen), actualDeviceId); else #endif length = handleFragment(srcHost, dstHost, &sport, &dport, ntohs(ip.ip_id), off, length, ip_len - hlen, actualDeviceId); } if(srcHost->fingerprint == NULL) { char fingerprint[64]; int WIN=0, MSS=-1, WS=-1, S=0, N=0, D=0, T=0; int ttl; char WSS[3], _MSS[5]; struct tcphdr *tcp = (struct tcphdr*)(bp+hlen); u_char *tcp_opt = (u_char *)(tcp + 1); u_char *tcp_data = (u_char *)(tcp + tp.th_off * 4); if(tcp->th_flags & TH_SYN) { /* only SYN or SYN-2ACK packets */ if(tcpUdpLen > 0) { #ifdef INET6 if(ip6) { if(!fragmented) D = 1; } else #endif if(ntohs(ip.ip_off) & IP_DF) D = 1; /* don't fragment bit is set */ WIN = ntohs(tcp->th_win); /* TCP window size */ if(tcp_data != tcp_opt) { /* there are some tcp_option to be parsed */ u_char *opt_start = tcp_opt, *opt_end = tcp_data; u_short num_loops = 0; while(opt_start < opt_end) { switch(*opt_start) { case TCPOPT_EOL: /* end option: exit */ opt_start = opt_end; break; case TCPOPT_NOP: N = 1; opt_start++; break; case TCPOPT_SACKOK: S = 1; opt_start += 2; break; case TCPOPT_MAXSEG: opt_start += 2; MSS = ntohs(ptohs(opt_start)); opt_start += 2; break; case TCPOPT_WSCALE: opt_start += 2; WS = *opt_start; opt_start++; break; case TCPOPT_TIMESTAMP: T = 1; opt_start++; opt_start += (*opt_start - 1); break; default: opt_start++; if(*opt_start > 0) opt_start += (*opt_start - 1); break; } num_loops++; if(num_loops > 16) { /* Suspicious packet: maybe the TCP options are wrong */ break; } } } if(WS == -1) safe_snprintf(__FILE__, __LINE__, WSS, sizeof(WSS), "WS"); else safe_snprintf(__FILE__, __LINE__, WSS, sizeof(WSS), "%02X", WS & 0xFFFF); if(MSS == -1) safe_snprintf(__FILE__, __LINE__, _MSS, sizeof(_MSS), "_MSS"); else safe_snprintf(__FILE__, __LINE__, _MSS, sizeof(_MSS), "%04X", MSS & 0xFFFFFFFF); safe_snprintf(__FILE__, __LINE__, fingerprint, sizeof(fingerprint), "%04X:%s:%02X:%s:%d:%d:%d:%d:%c:%02X", WIN, _MSS, ttl = TTL_PREDICTOR(ip.ip_ttl), WSS , S, N, D, T, (tcp->th_flags & TH_ACK) ? 'A' : 'S', tcpUdpLen); #if 0 traceEvent(CONST_TRACE_INFO, "[%s][%s]", srcHost->hostNumIpAddress, fingerprint); #endif accessAddrResMutex("processIpPkt"); srcHost->fingerprint = strdup(fingerprint); releaseAddrResMutex(); } } } if((sport > 0) || (dport > 0)) { /* It might be that tcpDataLength is 0 when the rcvd packet is fragmented and the main packet has not yet been rcvd */ updateInterfacePorts(actualDeviceId, sport, dport, length); if(tcpDataLength > 0) /* Don't update ports for all packets */ updateUsedPorts(srcHost, dstHost, sport, dport, tcpDataLength); if(subnetPseudoLocalHost(srcHost)) { if(subnetPseudoLocalHost(dstHost)) { incrementTrafficCounter(&srcHost->tcpSentLoc, length); incrementTrafficCounter(&dstHost->tcpRcvdLoc, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].tcpGlobalTrafficStats.local, length); } else { incrementTrafficCounter(&srcHost->tcpSentRem, length); incrementTrafficCounter(&dstHost->tcpRcvdLoc, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].tcpGlobalTrafficStats.local2remote, length); } } else { /* srcHost is remote */ if(subnetPseudoLocalHost(dstHost)) { incrementTrafficCounter(&srcHost->tcpSentLoc, length); incrementTrafficCounter(&dstHost->tcpRcvdFromRem, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].tcpGlobalTrafficStats.remote2local, length); } else { incrementTrafficCounter(&srcHost->tcpSentRem, length); incrementTrafficCounter(&dstHost->tcpRcvdFromRem, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].tcpGlobalTrafficStats.remote, length); nonFullyRemoteSession = 0; } } if(nonFullyRemoteSession) { #ifdef INET6 if(ip6) theSession = handleSession(h, fragmented, tp.th_win, srcHost, sport, dstHost, dport, ntohs(ip6->ip6_plen), &tp, tcpDataLength, theData, actualDeviceId, &newSession, 1); else #endif theSession = handleSession(h, (off & 0x3fff), tp.th_win, srcHost, sport, dstHost, dport, ip_len, &tp, tcpDataLength, theData, actualDeviceId, &newSession, 1); if(theSession == NULL) isPassiveSess = isVoipSess = 0; else { isPassiveSess = theSession->passiveFtpSession; isVoipSess = theSession->voipSession; } } sportIdx = mapGlobalToLocalIdx(sport), dportIdx = mapGlobalToLocalIdx(dport); if((myGlobals.runningPref.enableOtherPacketDump) && ((sportIdx == -1) && (dportIdx == -1))) { /* Both source & destination port are unknown. The packet will be counted to "Other TCP/UDP prot." : We dump the packet if requested */ dumpOtherPacket(actualDeviceId); } /* choose most likely port for protocol traffic accounting * by trying lower number port first. This is based * on the assumption that lower port numbers are more likely * to be the servers and clients usually dont use ports <1024 * This is only relevant if both port numbers are used to * gather service statistics. * e.g. traffic between port 2049 (nfsd) and 113 (nntp) will * be counted as nntp traffic in all directions by this heuristic * and not as nntp in one direction and nfs in the return direction. * * Courtesy of Andreas Pfaller */ if((dport < sport) && ((!((sportIdx != -1) && (dportIdx == -1))) || ((sportIdx == -1) && (dportIdx != -1)))) { /* traceEvent(CONST_TRACE_INFO, "[1] sportIdx(%d)=%d - dportIdx(%d)=%d", sport, sportIdx, dport, dportIdx); */ if(handleIP(dport, srcHost, dstHost, length, isPassiveSess, isVoipSess, theSession != NULL ? theSession->isP2P : 0, actualDeviceId, newSession) == -1) handleIP(sport, srcHost, dstHost, length, isPassiveSess, isVoipSess, theSession != NULL ? theSession->isP2P : 0, actualDeviceId, newSession); } else { /* traceEvent(CONST_TRACE_INFO, "[2] sportIdx(%d)=%d - dportIdx(%d)=%d", sport, sportIdx, dport, dportIdx); */ if(handleIP(sport, srcHost, dstHost, length, isPassiveSess, isVoipSess, theSession != NULL ? theSession->isP2P : 0, actualDeviceId, newSession) == -1) handleIP(dport, srcHost, dstHost, length, isPassiveSess, isVoipSess, theSession != NULL ? theSession->isP2P : 0, actualDeviceId, newSession); } } } #ifdef INET6 if(ip6) goto end; else #endif break; case IPPROTO_UDP: proto = "UDP"; incrementTrafficCounter(&myGlobals.device[actualDeviceId].udpBytes, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].udpGlobalTrafficStats.totalFlows, 1); if(tcpUdpLen < sizeof(struct udphdr)) { if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, "Malformed UDP pkt %s->%s detected (packet too short)", srcHost->hostResolvedName, dstHost->hostResolvedName); dumpSuspiciousPacket(actualDeviceId); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->malformedPktsSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->malformedPktsRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.malformedPkts, 1); } } else { udpDataLength = tcpUdpLen - sizeof(struct udphdr); memcpy(&up, bp+hlen, sizeof(struct udphdr)); sport = ntohs(up.uh_sport); dport = ntohs(up.uh_dport); if(!(fragmented)) { /* Not fragmented */ if(((sport == 53) || (dport == 53) /* domain */) || ((sport == 5353) && (dport == 5353)) /* Multicast DNS */) { short isRequest = 0, positiveReply = 0; u_int16_t transactionId = 0; if(myGlobals.runningPref.enablePacketDecoding && (bp != NULL) /* packet long enough */) { /* The DNS chain will be checked here */ transactionId = processDNSPacket(srcHost, sport, bp+hlen+sizeof(struct udphdr), udpDataLength, &isRequest, &positiveReply); #ifdef DNS_SNIFF_DEBUG traceEvent(CONST_TRACE_INFO, "DNS_SNIFF_DEBUG: %s:%d->%s:%d [request: %d][positive reply: %d]", srcHost->hostResolvedName, sport, dstHost->hostResolvedName, dport, isRequest, positiveReply); #endif if(srcHost->protocolInfo == NULL) srcHost->protocolInfo = calloc(1, sizeof(ProtocolInfo)); if(dstHost->protocolInfo == NULL) dstHost->protocolInfo = calloc(1, sizeof(ProtocolInfo)); if((srcHost->protocolInfo == NULL) || (dstHost->protocolInfo == NULL)) return; if(srcHost->protocolInfo->dnsStats == NULL) { srcHost->protocolInfo->dnsStats = (ServiceStats*)malloc(sizeof(ServiceStats)); if(srcHost->protocolInfo->dnsStats == NULL) return; memset(srcHost->protocolInfo->dnsStats, 0, sizeof(ServiceStats)); } if(dstHost->protocolInfo->dnsStats == NULL) { dstHost->protocolInfo->dnsStats = (ServiceStats*)malloc(sizeof(ServiceStats)); if(dstHost->protocolInfo->dnsStats == NULL) return; memset(dstHost->protocolInfo->dnsStats, 0, sizeof(ServiceStats)); } if(isRequest) { /* to be 64bit-proof we have to copy the elements */ tvstrct.tv_sec = h->ts.tv_sec; tvstrct.tv_usec = h->ts.tv_usec; addTimeMapping(transactionId, tvstrct); if(subnetLocalHost(dstHost)) incrementTrafficCounter(&srcHost->protocolInfo->dnsStats->numLocalReqSent, 1); else incrementTrafficCounter(&srcHost->protocolInfo->dnsStats->numRemReqSent, 1); if(subnetLocalHost(srcHost)) incrementTrafficCounter(&dstHost->protocolInfo->dnsStats->numLocalReqRcvd, 1); else incrementTrafficCounter(&dstHost->protocolInfo->dnsStats->numRemReqRcvd, 1); } else { time_t microSecTimeDiff; /* to be 64bit-safe we have to copy the elements */ tvstrct.tv_sec = h->ts.tv_sec; tvstrct.tv_usec = h->ts.tv_usec; microSecTimeDiff = getTimeMapping(transactionId, tvstrct); if(microSecTimeDiff > 0) { #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "TransactionId=0x%X [%.1f ms]", transactionId, ((float)microSecTimeDiff)/1000); #endif if(microSecTimeDiff > 0) { if(subnetLocalHost(dstHost)) { if((srcHost->protocolInfo->dnsStats->fastestMicrosecLocalReqServed == 0) || (microSecTimeDiff < srcHost->protocolInfo->dnsStats->fastestMicrosecLocalReqServed)) srcHost->protocolInfo->dnsStats->fastestMicrosecLocalReqServed = microSecTimeDiff; if(microSecTimeDiff > srcHost->protocolInfo->dnsStats->slowestMicrosecLocalReqServed) srcHost->protocolInfo->dnsStats->slowestMicrosecLocalReqServed = microSecTimeDiff; } else { if((srcHost->protocolInfo->dnsStats->fastestMicrosecRemReqServed == 0) || (microSecTimeDiff < srcHost->protocolInfo->dnsStats->fastestMicrosecRemReqServed)) srcHost->protocolInfo->dnsStats->fastestMicrosecRemReqServed = microSecTimeDiff; if(microSecTimeDiff > srcHost->protocolInfo->dnsStats->slowestMicrosecRemReqServed) srcHost->protocolInfo->dnsStats->slowestMicrosecRemReqServed = microSecTimeDiff; } if(subnetLocalHost(srcHost)) { if((dstHost->protocolInfo->dnsStats->fastestMicrosecLocalReqMade == 0) || (microSecTimeDiff < dstHost->protocolInfo->dnsStats->fastestMicrosecLocalReqMade)) dstHost->protocolInfo->dnsStats->fastestMicrosecLocalReqMade = microSecTimeDiff; if(microSecTimeDiff > dstHost->protocolInfo->dnsStats->slowestMicrosecLocalReqMade) dstHost->protocolInfo->dnsStats->slowestMicrosecLocalReqMade = microSecTimeDiff; } else { if((dstHost->protocolInfo->dnsStats->fastestMicrosecRemReqMade == 0) || (microSecTimeDiff < dstHost->protocolInfo->dnsStats->fastestMicrosecRemReqMade)) dstHost->protocolInfo->dnsStats->fastestMicrosecRemReqMade = microSecTimeDiff; if(microSecTimeDiff > dstHost->protocolInfo->dnsStats->slowestMicrosecRemReqMade) dstHost->protocolInfo->dnsStats->slowestMicrosecRemReqMade = microSecTimeDiff; } } else { #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "getTimeMapping(0x%X) failed for DNS", transactionId); #endif } } /* Courtesy of Roberto F. De Luca */ if(sport != 5353) FD_SET(FLAG_NAME_SERVER_HOST, &srcHost->flags); if(positiveReply) { incrementTrafficCounter(&srcHost->protocolInfo->dnsStats->numPositiveReplSent, 1); incrementTrafficCounter(&dstHost->protocolInfo->dnsStats->numPositiveReplRcvd, 1); } else { incrementTrafficCounter(&srcHost->protocolInfo->dnsStats->numNegativeReplSent, 1); incrementTrafficCounter(&dstHost->protocolInfo->dnsStats->numNegativeReplRcvd, 1); } } } else { /* no packet decoding (let's speculate a bit) */ if(sport != 5353) FD_SET(FLAG_NAME_SERVER_HOST, &srcHost->flags); } } else if(sport == 123) /* NTP */ { if(myGlobals.runningPref.enablePacketDecoding) { char *ntpPktPtr = (char*)bp+hlen+sizeof(struct udphdr); u_char ntpRole = ntpPktPtr[0] & 0x07; if(ntpRole == 4 /* NTP Server */) FD_SET(FLAG_HOST_TYPE_SVC_NTP_SERVER, &srcHost->flags); } } else { if(myGlobals.runningPref.enablePacketDecoding) handleNetbios(srcHost, dstHost, sport, dport, udpDataLength, bp, length, hlen); } } /* Don't move this code on top as it is supposed to stay here as it modifies sport/sport Courtesy of Andreas Pfaller */ if(myGlobals.enableFragmentHandling && (fragmented)) { /* Handle fragmented packets */ #ifdef INET6 if(ip6) length = handleFragment(srcHost, dstHost, &sport, &dport, (u_short)(ip6->ip6_flow & 0xffff), fragmented, length, ntohs(ip6->ip6_plen), actualDeviceId); else #endif length = handleFragment(srcHost, dstHost, &sport, &dport, ntohs(ip.ip_id), off, length, ip_len - hlen, actualDeviceId); } if((sport > 0) || (dport > 0)) { updateInterfacePorts(actualDeviceId, sport, dport, length); updateUsedPorts(srcHost, dstHost, sport, dport, udpDataLength); /* It might be that udpBytes is 0 when the rcvd packet is fragmented and the main packet has not yet been rcvd */ if(subnetPseudoLocalHost(srcHost)) { if(subnetPseudoLocalHost(dstHost)) { incrementTrafficCounter(&srcHost->udpSentLoc, length); incrementTrafficCounter(&dstHost->udpRcvdLoc, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].udpGlobalTrafficStats.local, length); } else { incrementTrafficCounter(&srcHost->udpSentRem, length); incrementTrafficCounter(&dstHost->udpRcvdLoc, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].udpGlobalTrafficStats.local2remote, length); } } else { /* srcHost is remote */ if(subnetPseudoLocalHost(dstHost)) { incrementTrafficCounter(&srcHost->udpSentLoc, length); incrementTrafficCounter(&dstHost->udpRcvdFromRem, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].udpGlobalTrafficStats.remote2local, length); } else { incrementTrafficCounter(&srcHost->udpSentRem, length); incrementTrafficCounter(&dstHost->udpRcvdFromRem, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].udpGlobalTrafficStats.remote, length); nonFullyRemoteSession = 0; } } sportIdx = mapGlobalToLocalIdx(sport), dportIdx = mapGlobalToLocalIdx(dport); if((myGlobals.runningPref.enableOtherPacketDump) && ((sportIdx == -1) && (dportIdx == -1))) { /* Both source & destination port are unknown. The packet will be counted to "Other TCP/UDP prot.". We dump the packet if requested */ dumpOtherPacket(actualDeviceId); } if(nonFullyRemoteSession) { /* There is no session structure returned for UDP sessions */ #ifdef INET6 if(ip6) theSession = handleSession(h, fragmented, 0, srcHost, sport, dstHost, dport, ntohs(ip6->ip6_plen), NULL, udpDataLength, (u_char*)(bp+hlen+sizeof(struct udphdr)), actualDeviceId, &newSession, 1); else #endif theSession = handleSession (h, (off & 0x3fff), 0, srcHost, sport, dstHost, dport, ip_len, NULL, udpDataLength, (u_char*)(bp+hlen+sizeof(struct udphdr)), actualDeviceId, &newSession, 1); } isPassiveSess = 0; if(theSession == NULL) isVoipSess = 0; else isVoipSess = theSession->voipSession; newSession = 1; /* Trick to account flows anyway */ if((sport == IP_TCP_PORT_SKYPE) || (dport == IP_TCP_PORT_SKYPE)) { if(theSession) theSession->voipSession = 1; isVoipSess = 1; FD_SET(FLAG_HOST_TYPE_SVC_VOIP_CLIENT, &srcHost->flags); FD_SET(FLAG_HOST_TYPE_SVC_VOIP_CLIENT, &dstHost->flags); } /* Handle UDP traffic like TCP, above - That is: if we know about the lower# port, even if it's the destination, classify the traffic that way. (BMS 12-2001) */ if(dport < sport) { if(handleIP(dport, srcHost, dstHost, length, isPassiveSess, isVoipSess, 0, actualDeviceId, newSession) == -1) handleIP(sport, srcHost, dstHost, length, isPassiveSess, isVoipSess, 0, actualDeviceId, newSession); } else { if(handleIP(sport, srcHost, dstHost, length, isPassiveSess, isVoipSess, 0, actualDeviceId, newSession) == -1) handleIP(dport, srcHost, dstHost, length, isPassiveSess, isVoipSess, 0, actualDeviceId, newSession); } } } #ifdef INET6 if(ip6) goto end; else #endif break; case IPPROTO_ICMP: incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpBytes, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.totalFlows, 1); if(tcpUdpLen < sizeof(struct icmp)) { if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, "Malformed ICMP pkt %s->%s detected (packet too short)", srcHost->hostResolvedName, dstHost->hostResolvedName); dumpSuspiciousPacket(actualDeviceId); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->malformedPktsSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->malformedPktsRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.malformedPkts, 1); } } else { proto = "ICMP"; memcpy(&icmpPkt, bp+hlen, sizeof(struct icmp)); incrementTrafficCounter(&srcHost->icmpSent, length); incrementTrafficCounter(&dstHost->icmpRcvd, length); if(off & 0x3fff) { char *fmt = "Detected ICMP fragment [%s -> %s] (network attack attempt?)"; incrementTrafficCounter(&srcHost->icmpFragmentsSent, length), incrementTrafficCounter(&dstHost->icmpFragmentsRcvd, length); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpFragmentSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpFragmentRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.icmpFragment, 1); if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, fmt, srcHost->hostResolvedName, dstHost->hostResolvedName); dumpSuspiciousPacket(actualDeviceId); } } /* ************************************************************* */ if(icmpPkt.icmp_type <= ICMP_MAXTYPE) { short dumpPacket = 1; if(srcHost->icmpInfo == NULL) { if((srcHost->icmpInfo = (IcmpHostInfo*)malloc(sizeof(IcmpHostInfo))) == NULL) return; memset(srcHost->icmpInfo, 0, sizeof(IcmpHostInfo)); } incrementTrafficCounter(&srcHost->icmpInfo->icmpMsgSent[icmpPkt.icmp_type], 1); if(dstHost->icmpInfo == NULL) { if( (dstHost->icmpInfo = (IcmpHostInfo*)malloc(sizeof(IcmpHostInfo))) == NULL) return; memset(dstHost->icmpInfo, 0, sizeof(IcmpHostInfo)); } incrementTrafficCounter(&dstHost->icmpInfo->icmpMsgRcvd[icmpPkt.icmp_type], 1); switch (icmpPkt.icmp_type) { case ICMP_ECHOREPLY: case ICMP_ECHO: /* Do not log anything */ dumpPacket = 0; break; case ICMP_UNREACH: case ICMP_REDIRECT: case ICMP_ROUTERADVERT: case ICMP_TIMXCEED: case ICMP_PARAMPROB: case ICMP_MASKREPLY: case ICMP_MASKREQ: case ICMP_INFO_REQUEST: case ICMP_INFO_REPLY: case ICMP_TIMESTAMP: case ICMP_TIMESTAMPREPLY: case ICMP_SOURCE_QUENCH: if(myGlobals.runningPref.enableSuspiciousPacketDump) { dumpSuspiciousPacket(actualDeviceId); } break; } if(myGlobals.runningPref.enableSuspiciousPacketDump && dumpPacket) { if(!((icmpPkt.icmp_type == 3) && (icmpPkt.icmp_code == 3))) { /* Avoid to print twice the same message: - Detected ICMP msg (type=3/code=3) from lhost -> ahost - Host [ahost] sent UDP data to a closed port of host [lhost:10001] (scan attempt?) */ traceEvent(CONST_TRACE_INFO, "Detected ICMP msg [type=%s/code=%d] %s->%s", mapIcmpType(icmpPkt.icmp_type), icmpPkt.icmp_code, srcHost->hostResolvedName, dstHost->hostResolvedName); } } } /* ************************************************************* */ if(subnetPseudoLocalHost(srcHost)) if(subnetPseudoLocalHost(dstHost)) incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.local, length); else incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.local2remote, length); else /* srcHost is remote */ if(subnetPseudoLocalHost(dstHost)) incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.remote2local, length); else incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.remote, length); if(myGlobals.runningPref.enableSuspiciousPacketDump && (icmpPkt.icmp_type == ICMP_ECHO) && (broadcastHost(dstHost) || multicastHost(dstHost))) { traceEvent(CONST_TRACE_WARNING, "Smurf packet detected for host [%s->%s]", srcHost->hostResolvedName, dstHost->hostResolvedName); } else if(icmpPkt.icmp_type == ICMP_DEST_UNREACHABLE /* Destination Unreachable */) { struct ip *oip = &icmpPkt.icmp_ip; switch(icmpPkt.icmp_code) { case ICMP_UNREACH_PORT: /* Port Unreachable */ memcpy(&dport, ((u_char *)bp+hlen+30), sizeof(dport)); dport = ntohs(dport); switch (oip->ip_p) { case IPPROTO_TCP: if(myGlobals.runningPref.enableSuspiciousPacketDump) traceEvent(CONST_TRACE_WARNING, "Host [%s] sent TCP data to a closed port of host [%s:%d] (scan attempt?)", dstHost->hostResolvedName, srcHost->hostResolvedName, dport); /* Simulation of rejected TCP connection */ allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->rejectedTCPConnSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->rejectedTCPConnRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.rejectedTCPConn, 1); break; case IPPROTO_UDP: if(myGlobals.runningPref.enableSuspiciousPacketDump) traceEvent(CONST_TRACE_WARNING, "Host [%s] sent UDP data to a closed port of host [%s:%d] (scan attempt?)", dstHost->hostResolvedName, srcHost->hostResolvedName, dport); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&dstHost->secHostPkts->udpToClosedPortSent, srcHost, actualDeviceId); incrementUsageCounter(&srcHost->secHostPkts->udpToClosedPortRcvd, dstHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.udpToClosedPort, 1); break; } allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpPortUnreachSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpPortUnreachRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.icmpPortUnreach, 1); break; case ICMP_UNREACH_NET: case ICMP_UNREACH_HOST: allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpHostNetUnreachSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpHostNetUnreachRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.icmpHostNetUnreach, 1); break; case ICMP_UNREACH_PROTOCOL: /* Protocol Unreachable */ if(myGlobals.runningPref.enableSuspiciousPacketDump) traceEvent(CONST_TRACE_WARNING, /* See http://www.packetfactory.net/firewalk/ */ "Host [%s] rcvd a ICMP protocol Unreachable from host [%s]" " (Firewalking scan attempt?)", dstHost->hostResolvedName, srcHost->hostResolvedName); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpProtocolUnreachSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpProtocolUnreachRcvd, srcHost, actualDeviceId); break; case ICMP_UNREACH_NET_PROHIB: /* Net Administratively Prohibited */ case ICMP_UNREACH_HOST_PROHIB: /* Host Administratively Prohibited */ case ICMP_UNREACH_FILTER_PROHIB: /* Access Administratively Prohibited */ if(myGlobals.runningPref.enableSuspiciousPacketDump) traceEvent(CONST_TRACE_WARNING, /* See http://www.packetfactory.net/firewalk/ */ "Host [%s] sent ICMP Administratively Prohibited packet to host [%s]" " (Firewalking scan attempt?)", dstHost->hostResolvedName, srcHost->hostResolvedName); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpAdminProhibitedSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpAdminProhibitedRcvd, srcHost, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].securityPkts.icmpAdminProhibited, 1); break; } if(myGlobals.runningPref.enableSuspiciousPacketDump) dumpSuspiciousPacket(actualDeviceId); } } break; #ifdef INET6 case IPPROTO_ICMPV6: if(ip6 == NULL) { if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING,"Protocol violation: ICMPv6 protocol in IPv4 packet: %s->%s", srcHost->hostResolvedName, dstHost->hostResolvedName); dumpSuspiciousPacket(actualDeviceId); } goto end; } incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmp6Bytes, length); if(ip6->ip6_plen) icmp6len = ntohs(ip6->ip6_plen); /* TODO: considering the pointers cp et bp*/ if(icmp6len < sizeof(struct icmp6_hdr)) { if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, "Malformed ICMPv6 pkt %s->%s detected (packet too short)", srcHost->hostResolvedName, dstHost->hostResolvedName); dumpSuspiciousPacket(actualDeviceId); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->malformedPktsSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->malformedPktsRcvd, srcHost, actualDeviceId); } } else { proto = "ICMPv6"; memcpy(&icmp6Pkt, bp+hlen, sizeof(struct icmp6_hdr)); incrementTrafficCounter(&srcHost->icmp6Sent, length); incrementTrafficCounter(&dstHost->icmp6Rcvd, length); if(fragmented) { char *fmt = "Detected ICMPv6 fragment [%s -> %s] (network attack attempt?)"; incrementTrafficCounter(&srcHost->icmp6FragmentsSent, length), incrementTrafficCounter(&dstHost->icmp6FragmentsRcvd, length); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpFragmentSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpFragmentRcvd, srcHost, actualDeviceId); if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, fmt, srcHost->hostResolvedName, dstHost->hostResolvedName); dumpSuspiciousPacket(actualDeviceId); } } /* ************************************************************* */ if(icmp6Pkt.icmp6_type <= ICMP6_MAXTYPE) { short dumpPacket = 1; if(srcHost->icmpInfo == NULL) { if((srcHost->icmpInfo = (IcmpHostInfo*)malloc(sizeof(IcmpHostInfo))) == NULL) return; memset(srcHost->icmpInfo, 0, sizeof(IcmpHostInfo)); } incrementTrafficCounter(&srcHost->icmpInfo->icmpMsgSent[icmp6Pkt.icmp6_type], 1); if(dstHost->icmpInfo == NULL) { if((dstHost->icmpInfo = (IcmpHostInfo*)malloc(sizeof(IcmpHostInfo))) == NULL) return; memset(dstHost->icmpInfo, 0, sizeof(IcmpHostInfo)); } incrementTrafficCounter(&dstHost->icmpInfo->icmpMsgRcvd[icmp6Pkt.icmp6_type], 1); switch (icmp6Pkt.icmp6_type) { case ICMP6_ECHO_REPLY: case ICMP6_ECHO_REQUEST: /* Do not log anything */ dumpPacket = 0; break; case ICMP6_DST_UNREACH: case ND_REDIRECT: case ICMP6_TIME_EXCEEDED: case ICMP6_PARAM_PROB: case ICMP6_NI_QUERY: case ICMP6_NI_REPLY: if(myGlobals.runningPref.enableSuspiciousPacketDump) { dumpSuspiciousPacket(actualDeviceId); } break; } } /* ************************************************************* */ if(subnetPseudoLocalHost(srcHost)) if(subnetPseudoLocalHost(dstHost)) incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.local, length); else incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.local2remote, length); else /* srcHost is remote */ if(subnetPseudoLocalHost(dstHost)) incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.remote2local, length); else incrementTrafficCounter(&myGlobals.device[actualDeviceId].icmpGlobalTrafficStats.remote, length); if(icmp6Pkt.icmp6_type == ND_ROUTER_ADVERT) { HostTraffic *router = lookupHost(NULL, ether_src, vlanId, 0, 0, actualDeviceId); if(router != NULL) FD_SET(FLAG_GATEWAY_HOST, &router->flags); } if(icmp6Pkt.icmp6_type == ICMP6_DST_UNREACH /* Destination Unreachable */) { struct ip6_hdr *oip = (struct ip6_hdr *)&icmp6Pkt+1; switch(icmp6Pkt.icmp6_code) { case ICMP6_DST_UNREACH_NOPORT: /* Port Unreachable */ memcpy(&dport, ((u_char *)bp+hlen+30), sizeof(dport)); dport = ntohs(dport); switch (oip->ip6_nxt) { case IPPROTO_TCP: if(myGlobals.runningPref.enableSuspiciousPacketDump) traceEvent(CONST_TRACE_WARNING, "Host [%s] sent TCP data to a closed port of host [%s:%d] (scan attempt?)", dstHost->hostResolvedName, srcHost->hostResolvedName, dport); /* Simulation of rejected TCP connection */ allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->rejectedTCPConnSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->rejectedTCPConnRcvd, srcHost, actualDeviceId); break; case IPPROTO_UDP: if(myGlobals.runningPref.enableSuspiciousPacketDump) traceEvent(CONST_TRACE_WARNING, "Host [%s] sent UDP data to a closed port of host [%s:%d] (scan attempt?)", dstHost->hostResolvedName, srcHost->hostResolvedName, dport); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&dstHost->secHostPkts->udpToClosedPortSent, srcHost, actualDeviceId); incrementUsageCounter(&srcHost->secHostPkts->udpToClosedPortRcvd, dstHost, actualDeviceId); break; } allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpPortUnreachSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpPortUnreachRcvd, srcHost, actualDeviceId); break; case ICMP6_DST_UNREACH_NOROUTE: case ICMP6_DST_UNREACH_ADDR: allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpHostNetUnreachSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpHostNetUnreachRcvd, srcHost, actualDeviceId); break; case ICMP6_DST_UNREACH_ADMIN: /* Administratively Prohibited */ if(myGlobals.runningPref.enableSuspiciousPacketDump) traceEvent(CONST_TRACE_WARNING, /* See http://www.packetfactory.net/firewalk/ */ "Host [%s] sent ICMPv6 Administratively Prohibited packet to host [%s]" " (Firewalking scan attempt?)", dstHost->hostResolvedName, srcHost->hostResolvedName); allocateSecurityHostPkts(srcHost); allocateSecurityHostPkts(dstHost); incrementUsageCounter(&srcHost->secHostPkts->icmpAdminProhibitedSent, dstHost, actualDeviceId); incrementUsageCounter(&dstHost->secHostPkts->icmpAdminProhibitedRcvd, srcHost, actualDeviceId); break; } if(myGlobals.runningPref.enableSuspiciousPacketDump) dumpSuspiciousPacket(actualDeviceId); } } break; #endif default: if(srcHost->ipProtosList != NULL) { protoList = myGlobals.ipProtosList; idx = 0; while(protoList != NULL) { if((protoList->protocolId == nh) || ((protoList->protocolIdAlias != 0) && (protoList->protocolIdAlias == nh))) { if(srcHost->ipProtosList) { if(srcHost->ipProtosList[idx] == NULL) { srcHost->ipProtosList[idx] = calloc(sizeof(ShortProtoTrafficInfo), 1); if(srcHost->ipProtosList[idx] == NULL) return; } incrementTrafficCounter(&srcHost->ipProtosList[idx]->sent, length); } if(dstHost->ipProtosList) { if(dstHost->ipProtosList[idx] == NULL) { dstHost->ipProtosList[idx] = calloc(sizeof(ShortProtoTrafficInfo), 1); if(dstHost->ipProtosList[idx] == NULL) return; } incrementTrafficCounter(&dstHost->ipProtosList[idx]->rcvd, length); } if(myGlobals.device[actualDeviceId].ipProtosList) incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipProtosList[idx], length); found = 1; break; } idx++, protoList = protoList->next; } } if(!found) { proto = "IP (Other)"; incrementTrafficCounter(&myGlobals.device[actualDeviceId].otherIpBytes, length); sport = dport = 0; if(myGlobals.runningPref.enableOtherPacketDump) dumpOtherPacket(actualDeviceId); if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->otherSent, length); incrementUnknownProto(srcHost, 0 /* sent */, 0 /* eth */, 0 /* dsap */, 0 /* ssap */, nh); incrementTrafficCounter(&dstHost->nonIPTraffic->otherRcvd, length); incrementUnknownProto(dstHost, 1 /* rcvd */, 0 /* eth */, 0 /* dsap */, 0 /* ssap */, nh); } break; } #ifdef INET6 end: ; /* Needed by some compilers */ #endif #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "IP=%d TCP=%d UDP=%d ICMP=%d (len=%d)", (int)myGlobals.device[actualDeviceId].ipBytes.value, (int)myGlobals.device[actualDeviceId].tcpBytes.value, (int)myGlobals.device[actualDeviceId].udpBytes.value, (int)myGlobals.device[actualDeviceId].icmpBytes.value, length); #endif } /* ************************************ */ #undef DEBUG void queuePacket(u_char *_deviceId, const struct pcap_pkthdr *h, const u_char *p) { int len, deviceId, actDeviceId; /* *************************** - If the queue is full then wait until a slot is freed - If the queue is getting full then periodically wait until a slot is freed **************************** */ #ifdef MAX_PROCESS_BUFFER if(myGlobals.queueBufferInit == 0) { myGlobals.queueBufferCount = 0; myGlobals.queueBufferInit = 1; memset(&myGlobals.queueBuffer, 0, sizeof(myGlobals.queueBuffer)); } #endif myGlobals.receivedPackets++; if((p == NULL) || (h == NULL)) { traceEvent(CONST_TRACE_WARNING, "Invalid packet received. Skipped."); } #ifdef WIN32_DEMO if(myGlobals.receivedPackets >= MAX_NUM_PACKETS) return; #endif if(myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN) return; deviceId = (int)((long)_deviceId); actDeviceId = getActualInterface(deviceId); incrementTrafficCounter(&myGlobals.device[actDeviceId].receivedPkts, 1); /* We assume that if there's a packet to queue for the sFlow interface then this has been queued by the sFlow plugins, while it was probably handling a queued packet */ #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "queuePacket: got packet from %s (%d)", myGlobals.device[deviceId].name, deviceId); #endif /* We don't sample on sFlow sampled interfaces */ if(myGlobals.device[deviceId].sflowGlobals == NULL) { if(myGlobals.device[actDeviceId].samplingRate > 1) { if(myGlobals.device[actDeviceId].droppedSamples < myGlobals.device[actDeviceId].samplingRate) { myGlobals.device[actDeviceId].droppedSamples++; return; /* Not enough samples received */ } else myGlobals.device[actDeviceId].droppedSamples = 0; } } if(myGlobals.runningPref.dontTrustMACaddr && (h->len <= 64)) { /* Filter out noise */ updateDevicePacketStats(h->len, actDeviceId); return; } if(tryLockMutex(&myGlobals.device[deviceId].packetProcessMutex, "queuePacket") == 0) { /* Locked so we can process the packet now */ u_char p1[MAX_PACKET_LEN]; myGlobals.receivedPacketsProcessed++; len = h->caplen; if (myGlobals.runningPref.printIpOnly) { /* When we do Fibre Channel, the end of the packet contains EOF * information and so truncating it isn't a good idea. */ if(len >= DEFAULT_SNAPLEN) len = DEFAULT_SNAPLEN-1; } if(h->caplen >= MAX_PACKET_LEN) { if(h->caplen > myGlobals.device[deviceId].mtuSize) { traceEvent(CONST_TRACE_WARNING, "packet truncated (%d->%d)", h->len, MAX_PACKET_LEN); } ((struct pcap_pkthdr*)h)->caplen = MAX_PACKET_LEN-1; } memcpy(p1, p, len); processPacket(_deviceId, h, p1); releaseMutex(&myGlobals.device[deviceId].packetProcessMutex); return; } /* If we reach this point it means that somebody was already processing a packet so we need to queue it. */ if(myGlobals.device[deviceId].packetQueueLen >= CONST_PACKET_QUEUE_LENGTH) { #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "Dropping packet [packet queue=%d/max=%d][id=%d]", myGlobals.device[deviceId].packetQueueLen, myGlobals.maxPacketQueueLen, deviceId); #endif myGlobals.receivedPacketsLostQ++; incrementTrafficCounter(&myGlobals.device[getActualInterface(deviceId)].droppedPkts, 1); ntop_conditional_sched_yield(); /* Allow other threads (dequeue) to run */ sleep(1); } else { #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "About to queue packet... "); #endif accessMutex(&myGlobals.device[deviceId].packetQueueMutex, "queuePacket"); myGlobals.receivedPacketsQueued++; memcpy(&myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].h, h, sizeof(struct pcap_pkthdr)); memset(myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].p, 0, sizeof(myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].p)); /* Just to be safe */ len = h->caplen; if(myGlobals.runningPref.printIpOnly) { if(len >= DEFAULT_SNAPLEN) len = DEFAULT_SNAPLEN-1; memcpy(myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].p, p, len); myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].h.caplen = len; } else { memcpy(myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].p, p, len); myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].h.caplen = len; } myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueHead].deviceId = (int)((long)((void*)_deviceId)); myGlobals.device[deviceId].packetQueueHead = (myGlobals.device[deviceId].packetQueueHead+1) % CONST_PACKET_QUEUE_LENGTH; myGlobals.device[deviceId].packetQueueLen++; if(myGlobals.device[deviceId].packetQueueLen > myGlobals.device[deviceId].maxPacketQueueLen) myGlobals.device[deviceId].maxPacketQueueLen = myGlobals.device[deviceId].packetQueueLen; releaseMutex(&myGlobals.device[deviceId].packetQueueMutex); #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "Queued packet... [packet queue=%d/max=%d]", myGlobals.device[deviceId].packetQueueLen, myGlobals.maxPacketQueueLen); #endif #ifdef DEBUG_THREADS traceEvent(CONST_TRACE_INFO, "+ [packet queue=%d/max=%d]", myGlobals.device[deviceId].packetQueueLen, myGlobals.maxPacketQueueLen); #endif } signalCondvar(&myGlobals.device[deviceId].queueCondvar); ntop_conditional_sched_yield(); /* Allow other threads (dequeue) to run */ } /* ************************************ */ void cleanupPacketQueue(void) { ; /* Nothing to do */ } /* ************************************ */ void* dequeuePacket(void* _deviceId) { u_int deviceId = (u_int)((long)_deviceId); struct pcap_pkthdr h; u_char p[MAX_PACKET_LEN]; traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: NPA: network packet analyzer (packet processor) thread running [p%d]", pthread_self(), getpid()); /* Don't bother stalling until RUN, start grabbing packets NOW ... */ while(myGlobals.ntopRunState <= FLAG_NTOPSTATE_RUN) { #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "Waiting for packet..."); #endif while((myGlobals.device[deviceId].packetQueueLen == 0) && (myGlobals.ntopRunState <= FLAG_NTOPSTATE_RUN) /* Courtesy of Wies-Software */) { waitCondvar(&myGlobals.device[deviceId].queueCondvar); } if(myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN) break; #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "Got packet..."); #endif accessMutex(&myGlobals.device[deviceId].packetQueueMutex, "dequeuePacket"); memcpy(&h, &myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueTail].h, sizeof(struct pcap_pkthdr)); deviceId = myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueTail].deviceId; /* This code should be changed ASAP. It is a bad trick that avoids ntop to go beyond packet boundaries (L.Deri 17/03/2003) 1. h->len is truncated 2. MAX_PACKET_LEN should probably be removed 3. all the functions must check that they are not going beyond packet boundaries */ if((h.caplen != h.len) && (myGlobals.device[deviceId].sflowGlobals == NULL) /* This warning is normal for sFlow */ && (myGlobals.runningPref.enablePacketDecoding /* Courtesy of Ken Beaty */)) traceEvent (CONST_TRACE_WARNING, "dequeuePacket: caplen %d != len %d\n", h.caplen, h.len); if (myGlobals.runningPref.printIpOnly) memcpy(p, myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueTail].p, DEFAULT_SNAPLEN); else memcpy(p, myGlobals.device[deviceId].packetQueue[myGlobals.device[deviceId].packetQueueTail].p, MAX_PACKET_LEN); if(h.len > MAX_PACKET_LEN) { traceEvent(CONST_TRACE_WARNING, "packet truncated (%d->%d)", h.len, MAX_PACKET_LEN); h.len = MAX_PACKET_LEN; } myGlobals.device[deviceId].packetQueueTail = (myGlobals.device[deviceId].packetQueueTail+1) % CONST_PACKET_QUEUE_LENGTH; myGlobals.device[deviceId].packetQueueLen--; releaseMutex(&myGlobals.device[deviceId].packetQueueMutex); #ifdef DEBUG_THREADS traceEvent(CONST_TRACE_INFO, "- [packet queue=%d/max=%d]", myGlobals.device[deviceId].packetQueueLen, myGlobals.maxPacketQueueLen); #endif #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "Processing packet... [packet queue=%d/max=%d][id=%d]", myGlobals.device[deviceId].packetQueueLen, myGlobals.maxPacketQueueLen, deviceId); #endif myGlobals.actTime = time(NULL); accessMutex(&myGlobals.device[deviceId].packetProcessMutex, "dequeuePacket"); processPacket((u_char*)((long)deviceId), &h, p); releaseMutex(&myGlobals.device[deviceId].packetProcessMutex); } myGlobals.device[deviceId].dequeuePacketThreadId = 0; traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: NPA: network packet analyzer (%s) thread terminated [p%d]", pthread_self(), myGlobals.device[deviceId].humanFriendlyName, getpid()); return(NULL); } /* ************************************ */ static void flowsProcess(const struct pcap_pkthdr *h, const u_char *p, int deviceId) { FlowFilterList *list = myGlobals.flowsList; while(list != NULL) { #ifdef DEBUG if(!list->pluginStatus.activePlugin) traceEvent(CONST_TRACE_NOISY, "%s inactive", list->flowName); else if(list->fcode[deviceId].bf_insns == NULL) traceEvent(CONST_TRACE_NOISY, "%s no filter", list->flowName); #endif if((list->pluginStatus.activePlugin) && (list->fcode[deviceId].bf_insns != NULL)) { #ifdef DEBUG { struct ether_header *ep; u_int16_t et=0, et8021q=0; ep = (struct ether_header *)p; et = ntohs(ep->ether_type); if(et == ETHERTYPE_802_1Q) { et8021q = et; ep = (struct ether_header *)(p+4); et = ntohs(ep->ether_type); } traceEvent(CONST_TRACE_NOISY, "%smatch on %s for '%s' %s0x%04x-%s-%d/%d", bpf_filter(list->fcode[deviceId].bf_insns, (u_char*)p, h->len, h->caplen) ? "" : "No ", myGlobals.device[deviceId].name, list->flowName, et8021q == ETHERTYPE_802_1Q ? "(802.1q) " : "", et, et == ETHERTYPE_IP ? "IPv4" : et == ETHERTYPE_IPv6 ? "IPv6" : et == ETHERTYPE_ARP ? "ARP" : et == ETHERTYPE_REVARP ? "RARP" : "other", h->len, h->caplen); } #endif if(bpf_filter(list->fcode[deviceId].bf_insns, (u_char*)p, h->len, h->caplen)) { incrementTrafficCounter(&list->bytes, h->len); incrementTrafficCounter(&list->packets, 1); if(list->pluginStatus.pluginPtr != NULL) { void(*pluginFunct)(u_char*, const struct pcap_pkthdr*, const u_char*); pluginFunct = (void(*)(u_char *_deviceId, const struct pcap_pkthdr*, const u_char*))list->pluginStatus.pluginPtr->pluginFunct; pluginFunct((u_char*)&deviceId, h, p); } } } list = list->next; } } /* ************************************ */ static void addNonIpTrafficInfo(HostTraffic *el, u_int16_t proto, u_short len, u_int direction) { NonIpProtoTrafficInfo *nonIp; int numIterations; if(el->nonIpProtoTrafficInfos == NULL) goto notFoundProto; else nonIp = el->nonIpProtoTrafficInfos; numIterations = 0; while(nonIp != NULL) { if(nonIp->protocolId == proto) break; numIterations++; if(numIterations == MAX_NUM_NON_IP_PROTO_TRAFFIC_INFO) return; /* Too many protocols */ nonIp = nonIp->next; } if(nonIp == NULL) { notFoundProto: /* Protocol not found */ nonIp = (NonIpProtoTrafficInfo*)calloc(1, sizeof(NonIpProtoTrafficInfo)); if(nonIp == NULL) return; nonIp->next = el->nonIpProtoTrafficInfos; el->nonIpProtoTrafficInfos = nonIp; nonIp->protocolId = proto; } if(direction == 0) incrementTrafficCounter(&nonIp->sentPkts, 1), incrementTrafficCounter(&nonIp->sentBytes, len); else incrementTrafficCounter(&nonIp->rcvdPkts, 1), incrementTrafficCounter(&nonIp->rcvdBytes, len); } /* ************************************ */ void updateDevicePacketStats(u_int length, int actualDeviceId) { if(length <= 64) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo64, 1); else if(length <= 128) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo128, 1); else if(length <= 256) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo256, 1); else if(length <= 512) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo512, 1); else if(length <= 1024) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo1024, 1); else if(length <= 1518) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo1518, 1); #ifdef MAKE_WITH_JUMBO_FRAMES else if(length <= 2500) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo2500, 1); else if(length <= 6500) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo6500, 1); else if(length <= 9000) incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.upTo9000, 1); else incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.above9000, 1); #else else incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.above1518, 1); #endif if((myGlobals.device[actualDeviceId].rcvdPktStats.shortest.value == 0) || (myGlobals.device[actualDeviceId].rcvdPktStats.shortest.value > length)) myGlobals.device[actualDeviceId].rcvdPktStats.shortest.value = length; if(myGlobals.device[actualDeviceId].rcvdPktStats.longest.value < length) myGlobals.device[actualDeviceId].rcvdPktStats.longest.value = length; } /* ***************************************************** */ void dumpSuspiciousPacket(int actualDeviceId) { if(myGlobals.device[actualDeviceId].pcapErrDumper != NULL) { pcap_dump((u_char*)myGlobals.device[actualDeviceId].pcapErrDumper, h_save, p_save); traceEvent(CONST_TRACE_INFO, "Dumped %d bytes suspicious packet", h_save->caplen); } } /* ***************************************************** */ void dumpOtherPacket(int actualDeviceId) { if(myGlobals.device[actualDeviceId].pcapOtherDumper != NULL) pcap_dump((u_char*)myGlobals.device[actualDeviceId].pcapOtherDumper, h_save, p_save); } /* ***************************************************** */ /* * This is the top level routine of the printer. 'p' is the points * to the ether header of the packet, 'tvp' is the timestamp, * 'length' is the length of the packet off the wire, and 'caplen' * is the number of bytes actually captured. */ void processPacket(u_char *_deviceId, const struct pcap_pkthdr *h, const u_char *p) { struct ether_header ehdr; struct tokenRing_header *trp; struct fddi_header *fddip; u_int hlen, caplen = h->caplen; u_int headerDisplacement = 0, length = h->len; const u_char *orig_p = p, *p1; u_char *ether_src=NULL, *ether_dst=NULL; u_short eth_type=0; /* Token-Ring Strings */ struct tokenRing_llc *trllc; unsigned char ipxBuffer[128]; int deviceId, actualDeviceId; u_int16_t vlanId=NO_VLAN; static time_t lastUpdateThptTime = 0; #ifdef LINUX AnyHeader *anyHeader; #endif #ifdef MAX_PROCESS_BUFFER struct timeval pktStartOfProcessing, pktEndOfProcessing; #endif #ifdef MEMORY_DEBUG #ifdef MEMORY_DEBUG_UNLIMITED #warning MEMORY_DEBUG defined for UNLIMITED usage! #else #ifdef MEMORY_DEBUG_PACKETS { static long numPkt=0; if(++numPkt >= MEMORY_DEBUG_PACKETS) { traceEvent(CONST_TRACE_ALWAYSDISPLAY, "NOTE: ntop shutting down - memory debug packet limit (%d) reached", MEMORY_DEBUG_PACKETS); cleanup(1); } } #endif /* MEMORY_DEBUG_PACKETS */ #ifdef MEMORY_DEBUG_SECONDS { static time_t memoryDebugAbortTime=0; if(memoryDebugAbortTime == 0) { memoryDebugAbortTime = time(NULL) + MEMORY_DEBUG_SECONDS; } else if(time(NULL) > memoryDebugAbortTime) { traceEvent(CONST_TRACE_ALWAYSDISPLAY, "NOTE: ntop shutting down - memory debug abort time reached"); cleanup(1); } } #endif /* MEMORY_DEBUG_SECONDS */ #endif /* MEMORY_DEBUG_UNLIMITED */ #endif /* MEMORY_DEBUG */ if(myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN) return; /* This allows me to fetch the time from the captured packet instead of calling time(NULL). */ myGlobals.actTime = h->ts.tv_sec; deviceId = (int)((long)_deviceId); actualDeviceId = getActualInterface(deviceId); #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "deviceId=%d - actualDeviceId=%ld", deviceId, actualDeviceId); #endif #ifdef MAX_PROCESS_BUFFER { float elapsed; gettimeofday(&pktStartOfProcessing, NULL); elapsed = timeval_subtract(pktStartOfProcessing, h->ts); myGlobals.queueBuffer[++myGlobals.queueBufferCount & (MAX_PROCESS_BUFFER - 1)] = elapsed; if((myGlobals.device[actualDeviceId].ethernetPkts.value > 100) && (elapsed > myGlobals.qmaxDelay)) myGlobals.qmaxDelay = elapsed; } #endif h_save = h, p_save = p; #ifdef DEBUG if(myGlobals.runningPref.rFileName != NULL) { traceEvent(CONST_TRACE_INFO, "."); fflush(stdout); } #endif updateDevicePacketStats(length, actualDeviceId); incrementTrafficCounter(&myGlobals.device[actualDeviceId].ethernetPkts, 1); incrementTrafficCounter(&myGlobals.device[actualDeviceId].ethernetBytes, h->len); if(myGlobals.runningPref.mergeInterfaces && actualDeviceId != deviceId) incrementTrafficCounter(&myGlobals.device[deviceId].ethernetPkts, 1); if(myGlobals.device[actualDeviceId].pcapDumper != NULL) pcap_dump((u_char*)myGlobals.device[actualDeviceId].pcapDumper, h, p); if((myGlobals.device[deviceId].mtuSize != CONST_UNKNOWN_MTU) && (length > myGlobals.device[deviceId].mtuSize) ) { /* Sanity check */ if(myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, "Packet # %u too long (len = %u)!", (unsigned int)myGlobals.device[deviceId].ethernetPkts.value, (unsigned int)length); dumpSuspiciousPacket(actualDeviceId); } /* Fix below courtesy of Andreas Pfaller */ length = myGlobals.device[deviceId].mtuSize; incrementTrafficCounter(&myGlobals.device[actualDeviceId].rcvdPktStats.tooLong, 1); } #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "actualDeviceId = %d", actualDeviceId); #endif /* Note: The code below starts by assuming that if we haven't captured at * least an Ethernet frame header's worth of bytes we drop the packet. * This might be a bad assumption - why aren't we using the DLT_ derived fields? * e.g.: hlen = myGlobals.device[deviceId].headerSize; * Also, we probably should account for these runt packets - both count the * # of packets and the associated # of bytes. */ hlen = (myGlobals.device[deviceId].datalink == DLT_NULL) ? CONST_NULL_HDRLEN : sizeof(struct ether_header); if(!myGlobals.initialSniffTime && (myGlobals.runningPref.rFileName != NULL)) { myGlobals.initialSniffTime = h->ts.tv_sec; myGlobals.device[deviceId].lastThptUpdate = myGlobals.device[deviceId].lastMinThptUpdate = myGlobals.device[deviceId].lastHourThptUpdate = myGlobals.device[deviceId].lastFiveMinsThptUpdate = myGlobals.initialSniffTime; } memcpy(&myGlobals.lastPktTime, &h->ts, sizeof(myGlobals.lastPktTime)); if(caplen >= hlen) { HostTraffic *srcHost=NULL, *dstHost=NULL; memcpy(&ehdr, p, sizeof(struct ether_header)); switch(myGlobals.device[deviceId].datalink) { case DLT_FDDI: fddip = (struct fddi_header *)p; length -= FDDI_HDRLEN; p += FDDI_HDRLEN; caplen -= FDDI_HDRLEN; extract_fddi_addrs(fddip, (char *)ESRC(&ehdr), (char *)EDST(&ehdr)); ether_src = (u_char*)ESRC(&ehdr), ether_dst = (u_char*)EDST(&ehdr); if((fddip->fc & CONST_FDDIFC_CLFF) == CONST_FDDIFC_CONST_LLC_ASYNC) { struct llc llc; /* Info on SNAP/LLC: http://www.erg.abdn.ac.uk/users/gorry/course/lan-pages/llc.html http://www.ece.wpi.edu/courses/ee535/hwk96/hwk3cd96/li/li.html http://www.ece.wpi.edu/courses/ee535/hwk96/hwk3cd96/li/li.html */ memcpy((char *)&llc, (char *)p, min(caplen, sizeof(llc))); if(llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP && llc.ctl.snap.snap_ui == CONST_LLC_UI) { if(caplen >= sizeof(llc)) { caplen -= sizeof(llc); length -= sizeof(llc); p += sizeof(llc); if(EXTRACT_16BITS(&llc.ctl.snap_ether.snap_ethertype[0]) == ETHERTYPE_IP) { /* encapsulated IP packet */ processIpPkt(p, h, length, ether_src, ether_dst, actualDeviceId, vlanId); /* Patch below courtesy of Fabrice Bellet */ return; } } } } break; #ifdef LINUX case DLT_ANY: /* Linux 'any' device */ anyHeader = (AnyHeader*)p; length -= sizeof(AnyHeader); /* don't count nullhdr */ eth_type = ntohs(anyHeader->protoType); #if PACKET_DEBUG printf("pktType: 0x%x\n", ntohs(anyHeader->pktType)); printf("llcAddressType: 0x%x\n", ntohs(anyHeader->llcAddressType)); printf("llcAddressLen: 0x%x\n", ntohs(anyHeader->llcAddressLen)); printf("eth_type: 0x%x\n", eth_type); #endif ether_src = ether_dst = myGlobals.dummyEthAddress; processIpPkt(p+sizeof(AnyHeader), h, length, ether_src, ether_dst, actualDeviceId, vlanId); break; #endif case DLT_NULL: /* loopaback interface */ /* Support for ethernet headerless interfaces (e.g. lo0) Courtesy of Martin Kammerhofer */ length -= CONST_NULL_HDRLEN; /* don't count nullhdr */ /* All this crap is due to the old little/big endian story... */ if(((p[0] == 0) && (p[1] == 0) && (p[2] == 8) && (p[3] == 0)) || ((p[0] == 2) && (p[1] == 0) && (p[2] == 0) && (p[3] == 0)) /* OSX */) eth_type = ETHERTYPE_IP; else if(((p[0] == 0) && (p[1] == 0) && (p[2] == 0x86) && (p[3] == 0xdd)) || ((p[0] == 0x1E) && (p[1] == 0) && (p[2] == 0) && (p[3] == 0)) /* OSX */) eth_type = ETHERTYPE_IPv6; else { // traceEvent(CONST_TRACE_INFO, "[%d][%d][%d][%d]", p[0], p[1], p[2], p[3]); } ether_src = ether_dst = myGlobals.dummyEthAddress; break; case DLT_PPP: headerDisplacement = CONST_PPP_HDRLEN; /* PPP is like RAW IP. The only difference is that PPP has a header that's not present in RAW IP. IMPORTANT: DO NOT PUT A break BELOW this comment */ case DLT_RAW: /* RAW IP (no ethernet header) */ length -= headerDisplacement; /* don't count PPP header */ ether_src = ether_dst = NULL; processIpPkt(p+headerDisplacement, h, length, NULL, NULL, actualDeviceId, vlanId); break; #if 0 /* Handled by DLT_ANY */ /* PPPoE patch courtesy of Stefano Picerno */ #ifdef LINUX case DLT_LINUX_SLL: /* Linux capture interface */ length = h->len; length -= SLL_HDR_LEN; ether_src = ether_dst = NULL; processIpPkt(p+ SLL_HDR_LEN , h, length, ether_src, ether_dst, actualDeviceId, vlanId); break; #endif #endif case DLT_IEEE802: /* Token Ring */ trp = (struct tokenRing_header*)p; ether_src = (u_char*)trp->trn_shost, ether_dst = (u_char*)trp->trn_dhost; hlen = sizeof(struct tokenRing_header) - 18; if(trp->trn_shost[0] & CONST_TR_RII) /* Source Routed Packet */ hlen += ((ntohs(trp->trn_rcf) & CONST_TR_RCF_LEN_MASK) >> 8); length -= hlen, caplen -= hlen; p += hlen; trllc = (struct tokenRing_llc *)p; if(trllc->dsap == 0xAA && trllc->ssap == 0xAA) hlen = sizeof(struct tokenRing_llc); else hlen = sizeof(struct tokenRing_llc) - 5; length -= hlen, caplen -= hlen; p += hlen; if(hlen == sizeof(struct tokenRing_llc)) eth_type = ntohs(trllc->ethType); else eth_type = 0; break; default: eth_type = ntohs(ehdr.ether_type); /* NOTE: eth_type is a 32 bit integer (eg. 0x0800). If the first byte is NOT null (08 in the example below) then this is a Ethernet II frame, otherwise is a IEEE 802.3 Ethernet frame. */ ether_src = ESRC(&ehdr), ether_dst = EDST(&ehdr); if(eth_type == ETHERTYPE_802_1Q) /* VLAN */ { Ether80211q qType; memcpy(&qType, p+sizeof(struct ether_header), sizeof(Ether80211q)); vlanId = ntohs(qType.vlanId) & 0xFFF; #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "VLAN Id: %d", vlanId); #endif eth_type = ntohs(qType.protoType); hlen += 4; /* Skip the 802.1q header */ if(myGlobals.device[deviceId].hasVLANs != TRUE) { myGlobals.device[deviceId].hasVLANs = TRUE; myGlobals.haveVLANs = TRUE; #ifndef MAKE_WITH_JUMBO_FRAMES traceEvent(CONST_TRACE_NOISY, "Device %s(%d) MTU adjusted for 802.1q VLAN", myGlobals.device[deviceId].name, deviceId); extend8021Qmtu(); myGlobals.device[deviceId].rcvdPktStats.tooLong.value = 0l; #endif } } else if((ether_dst[0] == 0x01) && (ether_dst[1] == 0x00) && (ether_dst[2] == 0x0C) && (ether_dst[3] == 0x00) && (ether_dst[4] == 0x00) && (ether_dst[5] == 0x00)) { /* Cisco InterSwitch Link (ISL) Protocol This is basically the Cisco proprietary VLAN tagging (vs. the standard 802.1q) http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm */ IslHeader islHdr; memcpy(&islHdr, p, sizeof(IslHeader)); vlanId = ntohs(islHdr.vlanId); hlen = sizeof(IslHeader); /* Skip the ISL header */ memcpy(&ehdr, p+hlen, sizeof(struct ether_header)); hlen += sizeof(struct ether_header); ether_src = ESRC(&ehdr), ether_dst = EDST(&ehdr); eth_type = ntohs(ehdr.ether_type); } } /* switch(myGlobals.device[deviceId].datalink) */ if((myGlobals.device[deviceId].datalink != DLT_PPP) && (myGlobals.device[deviceId].datalink != DLT_RAW) && (myGlobals.device[deviceId].datalink != DLT_ANY)) { if((!myGlobals.runningPref.dontTrustMACaddr) && (eth_type == 0x8137)) { /* IPX */ IPXpacket ipxPkt; srcHost = lookupHost(NULL, ether_src, vlanId, 0, 0, actualDeviceId); if(srcHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (5) [Low memory?]"); lowMemoryMsgShown = 1; return; } else { lockHostsHashMutex(srcHost, "processPacket-src"); } dstHost = lookupHost(NULL, ether_dst, vlanId, 0, 0, actualDeviceId); if(dstHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (6) [Low memory?]"); unlockHostsHashMutex(srcHost); lowMemoryMsgShown = 1; return; } else { lockHostsHashMutex(dstHost, "processPacket-dst"); } if(vlanId != NO_VLAN) { srcHost->vlanId = vlanId; dstHost->vlanId = vlanId; } memcpy((char *)&ipxPkt, (char *)p+sizeof(struct ether_header), sizeof(IPXpacket)); if(ntohs(ipxPkt.dstSocket) == 0x0452) { /* SAP */ int displ = sizeof(struct ether_header); p1 = p+displ; length -= displ; goto handleIPX; } else { TrafficCounter ctr; if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->ipxSent, length), incrementTrafficCounter(&dstHost->nonIPTraffic->ipxRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipxBytes, length); ctr.value = length; /* Even if this is IPX (i.e. no IP) the hostIpAddress field is fine because it is not used in this special case and I need a placeholder here. */ updatePacketCount(srcHost, &srcHost->hostIpAddress, dstHost, &dstHost->hostIpAddress, ctr, 1, actualDeviceId); } } else if((myGlobals.device[deviceId].datalink == DLT_IEEE802) && (eth_type < ETHERMTU)) { TrafficCounter ctr; trp = (struct tokenRing_header*)orig_p; ether_src = (u_char*)trp->trn_shost, ether_dst = (u_char*)trp->trn_dhost; srcHost = lookupHost(NULL, ether_src, vlanId, 0, 0, actualDeviceId); if(srcHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (7) [Low memory?]"); lowMemoryMsgShown = 1; return; } else { lockHostsHashMutex(srcHost, "processPacket-src-2"); } dstHost = lookupHost(NULL, ether_dst, vlanId, 0, 0, actualDeviceId); if(dstHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (8) [Low memory?]"); unlockHostsHashMutex(srcHost); lowMemoryMsgShown = 1; return; } else { lockHostsHashMutex(dstHost, "processPacket-dst-2"); } if(vlanId != NO_VLAN) { srcHost->vlanId = vlanId; dstHost->vlanId = vlanId; } if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->otherSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->otherRcvd, length); incrementUnknownProto(srcHost, 0 /* sent */, eth_type /* eth */, 0 /* dsap */, 0 /* ssap */, 0 /* ip */); incrementUnknownProto(dstHost, 1 /* rcvd */, eth_type /* eth */, 0 /* dsap */, 0 /* ssap */, 0 /* ip */); if(myGlobals.runningPref.enableOtherPacketDump) dumpOtherPacket(actualDeviceId); ctr.value = length; /* Even if this is probably not IP the hostIpAddress field is fine because it is not used in this special case and I need a placeholder here. */ updatePacketCount(srcHost, &srcHost->hostIpAddress, dstHost, &dstHost->hostIpAddress, ctr, 1, actualDeviceId); } else if((myGlobals.device[deviceId].datalink != DLT_IEEE802) && (eth_type <= ETHERMTU) && (length > 3)) { /* The code below has been taken from tcpdump */ u_char sap_type; struct llc llcHeader; char etherbuf[LEN_ETHERNET_ADDRESS_DISPLAY]; if((ether_dst != NULL) && (!myGlobals.runningPref.dontTrustMACaddr) && (strcmp(etheraddr_string(ether_dst, etherbuf), "FF:FF:FF:FF:FF:FF") == 0) && (p[sizeof(struct ether_header)] == 0xff) && (p[sizeof(struct ether_header)+1] == 0xff) && (p[sizeof(struct ether_header)+4] == 0x0)) { /* IPX */ srcHost = lookupHost(NULL, ether_src, vlanId, 0, 0, actualDeviceId); if(srcHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (9) [Low memory?]"); lowMemoryMsgShown = 1; return; } else { lockHostsHashMutex(srcHost, "processPacket-src-3"); } dstHost = lookupHost(NULL, ether_dst, vlanId, 0, 0, actualDeviceId); if(dstHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (10) [Low memory?]"); unlockHostsHashMutex(srcHost); lowMemoryMsgShown = 1; return; } else { lockHostsHashMutex(dstHost, "processPacket-dst-3"); } if(vlanId != NO_VLAN) { srcHost->vlanId = vlanId; dstHost->vlanId = vlanId; } if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->ipxSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->ipxRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipxBytes, length); } else if(!myGlobals.runningPref.dontTrustMACaddr) { /* MAC addresses are meaningful here */ srcHost = lookupHost(NULL, ether_src, vlanId, 0, 0, actualDeviceId); dstHost = lookupHost(NULL, ether_dst, vlanId, 0, 0, actualDeviceId); if((srcHost != NULL) && (dstHost != NULL)) { TrafficCounter ctr; int llcLen; lockHostsHashMutex(srcHost, "processPacket-src-4"); lockHostsHashMutex(dstHost, "processPacket-dst-4"); if(vlanId != NO_VLAN) { srcHost->vlanId = vlanId; dstHost->vlanId = vlanId; } p1 = (u_char*)(p+hlen); /* Watch out for possible alignment problems */ memcpy(&llcHeader, (char*)p1, (llcLen = min(length, sizeof(llcHeader)))); sap_type = llcHeader.ssap & ~CONST_LLC_GSAP; llcsap_string(sap_type); if((sap_type == 0xAA /* SNAP */) && (llcHeader.ctl.snap_ether.snap_orgcode[0] == 0x0) && (llcHeader.ctl.snap_ether.snap_orgcode[1] == 0x0) && (llcHeader.ctl.snap_ether.snap_orgcode[2] == 0xc) /* 0x00000C = Cisco */ && (llcHeader.ctl.snap_ether.snap_ethertype[0] == 0x20) && (llcHeader.ctl.snap_ether.snap_ethertype[1] == 0x00) /* 0x2000 Cisco Discovery Protocol */ ) { u_char *cdp; int cdp_idx = 0; cdp = (u_char*)(p+hlen+llcLen); if(cdp[cdp_idx] == 0x02) { /* CDP v2 */ struct cdp_element { u_int16_t cdp_type; u_int16_t cdp_len; // u_char cdp_content[255]; }; cdp_idx = 4; while((cdp_idx+sizeof(struct cdp_element)) < (length-(hlen+llcLen))) { struct cdp_element element; memcpy(&element, &cdp[cdp_idx], sizeof(struct cdp_element)); cdp_idx += sizeof(struct cdp_element); element.cdp_len = ntohs(element.cdp_len); element.cdp_type = ntohs(element.cdp_type); if(element.cdp_len == 0) break; /* Sanity check */ switch(element.cdp_type) { case 0x0001: /* Device Id */ if((srcHost->hostResolvedName[0] == '\0') || (strcmp(srcHost->hostResolvedName, srcHost->hostNumIpAddress))) { u_short tmpStrLen = min(element.cdp_len-4, MAX_LEN_SYM_HOST_NAME-1); strncpy(srcHost->hostResolvedName, (char*)&cdp[cdp_idx], tmpStrLen); srcHost->hostResolvedName[tmpStrLen] = '\0'; } break; case 0x0002: /* Addresses */ break; case 0x0003: /* Port Id */ break; case 0x0004: /* Capabilities */ break; case 0x0005: /* Sw Version */ if(srcHost->description == NULL) { char *tmpStr; u_short tmpStrLen = min(element.cdp_len-4, 255)+1; tmpStr = (char*)malloc(tmpStrLen); memcpy(tmpStr, &cdp[cdp_idx], tmpStrLen-2); tmpStr[tmpStrLen-1] = '\0'; srcHost->description = tmpStr; } break; case 0x0006: /* Platform */ if(srcHost->fingerprint == NULL) { char *tmpStr; u_short tmpStrLen = min(element.cdp_len-4, 64)+2; tmpStr = (char*)malloc(tmpStrLen); tmpStr[0] = ':'; memcpy(&tmpStr[1], &cdp[cdp_idx], tmpStrLen-2); tmpStr[tmpStrLen-1] = '\0'; srcHost->fingerprint = tmpStr; srcHost->hwModel = strdup(&tmpStr[1]); } break; case 0x0008: /* Cluster Management */ break; case 0x0009: /* VTP Management Domain */ break; } cdp_idx += (element.cdp_len-sizeof(struct cdp_element)); } if(srcHost->fingerprint == NULL) srcHost->fingerprint = strdup(":Cisco"); /* Default */ } } if(sap_type != 0x42 /* !STP */) { addNonIpTrafficInfo(srcHost, sap_type, length, 0 /* sent */); addNonIpTrafficInfo(dstHost, sap_type, length, 1 /* rcvd */); } if(sap_type == 0x42 /* STP */) { /* Spanning Tree */ if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->stpSent, length), incrementTrafficCounter(&dstHost->nonIPTraffic->stpRcvd, length); FD_SET(FLAG_HOST_TYPE_SVC_BRIDGE, &srcHost->flags); incrementTrafficCounter(&myGlobals.device[actualDeviceId].stpBytes, length); } else if(myGlobals.runningPref.enablePacketDecoding && (sap_type == 0xE0)) { /* NetWare */ if(!(llcHeader.ssap == LLCSAP_GLOBAL && llcHeader.dsap == LLCSAP_GLOBAL)) { p1 += 3; /* LLC Header (short myGlobals.version) */ } handleIPX: /* IPX packet beginning */ if(length > 128) memcpy(ipxBuffer, p1, 128); else memcpy(ipxBuffer, p1, length); if((ipxBuffer[16] == 0x04) /* SAP (Service Advertising Protocol) (byte 0) */ && (ipxBuffer[17] == 0x52) /* SAP (Service Advertising Protocol) (byte 1) */ && (ipxBuffer[30] == 0x0) /* SAP Response (byte 0) */ && (ipxBuffer[31] == 0x02) /* SAP Response (byte 1) */) { u_int16_t serverType; char serverName[57]; int i, found; memcpy(&serverType, &ipxBuffer[32], 2); serverType = ntohs(serverType); memcpy(serverName, &ipxBuffer[34], 56); serverName[56] = '\0'; for(i=0; i<56; i++) if(serverName[i] == '!') { serverName[i] = '\0'; break; } if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(srcHost->nonIPTraffic == NULL) return; for(i=0, found=0; inonIPTraffic->numIpxNodeTypes; i++) if(srcHost->nonIPTraffic->ipxNodeType[i] == serverType) { found = 1; break; } if((!found) && (srcHost->nonIPTraffic->numIpxNodeTypes < MAX_NODE_TYPES)) { srcHost->nonIPTraffic->ipxNodeType[srcHost->nonIPTraffic->numIpxNodeTypes] = serverType; srcHost->nonIPTraffic->numIpxNodeTypes++; switch(serverType) { case 0x0007: /* Print server */ case 0x0003: /* Print Queue */ case 0x8002: /* Intel NetPort Print Server */ case 0x030c: /* HP LaserJet / Quick Silver */ FD_SET(FLAG_HOST_TYPE_PRINTER, &srcHost->flags); break; case 0x0027: /* TCP/IP gateway */ case 0x0021: /* NAS SNA gateway */ case 0x055d: /* Attachmate SNA gateway */ FD_SET(FLAG_GATEWAY_HOST, &srcHost->flags); /* ==> updateRoutedTraffic(srcHost); is not needed as there are no routed packets */ break; case 0x0004: /* File server */ case 0x0005: /* Job server */ case 0x0008: /* Archive server */ case 0x0009: /* Archive server */ case 0x002e: /* Archive Server Dynamic SAP */ case 0x0098: /* NetWare access server */ case 0x009a: /* Named Pipes server */ case 0x0111: /* Test server */ case 0x03e1: /* UnixWare Application Server */ case 0x0810: /* ELAN License Server Demo */ FD_SET(FLAG_HOST_TYPE_SERVER, &srcHost->flags); break; case 0x0278: /* NetWare Directory server */ FD_SET(FLAG_HOST_TYPE_SVC_DIRECTORY, &srcHost->flags); break; case 0x0024: /* Rem bridge */ case 0x0026: /* Bridge server */ FD_SET(FLAG_HOST_TYPE_SVC_BRIDGE, &srcHost->flags); break; case 0x0640: /* NT Server-RPC/GW for NW/Win95 User Level Sec */ case 0x064e: /* NT Server-IIS */ FD_SET(FLAG_HOST_TYPE_SERVER, &srcHost->flags); break; case 0x0133: /* NetWare Name Service */ FD_SET(FLAG_NAME_SERVER_HOST, &srcHost->flags); break; } } if(srcHost->nonIPTraffic->ipxHostName == NULL) { int begin = 1; for(i=1; i= (MAX_LEN_SYM_HOST_NAME-1)) serverName[MAX_LEN_SYM_HOST_NAME-2] = '\0'; srcHost->nonIPTraffic->ipxHostName = strdup(&serverName[begin]); for(i=0; srcHost->nonIPTraffic->ipxHostName[i] != '\0'; i++) srcHost->nonIPTraffic->ipxHostName[i] = tolower(srcHost->nonIPTraffic->ipxHostName[i]); updateHostName(srcHost); } #ifdef DEBUG traceEvent(CONST_TRACE_INFO, "%s [%s][%x]", serverName, getSAPInfo(serverType, 0), serverType); #endif } if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->ipxSent, length), incrementTrafficCounter(&dstHost->nonIPTraffic->ipxRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipxBytes, length); } else if((llcHeader.ssap == LLCSAP_NETBIOS) && (llcHeader.dsap == LLCSAP_NETBIOS)) { /* Netbios */ if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->netbiosSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->netbiosRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].netbiosBytes, length); } else if((sap_type == 0xF0) || (sap_type == 0xB4) || (sap_type == 0xC4) || (sap_type == 0xF8)) { /* DLC (protocol used for printers) */ if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->dlcSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->dlcRcvd, length); FD_SET(FLAG_HOST_TYPE_PRINTER, &dstHost->flags); incrementTrafficCounter(&myGlobals.device[actualDeviceId].dlcBytes, length); } else if(sap_type == 0xAA /* SNAP */) { u_int16_t snapType; p1 = (u_char*)(p1+sizeof(llcHeader)); memcpy(&snapType, p1, sizeof(snapType)); snapType = ntohs(snapType); /* See section "ETHERNET NUMBERS OF INTEREST" in RFC 1060 http://www.faqs.org/rfcs/rfc1060.html */ if(myGlobals.runningPref.enablePacketDecoding && ((snapType == 0x809B) || (snapType == 0x80F3))) { /* Appletalk */ AtDDPheader ddpHeader; memcpy(&ddpHeader, (char*)p1, sizeof(AtDDPheader)); if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; srcHost->nonIPTraffic->atNetwork = ntohs(ddpHeader.srcNet), srcHost->nonIPTraffic->atNode = ddpHeader.srcNode; dstHost->nonIPTraffic->atNetwork = ntohs(ddpHeader.dstNet), dstHost->nonIPTraffic->atNode = ddpHeader.dstNode; if(ddpHeader.ddpType == 2) { /* Appletalk NBP (Name Binding Protocol) */ AtNBPheader nbpHeader; int numTuples, i; p1 = (u_char*)(p1+13); memcpy(&nbpHeader, (char*)p1, sizeof(AtNBPheader)); numTuples = nbpHeader.function & 0x0F; if((nbpHeader.function == 0x21) && (numTuples == 1)) { char nodeName[256]; int displ; p1 = (u_char*)(p1+2); if(p1[6] == '=') displ = 2; else displ = 0; memcpy(nodeName, &p1[6+displ], p1[5+displ]); nodeName[p1[5+displ]] = '\0'; if(strlen(nodeName) >= (MAX_LEN_SYM_HOST_NAME-1)) nodeName[MAX_LEN_SYM_HOST_NAME-2] = '\0'; if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(srcHost->nonIPTraffic == NULL) return; srcHost->nonIPTraffic->atNodeName = strdup(nodeName); updateHostName(srcHost); memcpy(nodeName, &p1[7+p1[5+displ]+displ], p1[6+p1[5+displ]+displ]); nodeName[p1[6+p1[5+displ]]] = '\0'; for(i=0; inonIPTraffic->atNodeType[i] == NULL) || (strcmp(srcHost->nonIPTraffic->atNodeType[i], nodeName) == 0)) break; if(srcHost->nonIPTraffic->atNodeType[i] == NULL) srcHost->nonIPTraffic->atNodeType[i] = strdup(nodeName); } } if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->appletalkSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->appletalkRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].atalkBytes, length); } else { if((llcHeader.ctl.snap_ether.snap_orgcode[0] == 0x0) && (llcHeader.ctl.snap_ether.snap_orgcode[1] == 0x0) && (llcHeader.ctl.snap_ether.snap_orgcode[2] == 0x0C) /* Cisco */) { /* NOTE: If llcHeader.ctl.snap_ether.snap_ethertype[0] == 0x20 && llcHeader.ctl.snap_ether.snap_ethertype[1] == 0x0 this is Cisco Discovery Protocol */ FD_SET(FLAG_GATEWAY_HOST, &srcHost->flags); } if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->otherSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->otherRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].otherBytes, length); incrementUnknownProto(srcHost, 0 /* sent */, 0 /* eth */, llcHeader.dsap /* dsap */, llcHeader.ssap /* ssap */, 0 /* ip */); incrementUnknownProto(dstHost, 1 /* rcvd */, 0 /* eth */, llcHeader.dsap /* dsap */, llcHeader.ssap /* ssap */, 0 /* ip */); if(myGlobals.runningPref.enableOtherPacketDump) dumpOtherPacket(actualDeviceId); } } else if(myGlobals.runningPref.enablePacketDecoding && ((sap_type == 0x06) || (sap_type == 0xFE) || (sap_type == 0xFC))) { /* OSI */ if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->osiSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->osiRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].osiBytes, length); } else { /* Unknown Protocol */ #ifdef UNKNOWN_PACKET_DEBUG traceEvent(CONST_TRACE_INFO, "UNKNOWN_PACKET_DEBUG: [%u] [%x] %s %s > %s", (u_short)sap_type,(u_short)sap_type, etheraddr_string(ether_src, etherbuf), llcsap_string(llcHeader.ssap & ~CONST_LLC_GSAP), etheraddr_string(ether_dst, etherbuf)); #endif if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (dstHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->otherSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->otherRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].otherBytes, length); incrementUnknownProto(srcHost, 0 /* sent */, 0 /* eth */, llcHeader.dsap /* dsap */, llcHeader.ssap /* ssap */, 0 /* ip */); incrementUnknownProto(dstHost, 1 /* rcvd */, 0 /* eth */, llcHeader.dsap /* dsap */, llcHeader.ssap /* ssap */, 0 /* ip */); if(myGlobals.runningPref.enableOtherPacketDump) dumpOtherPacket(actualDeviceId); } ctr.value = length; /* Even if this is not IP the hostIpAddress field is fine because it is not used in this special case and I need a placeholder here. */ updatePacketCount(srcHost, &srcHost->hostIpAddress, dstHost, &dstHost->hostIpAddress, ctr, 1, actualDeviceId); } } } else if (((eth_type == ETHERTYPE_MDSHDR) || (eth_type == ETHERTYPE_BRDWLK) || (eth_type == ETHERTYPE_UNKNOWN) || (eth_type == ETHERTYPE_BRDWLK_OLD)) && (!myGlobals.runningPref.printIpOnly)) { /* An FC packet can be captured as Ethernet for three different * Ethertypes. */ processFcPkt (p, h, eth_type, actualDeviceId); } else if((eth_type == ETHERTYPE_IP) || (eth_type == ETHERTYPE_IPv6)) { if((myGlobals.device[deviceId].datalink == DLT_IEEE802) && (eth_type > ETHERMTU)) { processIpPkt(p, h, length, ether_src, ether_dst, actualDeviceId, vlanId); } else { processIpPkt(p+hlen, h, length, ether_src, ether_dst, actualDeviceId, vlanId); } } else if(eth_type == 0xDEAD) /* Agilent */ { typedef struct { u_int8_t version; /* Protocol Version */ u_int8_t response_pdu; /* 0=Request, 1=Response */ u_int8_t fragment_id; /* Fragment Id (Only for fragmented FORWARD responses) */ u_int8_t pdu_type; /* See sgbic_pdu_type */ u_int16_t pdu_id; /* Unique (serial) PDU identifier */ u_int16_t pdu_len; /* length (bytes) of the PDU (not including this header) */ u_char digest[16]; /* MD5 digest */ } sgbic_header_v1; sgbic_header_v1 *pdu; if(length > hlen+sizeof(sgbic_header_v1)) { pdu = (sgbic_header_v1*)(p+hlen); if((pdu->version == 1) && (pdu->pdu_type == 2 /* forward */)) { static u_short last_pdu_len, last_pdu_id; u_short size_shift = hlen+sizeof(sgbic_header_v1); if(pdu->fragment_id == 0) { struct pcap_pkthdr h1; h1.caplen = h->caplen-size_shift; h1.len = h->len-size_shift; h1.ts.tv_sec = h->ts.tv_sec; h1.ts.tv_usec = h->ts.tv_usec; if(last_pdu_id == pdu->pdu_id) { if(0) traceEvent(CONST_TRACE_ERROR, "[vers=%d][pdu_type=%d][pdu_id=%d][len=%d][fragment_id=%d]", pdu->version, pdu->pdu_type, pdu->pdu_id, ntohs(pdu->pdu_len), pdu->fragment_id); h1.len += last_pdu_len; if(0) traceEvent(CONST_TRACE_ERROR, "[caplen=%d][len=%d][last_pdu_len=%d]", h1.caplen, h1.len, last_pdu_len); } processPacket(_deviceId, &h1, p+size_shift); } else { last_pdu_len = h->len-size_shift, last_pdu_id = pdu->pdu_id; if(0) traceEvent(CONST_TRACE_ERROR, "[vers=%d][pdu_type=%d][pdu_id=%d][len=%d][fragment_id=%d]", pdu->version, pdu->pdu_type, pdu->pdu_id, ntohs(pdu->pdu_len), pdu->fragment_id); } } } } else if(eth_type == 0x8864) /* PPPOE */ { /* PPPoE - Courtesy of Andreas Pfaller Feb20032 * This strips the PPPoE encapsulation for traffic transiting the network. */ struct pppoe_hdr *pppoe_hdr=(struct pppoe_hdr *) (p+hlen); int protocol=ntohs(*((int *) (p+hlen+6))); if(pppoe_hdr->ver==1 && pppoe_hdr->type==1 && pppoe_hdr->code==0 && protocol==0x0021) { hlen+=8; /* length of pppoe header */ processIpPkt(p+hlen, h, length, NULL, NULL, actualDeviceId, vlanId); } } else /* Non IP */ if(!myGlobals.runningPref.dontTrustMACaddr) { /* MAC addresses are meaningful here */ struct ether_arp arpHdr; HostAddr addr; TrafficCounter ctr; char buf[32]; if(length > hlen) length -= hlen; else length = 0; srcHost = lookupHost(NULL, ether_src, vlanId, 0, 0, actualDeviceId); if(srcHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (11) [Low memory?]"); lowMemoryMsgShown = 1; return; } else { /* traceEvent(CONST_TRACE_INFO, "lockHostsHashMutex(%s)(%s)", etheraddr_string(ether_src, ipxBuffer), srcHost->ethAddressString); */ lockHostsHashMutex(srcHost, "processPacket-src-5"); } dstHost = lookupHost(NULL, ether_dst, vlanId, 0, 0, actualDeviceId); if(dstHost == NULL) { /* Sanity check */ if(!lowMemoryMsgShown) traceEvent(CONST_TRACE_ERROR, "Sanity check failed (12) [Low memory?]"); unlockHostsHashMutex(srcHost); lowMemoryMsgShown = 1; return; } else { /* traceEvent(CONST_TRACE_INFO, "lockHostsHashMutex()"); */ lockHostsHashMutex(dstHost, "processPacket-src-5"); } if(vlanId != NO_VLAN) { srcHost->vlanId = vlanId; dstHost->vlanId = vlanId; } switch(eth_type) { case ETHERTYPE_ARP: /* ARP - Address resolution Protocol */ memcpy(&arpHdr, p+hlen, sizeof(arpHdr)); if(EXTRACT_16BITS(&arpHdr.arp_pro) == ETHERTYPE_IP) { int arpOp = EXTRACT_16BITS(&arpHdr.arp_op); switch(arpOp) { case ARPOP_REPLY: /* ARP REPLY */ addr.hostFamily = AF_INET; memcpy(&addr.Ip4Address.s_addr, &arpHdr.arp_tpa, sizeof(struct in_addr)); addr.Ip4Address.s_addr = ntohl(addr.Ip4Address.s_addr); unlockHostsHashMutex(dstHost); dstHost = lookupHost(&addr, (u_char*)&arpHdr.arp_tha, vlanId, 0, 0, actualDeviceId); memcpy(&addr.Ip4Address.s_addr, &arpHdr.arp_spa, sizeof(struct in_addr)); addr.Ip4Address.s_addr = ntohl(addr.Ip4Address.s_addr); unlockHostsHashMutex(srcHost); srcHost = lookupHost(&addr, (u_char*)&arpHdr.arp_sha, vlanId, 0, 0, actualDeviceId); if(srcHost != NULL) { lockHostsHashMutex(srcHost, "processPacket-src-6"); if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(srcHost->nonIPTraffic == NULL) return; incrementTrafficCounter(&srcHost->nonIPTraffic->arpReplyPktsSent, 1); } if(dstHost != NULL) { lockHostsHashMutex(dstHost, "processPacket-dst-6"); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) return; incrementTrafficCounter(&dstHost->nonIPTraffic->arpReplyPktsRcvd, 1); } /* DO NOT ADD A break ABOVE ! */ case ARPOP_REQUEST: /* ARP request */ if(srcHost != NULL) { srcHost->hostIpAddress.hostFamily = AF_INET; memcpy(&srcHost->hostIpAddress.Ip4Address.s_addr, arpHdr.arp_spa, sizeof(struct in_addr)); srcHost->hostIpAddress.Ip4Address.s_addr = ntohl(srcHost->hostIpAddress.Ip4Address.s_addr); setHostSerial(srcHost); strncpy(srcHost->hostNumIpAddress, _addrtostr(&srcHost->hostIpAddress, buf, sizeof(buf)), sizeof(srcHost->hostNumIpAddress)); setResolvedName(srcHost, srcHost->hostNumIpAddress, FLAG_HOST_SYM_ADDR_TYPE_IP); if(myGlobals.runningPref.numericFlag == 0) ipaddr2str(srcHost->hostIpAddress, 1); if(isPseudoLocalAddress(&srcHost->hostIpAddress, actualDeviceId, NULL, NULL)) { FD_SET(FLAG_SUBNET_LOCALHOST, &srcHost->flags); FD_SET(FLAG_SUBNET_PSEUDO_LOCALHOST, &srcHost->flags); } else { FD_CLR(FLAG_SUBNET_LOCALHOST, &srcHost->flags); FD_CLR(FLAG_SUBNET_PSEUDO_LOCALHOST, &srcHost->flags); } if((arpOp == ARPOP_REQUEST) && (srcHost != NULL)) { if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(srcHost->nonIPTraffic == NULL) return; incrementTrafficCounter(&srcHost->nonIPTraffic->arpReqPktsSent, 1); } } } } /* DO NOT ADD A break ABOVE ! */ case ETHERTYPE_REVARP: /* Reverse ARP */ if(srcHost != NULL) { if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(srcHost->nonIPTraffic == NULL) return; incrementTrafficCounter(&srcHost->nonIPTraffic->arp_rarpSent, length); } if(dstHost != NULL) { if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) return; incrementTrafficCounter(&dstHost->nonIPTraffic->arp_rarpRcvd, length); } incrementTrafficCounter(&myGlobals.device[actualDeviceId].arpRarpBytes, length); break; case ETHERTYPE_DN: /* Decnet */ if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (srcHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->decnetSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->decnetRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].decnetBytes, length); break; case ETHERTYPE_ATALK: /* AppleTalk */ case ETHERTYPE_AARP: if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (srcHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->appletalkSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->appletalkRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].atalkBytes, length); break; case ETHERTYPE_IPv6: processIpPkt(p+hlen, h, length, ether_src, ether_dst, actualDeviceId, vlanId); incrementTrafficCounter(&srcHost->ipv6Sent, length); incrementTrafficCounter(&dstHost->ipv6Rcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].ipv6Bytes, length); break; default: #ifdef UNKNOWN_PACKET_DEBUG traceEvent(CONST_TRACE_INFO, "UNKNOWN_PACKET_DEBUG: %s/%s->%s/%s [eth type %d (0x%x)]", srcHost->hostNumIpAddress, srcHost->ethAddressString, dstHost->hostNumIpAddress, dstHost->ethAddressString, eth_type, eth_type); #endif if(srcHost->nonIPTraffic == NULL) srcHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if(dstHost->nonIPTraffic == NULL) dstHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic)); if((srcHost->nonIPTraffic == NULL) || (srcHost->nonIPTraffic == NULL)) return; incrementTrafficCounter(&srcHost->nonIPTraffic->otherSent, length); incrementTrafficCounter(&dstHost->nonIPTraffic->otherRcvd, length); incrementTrafficCounter(&myGlobals.device[actualDeviceId].otherBytes, length); incrementUnknownProto(srcHost, 0 /* sent */, eth_type /* eth */, 0 /* dsap */, 0 /* ssap */, 0 /* ip */); incrementUnknownProto(dstHost, 1 /* rcvd */, eth_type /* eth */, 0 /* dsap */, 0 /* ssap */, 0 /* ip */); if(myGlobals.runningPref.enableOtherPacketDump) dumpOtherPacket(actualDeviceId); break; } ctr.value = length; /* Even if this is not IP the hostIpAddress field is fine because it is not used in this special case and I need a placeholder here. */ updatePacketCount(srcHost, &srcHost->hostIpAddress, dstHost, &dstHost->hostIpAddress, ctr, 1, actualDeviceId); } } if(srcHost) unlockHostsHashMutex(srcHost); if(dstHost) unlockHostsHashMutex(dstHost); } else { /* count runts somehow? */ } if(myGlobals.flowsList != NULL) /* Handle flows last */ flowsProcess(h, p, deviceId); #ifdef MAX_PROCESS_BUFFER { float elapsed; gettimeofday(&pktEndOfProcessing, NULL); elapsed = timeval_subtract(pktEndOfProcessing, pktStartOfProcessing); myGlobals.processBuffer[++myGlobals.processBufferCount & (MAX_PROCESS_BUFFER - 1)] = elapsed; if(elapsed > myGlobals.pmaxDelay) myGlobals.pmaxDelay = elapsed; } #endif if (myGlobals.runningPref.rFileName != NULL) { if (myGlobals.actTime > (lastUpdateThptTime + PARM_THROUGHPUT_REFRESH_INTERVAL)) { updateThpt (1); lastUpdateThptTime = myGlobals.actTime; } } if(myGlobals.resetHashNow == 1) { int i; traceEvent(CONST_TRACE_INFO, "Resetting stats on user request..."); for(i=0; i length)) myGlobals.device[actualDeviceId].rcvdFcPktStats.shortest.value = length; if(myGlobals.device[actualDeviceId].rcvdFcPktStats.longest.value < length) myGlobals.device[actualDeviceId].rcvdFcPktStats.longest.value = length; } /* ************************************ */ static void processFcPkt(const u_char *bp, const struct pcap_pkthdr *h, u_int16_t ethertype, int actualDeviceId) { FcHeaderAlign *hdralign; FcHeader fchdr; FcAddress srcFcAddr, dstFcAddr; u_char *hdrBytes; u_int16_t payload_len = h->len - 14; /* FC length = pkt len - arpa hdr len */ u_int16_t totlen = h->len; u_int16_t actLen = h->caplen; /* Used when pcap truncates frames */ char *proto; u_short protocol; HostTraffic *srcHost=NULL, *dstHost=NULL; TrafficCounter ctr; u_int32_t offset = 14; /* start past the ethernet header */ u_int16_t vsanId = 0, fcFrameLen = 0; u_int8_t sof = 0, eof = 0, error = 0; #if CFG_LITTLE_ENDIAN u_int16_t didx; /* source & dest port indices on MDS */ #endif u_char isFirstFrame = FALSE, isLastFrame = FALSE, isFragment = FALSE; u_char gs_type, gs_stype, isXchgOrig; u_int16_t nsOpcode; /* Deal with Vegas Header or Boardwalk Header based on ethertype */ if ((ethertype == ETHERTYPE_BRDWLK) || (ethertype == ETHERTYPE_BRDWLK_OLD)) { sof = (bp[offset] & 0xF0) >> 4; vsanId = ntohs (*(u_int16_t *)&bp[offset]) & 0x0FFF; eof = bp[totlen-1]; error = bp[totlen-2]; offset += 2; /* skip the brdwlk hdr field */ if ((error & 0x8) && (error & 0x1)) { /* This indicates that Boardwalk carries the original FC * length even though the frame is truncated */ payload_len = ntohl (*(u_int32_t *)&bp[payload_len+14-8]); payload_len *= 4; } /* If VSAN is not 0, there is an EISL header; skip it */ if (vsanId) { offset += 8; payload_len -= 8; } if ((error & 0x8) && (error & 0x1)) { fcFrameLen = payload_len; /* Skip CRC incl payload len */ payload_len -= (FC_HDR_SIZE + 4); } else { fcFrameLen = payload_len - 6; /* Brdwlk hdr + trlr */ /* Skip Brdwlk header & trlr & CRC incl payload len */ payload_len -= (FC_HDR_SIZE + 6); /* TBD: Handle optional headers */ } } else if ((ethertype == ETHERTYPE_UNKNOWN) || (ethertype == ETHERTYPE_MDSHDR)) { #if CFG_LITTLE_ENDIAN sof = (bp[offset+1] & 0x0F); fcFrameLen = ntohs (*((u_int16_t *)&bp[offset+2])); vsanId = ntohs (*(u_int16_t *)&bp[offset+14] & 0x0FFF); didx = ntohs (*((u_int16_t *)&bp[offset+6]) & 0x1FF8) >> 3; #else sof = bp[offset+1] & 0x0F; fcFrameLen = ntohs ((*(u_int16_t *)&bp[offset+3]) & 0x1FFF); vsanId = ntohs ((*(u_int16_t *)&bp[offset+14]) & 0x0FFF); #endif eof = bp[offset+MDSHDR_HEADER_SIZE+fcFrameLen-MDSHDR_TRAILER_SIZE]; offset += MDSHDR_HEADER_SIZE; payload_len -= (MDSHDR_HEADER_SIZE + MDSHDR_TRAILER_SIZE+FC_HDR_SIZE); } memcpy(&fchdr, bp+offset, sizeof(FcHeader)); hdralign = (FcHeaderAlign *)&fchdr; hdrBytes = (u_char *)&fchdr; #if CFG_LITTLE_ENDIAN memcpy (&srcFcAddr, &hdrBytes[5], 3); memcpy (&dstFcAddr, &hdrBytes[1], 3); #else memcpy (&srcFcAddr, &hdrBytes[5], 3); memcpy (&dstFcAddr, &hdrBytes[1], 3); #endif isFirstFrame = ((sof == MDSHDR_SOFi2) || (sof == MDSHDR_SOFi3) || ((sof == MDSHDR_SOFf) && (fchdr.seq_cnt == 0))); isLastFrame = (eof != MDSHDR_EOFn); /* This is bit 23 of F_CTL which indicates whether the S_ID is the * originator of the exchange or the responder. */ isXchgOrig = (bp[offset+9] & 0x80) ? 0 : 1; /* Unless a frame is truncated by libpcap, we should have valid EOF */ if ((actLen == h->len) && (eof != MDSHDR_EOFn) && (eof != MDSHDR_EOFt)) { incrementTrafficCounter (&myGlobals.device[actualDeviceId].rcvdFcPktStats.badCRC, 1); if (myGlobals.runningPref.enableSuspiciousPacketDump) { traceEvent(CONST_TRACE_WARNING, "Bad EOF Frame Received"); dumpSuspiciousPacket(actualDeviceId); } if (eof == MDSHDR_EOFa) { incrementTrafficCounter(&myGlobals.device[actualDeviceId].fcEofaPkts, 1); } else { incrementTrafficCounter(&myGlobals.device[actualDeviceId].fcEofAbnormalPkts, 1); } } incrementTrafficCounter(&myGlobals.device[actualDeviceId].fcPkts, 1); incrementTrafficCounter(&myGlobals.device[actualDeviceId].fcBytes, fcFrameLen); dstHost = lookupFcHost (&dstFcAddr, vsanId, actualDeviceId); srcHost = lookupFcHost (&srcFcAddr, vsanId, actualDeviceId); if(srcHost == NULL) { /* Sanity check */ traceEvent(CONST_TRACE_ERROR, "Sanity check failed (1) [Low memory?]"); return; /* It might be that there's not enough memory that that dstHostIdx = getHostInfo(&ip.ip_dst, ether_dst) caused srcHost to be freed */ } if(dstHost == NULL) { /* Sanity check */ traceEvent(CONST_TRACE_ERROR, "Sanity check failed (2) [Low memory?]"); return; } if (strncasecmp (dstHost->fcCounters->hostNumFcAddress, FC_BROADCAST_ADDR, strlen (FC_BROADCAST_ADDR)) == 0) { incrementTrafficCounter(&myGlobals.device[actualDeviceId].fcBroadcastPkts, 1); incrementTrafficCounter(&myGlobals.device[actualDeviceId].fcBroadcastBytes, fcFrameLen); } updateFcDevicePacketStats(fcFrameLen, actualDeviceId); ctr.value = fcFrameLen; updatePacketCount(srcHost, NULL, dstHost, NULL, ctr, 1, actualDeviceId); #ifdef NOT_YET updateTrafficMatrix (srcHost, dstHost, ctr, actualDeviceId); #endif incrementTrafficCounter(&srcHost->fcCounters->fcBytesSent, fcFrameLen); incrementTrafficCounter(&dstHost->fcCounters->fcBytesRcvd, fcFrameLen); incrementTrafficCounter(&srcHost->fcCounters->fcPktsSent, 1); incrementTrafficCounter(&dstHost->fcCounters->fcPktsRcvd, 1); /* Class-Based Stats */ if ((sof == MDSHDR_SOFi3) || (sof == MDSHDR_SOFn3)) { incrementTrafficCounter (&srcHost->fcCounters->class3Sent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->class3Rcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].class2Bytes, fcFrameLen); } else if ((sof == MDSHDR_SOFi2) || (sof == MDSHDR_SOFn2)) { incrementTrafficCounter (&srcHost->fcCounters->class2Sent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->class2Rcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].class3Bytes, fcFrameLen); } else if (sof == MDSHDR_SOFf) { incrementTrafficCounter (&srcHost->fcCounters->classFSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->classFRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].classFBytes, fcFrameLen); } isFragment = isFirstFrame && !(isLastFrame); if (isFragment) { incrementTrafficCounter(&myGlobals.device[actualDeviceId].fragmentedFcBytes, fcFrameLen); } protocol = getFcProtocol (fchdr.r_ctl, fchdr.type); if (protocol <= FC_FTYPE_UNDEF) { proto = fcProtocolStrings[protocol]; } switch (protocol) { case FC_FTYPE_SWILS: case FC_FTYPE_SWILS_RSP: incrementTrafficCounter (&srcHost->fcCounters->fcSwilsBytesSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->fcSwilsBytesRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].fcSwilsBytes, fcFrameLen); break; case FC_FTYPE_IP: incrementTrafficCounter (&srcHost->fcCounters->fcIpfcBytesSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->fcIpfcBytesRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].fcIpfcBytes, fcFrameLen); break; case FC_FTYPE_SCSI: incrementTrafficCounter (&srcHost->fcCounters->fcFcpBytesSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->fcFcpBytesRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].fcFcpBytes, fcFrameLen); if ((fchdr.r_ctl & 0xF) == FCP_IU_CMD) { /* We deal with command frames only for now */ fillFcpInfo (&bp[offset+24], srcHost, dstHost); } break; case FC_FTYPE_ELS: if (isPlogi (fchdr.r_ctl, fchdr.type, bp[offset+24])) { fillFcHostInfo (&bp[offset+24], srcHost); } incrementTrafficCounter (&srcHost->fcCounters->fcElsBytesSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->fcElsBytesRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].fcElsBytes, fcFrameLen); /* Count RSCNs separately */ if (isRscn (fchdr.r_ctl, fchdr.type, bp[offset+24])) { incrementTrafficCounter (&dstHost->fcCounters->fcRscnsRcvd, fcFrameLen); } break; case FC_FTYPE_FCCT: gs_type = bp[offset+24+4]; gs_stype = bp[offset+24+5]; if (((gs_type == FCCT_GSTYPE_DIRSVC) && (gs_stype == FCCT_GSSUBTYPE_DNS)) || ((gs_type == FCCT_GSTYPE_MGMTSVC) && (gs_stype == FCCT_GSSUBTYPE_UNS))) { nsOpcode = ntohs (*(u_int16_t *)&bp[offset+24+8]); /* Use registration information to save more information about * device. */ switch(nsOpcode) { case FCDNS_RNN_ID: strncpy ((char*)srcHost->fcCounters->nWWN.str, (char*)&bp[offset+24+16+4], LEN_WWN_ADDRESS); break; } incrementTrafficCounter (&srcHost->fcCounters->fcDnsBytesSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->fcDnsBytesRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].fcDnsBytes, fcFrameLen); } else { incrementTrafficCounter (&srcHost->fcCounters->otherFcBytesSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->otherFcBytesRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].otherFcBytes, fcFrameLen); } break; case FC_FTYPE_SBCCS: incrementTrafficCounter (&srcHost->fcCounters->fcFiconBytesSent, fcFrameLen); incrementTrafficCounter (&dstHost->fcCounters->fcFiconBytesRcvd, fcFrameLen); incrementTrafficCounter (&myGlobals.device[actualDeviceId].fcFiconBytes, fcFrameLen); break; case FC_FTYPE_LINKDATA: case FC_FTYPE_VDO: case FC_FTYPE_LINKCTL: case FC_FTYPE_BLS: default: incrementTrafficCounter(&myGlobals.device[actualDeviceId].otherFcBytes, fcFrameLen); incrementTrafficCounter(&srcHost->fcCounters->otherFcBytesSent, fcFrameLen); incrementTrafficCounter(&dstHost->fcCounters->otherFcBytesRcvd, fcFrameLen); break; } /* Update VSAN-based stats */ allocateElementHash(actualDeviceId, 2 /* VSAN hash */); updateFcFabricElementHash (myGlobals.device[actualDeviceId].vsanHash, vsanId, &bp[offset+24], &srcFcAddr, &dstFcAddr, protocol, fchdr.r_ctl, fcFrameLen); /* Update Session stats */ handleFcSession (h, FALSE, srcHost, dstHost, fcFrameLen, payload_len, ntohs(fchdr.oxid), ntohs (fchdr.rxid), protocol, fchdr.r_ctl, isXchgOrig, &bp[offset+24], actualDeviceId); } /* ************************************ */