/* * 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 #include "AgentConfig.h" #include "ScanData.h" #include "Probes.h" #include #ifdef WIN32 #include #include #include #include #include #else #include #include #include #include #include #include #include #include #endif #include #include "Debug.h" #include #include using namespace std; //--------------------------------------------------------------------------- // TODO: review this module to ensure everything is exception safe. /* * Global configuration read from command line or configuration file. */ TAgentConfig _GlobalConfig; pthread_mutex_t _PcapMutex = PTHREAD_MUTEX_INITIALIZER; //--------------------------------------------------------------------------- TConfigParam::TConfigParam(std::string ParamValue) : ParamValue(ParamValue) { /* * Parse the string into a series of comma separated fields. We need to * handle fields which are quoted because they contain commas. */ std::string CurrentField = ""; bool InString = false; bool Escaping = false; for (unsigned int i = 0; i < ParamValue.length(); i++) { if (Escaping) { CurrentField += ParamValue[i]; Escaping = false; } else { switch (ParamValue[i]) { case '"': InString = !InString; break; case '\\': Escaping = true; break; case ',': if (!InString) { ParamFields.push_back(CurrentField); CurrentField = ""; break; } /* Intentionally drop through. */ default: CurrentField += ParamValue[i]; } } } if (!CurrentField.empty()) { ParamFields.push_back(CurrentField); } } //--------------------------------------------------------------------------- std::string TConfigParam::Field(int Index) { if (Index < (int)ParamFields.size()) { string S = ParamFields[Index]; if (S.substr(0, strlen(ENCRYPTED_MAGIC)) == ENCRYPTED_MAGIC) { string S2 = S.substr(11); return DecryptAESwithSalt(_GlobalConfig.CredentialKey, S2); } return ParamFields[Index]; } else { return ""; } } //--------------------------------------------------------------------------- std::string TConfigParam::Escape(std::string Raw) { bool NeedsQuoting = false; std::string Output = ""; for (unsigned int i = 0; i < Raw.length(); i++) { if (Raw[i] == ',') { NeedsQuoting = true; } if (Raw[i] == '\\' || Raw[i] == '\"' || Raw[i] == ',') { Output += '\\'; } Output += Raw[i]; } if (NeedsQuoting) { Output = "\"" + Output + "\""; } return Output; } //--------------------------------------------------------------------------- /* * Look for the pcap_if_t structure corresponding to Name. If it exists and * it has a valid IP address associated with it, then return it. * Otherwise return NULL. */ pcap_if_t *FindPcapIface(pcap_if_t *DevList, string &Name) { pcap_if_t *Dev; for (Dev = DevList; Dev; Dev = Dev->next) { if (strcmp(Dev->name, Name.c_str()) == 0) { if (HasLink(Dev->name)) { for (pcap_addr_t *CurrAddr = Dev->addresses; CurrAddr; CurrAddr = CurrAddr->next) { if (CurrAddr->addr && CurrAddr->netmask) { if (CurrAddr->addr->sa_family == AF_INET && ((struct sockaddr_in *)CurrAddr->addr)->sin_addr.s_addr != 0) { return Dev; } } } } } } return NULL; } //--------------------------------------------------------------------------- int CountPcapAddresses(pcap_if_t *Dev) { int Count = 0; if (Dev) { for (pcap_addr_t *CurrAddr = Dev->addresses; CurrAddr; CurrAddr = CurrAddr->next) { if (CurrAddr->addr && CurrAddr->netmask) { if (CurrAddr->addr->sa_family == AF_INET && ((struct sockaddr_in *)CurrAddr->addr)->sin_addr.s_addr != 0) { Count++; } } } } return Count; } //--------------------------------------------------------------------------- pcap_if_t *FindFirstPcapIface(pcap_if_t *DevList) { pcap_if_t *Dev; for (Dev = DevList; Dev; Dev = Dev->next) { if (HasLink(Dev->name)) { for (pcap_addr_t *CurrAddr = Dev->addresses; CurrAddr; CurrAddr = CurrAddr->next) { if (CurrAddr->addr && CurrAddr->netmask) { if (CurrAddr->addr->sa_family == AF_INET && ((struct sockaddr_in *)CurrAddr->addr)->sin_addr.s_addr != 0) { return Dev; } } } } } return NULL; } //--------------------------------------------------------------------------- int CountPcapIfaces(pcap_if_t *DevList) { int Count = 0; pcap_if_t *Dev; for (Dev = DevList; Dev; Dev = Dev->next) { if (HasLink(Dev->name)) { for (pcap_addr_t *CurrAddr = Dev->addresses; CurrAddr; CurrAddr = CurrAddr->next) { if (CurrAddr->addr && CurrAddr->netmask) { if (CurrAddr->addr->sa_family == AF_INET && ((struct sockaddr_in *)CurrAddr->addr)->sin_addr.s_addr != 0) { Count++; } } } } } return Count; } //--------------------------------------------------------------------------- void TNetworkAdapter::Refresh(void) { time_t Now = time(NULL); if (Now > (LastRefreshed + ADAPTER_INFO_REFRESH)) { pcap_if_t *DevList, *Dev; pcap_addr_t *Addr; char ErrBuf[PCAP_ERRBUF_SIZE]; /* * Get list of network adapters and look for * the selected device. */ pthread_mutex_lock(&_PcapMutex); if (pcap_findalldevs(&DevList, ErrBuf) < 0) { string Msg = "Unable to get list of network adapters: "; Msg += ErrBuf; throw runtime_error(Msg); } for (Dev = DevList; Dev; Dev = Dev->next) { if (strcmp(Dev->name, this->Name.c_str()) == 0) { /* * Get the appropriate pcap_addr_t structure. */ if ((Addr = FindAddress(Dev->addresses)) != 0) { /* * Set the cached addresses. */ this->CachedIPAddress = TIPAddress(Addr->addr); this->CachedNetmask = TIPAddress(Addr->netmask); this->CachedNetwork = TIPAddress(this->CachedIPAddress.IPv4Value() & this->CachedNetmask.IPv4Value()); #ifdef WIN32 this->CachedBroadcast = TIPAddress(this->CachedIPAddress.IPv4Value() | ~this->CachedNetmask.IPv4Value()); #else if (Addr->broadaddr) { this->CachedBroadcast = TIPAddress(Addr->broadaddr); } else { this->CachedBroadcast = TIPAddress(this->CachedIPAddress.IPv4Value() | ~this->CachedNetmask.IPv4Value()); } #endif } else { string Msg = "Unable to find appropriate address info for interface: "; Msg += this->Name; throw runtime_error(Msg); } } } pcap_freealldevs(DevList); LastRefreshed = Now; pthread_mutex_unlock(&_PcapMutex); } /* Don't reload the MAC address since we assume it can't change. */ } //--------------------------------------------------------------------------- bool HasLink(string Name) { #ifdef WIN32 LPADAPTER AdapterHandle; PPACKET_OID_DATA OidData; bool HasLink = false; if ((AdapterHandle = PacketOpenAdapter((char *)Name.c_str()))) { if ((OidData = (PPACKET_OID_DATA)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(PACKET_OID_DATA) + sizeof(unsigned long) - 1))) { OidData->Oid = OID_GEN_MEDIA_CONNECT_STATUS; OidData->Length = sizeof(unsigned long); if (PacketRequest(AdapterHandle, FALSE, OidData)) { int LinkStatus = *((unsigned int *)OidData->Data); if (LinkStatus == NdisMediaStateConnected) { HasLink = true; } } GlobalFreePtr(OidData); } PacketCloseAdapter(AdapterHandle); } return HasLink; #else int Sock; struct ifreq InterfaceData; Sock = socket(AF_INET, SOCK_DGRAM, 0); memset(&InterfaceData, 0x00, sizeof(InterfaceData)); strncpy(InterfaceData.ifr_name, Name.c_str(), IFNAMSIZ); InterfaceData.ifr_name[IFNAMSIZ - 1] = '\0'; ioctl(Sock, SIOCGIFFLAGS, &InterfaceData); CloseSocket(Sock); return InterfaceData.ifr_flags & IFF_RUNNING; #endif } //--------------------------------------------------------------------------- pcap_addr_t *TNetworkAdapter::FindAddress(pcap_addr_t *AddrList) { pcap_addr_t *CurrAddr, *Addr = NULL; /* * If we were constructed with an IP address and netmask, the iterate through the device's list of addresses * and look for the IP/netmask we were constructed with and return it if found. * * Otherwise, just return the first pcap_addr_t structure that has a valid IP address. */ if (this->IPAddress.Valid() && this->Netmask.Valid()) { for (CurrAddr = AddrList; CurrAddr; CurrAddr = CurrAddr->next) { if (CurrAddr->addr && CurrAddr->netmask) { if (CurrAddr->addr->sa_family == AF_INET && ((struct sockaddr_in *)CurrAddr->addr)->sin_addr.s_addr != 0) { TIPAddress IP = TIPAddress(CurrAddr->addr); TIPAddress Mask = TIPAddress(CurrAddr->netmask); if (this->IPAddress == IP && this->Netmask == Mask) { Addr = CurrAddr; break; } } } } } else { for (CurrAddr = AddrList; CurrAddr; CurrAddr = CurrAddr->next) { if (CurrAddr->addr && CurrAddr->netmask) { if (CurrAddr->addr->sa_family == AF_INET && ((struct sockaddr_in *)CurrAddr->addr)->sin_addr.s_addr != 0) { Addr = CurrAddr; break; } } } } return Addr; } //--------------------------------------------------------------------------- TNetworkAdapter::TNetworkAdapter(void) { pcap_if_t *DevList, *Dev; char *DevName, ErrBuf[PCAP_ERRBUF_SIZE]; bool FoundDev = false; #ifdef WIN32 unsigned long LinkType, PhyType; LPADAPTER AdapterHandle; PPACKET_OID_DATA OidData; if (pcap_findalldevs(&DevList, ErrBuf) < 0) { string Msg = "Unable to get list of network adapters: "; Msg += ErrBuf; throw runtime_error(Msg); } else { for (Dev = DevList; Dev; Dev = Dev->next) { LinkType = NdisMediumMax; PhyType = NdisPhysicalMediumMax; if (strncmp(Dev->name, "\\Device\\NPF_{", 13) != 0 || strcmp(Dev->description, "VMware Virtual Ethernet Adapter") == 0) { continue; } /* * Open the adapter with Dev->name. Look up its link type and then close it. * If the link type is ethernet then we'll set our scanning and management * interface name strings to Dev->name. */ if ((AdapterHandle = PacketOpenAdapter(Dev->name)) != NULL) { if ((OidData = (PPACKET_OID_DATA)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(PACKET_OID_DATA) + sizeof(unsigned long) - 1)) != NULL) { OidData->Oid = OID_GEN_MEDIA_IN_USE; OidData->Length = sizeof(unsigned long); if (PacketRequest(AdapterHandle, FALSE, OidData)) { LinkType = *((unsigned int *)OidData->Data); if (LinkType == NdisMedium802_3) { memset(OidData, 0x00, sizeof(PACKET_OID_DATA) + sizeof(unsigned long) - 1); OidData->Oid = OID_GEN_PHYSICAL_MEDIUM; OidData->Length = sizeof(unsigned long); /* * It seems this branch is never taken for ethernet interfaces. * We can check later if PhyType is still set to NdisPhysicalMediumMax. */ if (PacketRequest(AdapterHandle, FALSE, OidData)) { PhyType = *((unsigned int *)OidData->Data); } } } /* * If this is true, then we have an ethernet interface. * Now see if it has an IP address set. */ if (PhyType == NdisPhysicalMediumMax) { if (FindAddress(Dev->addresses)) { Name = Dev->name; FoundDev = true; } } GlobalFreePtr(OidData); } PacketCloseAdapter(AdapterHandle); } } pcap_freealldevs(DevList); } #else if ((DevName = pcap_lookupdev(ErrBuf)) != 0) { Name = DevName; FoundDev = true; } #endif if (!FoundDev) { string Msg = "Unable to find a suitable network device: "; Msg += ErrBuf; throw runtime_error(ErrBuf); } /* * Find and cache our MAC address. */ LocalMacAddress(Name, CachedMacAddress); this->LastRefreshed = 0; this->Refresh(); if (!HasLink(this->Name)) { string Msg = this->Name; Msg += " does not have link."; throw runtime_error(Msg); } } //--------------------------------------------------------------------------- TNetworkAdapter::TNetworkAdapter(string &InterfaceName) { pcap_if_t *DevList, *Dev; pcap_addr_t *Addr; char ErrBuf[PCAP_ERRBUF_SIZE]; bool FoundDev = false; /* * Get list of network adapters and look for * the selected device. */ if (pcap_findalldevs(&DevList, ErrBuf) < 0) { string Msg = "Unable to get list of network adapters: "; Msg += ErrBuf; throw runtime_error(Msg); } for (Dev = DevList; Dev; Dev = Dev->next) { if (strcmp(Dev->name, InterfaceName.c_str()) == 0) { /* * Now make sure it has at least one valid IP address. */ if (FindAddress(Dev->addresses)) { Name = InterfaceName; FoundDev = true; break; } } } pcap_freealldevs(DevList); if (!FoundDev) { string Msg = "Unable to find the specified interface: "; Msg += InterfaceName; throw runtime_error(Msg); } /* * Find and cache our MAC address. */ LocalMacAddress(InterfaceName, CachedMacAddress); this->LastRefreshed = 0; this->Refresh(); if (!HasLink(this->Name)) { string Msg = this->Name; Msg += " does not have link."; throw runtime_error(Msg); } } //--------------------------------------------------------------------------- TNetworkAdapter::TNetworkAdapter(string &InterfaceName, TIPAddress &IP, TIPAddress &Mask) { pcap_if_t *DevList, *Dev; pcap_addr_t *Addr; char ErrBuf[PCAP_ERRBUF_SIZE]; bool FoundDev = false; /* * Get list of network adapters and look for * the selected device. */ if (pcap_findalldevs(&DevList, ErrBuf) < 0) { string Msg = "Unable to get list of network adapters: "; Msg += ErrBuf; throw runtime_error(Msg); } for (Dev = DevList; Dev; Dev = Dev->next) { if (strcmp(Dev->name, InterfaceName.c_str()) == 0) { /* * Now make sure it has the IP/netmask that was specified. */ this->IPAddress = IP; this->Netmask = Mask; if ((Addr = FindAddress(Dev->addresses)) != NULL) { TIPAddress TmpIP(IPAddress.IPv4Value() & Netmask.IPv4Value()); this->CachedNetwork = TmpIP; /* * For WIN32 we compute the adapter's broadcast address, because * this will often be set to 255.255.255.255. */ #ifdef WIN32 this->CachedBroadcast = TIPAddress(this->IPAddress.IPv4Value() | ~this->Netmask.IPv4Value()); #else if (Addr->broadaddr) { this->CachedBroadcast = TIPAddress(Addr->broadaddr); } else { this->CachedBroadcast = TIPAddress(this->IPAddress.IPv4Value() | ~this->Netmask.IPv4Value()); } #endif this->Name = InterfaceName; FoundDev = true; } else { pcap_freealldevs(DevList); string Msg = InterfaceName; Msg += " is not configured with the specified IP/Netmask ("; Msg += IP.Print(); Msg += "/"; Msg += Mask.Print(); Msg += ")."; throw runtime_error(Msg); } } } pcap_freealldevs(DevList); if (!FoundDev) { string Msg = "Unable to find the specified interface: "; Msg += InterfaceName; throw runtime_error(Msg); } /* * Find and cache our MAC address. */ LocalMacAddress(InterfaceName, CachedMacAddress); this->LastRefreshed = 0; this->Refresh(); if (!HasLink(this->Name)) { string Msg = this->Name; Msg += " does not have link."; throw runtime_error(Msg); } } //--------------------------------------------------------------------------- TNetworkAdapter::TNetworkAdapter(TNetworkAdapter const &Adapter) { this->Name = Adapter.Name; this->IPAddress = Adapter.IPAddress; this->Netmask = Adapter.Netmask; this->CachedIPAddress = Adapter.CachedIPAddress; this->CachedNetmask = Adapter.CachedNetmask; this->CachedBroadcast = Adapter.CachedBroadcast; this->CachedNetwork = Adapter.CachedNetwork; this->CachedMacAddress = Adapter.CachedMacAddress; this->LastRefreshed = Adapter.LastRefreshed; } //--------------------------------------------------------------------------- TIPAddress TNetworkAdapter::GetIPAddress(void) { if (this->CachedIPAddress.Valid()) { return this->CachedIPAddress; } string Msg = "No IP address found for interface: "; Msg += this->Name; throw runtime_error(Msg); } //--------------------------------------------------------------------------- TIPAddress TNetworkAdapter::GetNetmask(void) { if (this->CachedNetmask.Valid()) { return this->CachedNetmask; } string Msg = "No netmask found for interface: "; Msg += this->Name; throw runtime_error(Msg); } //--------------------------------------------------------------------------- TIPAddress TNetworkAdapter::GetNetwork(void) { if (this->CachedNetwork.Valid()) { return this->CachedNetwork; } string Msg = "No network address found for interface: "; Msg += this->Name; throw runtime_error(Msg); } //--------------------------------------------------------------------------- TIPAddress TNetworkAdapter::GetBroadcast(void) { if (this->CachedBroadcast.Valid()) { return this->CachedBroadcast; } string Msg = "No broadcast address found for interface: "; Msg += this->Name; throw runtime_error(Msg); } //--------------------------------------------------------------------------- TMacAddress TNetworkAdapter::GetMacAddress(void) { if (this->CachedMacAddress.Valid()) { return this->CachedMacAddress; } string Msg = "No MAC address found for interface: "; Msg += this->Name; throw runtime_error(Msg); } //--------------------------------------------------------------------------- TAgentConfig::TAgentConfig(void) { /* * Set the defaults. */ LogFile = DEFAULT_LOG_FILE; PidFilename = DEFAULT_PID_FILE; NumScanThreads = DEFAULT_SCAN_THREADS; BandwidthLim = DEFAULT_BANDWIDTH_LIMIT; DebugLevel = 0; EnableCLI = DEFAULT_CLI_ENABLED; EnablePromisc = true; Enabled = false; Interface = NULL; pthread_mutex_init(&InterfaceMutex, NULL); ScanLocalSubnet = true; ProxyPort = -1; TestMode = false; UseSSL = true; PollingInterval = DEFAULT_POLLING_INTERVAL; srand(time(NULL)); ScanNetworkInterval = DEFAULT_SCANNETWORK_INTERVAL - (60 * 60) + (rand() % (2 * 60 * 60 + 1)); #ifndef ROGUESCANNER Server = DEFAULT_SERVER; ServerPort = DEFAULT_SERVER_PORT; #ifdef WIN32 char PathBuffer[MAXPATH]; if (IsDebuggerPresent()) { /* * If we are running in the IDE switch to the main Crawler directory * so the ruby paths work. */ chdir(".."); } PluginDir = getcwd(PathBuffer, MAXPATH); #else PluginDir = DEFAULT_PLUGIN_DIR; #endif #endif InitialScanThreads = NumScanThreads; #ifdef WIN32 #if 0 char KeyPath[MAX_PATH]; SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, KeyPath); string KeyFilename = string(KeyPath) + "\\" + "paglo_crawler.key"; char KeyBuf[1024]; FILE *KeyFile; if ((KeyFile = fopen(KeyFilename.c_str(), "r"))) { fgets(KeyBuf, 1024, KeyFile); KeyBuf[strlen(KeyBuf) - 1] = '\0'; CredentialKey = KeyBuf; } #endif #endif } //--------------------------------------------------------------------------- TAgentConfig::TAgentConfig(TAgentConfig const &Config) { ScanLocalSubnet = Config.ScanLocalSubnet; TestMode = Config.TestMode; Enabled = Config.Enabled; if (Interface) { Interface = new TNetworkAdapter(*Config.Interface); } InterfaceIPAddress = Config.InterfaceIPAddress; InterfaceNetmask = Config.InterfaceNetmask; ConfigFile = Config.ConfigFile; LogFile = Config.LogFile; PidFilename = Config.PidFilename; NumScanThreads = Config.NumScanThreads; DebugLevel = Config.DebugLevel; EnableCLI = Config.EnableCLI; EnablePromisc = Config.EnablePromisc; BandwidthLim = Config.BandwidthLim; HomeNets = Config.HomeNets; SwitchDirs = Config.SwitchDirs; IgnoreBlocks = Config.IgnoreBlocks; IgnoreMacs = Config.IgnoreMacs; ProxyHost = Config.ProxyHost; ProxyPort = Config.ProxyPort; ProxyUserID = Config.ProxyUserID; ProxyPasswd = Config.ProxyPasswd; Server = Config.Server; ServerPort = Config.ServerPort; UseSSL = Config.UseSSL; Iface = Config.Iface; IfaceAddress = Config.IfaceAddress; IfaceNetmask = Config.IfaceNetmask; PollingInterval = Config.PollingInterval; ScanNetworkInterval = Config.ScanNetworkInterval; ConfigMap = Config.ConfigMap; CredentialKey = Config.CredentialKey; } //--------------------------------------------------------------------------- void TAgentConfig::operator =(TAgentConfig const &Config) { ScanLocalSubnet = Config.ScanLocalSubnet; TestMode = Config.TestMode; Enabled = Config.Enabled; if (Interface) { Interface = new TNetworkAdapter(*Config.Interface); } InterfaceIPAddress = Config.InterfaceIPAddress; InterfaceNetmask = Config.InterfaceNetmask; ConfigFile = Config.ConfigFile; LogFile = Config.LogFile; PidFilename = Config.PidFilename; NumScanThreads = Config.NumScanThreads; DebugLevel = Config.DebugLevel; EnableCLI = Config.EnableCLI; EnablePromisc = Config.EnablePromisc; BandwidthLim = Config.BandwidthLim; HomeNets = Config.HomeNets; SwitchDirs = Config.SwitchDirs; IgnoreBlocks = Config.IgnoreBlocks; IgnoreMacs = Config.IgnoreMacs; ProxyHost = Config.ProxyHost; ProxyPort = Config.ProxyPort; ProxyUserID = Config.ProxyUserID; ProxyPasswd = Config.ProxyPasswd; Server = Config.Server; ServerPort = Config.ServerPort; UseSSL = Config.UseSSL; Iface = Config.Iface; IfaceAddress = Config.IfaceAddress; IfaceNetmask = Config.IfaceNetmask; PollingInterval = Config.PollingInterval; ScanNetworkInterval = Config.ScanNetworkInterval; ConfigMap = Config.ConfigMap; CredentialKey = Config.CredentialKey; } //--------------------------------------------------------------------------- TAgentConfig::~TAgentConfig(void) { if (Interface) { delete Interface; } } //--------------------------------------------------------------------------- void TAgentConfig::ParseConfig(string Filename) { FILE *FileHandle = NULL; string Line = ""; ConfigFile = Filename; int CurrChar; if ((FileHandle = fopen(ConfigFile.c_str(), "r")) == 0) { LogMesg("Configuration file could not be found."); string ErrMsg = "Couldn't open configuration file: "; ErrMsg += ConfigFile; throw runtime_error(ErrMsg); } #ifndef HAVE_GUI fprintf(stderr, "Parsing configuration from %s.\n", ConfigFile.c_str()); #endif #ifdef WIN32 char KeyPath[MAX_PATH]; SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, KeyPath); string KeyFilename = string(KeyPath) + "\\" + "paglo_crawler.key"; char KeyBuf[1024]; FILE *KeyFile; if ((KeyFile = fopen(KeyFilename.c_str(), "r"))) { fgets(KeyBuf, 1024, KeyFile); KeyBuf[strlen(KeyBuf) - 1] = '\0'; CredentialKey = KeyBuf; } else if (KeyFile = fopen(KeyFilename.c_str(), "w")) { string S = GenerateAESKey(); fprintf(KeyFile, "%s\n", S.c_str()); fclose(KeyFile); CredentialKey = S; } #endif /* * Delete anything that's currently in the list (i.e., the default entry). * If it's still empty after parsing the config file, then we'll add * the scanning interface's network. */ ClearHomeNets(); do { CurrChar = fgetc(FileHandle); /* * If we've reached the end of the line, then parse it. */ if (CurrChar == '\n' || CurrChar == EOF) { if (Line.length() > 0) { /* * Skip comments and ini file section headers. */ if (Line.c_str()[0] != '#' && Line.c_str()[0] != '[') { ParseLine(Line); } Line = ""; } if (CurrChar != EOF) { continue; } } Line += CurrChar; } while (CurrChar != EOF); if (FileHandle) { fclose(FileHandle); } /* * Check to see if we need to setup any interface parameters. */ char ErrBuf[PCAP_ERRBUF_SIZE]; pcap_if_t *DevList; pcap_findalldevs(&DevList, ErrBuf); pcap_if_t *PcapIface = FindPcapIface(DevList, Iface); Interface = NULL; if (PcapIface) { /* * The selected interface is available. If a specific IP address * and netmask were selected by the user, then attempt to use it. */ if (IfaceAddress.Valid() && IfaceNetmask.Valid()) { fprintf(stderr, "Trying interface %s (%s, %s)\n", Iface.c_str(), IfaceAddress.Print().c_str(),IfaceNetmask.Print().c_str()); try { Interface = new TNetworkAdapter(Iface, IfaceAddress, IfaceNetmask); } catch (...) {} } if (!Interface) { /* * If there's more than one IP address, then tell the user they * need to select a specific one. Otherwise, use whatever IP * address the interface is configured with. */ if (CountPcapAddresses(PcapIface) > 1) { LogIssue(itNetworkAdapter, isError, "The IP address you selected is not available on the " "configured interface. Choose a different IP address in the " "Network Adapter settings on the Configure page."); } else { Interface = new TNetworkAdapter(Iface); } } } else if (CountPcapIfaces(DevList) == 1) { /* * The selected interface wasn't available, but there's only one * interface to choose from. First if we see if they've * configured an IP address for another interface. If it's * available on this one we use it. If it isn't, but there's only * one IP address, then we use that. Otherwise we tell the user * to reconfigure. */ PcapIface = FindFirstPcapIface(DevList); if (PcapIface) { try { string S = PcapIface->name; Interface = new TNetworkAdapter(S, IfaceAddress, IfaceNetmask); } catch (...) {} if (!Interface) { if (CountPcapAddresses(DevList) == 1) { string S = PcapIface->name; Interface = new TNetworkAdapter(S); } else { LogIssue(itNetworkAdapter, isError, "The adapter and IP address you selected are not available. " "Choose a different adapter in the Network Adapter settings on the Configure page."); } } } } else if (Iface.empty()) { LogIssue(itNetworkAdapter, isError, "More than one network adapter is available and one could not be auto-selected. " "Choose a different adapter in the Network Adapter settings on the Configure page."); } else { LogIssue(itNetworkAdapter, isError, "The adapter you selected is not available. " "Choose a different adapter in the Network Adapter settings on the Configure page."); } pcap_freealldevs(DevList); } //--------------------------------------------------------------------------- void TAgentConfig::SetInterface(TNetworkAdapter &Adapter) { pthread_mutex_lock(&InterfaceMutex); if (Interface) { delete Interface; } Interface = new TNetworkAdapter(Adapter); pthread_mutex_unlock(&InterfaceMutex); } //--------------------------------------------------------------------------- void TAgentConfig::ParseLine(string &Line) { char *BufPtr; DEBUG_MESSAGE(DEBUG_AGENTCONFIG, ("Parsing line: %s", Line.c_str())); unsigned int Index = Line.find('=', 0); if (Index != string::npos) { string Param = Line.substr(0, Index); string Value = Line.substr(Index + 1); if (Value.empty()) { return; } if (Param == "iface") { /* * Filter out the bogus device name that the Windows installer sets * when run in silet mode without specifying an adapter on the CLI. */ if (Value.substr(0, 14) != "\\Device\\NPF_") { Iface = Value; } ConfigMap.erase(Param); } else if (Param == "iface_address") { IfaceAddress = TIPAddress(Value); ConfigMap.erase(Param); } else if (Param == "iface_netmask") { IfaceNetmask = TIPAddress(Value); ConfigMap.erase(Param); } else if (Param == "home_net") { ParseHomeNets(Value); ConfigMap.erase(Param); } else if (Param == "logfile") { #ifndef HAVE_GUI fprintf(stderr, "Setting log file to %s.\n", Value.c_str()); #endif LogFile = Value; ConfigMap.erase(Param); } else if (Param == "pid_file") { PidFilename = Value; ConfigMap.erase(Param); } else if (Param == "switch_dir") { ParseSwitchDir(Value); ConfigMap.erase(Param); } else if (Param == "scan_threads") { char *EndPtr; int n = strtoul(Value.c_str(), &EndPtr, 10); if (*EndPtr == '\0') { #ifndef HAVE_GUI fprintf(stderr, "Setting number of scan threads to %s.\n", Value.c_str()); #endif NumScanThreads = n; } else { throw runtime_error("Value for scan threads should be a number."); } ConfigMap.erase(Param); } else if (Param == "debug") { char *EndPtr; unsigned long n; if (Value.substr(0, 2) == "0x") { n = strtoul(Value.c_str() + 2, &EndPtr, 16); } else { n = strtoul(Value.c_str(), &EndPtr, 10); } if (*EndPtr == '\0') { DebugLevel = n; #ifndef HAVE_GUI fprintf(stderr, "Setting debug level to 0x%08lX.\n", n); #endif } else { throw runtime_error("Value for debug should be a number."); } ConfigMap.erase(Param); } else if (Param == "enable_cli") { if (Value == "true" || Value == "TRUE" || Value == "1") { EnableCLI = true; #ifndef HAVE_GUI fprintf(stderr, "Enabling interactive CLI.\n"); #endif } else { EnableCLI = false; } ConfigMap.erase(Param); } else if (Param == "promisc") { if (Value == "false" || Value == "FALSE" || Value == "0") { EnablePromisc = false; #ifndef HAVE_GUI fprintf(stderr, "Disabling promiscuous mode.\n"); #endif } ConfigMap.erase(Param); } else if (Param == "bw_limit") { char *EndPtr; int n; n = strtoul(Value.c_str(), &EndPtr, 10); if (*EndPtr == '\0') { BandwidthLim = n; #ifndef HAVE_GUI fprintf(stderr, "Setting bandwidth limit to %d Kbps.\n", BandwidthLim); #endif } else { throw runtime_error("Value for bw_limit should be a number."); } ConfigMap.erase(Param); } else if (Param == "ignore_hosts") { ParseIgnoreHosts(Value); ConfigMap.erase(Param); } else if (Param == "proxy_host") { ProxyHost = Value; ConfigMap.erase(Param); } else if (Param == "proxy_port") { char *EndPtr; int n = strtoul(Value.c_str(), &EndPtr, 10); if (*EndPtr == '\0') { if (n < 0 || n > 65535) { throw runtime_error("Value for proxy_port should be between 0 and 65536."); } else { ProxyPort = n; } } else { throw runtime_error("Value for proxy_port should be between 0 and 65536."); } ConfigMap.erase(Param); } else if (Param == "proxy_userid") { ProxyUserID = Value; ConfigMap.erase(Param); } else if (Param == "proxy_passwd") { ProxyPasswd = Value; ConfigMap.erase(Param); } else if (Param == "subnet") { ParseSubnet(Value); } else if (Param == "scan_local_subnet") { if (Value == "false" || Value == "FALSE" || Value == "0") { ScanLocalSubnet = false; } } else if (Param == "scannetwork_interval") { char *EndPtr; int n = strtoul(Value.c_str(), &EndPtr, 10); if (*EndPtr == '\0') { #ifndef HAVE_GUI fprintf(stderr, "Setting network scanning interval to %s seconds.\n", Value.c_str()); #endif ScanNetworkInterval = n; } else { throw runtime_error("Value for network scanning interval should be a number."); } ConfigMap.erase(Param); } else if (Param == "polling_interval") { char *EndPtr; int n = strtoul(Value.c_str(), &EndPtr, 10); if (*EndPtr == '\0') { #ifndef HAVE_GUI fprintf(stderr, "Setting polling interval to %s seconds.\n", Value.c_str()); #endif PollingInterval = n; } else { throw runtime_error("Value for polling interval should be a number."); } ConfigMap.erase(Param); } else if (Param == "plugin_dir") { PluginDir = Value; ConfigMap.erase(Param); } else if (Param == "server") { Server = Value; ConfigMap.erase(Param); } else if (Param == "server_port") { char *EndPtr; int n = strtoul(Value.c_str(), &EndPtr, 10); if (*EndPtr == '\0') { if (n < 0 || n > 65535) { throw runtime_error("Value for server_port should be between 0 and 65536."); } else { ServerPort = n; } } else { throw runtime_error("Value for server_port should be between 0 and 65536."); } ConfigMap.erase(Param); } else if (Param == "wmi_user") { WmiUser = Value; ConfigMap.erase(Param); } else if (Param == "wmi_passwd") { TConfigParam ConfigParam(Value); WmiPassword = ConfigParam[0]; ConfigMap.erase(Param); } else if (Param == "wmi_domain") { WmiDomain = Value; ConfigMap.erase(Param); } else if (Param == "wmi_query") { int i = Value.find(":", 0); string Namespace = Value.substr(0, i); string Query = Value.substr(i + 1); TWmiQuery WmiQuery(Namespace, Query); WmiQueries.push_back(WmiQuery); } else if (Param == "snmp_credential") { TConfigParam ConfigParam(Value); string Community = ConfigParam[1]; AddCommunity(Community); } /* * Insert the value into the configuration map. */ ConfigMap.insert(pair(Param, Value)); } else { string ErrMsg = "Improperly formed configuration directive: "; ErrMsg += Line; throw runtime_error(ErrMsg); } } //--------------------------------------------------------------------------- void TAgentConfig::ParseSwitchDir(string SwitchConf) { DEBUG_MESSAGE(DEBUG_AGENTCONFIG, ("Adding switch directory: %s.", SwitchConf.c_str())); /* TODO: Strip trailing whitespace. */ SwitchDirs.push_back(SwitchConf); } //--------------------------------------------------------------------------- void TAgentConfig::ParseHomeNets(string HomeNetStr) { char *LocalStr, *Tok, *EndPtr; std::list::iterator CurrNet, TmpNet; ClearHomeNets(); LocalStr = strdup(HomeNetStr.c_str()); auto_ptr StrPtr(LocalStr); DEBUG_MESSAGE(DEBUG_AGENTCONFIG, ("Parsing \"home_net\" statement: %s.", LocalStr)); Tok = LocalStr; EndPtr = Tok; while (1) { if (*EndPtr == ',') { *EndPtr = '\0'; try { TCIDRBlock NetBlock(Tok); AddHomeNet(NetBlock); #ifndef HAVE_GUI fprintf(stderr, "Added %s to \"home_nets.\"\n", Tok); #endif } catch (exception &E) { string ErrMsg = "Error parsing CIDR block: "; ErrMsg += Tok; throw runtime_error(ErrMsg); } Tok = EndPtr + 1; } else if (*EndPtr == '\0') { try { TCIDRBlock NetBlock(Tok); AddHomeNet(NetBlock); #ifndef HAVE_GUI fprintf(stderr, "Added %s to \"home_nets.\"\n", Tok); #endif } catch (exception &E) { string ErrMsg = "Error parsing CIDR block: "; ErrMsg += Tok; throw runtime_error(ErrMsg); } break; } EndPtr++; } } //--------------------------------------------------------------------------- void TAgentConfig::AddHomeNet(TCIDRBlock &NetBlock) { HomeNets.push_back(NetBlock); NumScanThreads++; } //--------------------------------------------------------------------------- void TAgentConfig::ClearHomeNets(void) { HomeNets.clear(); NumScanThreads = InitialScanThreads; } //--------------------------------------------------------------------------- #ifndef ROGUESCANNER string TAgentConfig::GetGUID(void) { TMacAddress Addr; string AddrString, GUID; int Len; if (Interface) { Addr = Interface->GetMacAddress(); } AddrString = Addr.Print(); Len = AddrString.length(); for (int i = 0; i < Len; i++) { if (AddrString[i] != ':') { GUID += AddrString[i]; } } return GUID; } //--------------------------------------------------------------------------- #endif list TAgentConfig::GetConfigParam(const string &Param) { list ParamValues; multimap::iterator CurrParam; for (CurrParam = ConfigMap.lower_bound(Param); CurrParam != ConfigMap.upper_bound(Param); CurrParam++) { ParamValues.push_back(TConfigParam(CurrParam->second)); } return ParamValues; } //--------------------------------------------------------------------------- bool TAgentConfig::IsHomeNet(TIPAddress &Addr) { list::iterator CurrBlock; /* * Check to see if it is on the same subnet as the crawler. If it is * return true. */ if (Interface) { TIPAddress InterfaceNet(Interface->GetIPAddress().IPv4Value() & Interface->GetNetmask().IPv4Value()); TIPAddress InterfaceMask = Interface->GetNetmask(); TCIDRBlock InterfaceBlock(InterfaceNet, InterfaceMask); if (InterfaceBlock.Includes(Addr) && ScanLocalSubnet) { return true; } } /* * Go through the list of networks we're allowed to scan. Return true if * addr is a part of one of them. */ for (CurrBlock = HomeNets.begin(); CurrBlock != HomeNets.end(); CurrBlock++) { if (CurrBlock->Includes(Addr)) { return true; } } return false; } //--------------------------------------------------------------------------- bool TAgentConfig::IsIgnored(TIPAddress IPAddr) { list::iterator CurrBlock; for (CurrBlock = IgnoreBlocks.begin(); CurrBlock != IgnoreBlocks.end(); CurrBlock++) { if (CurrBlock->Includes(IPAddr)) { return true; } } return false; } //--------------------------------------------------------------------------- bool TAgentConfig::IsIgnored(TMacAddress MacAddr) { list::iterator CurrMac; for (CurrMac = IgnoreMacs.begin(); CurrMac != IgnoreMacs.end(); CurrMac++) { if (*CurrMac == MacAddr) { return true; } } return false; } //--------------------------------------------------------------------------- TIPAddress TAgentConfig::GetInterfaceIPAddress() { return Interface->GetIPAddress(); } //--------------------------------------------------------------------------- TIPAddress TAgentConfig::GetInterfaceNetmask() { return Interface->GetNetmask(); } //--------------------------------------------------------------------------- TIPAddress TAgentConfig::GetInterfaceNetwork() { return Interface->GetNetwork(); } //--------------------------------------------------------------------------- TIPAddress TAgentConfig::GetInterfaceBroadcast() { return Interface->GetBroadcast(); } //--------------------------------------------------------------------------- void TAgentConfig::ParseIgnoreHosts(string IgnoreStr) { char *LocalStr, *Tok, *EndPtr; LocalStr = strdup(IgnoreStr.c_str()); auto_ptr StrPtr(LocalStr); Tok = LocalStr; EndPtr = Tok; while (1) { if (*EndPtr == ',') { *EndPtr = '\0'; AddIgnored(Tok); Tok = EndPtr + 1; } else if (*EndPtr == '\0') { AddIgnored(Tok); break; } EndPtr++; } } //--------------------------------------------------------------------------- void TAgentConfig::AddIgnored(std::string IgnoredHost) { TMacAddress *MacAddr; TIPAddress *IpAddr; TCIDRBlock *Block; try { MacAddr = new TMacAddress(IgnoredHost); } catch (...) { MacAddr = NULL; } if (MacAddr) { IgnoreMacs.push_back(*MacAddr); #ifndef HAVE_GUI fprintf(stderr, "Adding %s to ignore list.\n", MacAddr->Print().c_str()); #endif delete MacAddr; } else { try { IpAddr = new TIPAddress(IgnoredHost); } catch (...) { IpAddr = NULL; } if (IpAddr) { TIPAddress Mask(0xFFFFFFFF); IgnoreBlocks.push_back(TCIDRBlock(*IpAddr, Mask)); #ifndef HAVE_GUI fprintf(stderr, "Adding %s to ignore list.\n", IpAddr->Print().c_str()); #endif delete IpAddr; } else { try { Block = new TCIDRBlock(IgnoredHost); } catch (...) { Block = NULL; } if (Block) { IgnoreBlocks.push_back(*Block); #ifndef HAVE_GUI fprintf(stderr, "Adding %s to ignore list.\n", Block->Print().c_str()); #endif delete Block; } else { string Mesg = "Error parsing \"ignore_hosts\" entry: " + IgnoredHost; throw runtime_error(Mesg); } } } } //--------------------------------------------------------------------------- void TAgentConfig::ParseSubnet(std::string SubnetStr) { char *LocalStr, *Tok, *BufPtr, *EndPtr; TCIDRBlock *SubnetBlock = NULL; char *CIDRStr = NULL, *Days = NULL; int Action = 0, BwLimit = 0, Start = 0, Duration = 0; LocalStr = strdup(SubnetStr.c_str()); auto_ptr StrPtr(LocalStr); /* * Tokenize the entry, separating the subnet from it's scanning policy. */ if ((CIDRStr = strtok_r(LocalStr, ":", &BufPtr)) != 0) { /* * Get the action this schedule applies to. */ if ((Tok = strtok_r(NULL, ":", &BufPtr)) != 0) { Action = strtoul(Tok, &EndPtr, 10); if (*EndPtr) { throw runtime_error("Schedule action must be a number."); } } /* * Get the bandwidth limit. */ if ((Tok = strtok_r(NULL, ":", &BufPtr)) != 0) { BwLimit = strtoul(Tok, &EndPtr, 10); if (*EndPtr) { throw runtime_error("Bandwidth limit must be a number."); } } /* * Get the list of days the schedule applies to. */ if ((Tok = strtok_r(NULL, ":", &BufPtr)) != 0) { Days = Tok; } /* * Get the start time and duration. */ if ((Tok = strtok_r(NULL, ":", &BufPtr)) != 0) { Start = strtoul(Tok, &EndPtr, 10); if (*EndPtr) { throw runtime_error("Start time must be a number."); } } if ((Tok = strtok_r(NULL, ":", &BufPtr)) != 0) { Duration = strtoul(Tok, &EndPtr, 10); if (*EndPtr) { throw runtime_error("Duration must be a number."); } } /* * A duration of 0 means to take as long as we need. */ if (Duration == 0) { Duration = INT_MAX; } } else { throw runtime_error("Improperly formed \"subnet\" entry."); } } //--------------------------------------------------------------------------- std::string TAgentConfig::GetPluginDir(void) { /* * For consistency make sure the plugin directory ends in a /. */ if (PluginDir.size() == 0) { return "./"; } else if (PluginDir[PluginDir.size()-1] != '/') { return PluginDir + "/"; } else { return PluginDir; } } //---------------------------------------------------------------------------