LocalIP: add support for Windows

This commit is contained in:
李通洲
2022-10-08 22:48:13 +08:00
parent 5114051725
commit 2c51252396
5 changed files with 225 additions and 74 deletions
+3
View File
@@ -270,6 +270,7 @@ if(LINUX OR APPLE OR ANDROID OR BSD)
src/detection/terminalshell/terminalshell_linux.c
src/detection/packages/packages_linux.c
src/detection/kernel/kernel_linux.c
src/detection/localip/localip_linux.c
)
endif()
@@ -342,6 +343,7 @@ if(WIN_MSYS)
src/detection/packages/packages_linux.c
src/detection/packages/packages_windows.c
src/detection/kernel/kernel_windows.cpp
src/detection/localip/localip_windows.c
src/util/windows/wmi.cpp
# Shared
@@ -483,6 +485,7 @@ elseif(WIN_MSYS)
PRIVATE "-ldwmapi"
PRIVATE "-lopengl32"
PRIVATE "-lgdi32"
PRIVATE "-liphlpapi"
)
endif()
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#ifndef FF_INCLUDED_detection_localip_localip
#define FF_INCLUDED_detection_localip_localip
#include "fastfetch.h"
typedef struct FFLocalIpResult
{
FFstrbuf name;
FFstrbuf addr;
bool ipv6;
} FFLocalIpResult;
const char* ffDetectLocalIps(const FFinstance* instance, FFlist* results);
#endif
+66
View File
@@ -0,0 +1,66 @@
#include "localip.h"
#include <string.h>
#include <ctype.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#ifdef __FreeBSD__
#include <sys/socket.h> // FreeBSD needs this for AF_INET
#endif
static void addNewIp(FFlist* list, const char* name, const char* addr, bool ipv6)
{
FFLocalIpResult* ip = (FFLocalIpResult*) ffListAdd(list);
ffStrbufInitS(&ip->name, name);
ffStrbufInitS(&ip->addr, addr);
ip->ipv6 = ipv6;
}
const char* ffDetectLocalIps(const FFinstance* instance, FFlist* results)
{
struct ifaddrs* ifAddrStruct = NULL;
if(getifaddrs(&ifAddrStruct) < 0)
return "getifaddrs(&ifAddrStruct) failed";
for (struct ifaddrs* ifa = ifAddrStruct; ifa; ifa = ifa->ifa_next)
{
if (!ifa->ifa_addr || !(ifa->ifa_flags & IFF_RUNNING))
continue;
// loop back
if (strncmp(ifa->ifa_name, "lo", 2) == 0 && (ifa->ifa_name[2] == '\0' || isdigit(ifa->ifa_name[2])) && !instance->config.localIpShowLoop)
continue;
if (instance->config.localIpNamePrefix.length && strncmp(ifa->ifa_name, instance->config.localIpNamePrefix.chars, instance->config.localIpNamePrefix.length) != 0)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
// IPv4
if (!instance->config.localIpShowIpV4)
continue;
struct sockaddr_in* ipv4 = (struct sockaddr_in*) ifa->ifa_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN);
addNewIp(results, ifa->ifa_name, addressBuffer, false);
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
// IPv6
if (!instance->config.localIpShowIpV6)
continue;
struct sockaddr_in6* ipv6 = (struct sockaddr_in6 *)ifa->ifa_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
addNewIp(results, ifa->ifa_name, addressBuffer, true);
}
}
if (ifAddrStruct) freeifaddrs(ifAddrStruct);
return NULL;
}
+89
View File
@@ -0,0 +1,89 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <wchar.h>
#include "localip.h"
static void addNewIp(FFlist* list, const wchar_t* name, const char* addr, bool ipv6)
{
FFLocalIpResult* ip = (FFLocalIpResult*) ffListAdd(list);
int len = (int)wcslen(name);
int size_needed = WideCharToMultiByte(CP_UTF8, 0, name, len, NULL, 0, NULL, NULL);
ffStrbufInitA(&ip->name, (uint32_t)size_needed + 1);
WideCharToMultiByte(CP_UTF8, 0, name, len, ip->name.chars, size_needed, NULL, NULL);
ip->name.length = (uint32_t)size_needed;
ip->name.chars[size_needed] = '\0';
ffStrbufInitS(&ip->addr, addr);
ip->ipv6 = ipv6;
}
const char* ffDetectLocalIps(const FFinstance* instance, FFlist* results)
{
IP_ADAPTER_ADDRESSES* adapter_addresses = NULL;
// Start with a 16 KB buffer and resize if needed -
// multiple attempts in case interfaces change while
// we are in the middle of querying them.
DWORD adapter_addresses_buffer_size = 16 * 1024;
for (int attempts = 0; attempts != 3; ++attempts)
{
adapter_addresses = (IP_ADAPTER_ADDRESSES*)realloc(adapter_addresses, adapter_addresses_buffer_size);
assert(adapter_addresses);
DWORD error = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
adapter_addresses,
&adapter_addresses_buffer_size);
if (error == ERROR_SUCCESS)
break;
else if (ERROR_BUFFER_OVERFLOW == error)
continue;
else
return "GetAdaptersAddresses() failed";
}
// Iterate through all of the adapters
for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next)
{
if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK && !instance->config.localIpShowLoop)
continue;
for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next)
{
if (ifa->Address.lpSockaddr->sa_family == AF_INET)
{
// IPv4
if (!instance->config.localIpShowIpV4)
continue;
SOCKADDR_IN* ipv4 = (SOCKADDR_IN*) ifa->Address.lpSockaddr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN);
addNewIp(results, adapter->FriendlyName, addressBuffer, false);
}
else if (ifa->Address.lpSockaddr->sa_family == AF_INET6)
{
// IPv6
if (!instance->config.localIpShowIpV6)
continue;
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
addNewIp(results, adapter->FriendlyName, addressBuffer, false);
}
}
}
free(adapter_addresses);
return NULL;
}
+50 -74
View File
@@ -1,90 +1,66 @@
#include "fastfetch.h"
#include "common/printing.h"
#include "detection/localip/localip.h"
#define FF_LOCALIP_MODULE_NAME "Local IP"
#define FF_LOCALIP_NUM_FORMAT_ARGS 1
#include <string.h>
#include <ctype.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef __FreeBSD__
#include <sys/socket.h> // FreeBSD needs this for AF_INET
#endif
static void printValue(FFinstance* instance, const char* ifaName, const char* addressBuffer)
{
FFstrbuf key;
ffStrbufInit(&key);
if (instance->config.localIP.key.length == 0)
{
ffStrbufAppendF(&key, FF_LOCALIP_MODULE_NAME " (%s)", ifaName);
}
else
{
ffParseFormatString(&key, &instance->config.localIP.key, 1, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRING, ifaName}
});
}
if (instance->config.localIP.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, key.chars, 0, NULL);
puts(addressBuffer);
}
else
{
ffPrintFormatString(instance, key.chars, 0, NULL, &instance->config.localIP.outputFormat, FF_LOCALIP_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRING, addressBuffer}
});
}
ffStrbufDestroy(&key);
}
#define FF_LOCALIP_NUM_FORMAT_ARGS 2
void ffPrintLocalIp(FFinstance* instance)
{
struct ifaddrs* ifAddrStruct = NULL;
int ret = getifaddrs(&ifAddrStruct);
if (ret < 0) {
ffPrintError(instance, FF_LOCALIP_MODULE_NAME, 0, &instance->config.localIP, "getifaddrs(&ifAddrStruct) < 0 (%i)", ret);
return;
FFlist results;
ffListInit(&results, sizeof(FFLocalIpResult));
const char* error = ffDetectLocalIps(instance, &results);
if(error)
{
ffPrintError(instance, FF_LOCALIP_MODULE_NAME, 0, &instance->config.localIP, "%s", error);
goto exit;
}
for (struct ifaddrs* ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr)
continue;
if(results.length == 0)
{
ffPrintError(instance, FF_LOCALIP_MODULE_NAME, 0, &instance->config.localIP, "Failed to detect any IPs");
goto exit;
}
// loop back
if (strncmp(ifa->ifa_name, "lo", 2) == 0 && (ifa->ifa_name[2] == '\0' || isdigit(ifa->ifa_name[2])) && !instance->config.localIpShowLoop)
continue;
FFstrbuf key;
ffStrbufInit(&key);
if (instance->config.localIpNamePrefix.length && strncmp(ifa->ifa_name, instance->config.localIpNamePrefix.chars, instance->config.localIpNamePrefix.length) != 0)
continue;
for(uint32_t i = 0; i < results.length; ++i)
{
FFLocalIpResult* ip = (FFLocalIpResult*) ffListGet(&results, i);
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
// is a valid IP4 Address
if (!instance->config.localIpShowIpV4)
continue;
void* tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
printValue(instance, ifa->ifa_name, addressBuffer);
} else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
// is a valid IP6 Address
if (!instance->config.localIpShowIpV6)
continue;
void* tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
printValue(instance, ifa->ifa_name, addressBuffer);
if(instance->config.localIP.key.length == 0)
{
ffStrbufSetF(&key, FF_LOCALIP_MODULE_NAME " (%*s)", ip->name.length, ip->name.chars);
}
else
{
ffParseFormatString(&key, &instance->config.localIP.key, 1, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &ip->name}
});
}
if(instance->config.localIP.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, key.chars, 0, NULL);
ffStrbufPutTo(&ip->addr, stdout);
}
else
{
ffPrintFormatString(instance, key.chars, 0, NULL, &instance->config.localIP.outputFormat, FF_LOCALIP_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &ip->addr},
{FF_FORMAT_ARG_TYPE_STRING, ip->ipv6 ? "IPv6" : "IPv4"}
});
}
ffStrbufDestroy(&ip->name);
ffStrbufDestroy(&ip->addr);
}
if (ifAddrStruct) freeifaddrs(ifAddrStruct);
ffStrbufDestroy(&key);
exit:
ffListDestroy(&results);
}