/* * Paglo Crawler * Copyright (C) 2006-2008 Paglo Labs Inc. All rights reserved. * www.paglo.com * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //--------------------------------------------------------------------------- #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_NETINET_IP_ICMP_H # include # include # include # include # include # include # ifndef ICMP_DEST_UNREACH # define ICMP_DEST_UNREACH ICMP_UNREACH # endif # ifndef ICMP_PORT_UNREACH # define ICMP_PORT_UNREACH ICMP_UNREACH_PORT # endif #endif #include "AnalysisManager.h" #include "AgentConfig.h" #include "ScanData.h" #include "EvidenceDescription.h" #include "Probes.h" #include "Debug.h" #include "ScanThread.h" #include "ScanAgentUtils.h" #include "ScanDHCP.h" #include "ParseCDP.h" #ifndef ROGUESCANNER #include "ParseSFlow.h" #endif #include "CommunicationThread.h" //--------------------------------------------------------------------------- extern TEventQueue _ScanReqQueue; //--------------------------------------------------------------------------- TAnalysisManager::TAnalysisManager(void) { PktQueue = new TPacketQueue(); InputQueue = new TEventQueue(); OutputQueue = NULL; DevMgr = new TDeviceManager(); ArpScanCompleted = false; } //--------------------------------------------------------------------------- TAnalysisManager::TAnalysisManager(std::string Name) : TPThread(Name) { PktQueue = new TPacketQueue(); InputQueue = new TEventQueue(); OutputQueue = NULL; DevMgr = new TDeviceManager(); ArpScanCompleted = false; } //--------------------------------------------------------------------------- TAnalysisManager::~TAnalysisManager(void) { delete PktQueue; delete InputQueue; delete DevMgr; } //--------------------------------------------------------------------------- void TAnalysisManager::Run(void) { TPacket *Pkt; TPEvent *InputEvent; TCondition WaitCond; list PacketList; DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Entering TAnalysisManager::Run()")); /* * Create a common condition variable for both the packet and * event queues to signal us with. */ PktQueue->SetCond(&WaitCond); InputQueue->SetCond(&WaitCond); /* * Execute until we're told to terminate. */ while(!IsTerminate()) { /* * Wait for packets and events to be placed into the queues. */ WaitCond.LockMutex(); #ifdef ENABLE_THROTTLING while(PktQueue->IsEmpty() && InputQueue->IsEmpty() && !IsTerminate() && ThrottleBroadcast()) { WaitCond.TimedWait(5); } #else while(PktQueue->IsEmpty() && InputQueue->IsEmpty() && !IsTerminate()) { WaitCond.TimedWait(5); } #endif /* * Attempt to gather 100 packets. */ for (int i = 0; i < 100; i++) { Pkt = PktQueue->Get(); if (Pkt) { PacketList.push_back(Pkt); } } /* * Attempt to get an event. */ InputEvent = InputQueue->Get(); WaitCond.UnLockMutex(); /* * Process all of the packets that we got. */ while (!PacketList.empty()) { Pkt = PacketList.front(); PacketList.pop_front(); ProcessPacket(Pkt); delete Pkt; } /* * Now process an event. */ if (InputEvent) { ProcessEvent(InputEvent); delete InputEvent; } } } //--------------------------------------------------------------------------- /* * ProcessEvent(): Processes an event received on the AnalysisManager's * input EventQueue. The event is deleted if appropriate. * * Arguments: TPEvent *InEvent -- the event that was received. * * Return Value: None * */ void TAnalysisManager::ProcessEvent(TPEvent *InEvent) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received an event on InputQueue.")); /* * See what kind of event we received. This switch statement should handle * every type of event we expect to see coming into the InputQueue. */ switch (InEvent->GetType()) { case EVT_NEW_DEVICE: IssueScans(InEvent->GetDevice(), false); break; case EVT_SCAN_RESULT: ProcessScanResult(InEvent->GetScanRes()); break; default: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Unhandled event type!")); } } //--------------------------------------------------------------------------- /* * ProcessPacket(): Processes a packet received on the AnalysisManager's * PacketQueue. This function always deletes the received * packet. * * Arguments: TPacket *Packet -- the packet that was received. * * Return Value: None * */ void TAnalysisManager::ProcessPacket(TPacket *Packet) { TIPAddress IPAddr; TMacAddress MacAddr; TNetworkDevice *NetDev; TPEvent *OutEvent; /* * Update outgoing bit count if the frame came from us. */ MacAddr = _GlobalConfig.GetInterface()->GetMacAddress(); #ifdef ENABLE_THROTTLING if (Packet->GetSrcMac() == MacAddr) { UpdateOutputBits(Packet->GetLength()); } #endif /* * If the packet is IP, then check to see if it's within our CIDR range. If it is and * it's a new IP address, then add it to the DeviceManager and issue scans * against the device. * * If it's a SYN|ACK, then add the port to the list of open ports for the device. */ if (Packet->GetProto() == ETHER_IPV4) { /* * Handle DHCP frames here because the source address may be 0.0.0.0 so * we cannot use it for filtering for finding the netdev. */ if (Packet->GetIPProto() == IPPROTO_UDP && Packet->GetDestPort() == UDP_PORT_DHCP) { ProcessIPv4DHCPPacket(Packet); } #ifndef ROGUESCANNER /* * Process sFlow records. */ if (Packet->GetIPProto() == IPPROTO_UDP && Packet->GetDestPort() == 6343) { ParseSFlow(Packet); } #endif IPAddr = Packet->GetSrcIP(); if (IPAddr.Valid()) { /* * Check to see if the IP is within our allocated ranges. */ if ((_GlobalConfig.IsHomeNet(IPAddr))) { /* * See if the device is new. If it is add it to the DeviceManager * and issue scans against it. * * If it's on the same subnet we can trust the MAC address otherwise, just * create the device without the MAC. */ if (_GlobalConfig.GetInterfaceNetwork().IPv4Value() == (IPAddr.IPv4Value() & _GlobalConfig.GetInterfaceNetmask().IPv4Value())) { NetDev = LookupOrCreateDevice(IPAddr, Packet->GetSrcMac()); if (NetDev == NULL) { return; } NetDev->SetLocal(true); NetDev->AddEvidence(CT_SUBNET, _GlobalConfig.GetInterfaceNetwork().Print() + "/" + Int2String(_GlobalConfig.GetInterfaceNetmask().Bits())); } else { NetDev = LookupOrCreateDevice(IPAddr); if (NetDev == NULL) { return; } } NetDev->UpdateLastSeen(); /* * If a we receive traffic from a device that we issued a PortVerify command against then * we report it to the server as reachable. We also rescan the switches to see what port it * moved to. */ if (NetDev->StatusCheckPending()) { /* * Report that it's reachable. */ LogMesg("%s is reachable. Reporting to server.", NetDev->GetIPAddress().Print().c_str()); TIPAddress DeviceIP = NetDev->GetIPAddress(); NetDev->SetStatusCheck(false); /* * Tell the switch scan thread that it should re-submit the device when it sees it, * and then re-scan the switches. */ NetDev->SwitchScanSubmit = true; _SchedulerThread->RunNow(TASK_SCANSWITCHES); } /* * Process the packet according to what IP protocol it's using. */ switch (Packet->GetIPProto()) { case IPPROTO_ICMP: if (Packet->GetICMPType() == ICMP_DEST_UNREACH) { if (Packet->GetICMPCode() == ICMP_PORT_UNREACH) { if ((Packet->Payload - Packet->GetData()) + sizeof(TIPv4Header) <= Packet->GetCaptureLength()) { /* * The protocol specified in the IP header after the * ICMP header is unsupported by the network device. * Remove it from the device's IPProtos bitset. */ TIPv4Header *ICMPInfo = (TIPv4Header*) Packet->Payload; DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Removing %d from list of supported protocols for %s.", ICMPInfo->Protocol, NetDev->GetIPAddress().Print().c_str())); NetDev->RemoveIpProto(ICMPInfo->Protocol); } } else if (Packet->GetICMPCode() == ICMP_PORT_UNREACH) { /* * The destination port in the UDP header following the * ICMP header is closed. * * Remove it from the device's UDP ports bitset. */ if (((Packet->Payload - Packet->GetData()) + sizeof(TIPv4Header) + sizeof(TUDPv4Header)) <= Packet->GetCaptureLength()) { TIPv4Header *EncapIPv4Hdr = (TIPv4Header *) Packet->Payload; TUDPv4Header *ICMPInfo = (TUDPv4Header*)(Packet->Payload + EncapIPv4Hdr->HeaderLen * 4); if ((Packet->Payload - Packet->GetData()) + sizeof(TUDPv4Header) <= Packet->GetCaptureLength()) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Removing UDP port %d from %s's list of open UDP ports.", ntohs(ICMPInfo->DestPort), NetDev->GetIPAddress().Print().c_str())); NetDev->RemoveUdpPort(ntohs(ICMPInfo->DestPort)); } } } } break; case IPPROTO_TCP: /* * If it's a TCP packet and is SYN|ACK, then add the source port * to the list of open ports for the device. */ if (Packet->GetTCPFlags() == (TCP_SYN | TCP_ACK)) { if (!NetDev->HasTcpPort(Packet->GetSrcPort())) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received ACK from %s:%d. Adding to list of open ports.", NetDev->GetIPAddress().Print().c_str(), Packet->GetSrcPort())); NetDev->AddTcpPort(Packet->GetSrcPort()); /* * Tell the main thread that we found an open port. */ OutEvent = new TPEvent(NetDev, Packet->GetSrcPort(), IPPROTO_TCP); OutputQueue->Put(OutEvent); if (NetDev->NumPendingScans() == 0) { LogMesg("Found open port on %s and no scans are pending. Submitting evidence.", NetDev->GetIPAddress().Print().c_str()); AnalyzeDevice(NetDev); } } } break; case IPPROTO_UDP: break; default: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Unhandled IP protocol: %d.", Packet->GetIPProto())); } } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Ignoring %s (not in CIDR block)", IPAddr.Print().c_str())); } } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Ether type was IP, but packet did not have a source IP address.")); } } else if (Packet->GetProto() == ETHER_ARP) { TARPHeader *ArpPtr = (TARPHeader *)Packet->GetData(); /* * We can always rely on the fact that ARP requests/responses are being generated * by devices on the same physical subnet, so we create a device for * any that don't correspond to our own interface. * * This will also allow us to pickup device's that are on the same physical subnet, * but not the same logical one. */ IPAddr = TIPAddress(ntohl(ArpPtr->ARPSourceProto)); if (IPAddr.Valid()) { /* * Only process ARP frames if they are for devices on the * same logical subnet as we are. This will prevent us * from getting fooled by proxy ARP. */ TIPAddress LocalNet(_GlobalConfig.GetInterfaceNetwork()); TIPAddress LocalMask(_GlobalConfig.GetInterfaceNetmask()); TCIDRBlock LocalBlock(LocalNet, LocalMask); if (LocalBlock.Includes(IPAddr) || Packet->IsSFlow) { MacAddr = TMacAddress(ArpPtr->ARPSourceHW); TMacAddress LocalMac; LocalMac = _GlobalConfig.GetInterface()->GetMacAddress(); if (LocalMac != MacAddr && MacAddr.Valid()) { /* * If the destination MAC address is FF:FF:FF:FF:FF:FE, then it's a promiscuous * mode test frame from another RogueScanner agent on the local subnet. * Ignore it. */ unsigned char WinPromiscMac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE }; if (memcmp(Packet->GetDstMac().Value(), WinPromiscMac, 6)) { /* * Since we must be on the same physical subnet to be seeing ARP, * we create the device with both an IP and MAC. */ NetDev = LookupOrCreateDevice(IPAddr, Packet->GetSrcMac()); if (NetDev == NULL) { return; } NetDev->SetLocal(true); if (_GlobalConfig.GetInterfaceNetwork().IPv4Value() == (IPAddr.IPv4Value() & _GlobalConfig.GetInterfaceNetmask().IPv4Value())) { NetDev->AddEvidence(CT_SUBNET, _GlobalConfig.GetInterfaceNetwork().Print() + "/" + Int2String(_GlobalConfig.GetInterfaceNetmask().Bits())); } NetDev->UpdateLastSeen(); } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Ignoring promiscuous mode test frame from %s.", Packet->GetSrcMac().Print().c_str())); } } } } } else if (Packet->GetProto() <= ETHER_LLC) { if (Packet->CDPPayload) { ParseCDP(Packet); } } } //--------------------------------------------------------------------------- void TAnalysisManager::ProcessScanResult(TScanResult *Result) { TNetworkDevice *NetDev = NULL; list *OpenPorts; std::list::iterator CurrPort; /* * This switch statement should handle every type of * scan result. */ switch(Result->GetType()) { case RESULT_NONE: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received RESULT_NONE.")); // The scan will be marked as not-pending later in this function. if (Result->GetIP().Valid()) { NetDev = LookupOrCreateDevice(Result->GetIP()); } break; case RESULT_MAC_ADDRESS: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received RESULT_MAC_ADDRESS.")); /* * Lookup the device that the scan was for. If it doesn't exist then * create one and add it to the pool of devices. If it does then * set it's MAC address to the one we just discovered. */ NetDev = LookupOrCreateDevice(Result->GetIP()); if (NetDev) { NetDev->SetMacAddress(Result->GetMacAddress()); } break; case RESULT_PROMISC: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received RESULT_PROMISC.")); /* * Lookup the device or create it if it doesn't exist. Then set its * promiscuous flag appropriately. */ NetDev = LookupOrCreateDevice(Result->GetIP()); if (NetDev) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Setting PromiscFlag to %s.", Result->GetFlag() ? "true" : "false")); NetDev->SetPromiscuous(Result->GetFlag()); } break; case RESULT_TCP_PORTS: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received RESULT_TCP_PORTS.")); /* * Go through list of ports and add them to the device. */ NetDev = LookupOrCreateDevice(Result->GetIP()); if (NetDev) { if ((OpenPorts = Result->GetPorts()) != NULL) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("%s has %d open TCP ports.", NetDev->GetIPAddress().Print().c_str(), OpenPorts->size())); for (CurrPort = OpenPorts->begin(); CurrPort != OpenPorts->end(); CurrPort++) { NetDev->AddTcpPort(*CurrPort); } } } break; case RESULT_PROBE: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Recieved RESULT_PROBE.")); /* * Fill in the response for the scan's entry in the EvidenceMap. */ NetDev = LookupOrCreateDevice(Result->GetIP()); if (NetDev) { NetDev->CompleteProbe(Result->GetRequestID(), Result->GetResponse()); } break; case RESULT_HOSTNAME: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received RESULT_HOSTNAME.")); /* * Put the hostname in the device's EvidenceMap. */ NetDev = LookupOrCreateDevice(Result->GetIP()); if (NetDev) { if (Result->GetResponse().length() > 0 && Result->GetResponse() != NetDev->GetIPAddress().Print()) { NetDev->AddEvidence(CT_DNS_NAME, Result->GetResponse()); } } break; case RESULT_NETBIOS_NAME: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received RESULT_NETBIOS_NAME.")); /* * Put the NetBIOS name in the device's EvidenceMap. */ NetDev = LookupOrCreateDevice(Result->GetIP()); if (NetDev) { if (Result->GetResponse().length() > 0) { NetDev->AddEvidence(CT_NETBIOS_NAME, Result->GetResponse()); } if (Result->GetMacAddress().Valid()) { NetDev->SetMacAddress(Result->GetMacAddress()); TAttributeData IsWindows(PT_ATTRIBUTE_WINDOWS_HOST, true); NetDev->AddEvidence(IsWindows); } } break; case RESULT_SUBNET_ARP: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received RESULT_SUBNET_ARP.")); ArpScanCompleted = true; break; default: DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Unhandled scan result type: %d!", Result->GetType())); } _Stats.CompletedProbes++; /* * Set the scan as completed and analyze the device if there * are no scans against it that are pending completion. */ if (NetDev) { if (NetDev->IsTcpScan(Result->GetRequestID())) { DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "null", 22, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "http_get", 80, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "http_get", 443, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TELNET, "null", 23, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TELNET, "null", 513, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "http_sonos_url", 1400, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "null", 21, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "null", 902, InputQueue); // vmware-authd DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "http_get", 8222, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_TCP, "http_get", 8333, InputQueue); } else if (NetDev->IsUdpScan(Result->GetRequestID())) { DispatchProbe(NetDev, PT_TECHNIQUE_SNMP, "snmp_sysdescr", 161, InputQueue); DispatchProbe(NetDev, PT_TECHNIQUE_SNMP, "snmp_sysname", 161, InputQueue); } NetDev->CompleteScan(Result->GetRequestID()); DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Received result for scan ID %d.", Result->GetRequestID())); /* * If there are still scans that are pending completion, then * don't analyze the device. Otherwise, begin analyzing it now. */ if (NetDev->NumPendingScans() > 0) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Waiting for %d scans to complete before analyzing %s.", NetDev->NumPendingScans(), NetDev->GetIPAddress().Print().c_str())); } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Analyzing %s", NetDev->GetIPAddress().Print().c_str())); AnalyzeDevice(NetDev); } } delete Result; } //--------------------------------------------------------------------------- void TAnalysisManager::AnalyzeDevice(TNetworkDevice *NetDev) { LogMesg("Submitting %s (%s).", NetDev->GetIPAddress().Print().c_str(), NetDev->GetMacAddress().Print().c_str()); /* * Submit information about the device. */ TTreeBuilder Tree = NetDev->ToMergeTree(); TSubmitTreeCmd *Cmd = new TSubmitTreeCmd(Tree.ToString(), Tree.GetStructure(), Tree.GetValues()); _CommThread->EnqueueCmd(Cmd); NetDev->SetSubmitted(); /* * Update last_seen separately. */ Tree = NetDev->LastSeenTree(); Cmd = new TSubmitTreeCmd(Tree.ToString(), Tree.GetStructure(), Tree.GetValues()); _CommThread->EnqueueCmd(Cmd); TIPAddress TargetIP = NetDev->GetIPAddress(); if (TargetIP.Valid()) { TScanRequest *ScanReq = ScanRequestFactory(SCAN_PLUGINS, TargetIP, NULL); TPEvent *OutEvent = new TPEvent(ScanReq); _RubyThread->GetInputQueue()->Put(OutEvent); } } //--------------------------------------------------------------------------- TNetworkDevice *TAnalysisManager::LookupOrCreateDevice(TIPAddress IPAddr) { TNetworkDevice *NetDev; TLocker Locker(LookupLock); /* * Refuse to create device's outside of our assignment. */ if (!_GlobalConfig.IsHomeNet(IPAddr)) { return NULL; } /* * If the device does not exist, then create it, add it, and then notify * the main thread that a new device was found. */ if ((NetDev = DevMgr->LookupDevice(IPAddr)) == NULL) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device not found! Adding %s.", IPAddr.Print().c_str())); NetDev = new TNetworkDevice(IPAddr); DevMgr->AddDevice(NetDev); /* * Send an event to say we discovered a new device. */ TPEvent *OutEvent = new TPEvent(NetDev); OutputQueue->Put(OutEvent); /* * Start issuing scans against the device. */ IssueScans(NetDev); } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device already exists: %s", NetDev->GetIPAddress().Print().c_str())); TickleExistingDevice(NetDev); } return NetDev; } //--------------------------------------------------------------------------- void TAnalysisManager::TickleExistingDevice(TNetworkDevice *NetDev) { /* * Issue scans if we have not scanned the device recently enough. */ if (NetDev->NeedsRescan() && !_GlobalConfig.IsIgnored(NetDev->GetIPAddress()) && !_GlobalConfig.IsIgnored(NetDev->GetMacAddress()) && _GlobalConfig.Enabled) { IssueScans(NetDev); } } //--------------------------------------------------------------------------- TNetworkDevice *TAnalysisManager::LookupOrCreateDevice(TMacAddress MacAddr) { TNetworkDevice *NetDev; TLocker Locker(LookupLock); /* * Filter out broadcast/multicast MAC addresses. */ if ((MacAddr.Value()[0] & 0x01) == 0x01) { return NULL; } /* * If the device does not exist, then create it, add it, and then notify * the main thread that a new device was found. */ if ((NetDev = DevMgr->LookupDevice(MacAddr)) == NULL) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device not found! Adding %s.", MacAddr.Print().c_str())); NetDev = new TNetworkDevice(MacAddr); DevMgr->AddDevice(NetDev); /* * Send an event to say we discovered a new device. */ TPEvent *OutEvent = new TPEvent(NetDev); OutputQueue->Put(OutEvent); /* * Start issuing scans against the device. */ IssueScans(NetDev); } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device already exists: %s", NetDev->GetMacAddress().Print().c_str())); TickleExistingDevice(NetDev); } return NetDev; } //--------------------------------------------------------------------------- TNetworkDevice *TAnalysisManager::LookupOrCreateDevice(TIPAddress IPAddr, TMacAddress MacAddr) { TNetworkDevice *NetDev; bool NewDev = false; TLocker Locker(LookupLock); /* * Refuse to create device's outside of our assignment. */ if (!_GlobalConfig.IsHomeNet(IPAddr)) { return NULL; } /* * If the device does not exist, then create it, add it, and then notify * the main thread that a new device was found. * * If any managed switches are configured it's likely that there may * be devices that only have a MAC set, so we'll lookup by that first * in order to ensure there aren't any duplicate devices. */ if ((NetDev = DevMgr->LookupDevice(MacAddr)) == NULL) { /* * We couldn't find a device with MacAddr, so we'll look for * one with IPAddr. */ DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device with MAC %s not found! Looking for %s.", MacAddr.Print().c_str(), IPAddr.Print().c_str())); if ((NetDev = DevMgr->LookupDevice(IPAddr)) == NULL) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device not found! Adding %s (%s).", IPAddr.Print().c_str(), MacAddr.Print().c_str())); NetDev = new TNetworkDevice(IPAddr); /* * Filter out broadcast/multicast MAC addresses. */ if ((MacAddr.Value()[0] & 0x01) != 0x01) { NetDev->SetMacAddress(MacAddr); } DevMgr->AddDevice(NetDev); NewDev = true; } else { /* * A device with IPAddr was found, but its MAC wasn't MacAddr. */ if (NetDev->GetMacAddress().Valid() && (NetDev->GetMacAddress() != MacAddr)) { LogMesg("Detected MAC address change for %s: was %s, now %s.", IPAddr.Print().c_str(), NetDev->GetMacAddress().Print().c_str(), MacAddr.Print().c_str()); /* * Update the device with the new MAC address and re-scan it, since it's likely that the actual * device responding to the IP has changed as well. * * Also filter out broadcast/multicast MAC addresses. */ if ((MacAddr.Value()[0] & 0x01) != 0x01) { NetDev->SetMacAddress(MacAddr); IssueScans(NetDev); } } } } else { /* * If the IP for the current device is valid, then we need to compare it's IP to IPAddr * and determine whether a new device needs to be created. */ if (NetDev->GetIPAddress().Valid()) { /* * See if the IPs match. If they don't then see if we have a device with that IP. * If there isn't, then we create a new device. */ if (NetDev->GetIPAddress() != IPAddr) { if ((NetDev = DevMgr->LookupDevice(IPAddr)) == NULL) { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device already exists (%s), but IP is not %s." "Adding %s (%s).", MacAddr.Print().c_str(), IPAddr.Print().c_str(), IPAddr.Print().c_str(), MacAddr.Print().c_str())); NetDev = new TNetworkDevice(IPAddr); /* * Filter out broadcast/multicast MAC addresses. */ if ((MacAddr.Value()[0] & 0x01) != 0x01) { NetDev->SetMacAddress(MacAddr); } DevMgr->AddDevice(NetDev); NewDev = true; } } } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Discovered IP for %s: %s.", MacAddr.Print().c_str(), IPAddr.Print().c_str())); NetDev->SetIPAddress(IPAddr); /* * Since we didn't know the IP address before, we were unable to scan the device. Now * that we know it, we can. */ IssueScans(NetDev); } } if (NewDev) { /* * Send an event to say we discovered a new device. */ TPEvent *OutEvent = new TPEvent(NetDev); OutputQueue->Put(OutEvent); /* * Send start issuing scans against the device. */ IssueScans(NetDev); } else { DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Device already exists: %s", NetDev->GetIPAddress().Print().c_str())); TickleExistingDevice(NetDev); } return NetDev; } //--------------------------------------------------------------------------- void TAnalysisManager::AddSubnet(TCIDRBlock Block, int Method) { /* * Filter anything that lies outside of of our assigned CIDR ranges. */ TIPAddress NetAddress = Block.GetAddress(); if (!_GlobalConfig.IsHomeNet(NetAddress)) { return; } /* * Filter out default routes, the loopback interface, and self-assigned IPs. */ TSubnet *Subnet = new TSubnet(Block, Method); if (!DevMgr->HasSubnet(Subnet) && Subnet->GetAddress().Valid() && Subnet->GetMask().Valid() && Subnet->GetAddress().IPv4Value() != 0x7f000000) { DevMgr->AddSubnet(Subnet); } else { delete Subnet; } } //--------------------------------------------------------------------------- void TAnalysisManager::IssueScans(TNetworkDevice *NetDev, bool Priority) { TScanRequest *ScanReq; TPEvent *OutEvent; int Action, ScanCount = 0; if (NetDev->GetIPAddress().Valid()) { if (NetDev->NumPendingScans() == 0) { /* * Only perform scans on the device if we weren't told to ignore it. * Otherwise just begin analyzing the device which will cause it to be * classified solely by MAC address. */ if (!_GlobalConfig.IsIgnored(NetDev->GetIPAddress()) && !_GlobalConfig.IsIgnored(NetDev->GetMacAddress())) { /* * Go through all of the available scan types and issue a scan * if it hasn't been performed on the device before or isn't pending. */ DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Issuing scans against %s.", NetDev->GetIPAddress().Print().c_str())); for (int i = 0; _AutoScanTypes[i] >= 0; i++) { ScanReq = ScanRequestFactory(_AutoScanTypes[i], NetDev->GetIPAddress(), InputQueue); /* * Defer SCAN_PROMISC scans until SCAN_SUBNET_ARP has completed, so that we can * ensure that the IP picked for spoofing is unused. */ /* * GCC doesn't like temporaries to be passed by reference. */ TIPAddress TargetIP = NetDev->GetIPAddress(); DEBUG_MESSAGE(DEBUG_ANALYSISMANAGER, ("Issuing %s against %s (ID: %d).", ScanReq->TypeString().c_str(), NetDev->GetIPAddress().Print().c_str(), ScanReq->GetID())); NetDev->AddScan(ScanReq->GetID(), ScanReq->TypeString()); if (ScanReq->GetType() == SCAN_TCP_PORTS) { NetDev->StartTcpScan(ScanReq->GetID()); } else if (ScanReq->GetType() == SCAN_UDP_PORTS) { NetDev->StartUdpScan(ScanReq->GetID()); } OutEvent = new TPEvent(ScanReq); if (Priority) { _ScanReqQueue.PutFront(OutEvent); } else { _ScanReqQueue.Put(OutEvent); } ScanCount++; } } else { LogMesg("%s (%s) is ignored. Skipping scans against it.", NetDev->GetIPAddress().Print().c_str(), NetDev->GetMacAddress().Print().c_str()); } } else { LogMesg("No new scans dispatched against %s. Device currently has %d scans pending.", NetDev->GetIPAddress().Print().c_str(), NetDev->NumPendingScans()); return; } } else if (NetDev->GetMacAddress().Valid()) { LogMesg("No IP information for %s. Classifying based on MAC address.", NetDev->GetMacAddress().Print().c_str()); NetDev->UpdateLastProbed(); } /* * Submit the device's evidence if no scans were launched. */ if (ScanCount == 0) { AnalyzeDevice(NetDev); } } //---------------------------------------------------------------------------