Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/lib/isc/unix/interfaceiter.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
5
 * Permission to use, copy, modify, and/or distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
 * PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/* $Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */
19
20
/*! \file */
21
22
#include <config.h>
23
24
#include <sys/types.h>
25
#include <sys/ioctl.h>
26
#ifdef HAVE_SYS_SOCKIO_H
27
#include <sys/sockio.h>   /* Required for ifiter_ioctl.c. */
28
#endif
29
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <unistd.h>
33
#include <errno.h>
34
35
#include <isc/interfaceiter.h>
36
#include <isc/log.h>
37
#include <isc/magic.h>
38
#include <isc/mem.h>
39
#include <isc/msgs.h>
40
#include <isc/net.h>
41
#include <isc/print.h>
42
#include <isc/result.h>
43
#include <isc/strerror.h>
44
#include <isc/string.h>
45
#include <isc/types.h>
46
#include <isc/util.h>
47
48
/* Must follow <isc/net.h>. */
49
#ifdef HAVE_NET_IF6_H
50
#include <net/if6.h>
51
#endif
52
#include <net/if.h>
53
54
#ifdef HAVE_LINUX_IF_ADDR_H
55
# include <linux/if_addr.h>
56
#endif
57
58
/* Common utility functions */
59
60
/*%
61
 * Extract the network address part from a "struct sockaddr".
62
 * \brief
63
 * The address family is given explicitly
64
 * instead of using src->sa_family, because the latter does not work
65
 * for copying a network mask obtained by SIOCGIFNETMASK (it does
66
 * not have a valid address family).
67
 */
68
69
static void
70
get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
71
   char *ifname)
72
5
{
73
5
  struct sockaddr_in6 *sa6;
74
75
#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
76
    !defined(ISC_PLATFORM_HAVESCOPEID)
77
  UNUSED(ifname);
78
#endif
79
80
  /* clear any remaining value for safety */
81
5
  memset(dst, 0, sizeof(*dst));
82
83
5
  dst->family = family;
84
5
  switch (family) {
85
5
  case AF_INET:
86
5
    memcpy(&dst->type.in,
87
5
           &((struct sockaddr_in *)(void *)src)->sin_addr,
88
5
           sizeof(struct in_addr));
89
5
    break;
90
0
  case AF_INET6:
91
0
    sa6 = (struct sockaddr_in6 *)(void *)src;
92
0
    memcpy(&dst->type.in6, &sa6->sin6_addr,
93
0
           sizeof(struct in6_addr));
94
0
#ifdef ISC_PLATFORM_HAVESCOPEID
95
0
    if (sa6->sin6_scope_id != 0)
96
0
      isc_netaddr_setzone(dst, sa6->sin6_scope_id);
97
0
    else {
98
      /*
99
       * BSD variants embed scope zone IDs in the 128bit
100
       * address as a kernel internal form.  Unfortunately,
101
       * the embedded IDs are not hidden from applications
102
       * when getting access to them by sysctl or ioctl.
103
       * We convert the internal format to the pure address
104
       * part and the zone ID part.
105
       * Since multicast addresses should not appear here
106
       * and they cannot be distinguished from netmasks,
107
       * we only consider unicast link-local addresses.
108
       */
109
0
      if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
110
0
        isc_uint16_t zone16;
111
112
0
        memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
113
0
               sizeof(zone16));
114
0
        zone16 = ntohs(zone16);
115
0
        if (zone16 != 0) {
116
          /* the zone ID is embedded */
117
0
          isc_netaddr_setzone(dst,
118
0
                  (isc_uint32_t)zone16);
119
0
          dst->type.in6.s6_addr[2] = 0;
120
0
          dst->type.in6.s6_addr[3] = 0;
121
0
#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
122
0
        } else if (ifname != NULL) {
123
0
          unsigned int zone;
124
125
          /*
126
           * sin6_scope_id is still not provided,
127
           * but the corresponding interface name
128
           * is know.  Use the interface ID as
129
           * the link ID.
130
           */
131
0
          zone = if_nametoindex(ifname);
132
0
          if (zone != 0) {
133
0
            isc_netaddr_setzone(dst,
134
0
                    (isc_uint32_t)zone);
135
0
          }
136
0
#endif
137
0
        }
138
0
      }
139
0
    }
140
0
#endif
141
0
    break;
142
0
  default:
143
0
    INSIST(0);
144
0
    break;
145
5
  }
146
5
}
147
148
/*
149
 * Include system-dependent code.
150
 */
151
152
#ifdef __linux
153
#define ISC_IF_INET6_SZ \
154
    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
155
static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
156
static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
157
static void linux_if_inet6_first(isc_interfaceiter_t *iter);
158
#endif
159
160
#if HAVE_GETIFADDRS
161
#include "ifiter_getifaddrs.c"
162
#elif HAVE_IFLIST_SYSCTL
163
#include "ifiter_sysctl.c"
164
#else
165
#include "ifiter_ioctl.c"
166
#endif
167
168
#ifdef __linux
169
static void
170
1
linux_if_inet6_first(isc_interfaceiter_t *iter) {
171
1
  if (iter->proc != NULL) {
172
1
    rewind(iter->proc);
173
1
    (void)linux_if_inet6_next(iter);
174
1
  } else
175
0
    iter->valid = ISC_R_NOMORE;
176
1
}
177
178
static isc_result_t
179
2
linux_if_inet6_next(isc_interfaceiter_t *iter) {
180
2
  if (iter->proc != NULL &&
181
2
      fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
182
0
    iter->valid = ISC_R_SUCCESS;
183
2
  else
184
2
    iter->valid = ISC_R_NOMORE;
185
2
  return (iter->valid);
186
2
}
187
188
static isc_result_t
189
0
linux_if_inet6_current(isc_interfaceiter_t *iter) {
190
0
  char address[33];
191
0
  char name[IF_NAMESIZE+1];
192
0
  struct in6_addr addr6;
193
0
  unsigned int ifindex;
194
0
  int prefix, scope, flags;
195
0
  int res;
196
0
  unsigned int i;
197
198
0
  if (iter->valid != ISC_R_SUCCESS)
199
0
    return (iter->valid);
200
0
  if (iter->proc == NULL) {
201
0
    isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
202
0
            ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
203
0
            "/proc/net/if_inet6:iter->proc == NULL");
204
0
    return (ISC_R_FAILURE);
205
0
  }
206
207
0
  res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
208
0
         address, &ifindex, &prefix, &scope, &flags, name);
209
0
  if (res != 6) {
210
0
    isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
211
0
            ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
212
0
            "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
213
0
            res);
214
0
    return (ISC_R_FAILURE);
215
0
  }
216
0
  if (strlen(address) != 32) {
217
0
    isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
218
0
            ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
219
0
            "/proc/net/if_inet6:strlen(%s) != 32", address);
220
0
    return (ISC_R_FAILURE);
221
0
  }
222
  /*
223
  ** Ignore DAD addresses --
224
  ** we can't bind to them until they are resolved
225
  */
226
0
#ifdef IFA_F_TENTATIVE
227
0
  if (flags & IFA_F_TENTATIVE)
228
0
    return (ISC_R_IGNORE);
229
0
#endif
230
231
0
  for (i = 0; i < 16; i++) {
232
0
    unsigned char byte;
233
0
    static const char hex[] = "0123456789abcdef";
234
0
    byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
235
0
           (strchr(hex, address[i * 2 + 1]) - hex);
236
0
    addr6.s6_addr[i] = byte;
237
0
  }
238
0
  iter->current.af = AF_INET6;
239
0
  iter->current.flags = INTERFACE_F_UP;
240
0
  isc_netaddr_fromin6(&iter->current.address, &addr6);
241
0
  iter->current.ifindex = ifindex;
242
0
  if (isc_netaddr_islinklocal(&iter->current.address)) {
243
0
    isc_netaddr_setzone(&iter->current.address,
244
0
            (isc_uint32_t)ifindex);
245
0
  }
246
0
  for (i = 0; i < 16; i++) {
247
0
    if (prefix > 8) {
248
0
      addr6.s6_addr[i] = 0xff;
249
0
      prefix -= 8;
250
0
    } else {
251
0
      addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
252
0
      prefix = 0;
253
0
    }
254
0
  }
255
0
  isc_netaddr_fromin6(&iter->current.netmask, &addr6);
256
0
  strncpy(iter->current.name, name, sizeof(iter->current.name));
257
0
  return (ISC_R_SUCCESS);
258
0
}
259
#endif
260
261
/*
262
 * The remaining code is common to the sysctl and ioctl case.
263
 */
264
265
isc_result_t
266
isc_interfaceiter_current(isc_interfaceiter_t *iter,
267
        isc_interface_t *ifdata)
268
2
{
269
2
  REQUIRE(iter->result == ISC_R_SUCCESS);
270
0
  memcpy(ifdata, &iter->current, sizeof(*ifdata));
271
2
  return (ISC_R_SUCCESS);
272
2
}
273
274
isc_result_t
275
1
isc_interfaceiter_first(isc_interfaceiter_t *iter) {
276
1
  isc_result_t result;
277
278
1
  REQUIRE(VALID_IFITER(iter));
279
280
0
  internal_first(iter);
281
3
  for (;;) {
282
3
    result = internal_current(iter);
283
3
    if (result != ISC_R_IGNORE)
284
1
      break;
285
2
    result = internal_next(iter);
286
2
    if (result != ISC_R_SUCCESS)
287
0
      break;
288
2
  }
289
1
  iter->result = result;
290
1
  return (result);
291
1
}
292
293
isc_result_t
294
2
isc_interfaceiter_next(isc_interfaceiter_t *iter) {
295
2
  isc_result_t result;
296
297
2
  REQUIRE(VALID_IFITER(iter));
298
2
  REQUIRE(iter->result == ISC_R_SUCCESS);
299
300
2
  for (;;) {
301
2
    result = internal_next(iter);
302
2
    if (result != ISC_R_SUCCESS)
303
1
      break;
304
1
    result = internal_current(iter);
305
1
    if (result != ISC_R_IGNORE)
306
1
      break;
307
1
  }
308
2
  iter->result = result;
309
2
  return (result);
310
2
}
311
312
void
313
isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
314
1
{
315
1
  isc_interfaceiter_t *iter;
316
1
  REQUIRE(iterp != NULL);
317
0
  iter = *iterp;
318
1
  REQUIRE(VALID_IFITER(iter));
319
320
0
  internal_destroy(iter);
321
1
  if (iter->buf != NULL)
322
0
    isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
323
324
1
  iter->magic = 0;
325
1
  isc_mem_put(iter->mctx, iter, sizeof(*iter));
326
1
  *iterp = NULL;
327
1
}