~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to services/plugins/guestInfo/getlib/guestInfoPosix.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2005 VMware, Inc. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License as published
 
6
 * by the Free Software Foundation version 2.1 and no later version.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
10
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
 
11
 * License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/**
 
20
 * @file guestInfoPosix.c
 
21
 *
 
22
 * Contains POSIX-specific bits of GuestInfo collector library.
 
23
 */
 
24
 
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <fcntl.h>
 
29
#ifdef sun
 
30
# include <sys/systeminfo.h>
 
31
#endif
 
32
#include <unistd.h>
 
33
#include <sys/types.h>
 
34
#include <sys/socket.h>
 
35
#include <sys/stat.h>
 
36
#include <errno.h>
 
37
#if defined(__FreeBSD__) || defined(__APPLE__)
 
38
# include <sys/sysctl.h>
 
39
#endif
 
40
#ifndef NO_DNET
 
41
# ifdef DNET_IS_DUMBNET
 
42
#  include <dumbnet.h>
 
43
# else
 
44
#  include <dnet.h>
 
45
# endif
 
46
#endif
 
47
 
 
48
#include <netinet/in.h>
 
49
#include <arpa/nameser.h>
 
50
#include <resolv.h>
 
51
 
 
52
#ifdef __linux__
 
53
#   include <net/if.h>
 
54
#endif
 
55
 
 
56
 
 
57
/*
 
58
 * resolver(3) and IPv6:
 
59
 *
 
60
 * The ISC BIND resolver included various IPv6 implementations over time, but
 
61
 * unfortunately the ISC hadn't bumped __RES accordingly.  (__RES is -supposed-
 
62
 * to behave as a version datestamp for the resolver interface.)  Similarly
 
63
 * the GNU C Library forked resolv.h and made modifications of their own, also
 
64
 * without changing __RES.
 
65
 *
 
66
 * glibc 2.1.92 included a patch which provides IPv6 name server support by
 
67
 * embedding in6_addr pointers in _res._u._ext.  Since I only care about major
 
68
 * and minor numbers, though, I'm going to condition this impl. on glibc 2.2.
 
69
 *
 
70
 * ISC, OTOH, provided accessing IPv6 servers via a res_getservers API.
 
71
 * TTBOMK, this went public with BIND 8.3.0.  Unfortunately __RES wasn't
 
72
 * bumped for this release, so instead I'm going to assume that appearance with
 
73
 * that release of a new macro, RES_F_DNS0ERR, implies this API is available.
 
74
 * (For internal builds, we'll know instantly when a build breaks.  The down-
 
75
 * side is that this could cause some trouble for Open VM Tools users. ,_,)
 
76
 *
 
77
 * resolv.h version     IPv6 API        __RES
 
78
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
79
 * glibc 2.2+           _ext            19991006
 
80
 * BIND 8.3.0           getservers      19991006
 
81
 * BIND 8.3.4+          getservers      20030124(+?)
 
82
 *
 
83
 * To distinguish between the variants where __RES == 19991006, I'll
 
84
 * discriminate on the existence of new macros included with the appropriate
 
85
 * version.
 
86
 */
 
87
 
 
88
#if defined __GLIBC__
 
89
#   if __GLIBC_PREREQ(2,2)
 
90
#      define      RESOLVER_IPV6_EXT
 
91
#   endif // __GLIBC_PREREQ(2,2)
 
92
#elif (__RES > 19991006 || (__RES == 19991006 && defined RES_F_EDNS0ERR))
 
93
#   define      RESOLVER_IPV6_GETSERVERS
 
94
#endif // if defined __GLIBC__
 
95
 
 
96
 
 
97
#include "util.h"
 
98
#include "sys/utsname.h"
 
99
#include "sys/ioctl.h"
 
100
#include "vmware.h"
 
101
#include "hostinfo.h"
 
102
#include "getlibInt.h"
 
103
#include "debug.h"
 
104
#include "str.h"
 
105
#include "guest_os.h"
 
106
#include "guestApp.h"
 
107
#include "guestInfo.h"
 
108
#include "xdrutil.h"
 
109
#ifdef USE_SLASH_PROC
 
110
#   include "slashProc.h"
 
111
#endif
 
112
#include "netutil.h"
 
113
#include "file.h"
 
114
 
 
115
 
 
116
/*
 
117
 * Local functions
 
118
 */
 
119
 
 
120
 
 
121
#ifndef NO_DNET
 
122
static void RecordNetworkAddress(GuestNicV3 *nic, const struct addr *addr);
 
123
static int ReadInterfaceDetails(const struct intf_entry *entry, void *arg);
 
124
static Bool RecordResolverInfo(NicInfoV3 *nicInfo);
 
125
static void RecordResolverNS(DnsConfigInfo *dnsConfigInfo);
 
126
static Bool RecordRoutingInfo(NicInfoV3 *nicInfo);
 
127
#endif
 
128
 
 
129
 
 
130
/*
 
131
 ******************************************************************************
 
132
 * GuestInfoGetFqdn --                                                   */ /**
 
133
 *
 
134
 * @copydoc GuestInfo_GetFqdn
 
135
 *
 
136
 ******************************************************************************
 
137
 */
 
138
 
 
139
Bool
 
140
GuestInfoGetFqdn(int outBufLen,    // IN: length of output buffer
 
141
                 char fqdn[])      // OUT: fully qualified domain name
 
142
{
 
143
   ASSERT(fqdn);
 
144
   if (gethostname(fqdn, outBufLen) < 0) {
 
145
      g_debug("Error, gethostname failed\n");
 
146
      return FALSE;
 
147
   }
 
148
 
 
149
   return TRUE;
 
150
}
 
151
 
 
152
 
 
153
/*
 
154
 ******************************************************************************
 
155
 * GuestInfoGetNicInfo --                                                */ /**
 
156
 *
 
157
 * @copydoc GuestInfo_GetNicInfo
 
158
 *
 
159
 ******************************************************************************
 
160
 */
 
161
 
 
162
Bool
 
163
GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT
 
164
{
 
165
#ifndef NO_DNET
 
166
   intf_t *intf;
 
167
 
 
168
   /* Get a handle to read the network interface configuration details. */
 
169
   if ((intf = intf_open()) == NULL) {
 
170
      g_debug("Error, failed NULL result from intf_open()\n");
 
171
      return FALSE;
 
172
   }
 
173
 
 
174
   if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) {
 
175
      intf_close(intf);
 
176
      g_debug("Error, negative result from intf_loop\n");
 
177
      return FALSE;
 
178
   }
 
179
 
 
180
   intf_close(intf);
 
181
 
 
182
   if (!RecordResolverInfo(nicInfo)) {
 
183
      return FALSE;
 
184
   }
 
185
 
 
186
   if (!RecordRoutingInfo(nicInfo)) {
 
187
      return FALSE;
 
188
   }
 
189
 
 
190
   return TRUE;
 
191
#else
 
192
   return FALSE;
 
193
#endif
 
194
}
 
195
 
 
196
 
 
197
/*
 
198
 ******************************************************************************
 
199
 * GuestInfo_GetDiskInfo --                                              */ /**
 
200
 *
 
201
 * Uses wiper library to enumerate fixed volumes and lookup utilization data.
 
202
 *
 
203
 * @return Pointer to a GuestDiskInfo structure on success or NULL on failure.
 
204
 *         Caller should free returned pointer with GuestInfoFreeDiskInfo.
 
205
 *
 
206
 ******************************************************************************
 
207
 */
 
208
 
 
209
GuestDiskInfo *
 
210
GuestInfo_GetDiskInfo(void)
 
211
{
 
212
   return GuestInfoGetDiskInfoWiper();
 
213
}
 
214
 
 
215
 
 
216
/*
 
217
 * Local functions
 
218
 */
 
219
 
 
220
 
 
221
#ifndef NO_DNET
 
222
/*
 
223
 ******************************************************************************
 
224
 * RecordNetworkAddress --                                               */ /**
 
225
 *
 
226
 * @brief Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores
 
227
 *        it as part of a GuestNicV3 structure.
 
228
 *
 
229
 * @param[in]  nic      Operand NIC.
 
230
 * @param[in]  addr     dnet(3) address.
 
231
 *
 
232
 ******************************************************************************
 
233
 */
 
234
 
 
235
static void
 
236
RecordNetworkAddress(GuestNicV3 *nic,           // IN: operand NIC
 
237
                     const struct addr *addr)   // IN: dnet(3) address to process
 
238
{
 
239
   struct sockaddr_storage ss;
 
240
   struct sockaddr *sa = (struct sockaddr *)&ss;
 
241
 
 
242
   memset(&ss, 0, sizeof ss);
 
243
   addr_ntos(addr, sa);
 
244
   GuestInfoAddIpAddress(nic, sa, addr->addr_bits, NULL, NULL);
 
245
}
 
246
 
 
247
 
 
248
/*
 
249
 ******************************************************************************
 
250
 * ReadInterfaceDetails --                                               */ /**
 
251
 *
 
252
 * @brief Callback function called by libdnet when iterating over all the NICs
 
253
 * on the host.
 
254
 *
 
255
 * @param[in]  entry    Current interface entry.
 
256
 * @param[in]  arg      Pointer to NicInfoV3 container.
 
257
 *
 
258
 * @note New GuestNicV3 structures are added to the NicInfoV3 structure.
 
259
 *
 
260
 * @retval 0    Success.
 
261
 * @retval -1   Failure.
 
262
 *
 
263
 ******************************************************************************
 
264
 */
 
265
 
 
266
static int
 
267
ReadInterfaceDetails(const struct intf_entry *entry,  // IN: current interface entry
 
268
                     void *arg)                       // IN: Pointer to the GuestNicList
 
269
{
 
270
   int i;
 
271
   NicInfoV3 *nicInfo = arg;
 
272
 
 
273
   ASSERT(entry);
 
274
   ASSERT(arg);
 
275
 
 
276
   if (entry->intf_type == INTF_TYPE_ETH &&
 
277
       entry->intf_link_addr.addr_type == ADDR_TYPE_ETH) {
 
278
      GuestNicV3 *nic = NULL;
 
279
      char macAddress[NICINFO_MAC_LEN];
 
280
 
 
281
      /*
 
282
       * There is a race where the guest info plugin might be iterating over the
 
283
       * interfaces while the OS is modifying them (i.e. by bringing them up
 
284
       * after a resume). If we see an ethernet interface with an invalid MAC,
 
285
       * then ignore it for now. Subsequent iterations of the gather loop will
 
286
       * pick up any changes.
 
287
       */
 
288
      if (entry->intf_link_addr.addr_type == ADDR_TYPE_ETH) {
 
289
         Str_Sprintf(macAddress, sizeof macAddress, "%s",
 
290
                     addr_ntoa(&entry->intf_link_addr));
 
291
         nic = GuestInfoAddNicEntry(nicInfo, macAddress, NULL, NULL);
 
292
         ASSERT_MEM_ALLOC(nic);
 
293
 
 
294
         /* Record the "primary" address. */
 
295
         if (entry->intf_addr.addr_type == ADDR_TYPE_IP ||
 
296
             entry->intf_addr.addr_type == ADDR_TYPE_IP6) {
 
297
            RecordNetworkAddress(nic, &entry->intf_addr);
 
298
         }
 
299
 
 
300
         /* Walk the list of alias's and add those that are IPV4 or IPV6 */
 
301
         for (i = 0; i < entry->intf_alias_num; i++) {
 
302
            const struct addr *alias = &entry->intf_alias_addrs[i];
 
303
            if (alias->addr_type == ADDR_TYPE_IP ||
 
304
                alias->addr_type == ADDR_TYPE_IP6) {
 
305
               RecordNetworkAddress(nic, alias);
 
306
            }
 
307
         }
 
308
      }
 
309
   }
 
310
 
 
311
   return 0;
 
312
}
 
313
 
 
314
 
 
315
/*
 
316
 ******************************************************************************
 
317
 * RecordResolverInfo --                                                 */ /**
 
318
 *
 
319
 * @brief Query resolver(3), mapping settings to DnsConfigInfo.
 
320
 *
 
321
 * @param[out] nicInfo  NicInfoV3 container.
 
322
 *
 
323
 * @retval TRUE         Values collected, attached to @a nicInfo.
 
324
 * @retval FALSE        Something went wrong.  @a nicInfo is unharmed.
 
325
 *
 
326
 ******************************************************************************
 
327
 */
 
328
 
 
329
static Bool
 
330
RecordResolverInfo(NicInfoV3 *nicInfo)  // OUT
 
331
{
 
332
   DnsConfigInfo *dnsConfigInfo = NULL;
 
333
   char namebuf[DNSINFO_MAX_ADDRLEN + 1];
 
334
   char **s;
 
335
 
 
336
   if (res_init() == -1) {
 
337
      return FALSE;
 
338
   }
 
339
 
 
340
   dnsConfigInfo = Util_SafeCalloc(1, sizeof *dnsConfigInfo);
 
341
 
 
342
   /*
 
343
    * Copy in the host name.
 
344
    */
 
345
   if (!GuestInfoGetFqdn(sizeof namebuf, namebuf)) {
 
346
      goto fail;
 
347
   }
 
348
   dnsConfigInfo->hostName =
 
349
      Util_SafeCalloc(1, sizeof *dnsConfigInfo->hostName);
 
350
   *dnsConfigInfo->hostName = Util_SafeStrdup(namebuf);
 
351
 
 
352
   /*
 
353
    * Repeat with the domain name.
 
354
    */
 
355
   dnsConfigInfo->domainName =
 
356
      Util_SafeCalloc(1, sizeof *dnsConfigInfo->domainName);
 
357
   *dnsConfigInfo->domainName = Util_SafeStrdup(_res.defdname);
 
358
 
 
359
   /*
 
360
    * Name servers.
 
361
    */
 
362
   RecordResolverNS(dnsConfigInfo);
 
363
 
 
364
   /*
 
365
    * Search suffixes.
 
366
    */
 
367
   for (s = _res.dnsrch; *s; s++) {
 
368
      DnsHostname *suffix;
 
369
 
 
370
      /* Check to see if we're going above our limit. See bug 605821. */
 
371
      if (dnsConfigInfo->searchSuffixes.searchSuffixes_len == DNSINFO_MAX_SUFFIXES) {
 
372
         g_message("%s: dns search suffix limit (%d) reached, skipping overflow.",
 
373
                   __FUNCTION__, DNSINFO_MAX_SUFFIXES);
 
374
         break;
 
375
      }
 
376
 
 
377
      suffix = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, searchSuffixes, 1);
 
378
      ASSERT_MEM_ALLOC(suffix);
 
379
      *suffix = Util_SafeStrdup(*s);
 
380
   }
 
381
 
 
382
   /*
 
383
    * "Commit" dnsConfigInfo to nicInfo.
 
384
    */
 
385
   nicInfo->dnsConfigInfo = dnsConfigInfo;
 
386
 
 
387
   return TRUE;
 
388
 
 
389
fail:
 
390
   VMX_XDR_FREE(xdr_DnsConfigInfo, dnsConfigInfo);
 
391
   free(dnsConfigInfo);
 
392
   return FALSE;
 
393
}
 
394
 
 
395
 
 
396
/*
 
397
 ******************************************************************************
 
398
 * RecordResolverNS --                                                   */ /**
 
399
 *
 
400
 * @brief Copies name servers used by resolver(3) to @a dnsConfigInfo.
 
401
 *
 
402
 * @param[out] dnsConfigInfo    Destination DnsConfigInfo container.
 
403
 *
 
404
 ******************************************************************************
 
405
 */
 
406
 
 
407
static void
 
408
RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN
 
409
{
 
410
   int i;
 
411
 
 
412
#if defined RESOLVER_IPV6_GETSERVERS
 
413
   {
 
414
      union res_sockaddr_union *ns;
 
415
      ns = Util_SafeCalloc(_res.nscount, sizeof *ns);
 
416
      if (res_getservers(&_res, ns, _res.nscount) != _res.nscount) {
 
417
         g_warning("%s: res_getservers failed.\n", __func__);
 
418
         return;
 
419
      }
 
420
      for (i = 0; i < _res.nscount; i++) {
 
421
         struct sockaddr *sa = (struct sockaddr *)&ns[i];
 
422
         if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
 
423
            TypedIpAddress *ip;
 
424
 
 
425
            /* Check to see if we're going above our limit. See bug 605821. */
 
426
            if (dnsConfigInfo->serverList.serverList_len == DNSINFO_MAX_SERVERS) {
 
427
               g_message("%s: dns server limit (%d) reached, skipping overflow.",
 
428
                         __FUNCTION__, DNSINFO_MAX_SERVERS);
 
429
               break;
 
430
            }
 
431
 
 
432
            ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
 
433
            ASSERT_MEM_ALLOC(ip);
 
434
            GuestInfoSockaddrToTypedIpAddress(sa, ip);
 
435
         }
 
436
      }
 
437
   }
 
438
#else                                   // if defined RESOLVER_IPV6_GETSERVERS
 
439
   {
 
440
      /*
 
441
       * Name servers (IPv4).
 
442
       */
 
443
      for (i = 0; i < MAXNS; i++) {
 
444
         struct sockaddr_in *sin = &_res.nsaddr_list[i];
 
445
         if (sin->sin_family == AF_INET) {
 
446
            TypedIpAddress *ip;
 
447
 
 
448
            /* Check to see if we're going above our limit. See bug 605821. */
 
449
            if (dnsConfigInfo->serverList.serverList_len == DNSINFO_MAX_SERVERS) {
 
450
               g_message("%s: dns server limit (%d) reached, skipping overflow.",
 
451
                         __FUNCTION__, DNSINFO_MAX_SERVERS);
 
452
               break;
 
453
            }
 
454
 
 
455
            ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
 
456
            ASSERT_MEM_ALLOC(ip);
 
457
            GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin, ip);
 
458
         }
 
459
      }
 
460
#   if defined RESOLVER_IPV6_EXT
 
461
      /*
 
462
       * Name servers (IPv6).
 
463
       */
 
464
      for (i = 0; i < MAXNS; i++) {
 
465
         struct sockaddr_in6 *sin6 = _res._u._ext.nsaddrs[i];
 
466
         if (sin6) {
 
467
            TypedIpAddress *ip;
 
468
 
 
469
            /* Check to see if we're going above our limit. See bug 605821. */
 
470
            if (dnsConfigInfo->serverList.serverList_len == DNSINFO_MAX_SERVERS) {
 
471
               g_message("%s: dns server limit (%d) reached, skipping overflow.",
 
472
                         __FUNCTION__, DNSINFO_MAX_SERVERS);
 
473
               break;
 
474
            }
 
475
 
 
476
            ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
 
477
            ASSERT_MEM_ALLOC(ip);
 
478
            GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
 
479
         }
 
480
      }
 
481
#   endif                               //    if defined RESOLVER_IPV6_EXT
 
482
   }
 
483
#endif                                  // if !defined RESOLVER_IPV6_GETSERVERS
 
484
}
 
485
 
 
486
 
 
487
#ifdef USE_SLASH_PROC
 
488
/*
 
489
 ******************************************************************************
 
490
 * RecordRoutingInfoIPv4 --                                              */ /**
 
491
 *
 
492
 * @brief Query the IPv4 routing subsystem and pack up contents
 
493
 * (struct rtentry) into InetCidrRouteEntries.
 
494
 *
 
495
 * @param[out] nicInfo  NicInfoV3 container.
 
496
 *
 
497
 * @note Do not call this routine without first populating @a nicInfo 's NIC
 
498
 * list.
 
499
 *
 
500
 * @retval TRUE         Values collected, attached to @a nicInfo.
 
501
 * @retval FALSE        Something went wrong.  @a nicInfo is unharmed.
 
502
 *
 
503
 ******************************************************************************
 
504
 */
 
505
 
 
506
static Bool
 
507
RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
 
508
{
 
509
   GPtrArray *routes = NULL;
 
510
   guint i;
 
511
   Bool ret = FALSE;
 
512
 
 
513
   if ((routes = SlashProcNet_GetRoute()) == NULL) {
 
514
      return FALSE;
 
515
   }
 
516
 
 
517
   for (i = 0; i < routes->len; i++) {
 
518
      struct rtentry *rtentry;
 
519
      struct sockaddr_in *sin_dst;
 
520
      struct sockaddr_in *sin_gateway;
 
521
      struct sockaddr_in *sin_genmask;
 
522
      InetCidrRouteEntry *icre;
 
523
      uint32_t ifIndex;
 
524
 
 
525
      /* Check to see if we're going above our limit. See bug 605821. */
 
526
      if (nicInfo->routes.routes_len == NICINFO_MAX_ROUTES) {
 
527
         g_message("%s: route limit (%d) reached, skipping overflow.",
 
528
                   __FUNCTION__, NICINFO_MAX_ROUTES);
 
529
         break;
 
530
      }
 
531
 
 
532
      rtentry = g_ptr_array_index(routes, i);
 
533
 
 
534
      if ((rtentry->rt_flags & RTF_UP) == 0 ||
 
535
          !GuestInfoGetNicInfoIfIndex(nicInfo,
 
536
                                      if_nametoindex(rtentry->rt_dev),
 
537
                                      &ifIndex)) {
 
538
         continue;
 
539
      }
 
540
 
 
541
      icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
 
542
      ASSERT_MEM_ALLOC(icre);
 
543
 
 
544
      sin_dst = (struct sockaddr_in *)&rtentry->rt_dst;
 
545
      sin_gateway = (struct sockaddr_in *)&rtentry->rt_gateway;
 
546
      sin_genmask = (struct sockaddr_in *)&rtentry->rt_genmask;
 
547
 
 
548
      GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_dst,
 
549
                                        &icre->inetCidrRouteDest);
 
550
 
 
551
      addr_stob((struct sockaddr *)sin_genmask,
 
552
                (uint16_t *)&icre->inetCidrRoutePfxLen);
 
553
 
 
554
      /*
 
555
       * Gateways are optional (ex: one can bind a route to an interface w/o
 
556
       * specifying a next hop address).
 
557
       */
 
558
      if (rtentry->rt_flags & RTF_GATEWAY) {
 
559
         TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
 
560
         GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_gateway, ip);
 
561
         icre->inetCidrRouteNextHop = ip;
 
562
      }
 
563
 
 
564
      /*
 
565
       * Interface, metric.
 
566
       */
 
567
      icre->inetCidrRouteIfIndex = ifIndex;
 
568
      icre->inetCidrRouteMetric = rtentry->rt_metric;
 
569
   }
 
570
 
 
571
   ret = TRUE;
 
572
 
 
573
   SlashProcNet_FreeRoute(routes);
 
574
   return ret;
 
575
}
 
576
 
 
577
 
 
578
/*
 
579
 ******************************************************************************
 
580
 * RecordRoutingInfoIPv6 --                                              */ /**
 
581
 *
 
582
 * @brief Query the IPv6 routing subsystem and pack up contents
 
583
 * (struct in6_rtmsg) into InetCidrRouteEntries.
 
584
 *
 
585
 * @param[out] nicInfo  NicInfoV3 container.
 
586
 *
 
587
 * @note Do not call this routine without first populating @a nicInfo 's NIC
 
588
 * list.
 
589
 *
 
590
 * @retval TRUE         Values collected, attached to @a nicInfo.
 
591
 * @retval FALSE        Something went wrong.  @a nicInfo is unharmed.
 
592
 *
 
593
 ******************************************************************************
 
594
 */
 
595
 
 
596
static Bool
 
597
RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
 
598
{
 
599
   GPtrArray *routes = NULL;
 
600
   guint i;
 
601
   Bool ret = FALSE;
 
602
 
 
603
   if ((routes = SlashProcNet_GetRoute6()) == NULL) {
 
604
      return FALSE;
 
605
   }
 
606
 
 
607
   for (i = 0; i < routes->len; i++) {
 
608
      struct sockaddr_storage ss;
 
609
      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
 
610
      struct in6_rtmsg *in6_rtmsg;
 
611
      InetCidrRouteEntry *icre;
 
612
      uint32_t ifIndex = -1;
 
613
 
 
614
      /* Check to see if we're going above our limit. See bug 605821. */
 
615
      if (nicInfo->routes.routes_len == NICINFO_MAX_ROUTES) {
 
616
         g_message("%s: route limit (%d) reached, skipping overflow.",
 
617
                   __FUNCTION__, NICINFO_MAX_ROUTES);
 
618
         break;
 
619
      }
 
620
 
 
621
      in6_rtmsg = g_ptr_array_index(routes, i);
 
622
 
 
623
      if ((in6_rtmsg->rtmsg_flags & RTF_UP) == 0 ||
 
624
          !GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex,
 
625
                                      &ifIndex)) {
 
626
         continue;
 
627
      }
 
628
 
 
629
      icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
 
630
      ASSERT_MEM_ALLOC(icre);
 
631
 
 
632
      /*
 
633
       * Destination.
 
634
       */
 
635
      sin6->sin6_family = AF_INET6;
 
636
      sin6->sin6_addr = in6_rtmsg->rtmsg_dst;
 
637
      GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6,
 
638
                                        &icre->inetCidrRouteDest);
 
639
 
 
640
      icre->inetCidrRoutePfxLen = in6_rtmsg->rtmsg_dst_len;
 
641
 
 
642
      /*
 
643
       * Next hop.
 
644
       */
 
645
      if (in6_rtmsg->rtmsg_flags & RTF_GATEWAY) {
 
646
         TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
 
647
         sin6->sin6_addr = in6_rtmsg->rtmsg_gateway;
 
648
         GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
 
649
         icre->inetCidrRouteNextHop = ip;
 
650
      }
 
651
 
 
652
      /*
 
653
       * Interface, metric.
 
654
       */
 
655
      icre->inetCidrRouteIfIndex = ifIndex;
 
656
      icre->inetCidrRouteMetric = in6_rtmsg->rtmsg_metric;
 
657
   }
 
658
 
 
659
   ret = TRUE;
 
660
 
 
661
   SlashProcNet_FreeRoute6(routes);
 
662
   return ret;
 
663
}
 
664
 
 
665
 
 
666
/*
 
667
 ******************************************************************************
 
668
 * RecordRoutingInfo --                                                  */ /**
 
669
 *
 
670
 * @brief Query the routing subsystem and pack up contents into
 
671
 * InetCidrRouteEntries.
 
672
 *
 
673
 * @param[out] nicInfo  NicInfoV3 container.
 
674
 *
 
675
 * @note Do not call this routine without first populating @a nicInfo 's NIC
 
676
 * list.
 
677
 *
 
678
 * @retval TRUE         Values collected, attached to @a nicInfo.
 
679
 * @retval FALSE        Something went wrong.
 
680
 *
 
681
 ******************************************************************************
 
682
 */
 
683
 
 
684
static Bool
 
685
RecordRoutingInfo(NicInfoV3 *nicInfo)
 
686
{
 
687
   Bool ret = TRUE;
 
688
 
 
689
   if (File_Exists("/proc/net/route") && !RecordRoutingInfoIPv4(nicInfo)) {
 
690
      g_warning("%s: Unable to collect IPv4 routing table.\n", __func__);
 
691
      ret = FALSE;
 
692
   }
 
693
 
 
694
   if (File_Exists("/proc/net/ipv6_route") && !RecordRoutingInfoIPv6(nicInfo)) {
 
695
      g_warning("%s: Unable to collect IPv6 routing table.\n", __func__);
 
696
      ret = FALSE;
 
697
   }
 
698
 
 
699
   return ret;
 
700
}
 
701
 
 
702
#else                                           // ifdef USE_SLASH_PROC
 
703
static Bool
 
704
RecordRoutingInfo(NicInfoV3 *nicInfo)
 
705
{
 
706
   return TRUE;
 
707
}
 
708
#endif                                          // else
 
709
 
 
710
#endif // ifndef NO_DNET