1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-06 00:13:33 +00:00
Files
MeshAgent/meshcore/meshinfo.c
2017-10-12 14:28:03 -07:00

591 lines
18 KiB
C

/*
Copyright 2006 - 2017 Intel Corporation
Licensed 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.
*/
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#if defined(WINSOCK2)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#elif defined(WINSOCK1)
#include <winsock.h>
#include <wininet.h>
#elif defined(_POSIX)
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <sys/syscall.h>
#include <linux/reboot.h>
#define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof sa.sin_port])
#define IFRSIZE ((int)(size * sizeof (struct ifreq)))
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../microstack/ILibParsers.h"
#include "../microstack/ILibCrypto.h"
#include "meshinfo.h"
#ifdef WINSOCK2
// This is the Windows implementation of a method that gets information about local interfaces
int info_GetLocalInterfaces(char* data, int maxdata)
{
#ifdef _MINCORE
return 0;
#else
IP_ADAPTER_INFO *pAdapterInfo;
IP_ADAPTER_ADDRESSES *pAdapterAddresses;
PIP_ADAPTER_INFO pAdapter;
PIP_ADAPTER_ADDRESSES pAdapterAddr;
ULONG ulOutBufLen = 0;
DWORD dwRetVal;
unsigned int j;
int adapterCount = 0;
unsigned long palen;
unsigned char pa[16];
int ptr = 0;
size_t templen;
char temp[1024];
IPAddr ip1;
IPAddr ip2;
// Lets see how much memory we need to get the list of local interfaces
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) return 0;
ulOutBufLen = sizeof(IP_ADAPTER_INFO);
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) { free(pAdapterInfo); if (ulOutBufLen == 0) return 0; pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); }
// Get the list of all local interfaces
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS || ulOutBufLen == 0) { free(pAdapterInfo); return 0; }
// Count how many interfaces are present
pAdapter = pAdapterInfo;
while (pAdapter) { adapterCount++; pAdapter = pAdapter->Next; }
// Lets see how much memory we need to get the list of local adapters
pAdapterAddresses = (IP_ADAPTER_ADDRESSES *)malloc(sizeof(IP_ADAPTER_ADDRESSES));
if (pAdapterAddresses == NULL) { free(pAdapterInfo); return 0; }
ulOutBufLen = sizeof(IP_ADAPTER_ADDRESSES);
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX, NULL, pAdapterAddresses, &ulOutBufLen) != ERROR_SUCCESS)
{
free(pAdapterAddresses);
if (ulOutBufLen == 0) return 0;
pAdapterAddresses = (IP_ADAPTER_ADDRESSES *)malloc(ulOutBufLen);
}
// Get the list of all local interfaces
if ((dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX, NULL, pAdapterAddresses, &ulOutBufLen)) != ERROR_SUCCESS || ulOutBufLen == 0) { free(pAdapterInfo); free(pAdapterAddresses); return 0; }
j = 0;
pAdapter = pAdapterInfo;
while (pAdapter)
{
// Find the corresponding adapter for this interface
pAdapterAddr = pAdapterAddresses;
while (pAdapterAddr != NULL && pAdapterAddr->IfIndex != pAdapter->Index) { pAdapterAddr = pAdapterAddr->Next; }
if (pAdapterAddr == NULL) { free(pAdapterInfo); free(pAdapterAddresses); return 0; }
if (j > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ","); }
ptr += snprintf(data + ptr, maxdata - ptr, "{");
// Interface type
ptr += snprintf(data + ptr, maxdata - ptr, "\"type\":%d", pAdapter->Type);
// Interface name
if (wcslen(pAdapterAddr->FriendlyName) > 0) {
wcstombs_s(&templen, temp, 1023, pAdapterAddr->FriendlyName, wcslen(pAdapterAddr->FriendlyName));
ptr += snprintf(data + ptr, maxdata - ptr, ",\"name\":\"%s\"", temp);
}
// Interface description
if (wcslen(pAdapterAddr->Description) > 0) {
wcstombs_s(&templen, temp, 1023, pAdapterAddr->Description, wcslen(pAdapterAddr->Description));
ptr += snprintf(data + ptr, maxdata - ptr, ",\"desc\":\"%s\"", temp);
}
// Interface MAC address
if (pAdapter->AddressLength == 6) {
ptr += snprintf(data + ptr, maxdata - ptr, ",\"mac\":\"%02x%02x%02x%02x%02x%02x\"", pAdapter->Address[0], pAdapter->Address[1], pAdapter->Address[2], pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]);
}
// Interface DNS suffix
if (wcslen(pAdapterAddr->DnsSuffix) > 0) {
wcstombs_s(&templen, temp, 1023, pAdapterAddr->DnsSuffix, wcslen(pAdapterAddr->DnsSuffix));
ptr += snprintf(data + ptr, maxdata - ptr, ",\"dnssuffix\":\"%s\"", temp);
}
// IPv4 address and subnet mask
ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4addr\":\"%s\"", pAdapter->IpAddressList.IpAddress.String);
ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4mask\":\"%s\"", pAdapter->IpAddressList.IpMask.String);
ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4gateway\":\"%s\"", pAdapter->GatewayList.IpAddress.String);
// Get the gateway MAC address
ILibInet_pton(AF_INET, pAdapter->IpAddressList.IpAddress.String, &ip1);
ILibInet_pton(AF_INET, pAdapter->GatewayList.IpAddress.String, &ip2);
SendARP(ip2, ip1, pa, &palen);
if (palen == 6) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"gatewaymac\":\"%02x%02x%02x%02x%02x%02x\"", pa[0], pa[1], pa[2], pa[3], pa[4], pa[5]); }
ptr += snprintf(data + ptr, maxdata - ptr, "}");
j++;
pAdapter = pAdapter->Next;
}
// Free the local interface memory
free(pAdapterInfo);
free(pAdapterAddresses);
return ptr;
#endif
}
#endif
#ifdef _POSIX
// This method reads a stream where the length of the file can't be determined. Useful in POSIX only
int __fastcall utilx_readfile2(char* filename, char** data)
{
FILE * pFile;
int count = 0;
int len = 0;
*data = NULL;
if (filename == NULL) return 0;
pFile = fopen(filename, "rb");
if (pFile != NULL)
{
*data = malloc(1024);
if (*data == NULL) { fclose(pFile); return 0; }
do
{
len = fread((*data) + count, 1, 1023, pFile);
count += len;
if (len == 1023) *data = realloc(*data, count + 1024);
} while (len == 100);
(*data)[count] = 0;
fclose(pFile);
}
return count;
}
// TODO: Add support for IPv6, and check that it's on the correct interface
int info_GetHwAddress(char* ipaddr, int ipaddrlen, char** hwaddr)
{
char* arpcache = NULL;
int len, r = 0;
char* ptr = NULL;
char substr[32];
*hwaddr = NULL;
if (ipaddrlen >= 30 || (ipaddrlen == 7 && memcmp(ipaddr, "0.0.0.0", 7) == 0)) return 0;
len = utilx_readfile2("/proc/net/arp", &arpcache);
if (len == 0) return 0;
substr[0] = '\n';
memcpy(substr + 1, ipaddr, ipaddrlen);
substr[ipaddrlen + 1] = ' ';
substr[ipaddrlen + 2] = 0;
ptr = strstr(arpcache, substr);
if ((ptr != NULL) && (ptr + 61 < arpcache + len) && (ptr[44] == ':') && (ptr[47] == ':') && (ptr[56] == ':'))
{
if ((*hwaddr = (char*)malloc(6)) == NULL) ILIBCRITICALEXIT(254);
for (; r < 6; r++) { (*hwaddr)[r] = util_hexToint(ptr + 42 + (r * 3), 2); }
}
free(arpcache);
return r;
}
// The Linux equal of Windows SendARP
int SendARP(char* DestIP, char* SrcIP, void* pMacAddr, int* PhyAddrLen)
{
char tmp[50];
char* ptr = NULL;
ILibInet_ntop(AF_INET, DestIP, tmp, 50);
if (*PhyAddrLen < 6) return -1;
*PhyAddrLen = info_GetHwAddress(tmp, strlen(tmp), &ptr);
if (ptr != NULL)
{
memcpy(pMacAddr, ptr, 6);
free(ptr);
return 0;
}
return -1;
}
// TODO: See if we can do this for each interface, right now interface is ignored
int info_GetDefaultFqdn(char* ifname, char** fqdn)
{
char* resolv;
int len, r = 0;
struct parser_result* parse;
struct parser_result_field* p;
struct parser_result* parse2;
struct parser_result_field* p2;
*fqdn = NULL;
len = utilx_readfile2("/etc/resolv.conf", &resolv);
if (len == 0) return 0;
parse = ILibParseString(resolv, 0, len, "\n", 1);
p = parse->FirstResult;
while (p != NULL)
{
parse2 = ILibParseString(p->data, 0, p->datalength, " ", 1);
p2 = parse2->FirstResult;
if (p2->datalength == 6 && memcmp(p2->data, "domain", 6) == 0)
{
// We found the system's default FQDN
r = p2->NextResult->datalength;
*fqdn = malloc(r + 1);
memcpy(*fqdn, p2->NextResult->data, r);
(*fqdn)[r] = 0;
ILibDestructParserResults(parse2);
break;
}
ILibDestructParserResults(parse2);
p = p->NextResult; // Skip to next line
}
ILibDestructParserResults(parse);
free(resolv);
return r;
}
// TODO: Add IPv6 support
int info_GetDefaultGateway(char* ifname, char** gateway)
{
char* route;
char* temp;
int len, r = 0, i;
int ifnamelen = strlen(ifname);
struct parser_result* parse;
struct parser_result_field* p;
struct parser_result* parse2;
struct parser_result_field* p2;
*gateway = NULL;
len = utilx_readfile2("/proc/net/route", &route);
if (len == 0) return 0;
parse = ILibParseString(route, 0, len, "\n", 1);
p = parse->FirstResult;
p = p->NextResult; // Skip the first line
while (p != NULL)
{
parse2 = ILibParseString(p->data, 0, p->datalength, "\t", 1);
p2 = parse2->FirstResult;
if (ifnamelen == p2->datalength && memcmp(p2->data, ifname, ifnamelen) == 0)
{
if (p2->NextResult->datalength == 8 && memcmp(p2->NextResult->data, "00000000", 8) == 0)
{
// We found the default gateway for this interface
r = p2->NextResult->NextResult->datalength / 2;
*gateway = malloc(r);
temp = p2->NextResult->NextResult->data;
for (i = 0; i < r; i++) { (*gateway)[r - (i + 1)] = util_hexToint(temp + (i * 2), 2); }
ILibDestructParserResults(parse2);
break;
}
}
ILibDestructParserResults(parse2);
p = p->NextResult; // Skip to next line
}
ILibDestructParserResults(parse);
free(route);
return r;
}
// This is the POSIX implementation of a method that gets information about local interfaces
int info_GetLocalInterfaces(char* data, int maxdata)
{
#ifdef NACL
return 0;
#else
int ptr = 0;
int sockfd, size = 1, j;
int adapterCount = 0;
struct ifreq *ifr;
struct ifconf ifc;
char temp[1024];
char* gateway = NULL;
// Fetch the list of local interfaces
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) return 0;
ifc.ifc_len = IFRSIZE;
ifc.ifc_req = NULL;
do
{
++size;
// realloc buffer size until no overflow occurs
if ((ifc.ifc_req = realloc(ifc.ifc_req, IFRSIZE)) == NULL) return 0;
ifc.ifc_len = IFRSIZE;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) != 0) return 0;
} while (IFRSIZE <= ifc.ifc_len);
ifr = ifc.ifc_req;
for (; (char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len; ++ifr)
{
if (ifr->ifr_addr.sa_data == (ifr + 1)->ifr_addr.sa_data) continue; // Duplicate
if (ioctl(sockfd, SIOCGIFFLAGS, ifr)) continue; // Failed
if (memcmp(ifr->ifr_name, "lo", 3) == 0) continue; // Loopback
if (adapterCount > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ","); }
ptr += snprintf(data + ptr, maxdata - ptr, "{");
// Get the name of the interface
ptr += snprintf(data + ptr, maxdata - ptr, "\"name\":\"%s\"", ifr->ifr_name);
// Get the FQDN (DNS Suffix)
j = info_GetDefaultFqdn(ifr->ifr_name, &gateway);
if (j > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"dnssuffix\":\"%s\"", gateway); }
if (gateway != NULL) { free(gateway); gateway = NULL; }
// Get the Default Gateway IP address
j = info_GetDefaultGateway(ifr->ifr_name, &gateway);
if (j == 4) { ILibInet_ntop(AF_INET, gateway, temp, 1024); ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4gateway\":\"%s\"", temp); }
if (gateway != NULL) { free(gateway); gateway = NULL; }
// Get the Default Gateway MAC address
j = info_GetHwAddress(temp, strlen(temp), &gateway);
if (j == 6) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"gatewaymac\":\"%02x%02x%02x%02x%02x%02x\"", (unsigned char)gateway[0], (unsigned char)gateway[1], (unsigned char)gateway[2], (unsigned char)gateway[3], (unsigned char)gateway[4], (unsigned char)gateway[5]); }
if (gateway != NULL) free(gateway);
// Attempt to figure out the interface type
j = 0;
if (strlen(ifr->ifr_name) > 3 && memcmp(ifr->ifr_name, "eth", 3) == 0) { j = 6; }
//if (strlen(ifr->ifr_name) > 2 && memcmp(ifr->ifr_name, "wl", 2) == 0) { j = 6; } // TODO: Wireless
if (j > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"type\":\"%d\"", j); }
// Get the hardware MAC address
if (ioctl(sockfd, SIOCGIFHWADDR, ifr) == 0) {
if (ifr->ifr_hwaddr.sa_family == 1) {
ptr += snprintf(data + ptr, maxdata - ptr, ",\"mac\":\"%02x%02x%02x%02x%02x%02x\"", (unsigned char)ifr->ifr_hwaddr.sa_data[0], (unsigned char)ifr->ifr_hwaddr.sa_data[1], (unsigned char)ifr->ifr_hwaddr.sa_data[2], (unsigned char)ifr->ifr_hwaddr.sa_data[3], (unsigned char)ifr->ifr_hwaddr.sa_data[4], (unsigned char)ifr->ifr_hwaddr.sa_data[5]);
}
}
// Get the IP address
if (ioctl(sockfd, SIOCGIFADDR, ifr) == 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4addr\":\"%s\"", inet_ntoa(((struct sockaddr_in*)(&(ifr->ifr_addr)))->sin_addr)); }
// Get the subnet mask
if (ioctl(sockfd, SIOCGIFNETMASK, ifr) == 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4mask\":\"%s\"", inet_ntoa(((struct sockaddr_in*)(&(ifr->ifr_addr)))->sin_addr)); }
ptr += snprintf(data + ptr, maxdata - ptr, "}");
adapterCount++;
}
free(ifc.ifc_req);
close(sockfd);
return ptr;
#endif
}
#endif
// Returns a JSON text with system information
int MeshInfo_GetSystemInformation(char** data)
{
int ptr = 0;
// Setup the response
*data = (char*)malloc(65536);
ptr += snprintf(*data + ptr, 65536 - ptr, "{\"netif\":[");
ptr += info_GetLocalInterfaces(*data + ptr, 65536 - ptr);
ptr += snprintf(*data + ptr, 65536 - ptr, "]}");
(*data)[ptr] = 0;
*data = realloc(*data, ptr + 1);
return ptr;
}
#ifdef WIN32
#if defined(_LINKVM)
DWORD WINAPI kvm_ctrlaltdel(LPVOID Param);
#endif
int MeshInfo_PowerState(enum AgentPowerStateActions flg, int force)
{
#ifdef _MINCORE
if (flg == 0 || flg > 5) return 0; // NOP
switch (flg)
{
case POWERSTATE_SHUTDOWN: // SHUTDOWN
InitiateSystemShutdownEx(NULL, NULL, 30, TRUE, FALSE, SHTDN_REASON_MINOR_OTHER);
break;
case POWERSTATE_REBOOT: // REBOOT
InitiateSystemShutdownEx(NULL, NULL, 30, TRUE, TRUE, SHTDN_REASON_MINOR_OTHER);
break;
}
return 1;
#else
TOKEN_PRIVILEGES tp;
BOOL fResult = 0;
HANDLE ht;
if (flg == POWERSTATE_NOP) return 0; // NOP
if (flg == POWERSTATE_DISPLAYON) { SetThreadExecutionState(ES_DISPLAY_REQUIRED); SetThreadExecutionState(ES_USER_PRESENT); return 1; } // Turn on display
if (flg == POWERSTATE_KEEPAWAKE) { SetThreadExecutionState(ES_SYSTEM_REQUIRED); return 1; } // Keep system awake
if (flg == POWERSTATE_BEEP) { MessageBeep(0xFFFFFFFF); return 1; }
if (flg == POWERSTATE_CTRLALTDEL)
{
#if defined(_LINKVM)
ht = CreateThread(NULL, 0, kvm_ctrlaltdel, 0, 0, 0);
if (ht != NULL) CloseHandle(ht);
return 1;
#else
return 0;
#endif
}
// Attempt to exit
if (flg > POWERSTATE_HIBERNATE) return 0; // NOP
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &ht)) return 0;
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(ht, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
if (GetLastError() != ERROR_SUCCESS) { CloseHandle(ht); return 0; }
switch (flg)
{
case POWERSTATE_LOGOFF: // LOGOFF
if (force) fResult = ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, SHTDN_REASON_FLAG_PLANNED);
else fResult = ExitWindowsEx(EWX_LOGOFF, SHTDN_REASON_FLAG_PLANNED);
break;
case POWERSTATE_SHUTDOWN: // SHUTDOWN
fResult = InitiateSystemShutdown(NULL, NULL, 30, TRUE, FALSE);
break;
case POWERSTATE_REBOOT: // REBOOT
fResult = InitiateSystemShutdown(NULL, NULL, 30, TRUE, TRUE);
break;
case POWERSTATE_SLEEP: // SLEEP
fResult = SetSystemPowerState(TRUE, force);
break;
case POWERSTATE_HIBERNATE: // HIBERNATE
fResult = SetSystemPowerState(FALSE, force);
break;
}
if (!fResult) { CloseHandle(ht); return 0; }
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(ht, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
CloseHandle(ht);
return 1;
#endif
}
#elif _VX_CPU // If VxWorks, we still need to implement this.
int MeshInfo_PowerState(enum AgentPowerStateActions flg, int force)
{
// TODO
return 0;
}
#else
int MeshInfo_PowerState(enum AgentPowerStateActions flg, int force)
{
switch (flg)
{
case POWERSTATE_NOP:
case POWERSTATE_DISPLAYON:
case POWERSTATE_KEEPAWAKE:
case POWERSTATE_BEEP:
case POWERSTATE_CTRLALTDEL:
// NO OP
break;
case POWERSTATE_LOGOFF: // LOGOFF
break;
case POWERSTATE_SHUTDOWN: // SHUTDOWN
#if defined(_ANDROID)
reboot(RB_POWER_OFF);
#elif defined(__APPLE__)
// TODO
#elif defined(NACL)
//do nothing
#else
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, 0);
#endif
return 1;
case POWERSTATE_REBOOT: // REBOOT
#if defined(_ANDROID) || defined(__APPLE__)
reboot(RB_AUTOBOOT);
#elif defined(NACL)
//do nothing
#else
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, 0);
#endif
return 1;
case POWERSTATE_SLEEP: // SLEEP
#if defined(__APPLE__)
{
io_connect_t port = IOPMFindPowerManagement(MACH_PORT_NULL);
IOPMSleepSystem(port);
IOServiceClose(port);
}
#endif
break;
#ifdef LINUX_REBOOT_CMD_SW_SUSPEND
case POWERSTATE_HIBERNATE: // HIBERNATE
#if defined(_ANDROID) || defined(__APPLE__)
// TODO
#else
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_SW_SUSPEND, 0);
#endif
return 1;
#endif
case POWERSTATE_VIBRATE: // VIBRATE
#if defined(ANDROID)
{
ai_vibrate(1000);
}
#endif
break;
case POWERSTATE_FLASH: // FLASH
#if defined(ANDROID)
{
ai_flash(1000);
}
#endif
break;
}
return 0;
}
#endif