49
#include <netinet/in.h>
50
#include <arpa/nameser.h>
59
* resolver(3) and IPv6:
61
* The ISC BIND resolver included various IPv6 implementations over time, but
62
* unfortunately the ISC hadn't bumped __RES accordingly. (__RES is -supposed-
63
* to behave as a version datestamp for the resolver interface.) Similarly
64
* the GNU C Library forked resolv.h and made modifications of their own, also
65
* without changing __RES.
67
* glibc 2.1.92 included a patch which provides IPv6 name server support by
68
* embedding in6_addr pointers in _res._u._ext. Since I only care about major
69
* and minor numbers, though, I'm going to condition this impl. on glibc 2.2.
71
* ISC, OTOH, provided accessing IPv6 servers via a res_getservers API.
72
* TTBOMK, this went public with BIND 8.3.0. Unfortunately __RES wasn't
73
* bumped for this release, so instead I'm going to assume that appearance with
74
* that release of a new macro, RES_F_DNS0ERR, implies this API is available.
75
* (For internal builds, we'll know instantly when a build breaks. The down-
76
* side is that this could cause some trouble for Open VM Tools users. ,_,)
78
* resolv.h version IPv6 API __RES
79
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80
* glibc 2.2+ _ext 19991006
81
* BIND 8.3.0 getservers 19991006
82
* BIND 8.3.4+ getservers 20030124(+?)
84
* To distinguish between the variants where __RES == 19991006, I'll
85
* discriminate on the existence of new macros included with the appropriate
90
# if __GLIBC_PREREQ(2,2)
91
# define RESOLVER_IPV6_EXT
92
# endif // __GLIBC_PREREQ(2,2)
93
#elif (__RES > 19991006 || (__RES == 19991006 && defined RES_F_EDNS0ERR))
94
# define RESOLVER_IPV6_GETSERVERS
95
#endif // if defined __GLIBC__
55
99
#include "sys/utsname.h"
56
100
#include "sys/ioctl.h"
101
*-----------------------------------------------------------------------------
103
* RecordNetworkAddress --
105
* Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores it
106
* as part of a GuestNic structure.
109
* If addr is IPv4 or IPv6, it will be appended to the GuestNic's list of
115
*-----------------------------------------------------------------------------
155
******************************************************************************
156
* GuestInfoGetNicInfo -- */ /**
158
* @copydoc GuestInfo_GetNicInfo
160
******************************************************************************
164
GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT
169
/* Get a handle to read the network interface configuration details. */
170
if ((intf = intf_open()) == NULL) {
171
Debug("GuestInfo: Error, failed NULL result from intf_open()\n");
175
if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) {
177
Debug("GuestInfo: Error, negative result from intf_loop\n");
183
if (!RecordResolverInfo(nicInfo)) {
187
if (!RecordRoutingInfo(nicInfo)) {
205
******************************************************************************
206
* RecordNetworkAddress -- */ /**
208
* @brief Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores
209
* it as part of a GuestNicV3 structure.
211
* @param[in] nic Operand NIC.
212
* @param[in] addr dnet(3) address.
214
******************************************************************************
119
RecordNetworkAddress(GuestNic *nic, // IN: operand NIC
218
RecordNetworkAddress(GuestNicV3 *nic, // IN: operand NIC
120
219
const struct addr *addr) // IN: dnet(3) address to process
122
char ipAddress[NICINFO_MAX_IP_LEN];
123
VmIpAddress *ip = NULL;
221
struct sockaddr_storage ss;
222
struct sockaddr *sa = (struct sockaddr *)&ss;
125
switch (addr->addr_type) {
128
* GuestNicInfo clients expect IPv4 addresses and netmasks to be stored
129
* as strings in separate fields. As such, we'll use ip_ntop instead of
130
* addr_ntop to get a string without the netmask bits.
132
ip_ntop(&addr->addr_ip, ipAddress, sizeof ipAddress);
133
ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV4);
135
GuestInfoAddSubnetMask(ip, addr->addr_bits, TRUE);
139
ip6_ntop(&addr->addr_ip6, ipAddress, sizeof ipAddress);
140
ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV6);
142
GuestInfoAddSubnetMask(ip, addr->addr_bits, FALSE);
146
Debug("%s: Unknown address type: %hu\n", __func__, addr->addr_type);
224
memset(&ss, 0, sizeof ss);
226
GuestInfoAddIpAddress(nic, sa, addr->addr_bits, NULL, NULL);
153
*-----------------------------------------------------------------------------
155
* ReadInterfaceDetails --
157
* Callback function called by libdnet when iterating over all the
161
* Returns 0 on success and -1 on failure.
162
* Adds the MAC addresses of all NICs and their corresponding IPs.
165
* Memory is allocated for each NIC, as well as IP addresses of all NICs
166
* on successful return.
168
*-----------------------------------------------------------------------------
231
******************************************************************************
232
* ReadInterfaceDetails -- */ /**
234
* @brief Callback function called by libdnet when iterating over all the NICs
237
* @param[in] entry Current interface entry.
238
* @param[in] arg Pointer to NicInfoV3 container.
240
* @note New GuestNicV3 structures are added to the NicInfoV3 structure.
243
* @retval -1 Failure.
245
******************************************************************************
172
249
ReadInterfaceDetails(const struct intf_entry *entry, // IN: current interface entry
173
250
void *arg) // IN: Pointer to the GuestNicList
176
GuestNicList *nicInfo = arg;
178
if ((entry->intf_type & INTF_TYPE_ETH) == INTF_TYPE_ETH) {
253
NicInfoV3 *nicInfo = arg;
258
if (entry->intf_type == INTF_TYPE_ETH) {
259
GuestNicV3 *nic = NULL;
180
260
char macAddress[NICINFO_MAC_LEN];
182
262
Str_Sprintf(macAddress, sizeof macAddress, "%s",
183
263
addr_ntoa(&entry->intf_link_addr));
184
nic = GuestInfoAddNicEntry(nicInfo, macAddress);
264
nic = GuestInfoAddNicEntry(nicInfo, macAddress, NULL, NULL);
265
ASSERT_MEM_ALLOC(nic);
190
267
/* Record the "primary" address. */
191
268
if (entry->intf_addr.addr_type == ADDR_TYPE_IP ||
212
*-----------------------------------------------------------------------------
214
* GuestInfoGetNicInfo --
216
* Return MAC addresses of all the NICs in the guest and their
217
* corresponding IP addresses.
220
* Returns TRUE on success and FALSE on failure.
221
* Return MAC addresses of all NICs and their corresponding IPs.
224
* Memory is allocated for each NIC, as well as IP addresses of all NICs
225
* on successful return.
227
*-----------------------------------------------------------------------------
288
******************************************************************************
289
* RecordResolverInfo -- */ /**
291
* @brief Query resolver(3), mapping settings to DnsConfigInfo.
293
* @param[out] nicInfo NicInfoV3 container.
295
* @retval TRUE Values collected, attached to @a nicInfo.
296
* @retval FALSE Something went wrong. @a nicInfo is unharmed.
298
******************************************************************************
231
GuestInfoGetNicInfo(GuestNicList *nicInfo) // OUT
302
RecordResolverInfo(NicInfoV3 *nicInfo) // OUT
236
memset(nicInfo, 0, sizeof *nicInfo);
238
/* Get a handle to read the network interface configuration details. */
239
if ((intf = intf_open()) == NULL) {
240
Debug("GuestInfo: Error, failed NULL result from intf_open()\n");
244
if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) {
246
Debug("GuestInfo: Error, negative result from intf_loop\n");
304
DnsConfigInfo *dnsConfigInfo = NULL;
305
char namebuf[DNSINFO_MAX_ADDRLEN + 1];
308
if (res_init() == -1) {
312
dnsConfigInfo = Util_SafeCalloc(1, sizeof *dnsConfigInfo);
315
* Copy in the host name.
317
if (!GuestInfoGetFqdn(sizeof namebuf, namebuf)) {
320
dnsConfigInfo->hostName =
321
Util_SafeCalloc(1, sizeof *dnsConfigInfo->hostName);
322
*dnsConfigInfo->hostName = Util_SafeStrdup(namebuf);
325
* Repeat with the domain name.
327
dnsConfigInfo->domainName =
328
Util_SafeCalloc(1, sizeof *dnsConfigInfo->domainName);
329
*dnsConfigInfo->domainName = Util_SafeStrdup(_res.defdname);
334
RecordResolverNS(dnsConfigInfo);
339
for (s = _res.dnsrch; *s; s++) {
340
DnsHostname *suffix = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, searchSuffixes, 1);
341
ASSERT_MEM_ALLOC(suffix);
342
*suffix = Util_SafeStrdup(*s);
346
* "Commit" dnsConfigInfo to nicInfo.
348
nicInfo->dnsConfigInfo = dnsConfigInfo;
353
VMX_XDR_FREE(xdr_DnsConfigInfo, dnsConfigInfo);
360
******************************************************************************
361
* RecordResolverNS -- */ /**
363
* @brief Copies name servers used by resolver(3) to @a dnsConfigInfo.
365
* @param[out] dnsConfigInfo Destination DnsConfigInfo container.
367
******************************************************************************
371
RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN
375
#if defined RESOLVER_IPV6_GETSERVERS
377
union res_sockaddr_union *ns;
378
ns = Util_SafeCalloc(_res.nscount, sizeof *ns);
379
if (res_getservers(&_res, ns, _res.nscount) != _res.nscount) {
380
Warning("%s: res_getservers failed.\n", __func__);
383
for (i = 0; i < _res.nscount; i++) {
384
struct sockaddr *sa = (struct sockaddr *)&ns[i];
385
if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
386
TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
387
ASSERT_MEM_ALLOC(ip);
388
GuestInfoSockaddrToTypedIpAddress(sa, ip);
392
#else // if defined RESOLVER_IPV6_GETSERVERS
395
* Name servers (IPv4).
397
for (i = 0; i < MAXNS; i++) {
398
struct sockaddr_in *sin = &_res.nsaddr_list[i];
399
if (sin->sin_family == AF_INET) {
400
TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
401
ASSERT_MEM_ALLOC(ip);
402
GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin, ip);
405
# if defined RESOLVER_IPV6_EXT
407
* Name servers (IPv6).
409
for (i = 0; i < MAXNS; i++) {
410
struct sockaddr_in6 *sin6 = _res._u._ext.nsaddrs[i];
412
TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
413
ASSERT_MEM_ALLOC(ip);
414
GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
417
# endif // if defined RESOLVER_IPV6_EXT
419
#endif // if !defined RESOLVER_IPV6_GETSERVERS
423
#ifdef USE_SLASH_PROC
425
******************************************************************************
426
* RecordRoutingInfoIPv4 -- */ /**
428
* @brief Query the IPv4 routing subsystem and pack up contents
429
* (struct rtentry) into InetCidrRouteEntries.
431
* @param[out] nicInfo NicInfoV3 container.
433
* @note Do not call this routine without first populating @a nicInfo 's NIC
436
* @retval TRUE Values collected, attached to @a nicInfo.
437
* @retval FALSE Something went wrong. @a nicInfo is unharmed.
439
******************************************************************************
443
RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
445
GPtrArray *routes = NULL;
449
if ((routes = SlashProcNet_GetRoute()) == NULL) {
453
for (i = 0; i < routes->len; i++) {
454
struct rtentry *rtentry;
455
struct sockaddr_in *sin_dst;
456
struct sockaddr_in *sin_gateway;
457
struct sockaddr_in *sin_genmask;
458
InetCidrRouteEntry *icre;
461
rtentry = g_ptr_array_index(routes, i);
463
if ((rtentry->rt_flags & RTF_UP) == 0 ||
464
!GuestInfoGetNicInfoIfIndex(nicInfo,
465
if_nametoindex(rtentry->rt_dev),
470
icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
471
ASSERT_MEM_ALLOC(icre);
473
sin_dst = (struct sockaddr_in *)&rtentry->rt_dst;
474
sin_gateway = (struct sockaddr_in *)&rtentry->rt_gateway;
475
sin_genmask = (struct sockaddr_in *)&rtentry->rt_genmask;
477
GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_dst,
478
&icre->inetCidrRouteDest);
480
addr_stob((struct sockaddr *)sin_genmask,
481
(uint16_t *)&icre->inetCidrRoutePfxLen);
484
* Gateways are optional (ex: one can bind a route to an interface w/o
485
* specifying a next hop address).
487
if (rtentry->rt_flags & RTF_GATEWAY) {
488
TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
489
GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_gateway, ip);
490
icre->inetCidrRouteNextHop = ip;
496
icre->inetCidrRouteIfIndex = ifIndex;
497
icre->inetCidrRouteMetric = rtentry->rt_metric;
502
SlashProcNet_FreeRoute(routes);
508
******************************************************************************
509
* RecordRoutingInfoIPv6 -- */ /**
511
* @brief Query the IPv6 routing subsystem and pack up contents
512
* (struct in6_rtmsg) into InetCidrRouteEntries.
514
* @param[out] nicInfo NicInfoV3 container.
516
* @note Do not call this routine without first populating @a nicInfo 's NIC
519
* @retval TRUE Values collected, attached to @a nicInfo.
520
* @retval FALSE Something went wrong. @a nicInfo is unharmed.
522
******************************************************************************
526
RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
528
GPtrArray *routes = NULL;
532
if ((routes = SlashProcNet_GetRoute6()) == NULL) {
536
for (i = 0; i < routes->len; i++) {
537
struct sockaddr_storage ss;
538
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
539
struct in6_rtmsg *in6_rtmsg;
540
InetCidrRouteEntry *icre;
541
uint32_t ifIndex = -1;
543
in6_rtmsg = g_ptr_array_index(routes, i);
545
if ((in6_rtmsg->rtmsg_flags & RTF_UP) == 0 ||
546
!GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex,
551
icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
552
ASSERT_MEM_ALLOC(icre);
557
sin6->sin6_family = AF_INET6;
558
sin6->sin6_addr = in6_rtmsg->rtmsg_dst;
559
GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6,
560
&icre->inetCidrRouteDest);
562
icre->inetCidrRoutePfxLen = in6_rtmsg->rtmsg_dst_len;
567
if (in6_rtmsg->rtmsg_flags & RTF_GATEWAY) {
568
TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
569
sin6->sin6_addr = in6_rtmsg->rtmsg_gateway;
570
GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
571
icre->inetCidrRouteNextHop = ip;
577
icre->inetCidrRouteIfIndex = ifIndex;
578
icre->inetCidrRouteMetric = in6_rtmsg->rtmsg_metric;
583
SlashProcNet_FreeRoute6(routes);
589
******************************************************************************
590
* RecordRoutingInfo -- */ /**
592
* @brief Query the routing subsystem and pack up contents into
593
* InetCidrRouteEntries.
595
* @param[out] nicInfo NicInfoV3 container.
597
* @note Do not call this routine without first populating @a nicInfo 's NIC
600
* @retval TRUE Values collected, attached to @a nicInfo.
601
* @retval FALSE Something went wrong.
603
******************************************************************************
607
RecordRoutingInfo(NicInfoV3 *nicInfo)
611
if (File_Exists("/proc/net/route") && !RecordRoutingInfoIPv4(nicInfo)) {
612
Warning("%s: Unable to collect IPv4 routing table.\n", __func__);
616
if (File_Exists("/proc/net/ipv6_route") && !RecordRoutingInfoIPv6(nicInfo)) {
617
Warning("%s: Unable to collect IPv6 routing table.\n", __func__);
624
#else // ifdef USE_SLASH_PROC
626
RecordRoutingInfo(NicInfoV3 *nicInfo)
632
#endif // ifndef NO_DNET