| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #ifndef LIBMINIFI_INCLUDE_CORE_STATE_NODES_DEVICEINFORMATION_H_ |
| #define LIBMINIFI_INCLUDE_CORE_STATE_NODES_DEVICEINFORMATION_H_ |
| |
| #include "core/Resource.h" |
| |
| #ifndef WIN32 |
| #if ( defined(__APPLE__) || defined(__MACH__) || defined(BSD)) |
| #include <net/if_dl.h> |
| #include <net/if_types.h> |
| #endif |
| |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <sys/ioctl.h> |
| #include <sys/utsname.h> |
| |
| #include <ifaddrs.h> |
| #include <net/if.h> |
| #include <netdb.h> |
| #include <unistd.h> |
| |
| #else |
| #pragma comment(lib, "iphlpapi.lib") |
| #include <iphlpapi.h> |
| |
| #endif |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <set> |
| #include <string> |
| #include <vector> |
| #include <fstream> |
| #include <functional> |
| #include <map> |
| #include <sstream> |
| |
| #include "../nodes/MetricsBase.h" |
| #include "Connection.h" |
| #include "io/ClientSocket.h" |
| |
| namespace org { |
| namespace apache { |
| namespace nifi { |
| namespace minifi { |
| namespace state { |
| namespace response { |
| |
| class Device { |
| public: |
| Device() { |
| initialize(); |
| } |
| void initialize() { |
| addrinfo hints = { sizeof(addrinfo) }; |
| memset(&hints, 0, sizeof hints); // make sure the struct is empty |
| hints.ai_family = AF_UNSPEC; |
| hints.ai_socktype = SOCK_STREAM; |
| hints.ai_flags = AI_CANONNAME; |
| hints.ai_protocol = 0; /* any protocol */ |
| |
| char hostname[1024]; |
| hostname[1023] = '\0'; |
| gethostname(hostname, 1023); |
| |
| std::ifstream device_id_file(".device_id"); |
| if (device_id_file) { |
| std::string line; |
| while (device_id_file) { |
| if (std::getline(device_id_file, line)) |
| device_id_ += line; |
| } |
| device_id_file.close(); |
| } else { |
| device_id_ = getDeviceId(); |
| |
| std::ofstream outputFile(".device_id"); |
| if (outputFile) { |
| outputFile.write(device_id_.c_str(), device_id_.length()); |
| } |
| outputFile.close(); |
| } |
| |
| canonical_hostname_ = hostname; |
| |
| std::stringstream ips; |
| auto ipaddressess = getIpAddresses(); |
| for (auto ip : ipaddressess) { |
| if (ipaddressess.size() > 1 && (ip.find("127") == 0 || ip.find("192") == 0)) |
| continue; |
| ip_ = ip; |
| break; |
| } |
| } |
| |
| std::string canonical_hostname_; |
| std::string ip_; |
| std::string device_id_; |
| |
| protected: |
| std::vector<std::string> getIpAddresses() { |
| static std::vector<std::string> ips; |
| if (ips.empty()) { |
| #ifndef WIN32 |
| struct ifaddrs *ifaddr, *ifa; |
| if (getifaddrs(&ifaddr) == -1) { |
| perror("getifaddrs"); |
| exit(EXIT_FAILURE); |
| } |
| |
| for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { |
| if ((strcmp("lo", ifa->ifa_name) == 0) || !(ifa->ifa_flags & (IFF_RUNNING))) |
| continue; |
| if ((ifa->ifa_addr != NULL) && (ifa->ifa_addr->sa_family == AF_INET)) { |
| ips.push_back(inet_ntoa(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr)); |
| } |
| } |
| |
| freeifaddrs(ifaddr); |
| #else |
| PIP_ADAPTER_INFO adapterPtr; |
| PIP_ADAPTER_INFO adapter = NULL; |
| |
| DWORD dwRetVal = 0; |
| |
| std::hash<std::string> hash_fn; |
| std::set<std::string> macs; |
| |
| ULONG adapterLen = sizeof(IP_ADAPTER_INFO); |
| adapterPtr = reinterpret_cast<IP_ADAPTER_INFO*>(malloc(sizeof(IP_ADAPTER_INFO))); |
| if (adapterPtr == NULL) { |
| return ips; |
| } |
| if (GetAdaptersInfo(adapterPtr, &adapterLen) == ERROR_BUFFER_OVERFLOW) { |
| free(adapterPtr); |
| adapterPtr = reinterpret_cast<IP_ADAPTER_INFO*>(malloc(adapterLen)); |
| if (adapterPtr == NULL) { |
| return ips; |
| } |
| } |
| |
| if ((dwRetVal = GetAdaptersInfo(adapterPtr, &adapterLen)) == NO_ERROR) { |
| adapter = adapterPtr; |
| while (adapter) { |
| ips.emplace_back(adapter->IpAddressList.IpAddress.String); |
| adapter = adapter->Next; |
| } |
| } |
| |
| if (adapterPtr) |
| free(adapterPtr); |
| #endif |
| } |
| return ips; |
| } |
| |
| #if __linux__ |
| std::string getDeviceId() { |
| std::hash<std::string> hash_fn; |
| std::string macs; |
| struct ifaddrs *ifaddr, *ifa; |
| int family, s, n; |
| char host[NI_MAXHOST]; |
| |
| if (getifaddrs(&ifaddr) == -1) { |
| exit(EXIT_FAILURE); |
| } |
| |
| /* Walk through linked list, maintaining head pointer so we |
| can free list later */ |
| for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) { |
| if (ifa->ifa_addr == NULL) |
| continue; |
| |
| family = ifa->ifa_addr->sa_family; |
| |
| /* Display interface name and family (including symbolic |
| form of the latter for the common families) */ |
| |
| /* For an AF_INET* interface address, display the address */ |
| |
| if (family == AF_INET || family == AF_INET6) { |
| s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), host, NI_MAXHOST, |
| NULL, |
| 0, NI_NUMERICHOST); |
| if (s != 0) { |
| printf("getnameinfo() failed: %s\n", gai_strerror(s)); |
| exit(EXIT_FAILURE); |
| } |
| } |
| } |
| |
| freeifaddrs(ifaddr); |
| |
| int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
| struct ifreq ifr; |
| struct ifconf ifc; |
| char buf[1024]; |
| ifc.ifc_len = sizeof(buf); |
| ifc.ifc_buf = buf; |
| if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { /* handle error */ |
| } |
| |
| struct ifreq* it = ifc.ifc_req; |
| const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq)); |
| |
| for (; it != end; ++it) { |
| strcpy(ifr.ifr_name, it->ifr_name); // NOLINT |
| if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { |
| if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback |
| if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) { |
| unsigned char mac[6]; |
| |
| memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); |
| |
| char mac_add[13]; |
| snprintf(mac_add, 13, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); // NOLINT |
| |
| macs += mac_add; |
| } |
| } |
| |
| } else { /* handle error */ |
| } |
| } |
| |
| close(sock); |
| |
| return std::to_string(hash_fn(macs)); |
| } |
| #elif(defined(__unix__) || defined(__APPLE__) || defined(__MACH__) || defined(BSD)) // should work on bsd variants as well |
| std::string getDeviceId() { |
| ifaddrs* iflist; |
| std::hash<std::string> hash_fn; |
| std::set<std::string> macs; |
| |
| if (getifaddrs(&iflist) == 0) { |
| for (ifaddrs* cur = iflist; cur; cur = cur->ifa_next) { |
| if (cur->ifa_addr && (cur->ifa_addr->sa_family == AF_LINK) && (reinterpret_cast<sockaddr_dl*>(cur->ifa_addr))->sdl_alen) { |
| sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(cur->ifa_addr); |
| |
| if (sdl->sdl_type != IFT_ETHER) { |
| continue; |
| } else { |
| } |
| char mac[32]; |
| memcpy(mac, LLADDR(sdl), sdl->sdl_alen); |
| char mac_add[13]; |
| snprintf(mac_add, 13, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); // NOLINT |
| // macs += mac_add; |
| macs.insert(mac_add); |
| } |
| } |
| |
| freeifaddrs(iflist); |
| } |
| std::string macstr; |
| for (auto &mac : macs) { |
| macstr += mac; |
| } |
| return macstr.length() > 0 ? std::to_string(hash_fn(macstr)) : "8675309"; |
| } |
| #else |
| std::string getDeviceId() { |
| PIP_ADAPTER_INFO adapterPtr; |
| PIP_ADAPTER_INFO adapter = NULL; |
| |
| DWORD dwRetVal = 0; |
| |
| std::hash<std::string> hash_fn; |
| std::set<std::string> macs; |
| |
| ULONG adapterLen = sizeof(IP_ADAPTER_INFO); |
| adapterPtr = reinterpret_cast<IP_ADAPTER_INFO*>(malloc(sizeof(IP_ADAPTER_INFO))); |
| if (adapterPtr == NULL) { |
| return ""; |
| } |
| if (GetAdaptersInfo(adapterPtr, &adapterLen) == ERROR_BUFFER_OVERFLOW) { |
| free(adapterPtr); |
| adapterPtr = reinterpret_cast<IP_ADAPTER_INFO*>(malloc(adapterLen)); |
| if (adapterPtr == NULL) { |
| return ""; |
| } |
| } |
| |
| if ((dwRetVal = GetAdaptersInfo(adapterPtr, &adapterLen)) == NO_ERROR) { |
| adapter = adapterPtr; |
| while (adapter) { |
| char mac_add[13]; |
| snprintf(mac_add, 13, "%02X%02X%02X%02X%02X%02X", adapter->Address[0], adapter->Address[1], adapter->Address[2], adapter->Address[3], adapter->Address[4], adapter->Address[5]); // NOLINT |
| macs.insert(mac_add); |
| adapter = adapter->Next; |
| } |
| } |
| |
| if (adapterPtr) |
| free(adapterPtr); |
| std::string macstr; |
| for (auto &mac : macs) { |
| macstr += mac; |
| } |
| return macstr.length() > 0 ? std::to_string(hash_fn(macstr)) : "8675309"; |
| } |
| #endif |
| |
| // connection information |
| int32_t socket_file_descriptor_; |
| |
| addrinfo *addr_info_; |
| }; |
| |
| /** |
| * Justification and Purpose: Provides Device Information |
| */ |
| class DeviceInfoNode : public DeviceInformation { |
| public: |
| DeviceInfoNode(std::string name, utils::Identifier & uuid) |
| : DeviceInformation(name, uuid) { |
| static Device device; |
| hostname_ = device.canonical_hostname_; |
| ip_ = device.ip_; |
| device_id_ = device.device_id_; |
| } |
| |
| DeviceInfoNode(const std::string &name) // NOLINT |
| : DeviceInformation(name) { |
| static Device device; |
| hostname_ = device.canonical_hostname_; |
| ip_ = device.ip_; |
| device_id_ = device.device_id_; |
| } |
| |
| std::string getName() const { |
| return "deviceInfo"; |
| } |
| |
| std::vector<SerializedResponseNode> serialize() { |
| std::vector<SerializedResponseNode> serialized; |
| |
| SerializedResponseNode identifier; |
| identifier.name = "identifier"; |
| identifier.value = device_id_; |
| |
| SerializedResponseNode systemInfo; |
| systemInfo.name = "systemInfo"; |
| |
| SerializedResponseNode vcores; |
| vcores.name = "vCores"; |
| size_t ncpus = std::thread::hardware_concurrency(); |
| |
| vcores.value = ncpus; |
| |
| systemInfo.children.push_back(vcores); |
| |
| SerializedResponseNode ostype; |
| ostype.name = "operatingSystem"; |
| ostype.value = getOperatingSystem(); |
| |
| systemInfo.children.push_back(ostype); |
| #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) |
| SerializedResponseNode mem; |
| mem.name = "physicalMem"; |
| |
| uint64_t mema = (size_t) sysconf(_SC_PHYS_PAGES) * (size_t) sysconf(_SC_PAGESIZE); |
| |
| mem.value = mema; |
| |
| systemInfo.children.push_back(mem); |
| #endif |
| #ifndef WIN32 |
| SerializedResponseNode arch; |
| arch.name = "machinearch"; |
| |
| utsname buf; |
| |
| if (uname(&buf) == -1) { |
| arch.value = "unknown"; |
| } else { |
| arch.value = buf.machine; |
| } |
| |
| systemInfo.children.push_back(arch); |
| #else |
| SYSTEM_INFO si; |
| GetSystemInfo(&si); |
| |
| SerializedResponseNode mem; |
| mem.name = "physicalMem"; |
| |
| MEMORYSTATUSEX statex; |
| |
| statex.dwLength = sizeof(statex); |
| |
| GlobalMemoryStatusEx(&statex); |
| |
| mem.value = statex.ullTotalPhys; |
| |
| systemInfo.children.push_back(mem); |
| |
| SerializedResponseNode arch; |
| arch.name = "machinearch"; |
| |
| switch (si.wProcessorArchitecture) { |
| #ifdef PROCESSOR_ARCHITECTURE_ARM |
| case PROCESSOR_ARCHITECTURE_ARM: |
| arch.value = "arm32"; |
| break; |
| #endif |
| #ifdef PROCESSOR_ARCHITECTURE_ARM64 |
| case PROCESSOR_ARCHITECTURE_ARM64: |
| arch.value = "arm64"; |
| break; |
| #endif |
| case PROCESSOR_ARCHITECTURE_INTEL: |
| #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 |
| case PROCESSOR_ARCHITECTURE_IA32_ON_ARM64: |
| arch.value = "x32"; |
| break; |
| #endif |
| case PROCESSOR_ARCHITECTURE_AMD64: |
| case PROCESSOR_ARCHITECTURE_IA64: |
| arch.value = "x64"; |
| break; |
| default: |
| arch.value = "unknown"; |
| } |
| |
| systemInfo.children.push_back(arch); |
| #endif |
| serialized.push_back(identifier); |
| serialized.push_back(systemInfo); |
| |
| SerializedResponseNode networkinfo; |
| networkinfo.name = "networkInfo"; |
| |
| SerializedResponseNode hostname; |
| hostname.name = "hostname"; |
| hostname.value = hostname_; |
| |
| SerializedResponseNode ip; |
| ip.name = "ipAddress"; |
| ip.value = !ip_.empty() ? ip_ : "127.0.0.1"; |
| |
| networkinfo.children.push_back(hostname); |
| networkinfo.children.push_back(ip); |
| |
| serialized.push_back(networkinfo); |
| |
| return serialized; |
| } |
| |
| protected: |
| /** |
| * Have found various ways of identifying different operating system variants |
| * so these were either pulled from header files or online. |
| */ |
| static inline std::string getOperatingSystem() { |
| /** |
| * We define WIN32, but *most* compilers should provide _WIN32. |
| */ |
| #if defined(WIN32) || defined(_WIN32) || defined(_WIN64) |
| return "Windows"; |
| #elif defined(__APPLE__) || defined(__MACH__) |
| return "Mac OSX"; |
| #elif defined(__linux__) |
| return "Linux"; |
| #elif defined(__unix) || defined(__unix__) || defined(__FreeBSD__) |
| return "Unix"; |
| #else |
| return "Other"; |
| #endif |
| } |
| |
| std::string hostname_; |
| std::string ip_; |
| std::string device_id_; |
| }; |
| |
| REGISTER_RESOURCE(DeviceInfoNode, "Node part of an AST that defines device characteristics to the C2 protocol"); |
| |
| } // namespace response |
| } // namespace state |
| } // namespace minifi |
| } // namespace nifi |
| } // namespace apache |
| } // namespace org |
| |
| #endif // LIBMINIFI_INCLUDE_CORE_STATE_NODES_DEVICEINFORMATION_H_ |