mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
440 lines
13 KiB
C
440 lines
13 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2024 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
│ │
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/assert.h"
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/calls/internal.h"
|
|
#include "libc/calls/syscall-sysv.internal.h"
|
|
#include "libc/dce.h"
|
|
#include "libc/log/check.h"
|
|
#include "libc/log/log.h"
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/nt/enum/formatmessageflags.h"
|
|
#include "libc/nt/enum/lang.h"
|
|
#include "libc/nt/errors.h"
|
|
#include "libc/nt/iphlpapi.h"
|
|
#include "libc/nt/memory.h"
|
|
#include "libc/nt/process.h"
|
|
#include "libc/nt/struct/ipadapteraddresses.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/serialize.h"
|
|
#include "libc/sock/sock.h"
|
|
#include "libc/sock/struct/sockaddr6.h"
|
|
#include "libc/stdalign.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/sysv/consts/af.h"
|
|
#include "libc/sysv/consts/ipproto.h"
|
|
#include "libc/sysv/consts/sio.h"
|
|
#include "libc/sysv/consts/sock.h"
|
|
|
|
/**
|
|
* @fileoverview prints detailed network interface info on windows
|
|
*/
|
|
|
|
const char *DescribeIfType(int x) {
|
|
switch (x) {
|
|
case kNtIfTypeOther:
|
|
return "OTHER";
|
|
case kNtIfTypeEthernetCsmacd:
|
|
return "ETHERNET";
|
|
case kNtIfTypeIso88025Tokenring:
|
|
return "TOKENRING";
|
|
case kNtIfTypePpp:
|
|
return "PPP";
|
|
case kNtIfTypeSoftwareLoopback:
|
|
return "LOOPBACK";
|
|
case kNtIfTypeAtm:
|
|
return "ATM";
|
|
case kNtIfTypeIeee80211:
|
|
return "WIFI";
|
|
case kNtIfTypeTunnel:
|
|
return "TUNNEL";
|
|
case kNtIfTypeIeee1394:
|
|
return "FIREWIRE";
|
|
default:
|
|
return "WUT";
|
|
}
|
|
}
|
|
|
|
const char *DescribeTunnelType(int x) {
|
|
switch (x) {
|
|
case kNtTunnelTypeNone:
|
|
return "NONE";
|
|
case kNtTunnelTypeOther:
|
|
return "OTHER";
|
|
case kNtTunnelTypeDirect:
|
|
return "DIRECT";
|
|
case kNtTunnelType6to4:
|
|
return "6TO4";
|
|
case kNtTunnelTypeIsatap:
|
|
return "ISATAP";
|
|
case kNtTunnelTypeTeredo:
|
|
return "TEREDO";
|
|
case kNtTunnelTypeIphttps:
|
|
return "IPHTTPS";
|
|
default:
|
|
return "WUT";
|
|
}
|
|
}
|
|
|
|
const char *DescribeOperStatus(int x) {
|
|
switch (x) {
|
|
case kNtIfOperStatusUp:
|
|
return "UP";
|
|
case kNtIfOperStatusDown:
|
|
return "DOWN";
|
|
case kNtIfOperStatusTesting:
|
|
return "TESTING";
|
|
case kNtIfOperStatusUnknown:
|
|
return "UNKNOWN";
|
|
case kNtIfOperStatusDormant:
|
|
return "DORMANT";
|
|
case kNtIfOperStatusNotPresent:
|
|
return "NOTPRESENT";
|
|
case kNtIfOperStatusLowerLayerDown:
|
|
return "LOWERLAYERDOWN";
|
|
default:
|
|
return "WUT";
|
|
}
|
|
}
|
|
|
|
const char *DescribeDadState(int x) {
|
|
switch (x) {
|
|
case kNtIpDadStateInvalid:
|
|
return "INVALID";
|
|
case kNtIpDadStateTentative:
|
|
return "TENTATIVE";
|
|
case kNtIpDadStateDuplicate:
|
|
return "DUPLICATE";
|
|
case kNtIpDadStateDeprecated:
|
|
return "DEPRECATED";
|
|
case kNtIpDadStatePreferred:
|
|
return "PREFERRED";
|
|
default:
|
|
return "WUT";
|
|
}
|
|
}
|
|
|
|
const char *DescribeSuffixOrigin(int x) {
|
|
switch (x) {
|
|
case kNtIpPrefixOriginOther:
|
|
return "OTHER";
|
|
case kNtIpPrefixOriginManual:
|
|
return "MANUAL";
|
|
case kNtIpPrefixOriginWellKnown:
|
|
return "WELLKNOWN";
|
|
case kNtIpPrefixOriginDhcp:
|
|
return "DHCP";
|
|
case kNtIpPrefixOriginRouterAdvertisement:
|
|
return "ROUTERADVERTISEMENT";
|
|
case kNtIpPrefixOriginUnchanged:
|
|
return "UNCHANGED";
|
|
default:
|
|
return "WUT";
|
|
}
|
|
}
|
|
|
|
const char *DescribePrefixOrigin(int x) {
|
|
switch (x) {
|
|
case kNtIpPrefixOriginOther:
|
|
return "OTHER";
|
|
case kNtIpPrefixOriginManual:
|
|
return "MANUAL";
|
|
case kNtIpPrefixOriginWellKnown:
|
|
return "WELLKNOWN";
|
|
case kNtIpPrefixOriginDhcp:
|
|
return "DHCP";
|
|
case kNtIpPrefixOriginRouterAdvertisement:
|
|
return "ROUTERADVERTISEMENT";
|
|
case kNtIpPrefixOriginUnchanged:
|
|
return "UNCHANGED";
|
|
default:
|
|
return "WUT";
|
|
}
|
|
}
|
|
|
|
const char *DescribeIpAdapterFlags(int x) {
|
|
char *p;
|
|
static char buf[256];
|
|
p = buf;
|
|
if (x & kNtIpAdapterDdnsEnabled) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "DDNS");
|
|
}
|
|
if (x & kNtIpAdapterDhcpv4Enabled) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "DHCPv4");
|
|
}
|
|
if (x & kNtIpAdapterReceiveOnly) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "RECV_ONLY");
|
|
}
|
|
if (x & kNtIpAdapterNoMulticast) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "NO_MULTICAST");
|
|
}
|
|
if (x & kNtIpAdapterIpv4Enabled) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "IPv4");
|
|
}
|
|
if (x & kNtIpAdapterIpv6Enabled) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "IPv6");
|
|
}
|
|
if (x & kNtIpAdapterIpv6Managed) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "IPv6_MANAGED");
|
|
}
|
|
if (x & kNtIpAdapterIpv6OtherStatefulConfig) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "IPv6_OTHER_STATEFUL_CONFIG");
|
|
}
|
|
if (x & kNtIpAdapterNetbiosOverTcpipEnabled) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "NETBIOS_OVER_TCP");
|
|
}
|
|
if (x & kNtIpAdapterRegisterAdapterSuffix) {
|
|
if (p > buf)
|
|
*p++ = ' ';
|
|
p = stpcpy(p, "REGISTER_ADAPTER_SUFFIX");
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
char *ConvertIpv6ToStr(const struct in6_addr *addr) {
|
|
char *p;
|
|
int i, t, a, b, c, d;
|
|
static char buf[16 * 4 + 8];
|
|
t = 0;
|
|
i = 0;
|
|
p = buf;
|
|
for (i = 0; i < 16; i += 2) {
|
|
switch (t) {
|
|
case 0:
|
|
if (!addr->s6_addr[i] && !addr->s6_addr[i + 1]) {
|
|
t = 1;
|
|
*p++ = ':';
|
|
*p++ = ':';
|
|
continue;
|
|
} else if (i) {
|
|
*p++ = ':';
|
|
}
|
|
break;
|
|
case 1:
|
|
if (!addr->s6_addr[i] && !addr->s6_addr[i + 1]) {
|
|
continue;
|
|
} else {
|
|
t = 2;
|
|
}
|
|
break;
|
|
case 2:
|
|
*p++ = ':';
|
|
break;
|
|
default:
|
|
__builtin_unreachable();
|
|
}
|
|
a = (addr->s6_addr[i + 0] & 0xF0) >> 4;
|
|
b = (addr->s6_addr[i + 0] & 0x0F) >> 0;
|
|
c = (addr->s6_addr[i + 1] & 0xF0) >> 4;
|
|
d = (addr->s6_addr[i + 1] & 0x0F) >> 0;
|
|
if (a)
|
|
*p++ = "0123456789abcdef"[a];
|
|
if (a || b)
|
|
*p++ = "0123456789abcdef"[b];
|
|
if (a || b || c)
|
|
*p++ = "0123456789abcdef"[c];
|
|
*p++ = "0123456789abcdef"[d];
|
|
}
|
|
*p = '\0';
|
|
return buf;
|
|
}
|
|
|
|
void PrintSockAddr(struct sockaddr *addr) {
|
|
if (addr->sa_family == AF_INET) {
|
|
printf("%s", inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
|
|
} else if (addr->sa_family == AF_INET6) {
|
|
printf("%s", ConvertIpv6ToStr(&((struct sockaddr_in6 *)addr)->sin6_addr));
|
|
} else {
|
|
printf("[UNKNOWN FAMILY: %d]", addr->sa_family);
|
|
}
|
|
}
|
|
|
|
void ShowWinNicCidrs(void) {
|
|
// uint32_t dwSize = 0;
|
|
uint32_t dwRetVal = 0;
|
|
unsigned int i = 0;
|
|
// default to unspecified address family (both)
|
|
uint32_t family = AF_UNSPEC;
|
|
void *lpMsgBuf = NULL;
|
|
struct NtIpAdapterAddresses *pAddresses = NULL;
|
|
uint32_t outBufLen = 0;
|
|
uint32_t Iterations = 0;
|
|
struct NtIpAdapterAddresses *p = NULL;
|
|
struct NtIpAdapterUnicastAddress *pu = NULL;
|
|
struct NtIpAdapterAnycastAddress *pa = NULL;
|
|
struct NtIpAdapterMulticastAddress *pm = NULL;
|
|
struct NtIpAdapterDnsServerAddress *pd = NULL;
|
|
struct NtIpAdapterGatewayAddress *pg = NULL;
|
|
struct NtIpAdapterWinsServerAddress *pw = NULL;
|
|
struct NtIpAdapterPrefix *pp = NULL;
|
|
outBufLen = 15000;
|
|
|
|
do {
|
|
pAddresses = malloc(outBufLen);
|
|
if (pAddresses == NULL) {
|
|
printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
|
|
exit(1);
|
|
}
|
|
dwRetVal = GetAdaptersAddresses(
|
|
family,
|
|
kNtGaaFlagIncludePrefix | kNtGaaFlagIncludeWinsInfo |
|
|
kNtGaaFlagIncludeGateways | kNtGaaFlagIncludeAllInterfaces,
|
|
NULL, pAddresses, &outBufLen);
|
|
if (dwRetVal == kNtErrorBufferOverflow) {
|
|
free(pAddresses);
|
|
pAddresses = NULL;
|
|
} else {
|
|
break;
|
|
}
|
|
Iterations++;
|
|
} while ((dwRetVal == kNtErrorBufferOverflow) && (Iterations < 3));
|
|
|
|
if (dwRetVal == kNtNoError) {
|
|
for (p = pAddresses; p; p = p->Next) {
|
|
/* if (p->OperStatus != kNtIfOperStatusUp) continue; */
|
|
|
|
printf("\t%s %s %s\n", DescribeOperStatus(p->OperStatus),
|
|
DescribeIfType(p->IfType), p->AdapterName);
|
|
printf("\t%hs (%hs)\n", p->Description, p->FriendlyName);
|
|
|
|
if (p->PhysicalAddressLength != 0) {
|
|
printf("\tPhysical address: ");
|
|
for (i = 0; i < (int)p->PhysicalAddressLength; i++) {
|
|
if (i == (p->PhysicalAddressLength - 1))
|
|
printf("%.2X\n", (int)p->PhysicalAddress[i]);
|
|
else
|
|
printf("%.2X-", (int)p->PhysicalAddress[i]);
|
|
}
|
|
}
|
|
|
|
for (pu = p->FirstUnicastAddress; pu; pu = pu->Next) {
|
|
printf("\tAddress: ");
|
|
PrintSockAddr(pu->Address.lpSockaddr);
|
|
printf("/%d %s %s %s VALID:%u PREFERRED:%u LEASE:%u",
|
|
pu->OnLinkPrefixLength,
|
|
inet_ntoa((struct in_addr){
|
|
htonl((uint32_t)-1 << (32 - pu->OnLinkPrefixLength))}),
|
|
DescribePrefixOrigin(pu->PrefixOrigin),
|
|
DescribeSuffixOrigin(pu->SuffixOrigin),
|
|
DescribeDadState(pu->DadState), pu->ValidLifetime,
|
|
pu->PreferredLifetime);
|
|
printf("\n");
|
|
}
|
|
|
|
for (pg = p->FirstGatewayAddress; pg; pg = pg->Next) {
|
|
printf("\tGateway: ");
|
|
PrintSockAddr(pg->Address.lpSockaddr);
|
|
printf("\n");
|
|
}
|
|
|
|
for (pd = p->FirstDnsServerAddress; pd; pd = pd->Next) {
|
|
printf("\tDNS Server: ");
|
|
PrintSockAddr(pd->Address.lpSockaddr);
|
|
printf("\n");
|
|
}
|
|
if (p->DnsSuffix && p->DnsSuffix[0]) {
|
|
printf("\tDNS Suffix: %hs\n", p->DnsSuffix);
|
|
}
|
|
|
|
for (pp = p->FirstPrefix; pp; pp = pp->Next) {
|
|
printf("\tRoute: ");
|
|
PrintSockAddr(pp->Address.lpSockaddr);
|
|
printf("/%d", pp->PrefixLength);
|
|
printf("\n");
|
|
}
|
|
|
|
for (pm = p->FirstMulticastAddress; pm; pm = pm->Next) {
|
|
printf("\tMulticast: ");
|
|
PrintSockAddr(pm->Address.lpSockaddr);
|
|
printf("\n");
|
|
}
|
|
|
|
for (pa = p->FirstAnycastAddress; pa; pa = pa->Next) {
|
|
printf("\tAnycast: ");
|
|
PrintSockAddr(pa->Address.lpSockaddr);
|
|
printf("\n");
|
|
}
|
|
|
|
for (pw = p->FirstWinsServerAddress; pw; pw = pw->Next) {
|
|
printf("\tWINS: ");
|
|
PrintSockAddr(pw->Address.lpSockaddr);
|
|
printf("\n");
|
|
}
|
|
|
|
if (p->TunnelType) {
|
|
printf("\tTunnel Type: %s\n", DescribeTunnelType(p->TunnelType));
|
|
}
|
|
|
|
printf("\tFlags: %ld %s\n", p->Flags, DescribeIpAdapterFlags(p->Flags));
|
|
printf("\tMTU: %lu\n", p->Mtu);
|
|
printf("\tTx Speed: %,lu\n", p->TransmitLinkSpeed);
|
|
printf("\tRx Speed: %,lu\n", p->ReceiveLinkSpeed);
|
|
printf("\n");
|
|
}
|
|
} else {
|
|
printf("Call to GetAdaptersAddresses failed with error: %d\n", dwRetVal);
|
|
if (dwRetVal == kNtErrorNoData)
|
|
printf("\tNo addresses were found for the requested parameters\n");
|
|
else {
|
|
if (FormatMessage(
|
|
kNtFormatMessageAllocateBuffer | kNtFormatMessageFromSystem |
|
|
kNtFormatMessageIgnoreInserts,
|
|
NULL, dwRetVal, MAKELANGID(kNtLangNeutral, kNtSublangDefault),
|
|
// Default language
|
|
(char16_t *)&lpMsgBuf, 0, NULL)) {
|
|
printf("\tError: %s", lpMsgBuf);
|
|
LocalFree(lpMsgBuf);
|
|
if (pAddresses)
|
|
free(pAddresses);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
if (pAddresses) {
|
|
free(pAddresses);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
if (!IsWindows()) {
|
|
fprintf(stderr, "error: this tool is intended for windows\n");
|
|
return 1;
|
|
}
|
|
ShowWinNicCidrs();
|
|
return 0;
|
|
}
|