diff --git a/CMakeLists.txt b/CMakeLists.txt index 90f071fca..96712e4c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/src/detection/localip/localip.h b/src/detection/localip/localip.h new file mode 100644 index 000000000..ef16da50f --- /dev/null +++ b/src/detection/localip/localip.h @@ -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 diff --git a/src/detection/localip/localip_linux.c b/src/detection/localip/localip_linux.c new file mode 100644 index 000000000..b38958b19 --- /dev/null +++ b/src/detection/localip/localip_linux.c @@ -0,0 +1,66 @@ +#include "localip.h" + +#include +#include +#include +#include +#include +#include + +#ifdef __FreeBSD__ + #include // 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; +} diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c new file mode 100644 index 000000000..881dd2d6e --- /dev/null +++ b/src/detection/localip/localip_windows.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#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; +} diff --git a/src/modules/localip.c b/src/modules/localip.c index 9308d246a..07508f3bd 100644 --- a/src/modules/localip.c +++ b/src/modules/localip.c @@ -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 -#include -#include -#include -#include - -#ifdef __FreeBSD__ - #include // 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); }