/* * 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 */ //--------------------------------------------------------------------------- #include "Debug.h" #include "ScanData.h" #include "NetworkDevice.h" #include "AgentConfig.h" #include "ScanAgentUtils.h" #include "EvidenceDescription.h" #include "UdpScanPorts.h" #include "SchedulerThread.h" #include //--------------------------------------------------------------------------- TProbeData::TProbeData(string Technique, string Label, string Request, string Response, int Port, int ScanId) { this->Technique = Technique; this->Label = Label; this->Request = Request; this->Response = Response; this->Port = Port; this->ScanId = ScanId; } //--------------------------------------------------------------------------- TSwitchData::TSwitchData(string Name, string IPAddress, string Port, int VLAN) { this->Name = Name; this->IPAddress = IPAddress; this->Port = Port; this->VLAN = VLAN; } //--------------------------------------------------------------------------- TAttributeData::TAttributeData(string Attribute, bool Value) { this->Attribute = Attribute; this->Value = Value; } //--------------------------------------------------------------------------- TDHCPData::TDHCPData(string VendorClass, string HostName, string ParamRequestList) { this->VendorClass = VendorClass; this->HostName = HostName; this->ParamRequestList = ParamRequestList; } //--------------------------------------------------------------------------- /* TDiscoveryProtoData::TDiscoveryProtoData(TSwitchQueryCDPInfo &CDPInfo) { ProtoType = DISCOVERY_PROTO_CDP; this->SwitchIP = CDPInfo.SwitchIP; this->DeviceId = CDPInfo.DeviceId; this->Version = CDPInfo.Version; this->Platform = CDPInfo.Platform; this->LocalPort = CDPInfo.LocalPort; this->RemotePort = CDPInfo.RemotePort; this->RemoteVlan = CDPInfo.RemoteVlan; this->Capabilities = CDPInfo.Capabilities; } //--------------------------------------------------------------------------- */ string TDiscoveryProtoData::TypeString(void) { switch (ProtoType) { case DISCOVERY_PROTO_CDP: return "CDP"; case DISCOVERY_PROTO_FDP: return "FDP"; default: return "unknown"; } } //--------------------------------------------------------------------------- TMultiTypeMapValue::TMultiTypeMapValue(TProbeData &ProbeData) { ValueType = TYPE_PROBEDATA; MapValue.ProbeData = new TProbeData(ProbeData.Technique, ProbeData.Label, ProbeData.Request, ProbeData.Response, ProbeData.Port, ProbeData.ScanId); } //--------------------------------------------------------------------------- TMultiTypeMapValue::TMultiTypeMapValue(TSwitchData &SwitchData) { ValueType = TYPE_SWITCHDATA; MapValue.SwitchData = new TSwitchData(SwitchData.Name, SwitchData.IPAddress, SwitchData.Port, SwitchData.VLAN); } //--------------------------------------------------------------------------- TMultiTypeMapValue::TMultiTypeMapValue(TAttributeData &AttributeData) { ValueType = TYPE_ATTRIBUTEDATA; MapValue.AttributeData = new TAttributeData(AttributeData.Attribute, AttributeData.Value); } //--------------------------------------------------------------------------- TMultiTypeMapValue::TMultiTypeMapValue(TDHCPData &DHCPData) { ValueType = TYPE_DHCPDATA; MapValue.DHCPData = new TDHCPData(DHCPData.VendorClass, DHCPData.HostName, DHCPData.ParamRequestList); } //--------------------------------------------------------------------------- TMultiTypeMapValue::TMultiTypeMapValue(TDiscoveryProtoData &DscProtoData) { ValueType = TYPE_DISCOVERY_PROTO_DATA; MapValue.DscProtoData = new TDiscoveryProtoData(); *MapValue.DscProtoData = DscProtoData; } //--------------------------------------------------------------------------- TMultiTypeMapValue::TMultiTypeMapValue(TWmiData &WmiData) { ValueType = TYPE_WMI_DATA; MapValue.WmiData = new TWmiData(); *MapValue.WmiData = WmiData; } //--------------------------------------------------------------------------- TMultiTypeMapValue::TMultiTypeMapValue(const TMultiTypeMapValue &MTMVal) { ValueType = MTMVal.ValueType; switch (MTMVal.ValueType) { case TYPE_IPADDRESS: MapValue.IPAddr = new TIPAddress(*MTMVal.MapValue.IPAddr); break; case TYPE_MACADDRESS: MapValue.MacAddr = new TMacAddress(*MTMVal.MapValue.MacAddr); break; case TYPE_STRING: MapValue.Str = new string(*MTMVal.MapValue.Str); break; case TYPE_INTEGER: MapValue.IntVal = MTMVal.MapValue.IntVal; break; case TYPE_BOOL: MapValue.BoolVal = MTMVal.MapValue.BoolVal; break; case TYPE_PROBEDATA: MapValue.ProbeData = new TProbeData(MTMVal.MapValue.ProbeData->Technique, MTMVal.MapValue.ProbeData->Label, MTMVal.MapValue.ProbeData->Request, MTMVal.MapValue.ProbeData->Response, MTMVal.MapValue.ProbeData->Port, MTMVal.MapValue.ProbeData->ScanId); break; case TYPE_SWITCHDATA: MapValue.SwitchData = new TSwitchData(MTMVal.MapValue.SwitchData->Name, MTMVal.MapValue.SwitchData->IPAddress, MTMVal.MapValue.SwitchData->Port, MTMVal.MapValue.SwitchData->VLAN); break; case TYPE_ATTRIBUTEDATA: MapValue.AttributeData = new TAttributeData(MTMVal.MapValue.AttributeData->Attribute, MTMVal.MapValue.AttributeData->Value); break; case TYPE_DHCPDATA: MapValue.DHCPData = new TDHCPData(MTMVal.MapValue.DHCPData->VendorClass, MTMVal.MapValue.DHCPData->HostName, MTMVal.MapValue.DHCPData->ParamRequestList); break; case TYPE_DISCOVERY_PROTO_DATA: MapValue.DscProtoData = new TDiscoveryProtoData(); *MapValue.DscProtoData = *MTMVal.MapValue.DscProtoData; break; case TYPE_WMI_DATA: MapValue.WmiData = new TWmiData(); *MapValue.WmiData = *MTMVal.MapValue.WmiData; break; /* * Nothing is copied. */ case TYPE_NONE: default: ; } } //--------------------------------------------------------------------------- TMultiTypeMapValue::~TMultiTypeMapValue(void) { switch (ValueType) { case TYPE_IPADDRESS: delete MapValue.IPAddr; break; case TYPE_MACADDRESS: delete MapValue.MacAddr; break; case TYPE_STRING: delete MapValue.Str; break; case TYPE_PROBEDATA: delete MapValue.ProbeData; break; case TYPE_SWITCHDATA: delete MapValue.SwitchData; break; case TYPE_ATTRIBUTEDATA: delete MapValue.AttributeData; break; case TYPE_DHCPDATA: delete MapValue.DHCPData; break; case TYPE_DISCOVERY_PROTO_DATA: delete MapValue.DscProtoData; break; case TYPE_WMI_DATA: delete MapValue.WmiData; break; /* * Nothing to delete for these types. */ case TYPE_NONE: case TYPE_INTEGER: case TYPE_BOOL: default: ; } } //--------------------------------------------------------------------------- string TMultiTypeMapValue::Print(void) { string ValString = ""; switch(ValueType) { case TYPE_IPADDRESS: ValString = MapValue.IPAddr->Print(); break; case TYPE_MACADDRESS: ValString = MapValue.MacAddr->Print(); break; case TYPE_STRING: ValString = *MapValue.Str; break; case TYPE_INTEGER: ValString = Int2String(MapValue.IntVal); break; case TYPE_BOOL: ValString = MapValue.BoolVal ? "true" : "false"; break; case TYPE_PROBEDATA: ValString = MapValue.ProbeData->Technique; ValString += "("; ValString += "label:"; ValString += MapValue.ProbeData->Label; ValString += ", "; ValString += "scan_id:"; ValString += Int2String(MapValue.ProbeData->ScanId); ValString += ", "; ValString += "port:"; ValString += Int2String(MapValue.ProbeData->Port); ValString += ", "; ValString += "request:\""; ValString += MapValue.ProbeData->Request; ValString += "\", "; ValString += "response:\""; ValString += MapValue.ProbeData->Response; ValString += "\")"; break; case TYPE_SWITCHDATA: ValString = "name:" + MapValue.SwitchData->Name; ValString += ", ip_address:" + MapValue.SwitchData->IPAddress; ValString += ", port:" + MapValue.SwitchData->Port; ValString += ", vlan:" + Int2String(MapValue.SwitchData->VLAN); break; case TYPE_ATTRIBUTEDATA: ValString = MapValue.AttributeData->Attribute; ValString += ": "; ValString += MapValue.AttributeData->Value ? "true" : "false"; break; case TYPE_DHCPDATA: ValString = "vendor_name:" + MapValue.DHCPData->VendorClass; ValString += ", host_name:" + MapValue.DHCPData->HostName; ValString += ", param_request_list:" + MapValue.DHCPData->ParamRequestList; break; case TYPE_DISCOVERY_PROTO_DATA: ValString = "proto:" + MapValue.DscProtoData->TypeString(); ValString += ", switch_ip:" + MapValue.DscProtoData->SwitchIP.Print(); ValString += ", device_id:" + MapValue.DscProtoData->DeviceId; ValString += ", version:" + MapValue.DscProtoData->Version; ValString += ", platform:" + MapValue.DscProtoData->Platform; ValString += ", local_port:" + MapValue.DscProtoData->LocalPort; ValString += ", remote_port:" + MapValue.DscProtoData->RemotePort; ValString += ", remote_vlan:" + Int2String(MapValue.DscProtoData->RemoteVlan); ValString += ", capabilities:" + MapValue.DscProtoData->Capabilities; break; case TYPE_WMI_DATA: ValString = "namespace:" + MapValue.WmiData->Namespace; ValString += ", query:" + MapValue.WmiData->Query; ValString += ", result:" + MapValue.WmiData->Result; break; /* * These return an empty string. */ case TYPE_NONE: default: ; } return ValString; } //--------------------------------------------------------------------------- bool TMultiTypeMapValue::operator== (TMultiTypeMapValue &V) { switch(ValueType) { case TYPE_NONE: return true; case TYPE_IPADDRESS: return *V.MapValue.IPAddr == *MapValue.IPAddr; case TYPE_MACADDRESS: return *V.MapValue.MacAddr == *MapValue.MacAddr; case TYPE_STRING: return *V.MapValue.Str == *MapValue.Str; case TYPE_INTEGER: return V.MapValue.IntVal == MapValue.IntVal; case TYPE_BOOL: return V.MapValue.BoolVal == MapValue.BoolVal; case TYPE_PROBEDATA: return V.MapValue.ProbeData->Technique == MapValue.ProbeData->Technique && V.MapValue.ProbeData->Label == MapValue.ProbeData->Label && V.MapValue.ProbeData->Port == MapValue.ProbeData->Port; case TYPE_SWITCHDATA: return V.MapValue.SwitchData->IPAddress == MapValue.SwitchData->IPAddress; case TYPE_ATTRIBUTEDATA: return V.MapValue.AttributeData->Attribute == MapValue.AttributeData->Attribute; case TYPE_WMI_DATA: return V.MapValue.WmiData->Namespace == MapValue.WmiData->Namespace && V.MapValue.WmiData->Query == MapValue.WmiData->Query && V.MapValue.WmiData->Result == MapValue.WmiData->Result; case TYPE_DHCPDATA: return V.MapValue.DHCPData->VendorClass == MapValue.DHCPData->VendorClass && V.MapValue.DHCPData->HostName == MapValue.DHCPData->HostName && V.MapValue.DHCPData->ParamRequestList == MapValue.DHCPData->ParamRequestList; case TYPE_DISCOVERY_PROTO_DATA: return V.MapValue.DscProtoData->ProtoType == MapValue.DscProtoData->ProtoType && V.MapValue.DscProtoData->DeviceId == MapValue.DscProtoData->DeviceId; default: return false; } } //--------------------------------------------------------------------------- TNetworkDevice::TNetworkDevice(TIPAddress IPAddr) { InitLocks(); this->IPAddr = IPAddr; AddEvidence(CT_IP_ADDRESS, TMultiTypeMapValue(IPAddr)); if (_GlobalConfig.GetInterfaceIPAddress().IPv4Value() & _GlobalConfig.GetInterfaceNetmask().IPv4Value() == (IPAddr.IPv4Value() & _GlobalConfig.GetInterfaceNetmask().IPv4Value())) { SameSubnet = true; } else { SameSubnet = false; } /* * Set all the bits. We'll clear them as we see * ICMP protocol unreachable or port unreachable * messages come in. */ IpProtos.set(); TcpScanID = -1; UdpScanID = -1; UdpPorts = NULL; HaveSwitchMac = false; LastProbed = 0; StatusPending = false; StatusTimestamp = 0; SubmitFlag = false; SwitchScanSubmit = false; UpdateLastSeen(); } //--------------------------------------------------------------------------- TNetworkDevice::TNetworkDevice(TMacAddress Mac) { InitLocks(); if (Mac.Valid()) { MacAddr = Mac; AddEvidence(CT_MAC_ADDRESS, TMultiTypeMapValue(Mac)); } /* * Set all the bits. We'll clear them as we see * ICMP protocol unreachable or port unreachable * messages come in. */ IpProtos.set(); TcpScanID = -1; UdpScanID = -1; UdpPorts = NULL; HaveSwitchMac = false; LastProbed = 0; StatusPending = false; StatusTimestamp = 0; SubmitFlag = false; UpdateLastSeen(); } //--------------------------------------------------------------------------- TNetworkDevice::~TNetworkDevice(void) { if (UdpPorts) { delete UdpPorts; } } //--------------------------------------------------------------------------- void TNetworkDevice::InitLocks(void) { pthread_mutex_init(&IPAddrMutex, NULL); pthread_mutex_init(&MacAddrMutex, NULL); pthread_mutex_init(&UdpPortsMutex, NULL); pthread_mutex_init(&IpProtosMutex, NULL); pthread_mutex_init(&PendingScansMutex, NULL); pthread_mutex_init(&ClassificationsMutex, NULL); pthread_mutex_init(&EvidenceMutex, NULL); } //--------------------------------------------------------------------------- string TNetworkDevice::ShortDescription() { TIPAddress IPAddr = GetIPAddress(); TMacAddress MacAddr = GetMacAddress(); string Desc = ""; /* TODO: If the device has a name we should use it here. */ if (IPAddr.Valid()) { Desc += IPAddr.Print() + " "; } if (MacAddr.Valid()) { Desc += "(" + MacAddr.Print() + ") "; } return Desc; } //--------------------------------------------------------------------------- string TNetworkDevice::Description() { TIPAddress IPAddr = GetIPAddress(); TMacAddress MacAddr = GetMacAddress(); string Desc = ""; if (IPAddr.Valid()) { Desc += IPAddr.Print() + " "; } if (MacAddr.Valid()) { Desc += "(" + MacAddr.Print() + ") "; } pthread_mutex_lock(&ClassificationsMutex); if (Classifications.size() > 0) { TClassification C = Classifications.front(); Desc += " " + C.GetValue(CR_VENDOR); Desc += " " + C.GetValue(CR_MODEL); } pthread_mutex_unlock(&ClassificationsMutex); return Desc; } //--------------------------------------------------------------------------- string TNetworkDevice::DetailedDescription() { string D = ""; D += "IP Address: " + GetIPAddress().Print() + "\n"; D += "MAC Address: " + GetMacAddress().Print() + "\n"; D += "Local: " + string(IsLocal() ? "yes" : "no") + "\n"; D += "Submitted: "+ string(Submitted() ? "yes" : "no") + "\n"; D += "Evidence: \n"; D += PrintMultiTypeMap(EvidenceMap); D += "\n"; D += "Classification: \n"; pthread_mutex_lock(&ClassificationsMutex); vector::iterator CurrClass; int i = 1; for (CurrClass = Classifications.begin(); CurrClass != Classifications.end(); CurrClass++) { D += " [" + Int2String(i++) + "] Score = " + Int2String((*CurrClass).Score) + "\n"; map::iterator CurrMap; for (CurrMap = (*CurrClass).Values.begin(); CurrMap != (*CurrClass).Values.end(); CurrMap++) { D += " " + (*CurrMap).first + " = " + (*CurrMap).second + "\n"; } } pthread_mutex_unlock(&ClassificationsMutex); return D; } //--------------------------------------------------------------------------- string TNetworkDevice::CSVSummaryHeadings() { return "IP Address,MAC Address,Vendor,Model,Best Score,Classes"; } //--------------------------------------------------------------------------- string TNetworkDevice::CSVSummary() { string D; D += GetIPAddress().Print(); D += ","; D += GetMacAddress().Print(); D += ","; if (Classifications.size() > 0) { TClassification C = Classifications.front(); D += C.GetValue(CR_VENDOR); D += ","; D += C.GetValue(CR_MODEL); D += ","; D += Int2String(C.Score); D += ","; D += C.GetValue(CR_CLASS); } else { D += ",,,"; } return D; } //--------------------------------------------------------------------------- void TNetworkDevice::SetIPAddress(TIPAddress IP) { if (IP.Valid()) { pthread_mutex_lock(&IPAddrMutex); IPAddr = IP; AddEvidence(CT_IP_ADDRESS, TMultiTypeMapValue(IP)); pthread_mutex_unlock(&IPAddrMutex); } } //--------------------------------------------------------------------------- TIPAddress TNetworkDevice::GetIPAddress(void) { return IPAddr; } //--------------------------------------------------------------------------- void TNetworkDevice::SetMacAddress(TMacAddress Mac) { if (Mac.Valid() && !HaveSwitchMac && ((Mac.Value()[0] & 0x01) != 0x01)) { pthread_mutex_lock(&MacAddrMutex); MacAddr = Mac; AddEvidence(CT_MAC_ADDRESS, TMultiTypeMapValue(MacAddr)); pthread_mutex_unlock(&MacAddrMutex); } } //--------------------------------------------------------------------------- void TNetworkDevice::SetSwitchMacAddress(TMacAddress Mac) { if (Mac.Valid() && ((Mac.Value()[0] & 0x01) != 0x01)) { pthread_mutex_lock(&MacAddrMutex); HaveSwitchMac = true; MacAddr = Mac; AddEvidence(CT_MAC_ADDRESS, TMultiTypeMapValue(MacAddr)); pthread_mutex_unlock(&MacAddrMutex); } } //--------------------------------------------------------------------------- void TNetworkDevice::SetPromiscuous(bool IsPromiscuous) { AddEvidence(CT_PROMISCUOUS, IsPromiscuous); } //--------------------------------------------------------------------------- TMacAddress TNetworkDevice::GetMacAddress(void) { return MacAddr; } //--------------------------------------------------------------------------- void TNetworkDevice::AddScan(int ScanRequestID, const string &TypeString) { TScanStatus Scan(ScanRequestID, TypeString, false); AddEvidence(Scan); pthread_mutex_lock(&PendingScansMutex); PendingScans.push_back(Scan); LastProbed = time(NULL); pthread_mutex_unlock(&PendingScansMutex); } //--------------------------------------------------------------------------- void TNetworkDevice::CompleteScan(int ScanRequestID) { int AdjacentOpen = 0, TotalOpen = 0; string TypeString; pthread_mutex_lock(&PendingScansMutex); list::iterator CurrScan, TmpScan; for (CurrScan = PendingScans.begin(); CurrScan != PendingScans.end();) { if (CurrScan->ScanRequestID == ScanRequestID) { CurrScan->Completed = true; AddEvidence(*CurrScan); TmpScan = CurrScan; CurrScan++; PendingScans.erase(TmpScan); } CurrScan++; } pthread_mutex_unlock(&PendingScansMutex); /* * If a UDP scan completed, then load the contents of the UdpPorts bitset * into the EvidenceMap. Then deallocate the bitset. * * Only the ports specified in the _UdpScanPorts array are tested. * * TODO: change UdpPorts to something more efficient than a bitset. */ if (ScanRequestID == UdpScanID && UdpPorts) { for (int i = 0; _UdpScanPorts[i] > 0; i++) { if (UdpPorts->test(_UdpScanPorts[i])) { AddEvidence(CT_UDP_PORT, TMultiTypeMapValue(_UdpScanPorts[i])); TotalOpen++; if (i > 0) { if (UdpPorts->test(_UdpScanPorts[i - 1])) { AdjacentOpen++; } else { AdjacentOpen = 0; } } } /* * If the number of adjacent open ports from _UdpScanPorts exceeds * UDP_ADJACENT_INVALIDATE, then remove all data associated with * the "udp_ports" key from the EvidenceMap and stop processing the * UdpPorts bitset. */ if (AdjacentOpen >= UDP_ADJACENT_INVALIDATE) { EvidenceMap.erase(CT_UDP_PORT); break; } /* * If the total number of open ports exceeds UDP_OPEN_INVALIDATE, * then remove all data associated with the "udp_ports" key from * EvidenceMap and stop processing the UdpPorts bitset. */ if (TotalOpen >= UDP_OPEN_INVALIDATE) { EvidenceMap.erase(CT_UDP_PORT); break; } } delete UdpPorts; UdpPorts = NULL; UdpScanID = -1; } else if (ScanRequestID == TcpScanID) { TcpScanID = -1; } } //--------------------------------------------------------------------------- void TNetworkDevice::CompleteProbe(int ScanId, std::string Response) { TMultiTypeMap::iterator CurrPair; TProbeData *ProbeData; for (CurrPair = EvidenceMap.lower_bound(CT_PROBE); CurrPair != EvidenceMap.upper_bound(CT_PROBE); CurrPair++) { if (CurrPair->second.ValueType == TYPE_PROBEDATA) { ProbeData = CurrPair->second.MapValue.ProbeData; if (ProbeData->ScanId == ScanId) { ProbeData->Response = Response; } } } } //--------------------------------------------------------------------------- void TNetworkDevice::StartUdpScan(int ScanRequestID) { if (UdpScanID < 0 && UdpPorts == NULL) { UdpScanID = ScanRequestID; UdpPorts = new bitset<65536>; UdpPorts->set(); } } //--------------------------------------------------------------------------- int TNetworkDevice::NumPendingScans(void) { return PendingScans.size(); } //--------------------------------------------------------------------------- void TNetworkDevice::AddTcpPort(unsigned short Port) { /* * Look through the list and see if the port is already in it. * If it isn't, then add it to the list. */ if (!HasTcpPort(Port)) { AddEvidence(CT_TCP_PORT, TMultiTypeMapValue(Port)); DEBUG_MESSAGE(DEBUG_NETWORKDEVICE, ("Added TCP port %d to %s's list of open ports.\n", Port, this->GetIPAddress().Print().c_str())); } } //--------------------------------------------------------------------------- void TNetworkDevice::RemoveUdpPort(unsigned short Port) { pthread_mutex_lock(&UdpPortsMutex); if (UdpScanID >= 0 && UdpPorts) { UdpPorts->set(Port, 0); } pthread_mutex_unlock(&UdpPortsMutex); } //--------------------------------------------------------------------------- void TNetworkDevice::RemoveIpProto(unsigned char Proto) { pthread_mutex_lock(&IpProtosMutex); IpProtos.set(Proto, 0); pthread_mutex_unlock(&IpProtosMutex); } //--------------------------------------------------------------------------- bool TNetworkDevice::HasTcpPort(unsigned short Port) { TMultiTypeMapValue PortValue(Port); TMultiTypeMap::iterator CurrPair; /* * Go through the list of TCP ports and see if there's a match. */ for (CurrPair = EvidenceMap.lower_bound(CT_TCP_PORT); CurrPair != EvidenceMap.upper_bound(CT_TCP_PORT); CurrPair++) { if (CurrPair->second == PortValue) { return true; } } return false; } //--------------------------------------------------------------------------- bool TNetworkDevice::HasUdpPort(unsigned short Port) { TMultiTypeMapValue PortValue(Port); TMultiTypeMap::iterator CurrPair; /* * Go through the list of UDP ports and see if there's a match. */ for (CurrPair = EvidenceMap.lower_bound(CT_UDP_PORT); CurrPair != EvidenceMap.upper_bound(CT_UDP_PORT); CurrPair++) { if (CurrPair->second == PortValue) { return true; } } return false; } //--------------------------------------------------------------------------- bool TNetworkDevice::HasPort(unsigned char Proto, unsigned short Port) { bool Matched = false; switch (Proto) { case IPPROTO_TCP: Matched = HasTcpPort(Port); break; case IPPROTO_UDP: Matched = HasUdpPort(Port); break; default: DEBUG_MESSAGE(DEBUG_NETWORKDEVICE, ("Unsupported protocol specified: %d", Proto)); } return Matched; } //--------------------------------------------------------------------------- bool TNetworkDevice::HasIpProto(unsigned char Proto) { bool Matched; pthread_mutex_lock(&IpProtosMutex); Matched = IpProtos.test(Proto); pthread_mutex_unlock(&IpProtosMutex); return Matched; } //--------------------------------------------------------------------------- list TNetworkDevice::FindEvidence(std::string Key) { TMultiTypeMap::iterator CurrPair; list ValueList; pthread_mutex_lock(&EvidenceMutex); for (CurrPair = EvidenceMap.lower_bound(Key); CurrPair != EvidenceMap.upper_bound(Key); CurrPair++) { ValueList.push_back(CurrPair->second); } pthread_mutex_unlock(&EvidenceMutex); return ValueList; } //--------------------------------------------------------------------------- void TNetworkDevice::AddClassification(TClassification &Classification) { pthread_mutex_lock(&ClassificationsMutex); Classifications.push_back(Classification); sort(Classifications.begin(), Classifications.end()); pthread_mutex_unlock(&ClassificationsMutex); } //--------------------------------------------------------------------------- void TNetworkDevice::ClearClassification() { pthread_mutex_lock(&ClassificationsMutex); Classifications.clear(); pthread_mutex_unlock(&ClassificationsMutex); } //--------------------------------------------------------------------------- TClassification TNetworkDevice::GetClassification(int Index) { TClassification C; pthread_mutex_lock(&ClassificationsMutex); if ((unsigned int)Index < Classifications.size()) { C = Classifications[Index]; } pthread_mutex_unlock(&ClassificationsMutex); return C; } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(string Characteristic, TMultiTypeMapValue Value) { TMultiTypeMap::iterator CurrPair; pthread_mutex_lock(&EvidenceMutex); /* * For some characteristics we can have multiple values. However, we don't * want duplicate values. The following ones fall into this category. */ if (Characteristic == CT_TCP_PORT || Characteristic == CT_UDP_PORT || Characteristic == CT_IP_PROTOCOL || Characteristic == CT_PROBE || Characteristic == CT_CONNECTED_SWITCH || Characteristic == CT_ATTRIBUTE || Characteristic == CT_SCANSTATUS || Characteristic == CT_DISCOVERY_PROTO || Characteristic == CT_WMI_DATA) { /* * Check for duplicates and delete them if they exist. */ for (CurrPair = EvidenceMap.lower_bound(Characteristic); CurrPair != EvidenceMap.upper_bound(Characteristic); CurrPair++) { if (Value == CurrPair->second) { /* * We have found a duplicate. Delete it. We assume the newer data is * more up to date. */ EvidenceMap.erase(CurrPair); break; } } } else { /* * Erase the current value, since this characteristic only allows a single value. */ if (EvidenceMap.count(Characteristic) > 0) { EvidenceMap.erase(Characteristic); } } /* * Create the new characteristic. */ EvidenceMap.insert(TMapPair(Characteristic, Value)); pthread_mutex_unlock(&EvidenceMutex); UpdateLastSeen(); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(string Characteristic, int Value) { AddEvidence(Characteristic, TMultiTypeMapValue(Value)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(string Characteristic, string Value) { AddEvidence(Characteristic, TMultiTypeMapValue(Value)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(TProbeData &ProbeResponse) { AddEvidence(CT_PROBE, TMultiTypeMapValue(ProbeResponse)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(TSwitchData &SwitchData) { AddEvidence(CT_CONNECTED_SWITCH, TMultiTypeMapValue(SwitchData)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(TAttributeData &AttributeData) { AddEvidence(CT_ATTRIBUTE, TMultiTypeMapValue(AttributeData)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(TScanStatus &ScanStatus) { TAttributeData AttributeData(ScanStatus.TypeString, ScanStatus.Completed); AddEvidence(CT_SCANSTATUS, TMultiTypeMapValue(AttributeData)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(TDHCPData &DHCPData) { AddEvidence(CT_DHCP, TMultiTypeMapValue(DHCPData)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(TDiscoveryProtoData &DscProtoData) { AddEvidence(CT_DISCOVERY_PROTO, TMultiTypeMapValue(DscProtoData)); } //--------------------------------------------------------------------------- void TNetworkDevice::AddEvidence(TWmiData &WmiData) { AddEvidence(CT_WMI_DATA, TMultiTypeMapValue(WmiData)); } //--------------------------------------------------------------------------- string TNetworkDevice::PrimaryClass() { if (Classifications.size() > 0) { TClassification C = Classifications.front(); return C.GetValue(CR_CLASS); } else { return ""; } } //--------------------------------------------------------------------------- bool TNetworkDevice::NeedsRescan(void) { time_t Now = time(NULL); /* * If the device hasn't been probed since the most recent network scan, then * this will tell the AnalysisManager that it needs to be probed. * * 60 seconds is taken off of SCANNETWORK_INTERVAL here, so that we avoid the * race where NeedsRescan is called at the same second that the network scan * is launched. Otherwise the first IPs that are picked up by the network scan * may be missed. */ if ((Now - LastProbed) >= (_GlobalConfig.GetScanNetworkInterval() - 60)) { return true; } return false; } //--------------------------------------------------------------------------- void TNetworkDevice::SetStatusCheck(bool B) { StatusPending = B; if (B) { StatusTimestamp = time(NULL); } else { StatusTimestamp = 0; } } //--------------------------------------------------------------------------- bool TNetworkDevice::StatusCheckExpired(void) { time_t Now = time(NULL); return (Now - StatusTimestamp) >= REACHABILITY_TIMEOUT; } //--------------------------------------------------------------------------- TTreeBuilder TNetworkDevice::ToMergeTree(void) { TTreeBuilder Tree; list Conditions; if (GetMacAddress().Valid()) { Conditions.push_back("interface/mac_address = '" + GetMacAddress().Print() + "'"); } if (GetIPAddress().Valid()) { Conditions.push_back("interface/inet/ip_address = '" + GetIPAddress().Print() + "'"); } Tree.StartTree("network"); Tree.StartTree("device", JoinStrings(" or ", Conditions)); //Tree.AddValue("last_seen", PrintLastSeen()); TreeAddInterface(&Tree); TreeAddSystem(&Tree); TreeAddEvidence(&Tree); Tree.EndTree(); // device Tree.EndTree(); // network return Tree; } //--------------------------------------------------------------------------- TTreeBuilder TNetworkDevice::LastSeenTree(void) { TTreeBuilder Tree; list Conditions; if (GetMacAddress().Valid()) { Conditions.push_back("interface/mac_address = '" + GetMacAddress().Print() + "'"); } if (GetIPAddress().Valid()) { Conditions.push_back("interface/inet/ip_address = '" + GetIPAddress().Print() + "'"); } Tree.StartTree("network"); Tree.StartTree("device", JoinStrings(" or ", Conditions)); TreeAddInterface(&Tree); Tree.AddValue("last_seen", PrintLastSeen()); Tree.EndTree(); // device Tree.EndTree(); // network return Tree; } //--------------------------------------------------------------------------- string TNetworkDevice::PrintLastSeen(void) { char TimeStamp[29]; struct tm TmLastSeen; gmtime_r(&LastSeen, &TmLastSeen); strftime(TimeStamp, 29, "%Y-%m-%dT%H:%M:%S.0000000Z", &TmLastSeen); TimeStamp[28] = '\0'; return string(TimeStamp); } //--------------------------------------------------------------------------- void TNetworkDevice::TreeAddInterface(TTreeBuilder *Tree) { list Conditions; if (GetMacAddress().Valid()) { Conditions.push_back("mac_address = '" + GetMacAddress().Print() + "'"); } if (GetIPAddress().Valid()) { Conditions.push_back("inet/ip_address = '" + GetIPAddress().Print() + "'"); } Tree->StartTree("interface", JoinStrings(" or ", Conditions)); if (GetMacAddress().Valid()) { Tree->AddValue("mac_address", GetMacAddress().Print()); } if (GetIPAddress().Valid()) { Tree->StartTree("inet", "ip_address = '" + GetIPAddress().Print() + "'"); Tree->AddValue("ip_address", GetIPAddress().Print()); Tree->EndTree(); // inet } Tree->EndTree(); // interface } //--------------------------------------------------------------------------- void TNetworkDevice::TreeAddSystem(TTreeBuilder *Tree) { Tree->StartTree("system"); TMultiTypeMap::iterator MapEntry = EvidenceMap.find(CT_DNS_NAME); if (MapEntry != EvidenceMap.end()) { if (MapEntry->second.MapValue.Str) { Tree->AddValue("dns_name", *MapEntry->second.MapValue.Str); } } MapEntry = EvidenceMap.find(CT_NETBIOS_NAME); if (MapEntry != EvidenceMap.end()) { if (MapEntry->second.MapValue.Str) { Tree->AddValue("netbios_name", *MapEntry->second.MapValue.Str); } } for (TMultiTypeMap::iterator CurrAttr = EvidenceMap.lower_bound(CT_ATTRIBUTE); CurrAttr != EvidenceMap.upper_bound(CT_ATTRIBUTE); CurrAttr++) { Tree->AddValue(CurrAttr->second.MapValue.AttributeData->Attribute, CurrAttr->second.MapValue.AttributeData->Value ? "true" : "false"); } Tree->EndTree(); // system } //--------------------------------------------------------------------------- static void AddParam(TTreeBuilder *Tree, string Name, string Value) { Tree->StartTree("param"); Tree->AddValue(Name, Value); Tree->EndTree(); // param } //--------------------------------------------------------------------------- static void AddValue(TTreeBuilder *Tree, string Name, string Value) { Tree->StartTree("value"); Tree->AddValue(Name, Value); Tree->EndTree(); // value } //--------------------------------------------------------------------------- void TNetworkDevice::TreeAddEvidence(TTreeBuilder *Tree) { /* * We erase and replace the entire evidence each time it is submitted so * we track ports which are closed. * * To support history on evidence we will need to add sub-tree history to * PQL. */ Tree->StartTree("evidence", ""); /* * Add the evidence. */ TMultiTypeMap Evidence = StartDumpEvidence(); try { for (TMultiTypeMap::iterator MapIterator = Evidence.begin(); MapIterator != Evidence.end(); MapIterator++) { string Characteristic = (*MapIterator).first; TMultiTypeMapValue Value = (*MapIterator).second; Tree->StartTree(Characteristic, "false"); if (Characteristic == CT_TCP_PORT || Characteristic == CT_UDP_PORT) { AddParam(Tree, PT_PORT, Int2String(Value.MapValue.IntVal)); AddValue(Tree, RT_VALUE, RV_OPEN); } else if (Characteristic == CT_IP_PROTOCOL) { AddParam(Tree, PT_PROTOCOL, Int2String(Value.MapValue.IntVal)); AddValue(Tree, RT_VALUE, RV_OPEN); } else if (Characteristic == CT_PROBE) { TProbeData *PD = Value.MapValue.ProbeData; AddParam(Tree, PT_TECHNIQUE, PD->Technique); AddParam(Tree, PT_PORT, Int2String(PD->Port)); AddParam(Tree, PT_REQUEST_LABEL, PD->Label); AddParam(Tree, PT_REQUEST, PD->Request); AddValue(Tree, RT_RESPONSE, PD->Response); } else if (Characteristic == CT_CONNECTED_SWITCH) { TSwitchData *SD = Value.MapValue.SwitchData; AddParam(Tree, PT_SWITCH_NAME, SD->Name); AddParam(Tree, PT_SWITCH_IP_ADDRESS, SD->IPAddress); AddParam(Tree, PT_SWITCH_PORT, SD->Port); AddParam(Tree, PT_SWITCH_VLAN, Int2String(SD->VLAN)); } else if (Characteristic == CT_ATTRIBUTE) { TAttributeData *AD = Value.MapValue.AttributeData; AddParam(Tree, PT_ATTRIBUTE, AD->Attribute); AddValue(Tree, RT_VALUE, AD->Value?RV_TRUE:RV_FALSE); } else if (Characteristic == CT_DHCP) { TDHCPData *DD = Value.MapValue.DHCPData; AddValue(Tree, RT_VENDOR_CLASS, DD->VendorClass); AddValue(Tree, RT_HOST_NAME, DD->HostName); AddValue(Tree, RT_PARAM_REQUEST_LIST, DD->ParamRequestList); } else if (Characteristic == CT_SCANSTATUS) { TAttributeData *AD = Value.MapValue.AttributeData; AddParam(Tree, PT_SCAN, AD->Attribute); AddValue(Tree, RT_VALUE, AD->Value ? "completed" : "pending"); } else if (Characteristic == CT_DISCOVERY_PROTO) { TDiscoveryProtoData *DscProtoData = Value.MapValue.DscProtoData; AddValue(Tree, RT_DEVICE_ID, DscProtoData->DeviceId); AddValue(Tree, RT_VER, DscProtoData->Version); AddValue(Tree, RT_PLATFORM, DscProtoData->Platform); AddValue(Tree, RT_LOCAL_PORT, DscProtoData->LocalPort); AddValue(Tree, RT_REMOTE_PORT, DscProtoData->RemotePort); AddValue(Tree, RT_REMOTE_VLAN, Int2String(DscProtoData->RemoteVlan)); AddValue(Tree, RT_CAPABILITIES, DscProtoData->Capabilities); } else if (Characteristic == CT_WMI_DATA) { TWmiData *WmiData = Value.MapValue.WmiData; AddParam(Tree, PT_WMI_NAMESPACE, WmiData->Namespace); AddParam(Tree, PT_WMI_QUERY, WmiData->Query); AddValue(Tree, RT_WMI_RESULT, WmiData->Result); } else { switch (Value.ValueType) { case TYPE_IPADDRESS: AddValue(Tree, RT_VALUE, Value.MapValue.IPAddr->Print()); break; case TYPE_MACADDRESS: AddValue(Tree, RT_VALUE, Value.MapValue.MacAddr->Print()); break; case TYPE_STRING: AddValue(Tree, RT_VALUE, *Value.MapValue.Str); break; case TYPE_INTEGER: AddValue(Tree, RT_VALUE, Int2String(Value.MapValue.IntVal)); break; case TYPE_BOOL: AddValue(Tree, RT_VALUE, Value.MapValue.BoolVal?RV_TRUE:RV_FALSE); break; default: LogError("Unhandled characteristic: %s\n", Characteristic.c_str()); } } Tree->EndTree(); // %characteristic% } EndDumpEvidence(); } catch (exception &E) { EndDumpEvidence(); throw E; } Tree->EndTree(); // evidence } //--------------------------------------------------------------------------- string PrintMultiTypeMap(TMultiTypeMap &MTMap) { string MapString = ""; string LastKey; TMultiTypeMap::iterator MapIterator; bool First = true; /* * Go through the map. */ for (MapIterator = MTMap.begin(); MapIterator != MTMap.end(); MapIterator++) { /* * Check to see if the key changed. Start a newline if it has. */ if (LastKey != (*MapIterator).first) { LastKey = (*MapIterator).first; if (!First) { MapString += "\n"; } First = false; MapString += " " + LastKey; MapString += " = "; MapString += (*MapIterator).second.Print(); } else { MapString += ", "; MapString += (*MapIterator).second.Print(); } } return MapString; } //--------------------------------------------------------------------------- string TClassification::GetValue(string Key) { return Values[Key]; } //--------------------------------------------------------------------------- void TClassification::AddValue(string Key, string Value) { Values[Key] = Value; } //---------------------------------------------------------------------------