-
Notifications
You must be signed in to change notification settings - Fork 2
/
net_adapter_win.c
145 lines (124 loc) · 5.93 KB
/
net_adapter_win.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <winsock2.h>
#include <ws2ipdef.h>
#include <windows.h>
#include <iptypes.h>
#include <iphlpapi.h>
#include "log.h"
#include "net_adapter.h"
#include "util.h"
#include "util_win.h"
bool net_adapter_enum(void *user_data, net_adapter_cb callback) {
IP_ADAPTER_ADDRESSES *adapter_addresses = NULL;
IP_ADAPTER_GATEWAY_ADDRESS *gateway_address = NULL;
IP_ADAPTER_UNICAST_ADDRESS *unicast_address = NULL;
IP_ADAPTER_DNS_SERVER_ADDRESS_XP *dns_address = NULL;
IP_ADAPTER_PREFIX *prefix = NULL;
ULONG buffer_size = 0;
ULONG required_size = 0;
ULONG error = 0;
net_adapter_s adapter = {0};
uint8_t *buffer = NULL;
if (!callback)
return false;
error = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS, 0, NULL, &buffer_size);
if (error != ERROR_SUCCESS && error != ERROR_BUFFER_OVERFLOW) {
LOG_ERROR("Unable to allocate memory for %s (%lu)\n", "adapter info", error);
return false;
}
buffer_size += 32; // Prevent GetAdaptersAddresses overflow by 1 byte
buffer = calloc(buffer_size, sizeof(uint8_t));
required_size = buffer_size;
error = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS, 0,
(IP_ADAPTER_ADDRESSES *)buffer, &required_size);
if (error != ERROR_SUCCESS) {
LOG_ERROR("Unable to get adapter info (%lu / %lu:%lu)\n", error, buffer_size, required_size);
goto net_adapter_cleanup;
}
// Enumerate each adapter returned by the operating system
for (adapter_addresses = (IP_ADAPTER_ADDRESSES *)buffer; adapter_addresses;
adapter_addresses = adapter_addresses->Next) {
// Ignore non-physical adapters
if (adapter_addresses->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
continue;
if (adapter_addresses->IfType != IF_TYPE_ETHERNET_CSMACD && adapter_addresses->IfType != IF_TYPE_IEEE80211)
continue;
memset(&adapter, 0, sizeof(adapter));
// Populate adapter address
adapter.mac_length = sizeof(adapter.mac);
if (adapter.mac_length > adapter_addresses->PhysicalAddressLength)
adapter.mac_length = (uint8_t)adapter_addresses->PhysicalAddressLength;
memcpy(adapter.mac, adapter_addresses->PhysicalAddress, adapter.mac_length);
// Populate connection state
if (adapter_addresses->OperStatus == IfOperStatusUp)
adapter.is_connected = true;
if (adapter_addresses->Flags & IP_ADAPTER_DHCP_ENABLED && adapter_addresses->Dhcpv4Enabled &&
adapter_addresses->Dhcpv4Server.iSockaddrLength >= (int32_t)sizeof(adapter.dhcp))
adapter.is_dhcp_v4 = true;
// Populate adapter name, guid, and description
char *friendly_name = wchar_dup_to_utf8(adapter_addresses->FriendlyName);
if (friendly_name)
strncat(adapter.name, friendly_name, sizeof(adapter.name) - 1);
free(friendly_name);
if (adapter_addresses->AdapterName)
strncat(adapter.guid, adapter_addresses->AdapterName, sizeof(adapter.guid) - 1);
char *description = wchar_dup_to_utf8(adapter_addresses->Description);
if (description)
strncat(adapter.description, description, sizeof(adapter.description) - 1);
free(description);
// Populate DHCPv4 server
if (adapter.is_dhcp_v4)
memcpy(adapter.dhcp, &adapter_addresses->Dhcpv4Server.lpSockaddr->sa_data[2], sizeof(adapter.dhcp));
// Populate adapter ip address
unicast_address = adapter_addresses->FirstUnicastAddress;
while (unicast_address) {
if (unicast_address->Address.lpSockaddr->sa_family == AF_INET) {
memcpy(adapter.ip, &unicast_address->Address.lpSockaddr->sa_data[2], sizeof(adapter.ip));
} else if (unicast_address->Address.lpSockaddr->sa_family == AF_INET6) {
struct sockaddr_in6 *sockaddr_ipv6 = (struct sockaddr_in6 *)unicast_address->Address.lpSockaddr;
memcpy(adapter.ipv6, &sockaddr_ipv6->sin6_addr, sizeof(adapter.ipv6));
adapter.is_ipv6 = true;
}
unicast_address = unicast_address->Next;
}
// Populate adapter netmask
prefix = adapter_addresses->FirstPrefix;
while (prefix) {
if (prefix->Address.lpSockaddr->sa_family == AF_INET) {
memcpy(adapter.netmask, &prefix->Address.lpSockaddr->sa_data[2], sizeof(adapter.netmask));
} else if (prefix->Address.lpSockaddr->sa_family == AF_INET6) {
struct sockaddr_in6 *sockaddr_ipv6 = (struct sockaddr_in6 *)prefix->Address.lpSockaddr;
memcpy(adapter.netmaskv6, &sockaddr_ipv6->sin6_addr, sizeof(adapter.netmaskv6));
adapter.is_ipv6 = true;
}
prefix = prefix->Next;
}
// Populate adapter dns servers
dns_address = adapter_addresses->FirstDnsServerAddress;
while (dns_address) {
if (*adapter.primary_dns == 0) {
memcpy(adapter.primary_dns, &dns_address->Address.lpSockaddr->sa_data[2], sizeof(adapter.primary_dns));
} else if (*adapter.secondary_dns == 0) {
memcpy(adapter.secondary_dns, &dns_address->Address.lpSockaddr->sa_data[2],
sizeof(adapter.secondary_dns));
}
dns_address = dns_address->Next;
}
// Populate adapter gateway
gateway_address = adapter_addresses->FirstGatewayAddress;
while (gateway_address) {
memcpy(adapter.gateway, &gateway_address->Address.lpSockaddr->sa_data[2], sizeof(adapter.gateway));
gateway_address = gateway_address->Next;
break;
}
if (!callback(user_data, &adapter))
break;
}
net_adapter_cleanup:
free(buffer);
return true;
}