Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/src/net_ifs.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 1996, 1998-2005, 2007-2015, 2018-2021
5
* Todd C. Miller <[email protected]>
6
*
7
* Permission to use, copy, modify, and distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*
19
* Sponsored in part by the Defense Advanced Research Projects
20
* Agency (DARPA) and Air Force Research Laboratory, Air Force
21
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
22
*/
23
24
/*
25
* Suppress a warning w/ gcc on Digital UN*X.
26
* The system headers should really do this....
27
*/
28
#if defined(__osf__) && !defined(__cplusplus)
29
struct mbuf;
30
struct rtentry;
31
#endif
32
33
/* Avoid a compilation problem with gcc and machine/sys/getppdp.h */
34
#define _MACHINE_SYS_GETPPDP_INCLUDED
35
36
#include <config.h>
37
38
#include <sys/types.h>
39
#include <sys/socket.h>
40
#include <sys/ioctl.h>
41
#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
42
# include <sys/sockio.h>
43
#endif
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <string.h>
47
#include <unistd.h>
48
#include <netdb.h>
49
#include <errno.h>
50
#include <netinet/in.h>
51
#include <arpa/inet.h>
52
#ifdef NEED_RESOLV_H
53
# include <arpa/nameser.h>
54
# include <resolv.h>
55
#endif /* NEED_RESOLV_H */
56
#include <net/if.h>
57
#ifdef HAVE_GETIFADDRS
58
# include <ifaddrs.h>
59
#endif
60
61
#define NEED_INET_NTOP /* to expose sudo_inet_ntop in sudo_compat.h */
62
63
#define DEFAULT_TEXT_DOMAIN "sudo"
64
65
#include "sudo.h"
66
67
/* Minix apparently lacks IFF_LOOPBACK */
68
#ifndef IFF_LOOPBACK
69
# define IFF_LOOPBACK 0
70
#endif
71
72
#ifndef INET6_ADDRSTRLEN
73
# define INET6_ADDRSTRLEN 46
74
#endif
75
76
#ifndef INADDR_NONE
77
# define INADDR_NONE 0xffffffffU
78
#endif
79
80
#if defined(STUB_LOAD_INTERFACES) || \
81
!(defined(HAVE_GETIFADDRS) || defined(SIOCGIFCONF) || defined(SIOCGLIFCONF))
82
83
/*
84
* Stub function for those without SIOCGIFCONF or getifaddrs()
85
*/
86
int
87
get_net_ifs(char **addrinfo_out)
88
{
89
debug_decl(get_net_ifs, SUDO_DEBUG_NETIF);
90
debug_return_int(0);
91
}
92
93
#elif defined(HAVE_GETIFADDRS)
94
95
/*
96
* Fill in the interfaces string with the machine's ip addresses and netmasks
97
* and return the number of interfaces found. Returns -1 on error.
98
*/
99
int
100
get_net_ifs(char **addrinfo_out)
101
{
102
struct ifaddrs *ifa, *ifaddrs;
103
struct sockaddr_in *sin4;
104
# ifdef HAVE_STRUCT_IN6_ADDR
105
struct sockaddr_in6 *sin6;
106
# endif
107
char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN];
108
char *addrinfo = NULL;
109
int len, num_interfaces = 0;
110
size_t ailen;
111
char *cp;
112
debug_decl(get_net_ifs, SUDO_DEBUG_NETIF);
113
114
if (!sudo_conf_probe_interfaces())
115
debug_return_int(0);
116
117
if (getifaddrs(&ifaddrs) == -1)
118
debug_return_int(-1);
119
120
/* Allocate space for the interfaces info string. */
121
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
122
/* Skip interfaces marked "down" and "loopback". */
123
if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
124
!ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
125
continue;
126
127
switch (ifa->ifa_addr->sa_family) {
128
case AF_INET:
129
# ifdef HAVE_STRUCT_IN6_ADDR
130
case AF_INET6:
131
# endif
132
num_interfaces++;
133
break;
134
}
135
}
136
if (num_interfaces == 0)
137
goto done;
138
ailen = (size_t)num_interfaces * 2 * INET6_ADDRSTRLEN;
139
if ((cp = malloc(ailen)) == NULL) {
140
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
141
"unable to allocate memory");
142
goto bad;
143
}
144
addrinfo = cp;
145
146
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
147
/* Skip interfaces marked "down" and "loopback". */
148
if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
149
!ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
150
continue;
151
152
switch (ifa->ifa_addr->sa_family) {
153
case AF_INET:
154
sin4 = (struct sockaddr_in *)ifa->ifa_addr;
155
if (sin4->sin_addr.s_addr == INADDR_ANY || sin4->sin_addr.s_addr == INADDR_NONE) {
156
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
157
"ignoring unspecified AF_INET addr for %s", ifa->ifa_name);
158
continue;
159
}
160
if (inet_ntop(AF_INET, &sin4->sin_addr, addrstr, sizeof(addrstr)) == NULL) {
161
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
162
"ignoring bad AF_INET addr for %s", ifa->ifa_name);
163
continue;
164
}
165
sin4 = (struct sockaddr_in *)ifa->ifa_netmask;
166
if (inet_ntop(AF_INET, &sin4->sin_addr, maskstr, sizeof(maskstr)) == NULL) {
167
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
168
"ignoring bad AF_INET mask for %s", ifa->ifa_name);
169
continue;
170
}
171
break;
172
# ifdef HAVE_STRUCT_IN6_ADDR
173
case AF_INET6:
174
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
175
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
176
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
177
"ignoring unspecified AF_INET6 addr for %s", ifa->ifa_name);
178
continue;
179
}
180
if (inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, sizeof(addrstr)) == NULL) {
181
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
182
"ignoring bad AF_INET6 addr for %s", ifa->ifa_name);
183
continue;
184
}
185
sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
186
if (inet_ntop(AF_INET6, &sin6->sin6_addr, maskstr, sizeof(maskstr)) == NULL) {
187
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
188
"ignoring bad AF_INET6 mask for %s", ifa->ifa_name);
189
continue;
190
}
191
break;
192
# endif /* HAVE_STRUCT_IN6_ADDR */
193
default:
194
continue;
195
}
196
197
/* Store the IP addr/netmask pairs. */
198
len = snprintf(cp, ailen, "%s%s/%s",
199
cp == addrinfo ? "" : " ", addrstr, maskstr);
200
if (len < 0 || (size_t)len >= ailen) {
201
sudo_warnx(U_("internal error, %s overflow"), __func__);
202
goto bad;
203
}
204
cp += len;
205
ailen -= (size_t)len;
206
}
207
*addrinfo_out = addrinfo;
208
goto done;
209
210
bad:
211
free(addrinfo);
212
num_interfaces = -1;
213
done:
214
# ifdef HAVE_FREEIFADDRS
215
freeifaddrs(ifaddrs);
216
# else
217
free(ifaddrs);
218
# endif
219
debug_return_int(num_interfaces);
220
}
221
222
#elif defined(SIOCGLIFCONF)
223
224
# if defined(__hpux)
225
226
/*
227
* Fill in the interfaces string with the machine's ip addresses and netmasks
228
* and return the number of interfaces found. Returns -1 on error.
229
* HP-UX has incompatible SIOCGLIFNUM and SIOCGLIFCONF ioctls.
230
*/
231
int
232
get_net_ifs(char **addrinfo_out)
233
{
234
struct if_laddrconf laddrconf;
235
struct ifconf ifconf;
236
char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN];
237
char *addrinfo = NULL;
238
int i, n, sock4, sock6 = -1;
239
int num_interfaces = 0;
240
size_t ailen;
241
char *cp;
242
debug_decl(get_net_ifs, SUDO_DEBUG_NETIF);
243
244
if (!sudo_conf_probe_interfaces())
245
debug_return_int(0);
246
247
memset(&ifconf, 0, sizeof(ifconf));
248
memset(&laddrconf, 0, sizeof(laddrconf));
249
250
/* Allocate and fill in the IPv4 interface list. */
251
sock4 = socket(AF_INET, SOCK_DGRAM, 0);
252
if (sock4 != -1 && ioctl(sock4, SIOCGIFNUM, &n) != -1) {
253
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
254
"SIOCGIFNUM reports %d interfaces", n);
255
n += 4; /* in case new interfaces come up */
256
257
ifconf.ifc_len = n * sizeof(struct ifreq);
258
ifconf.ifc_buf = malloc(ifconf.ifc_len);
259
if (ifconf.ifc_buf == NULL) {
260
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
261
"unable to allocate memory");
262
goto bad;
263
}
264
265
if (ioctl(sock4, SIOCGIFCONF, &ifconf) < 0) {
266
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
267
"unable to get interface list (SIOCGIFCONF)");
268
goto bad;
269
}
270
}
271
272
/* Allocate and fill in the IPv6 interface list. */
273
sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
274
if (sock6 != -1 && ioctl(sock6, SIOCGLIFNUM, &n) != -1) {
275
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
276
"SIOCGLIFNUM reports %d interfaces", n);
277
n += 4; /* in case new interfaces come up */
278
279
laddrconf.iflc_len = n * sizeof(struct if_laddrreq);
280
laddrconf.iflc_buf = malloc(laddrconf.iflc_len);
281
if (laddrconf.iflc_buf == NULL) {
282
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
283
"unable to allocate memory");
284
goto bad;
285
}
286
287
if (ioctl(sock4, SIOCGLIFCONF, &laddrconf) < 0) {
288
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
289
"unable to get interface list (SIOCGLIFCONF)");
290
goto bad;
291
}
292
}
293
294
/* Allocate space for the maximum number of interfaces that could exist. */
295
n = ifconf.ifc_len / sizeof(struct ifconf) +
296
laddrconf.iflc_len / sizeof(struct if_laddrreq);
297
if (n == 0)
298
goto done;
299
ailen = n * 2 * INET6_ADDRSTRLEN;
300
if ((cp = malloc(ailen)) == NULL) {
301
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
302
"unable to allocate memory");
303
goto bad;
304
}
305
addrinfo = cp;
306
307
/*
308
* For each interface, store the ip address and netmask.
309
* Keep a copy of the address family, else it will be overwritten.
310
*/
311
for (i = 0; i < ifconf.ifc_len; ) {
312
struct ifreq *ifr = (struct ifreq *)&ifconf.ifc_buf[i];
313
struct sockaddr_in *sin4;
314
315
/* Set i to the subscript of the next interface (no sa_len). */
316
i += sizeof(struct ifreq);
317
318
/* IPv4 only. */
319
if (ifr->ifr_addr.sa_family != AF_INET) {
320
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
321
"unexpected address family %d for %s",
322
ifr->ifr_addr.sa_family, ifr->ifr_name);
323
continue;
324
}
325
326
/* Store the address. */
327
sin4 = (struct sockaddr_in *)&ifr->ifr_addr;
328
if (sin4->sin_addr.s_addr == INADDR_ANY || sin4->sin_addr.s_addr == INADDR_NONE) {
329
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
330
"ignoring unspecified AF_INET addr for %s", ifr->ifr_name);
331
continue;
332
}
333
if (inet_ntop(AF_INET, &sin4->sin_addr, addrstr, sizeof(addrstr)) == NULL) {
334
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
335
"ignoring bad AF_INET addr for %s", ifr->ifr_name);
336
continue;
337
}
338
339
/* Skip interfaces marked "down" and "loopback". */
340
if (ioctl(sock4, SIOCGIFFLAGS, ifr) < 0) {
341
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
342
"SIOCGLIFFLAGS for %s", ifr->ifr_name);
343
continue;
344
}
345
if (!ISSET(ifr->ifr_flags, IFF_UP) ||
346
ISSET(ifr->ifr_flags, IFF_LOOPBACK))
347
continue;
348
349
/* Fetch and store the netmask. */
350
if (ioctl(sock4, SIOCGIFNETMASK, ifr) < 0) {
351
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
352
"SIOCGLIFNETMASK for %s", ifr->ifr_name);
353
continue;
354
}
355
356
/* Convert the mask to string form. */
357
sin4 = (struct sockaddr_in *)&ifr->ifr_addr;
358
if (inet_ntop(AF_INET, &sin4->sin_addr, maskstr, sizeof(maskstr)) == NULL) {
359
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
360
"ignoring bad AF_INET mask for %s", ifr->ifr_name);
361
continue;
362
}
363
364
n = snprintf(cp, ailen, "%s%s/%s",
365
cp == addrinfo ? "" : " ", addrstr, maskstr);
366
if (n < 0 || (size_t)n >= ailen) {
367
sudo_warnx(U_("internal error, %s overflow"), __func__);
368
goto bad;
369
}
370
cp += n;
371
ailen -= n;
372
373
num_interfaces++;
374
}
375
for (i = 0; i < laddrconf.iflc_len; ) {
376
struct if_laddrreq *lreq = (struct if_laddrreq *)&laddrconf.iflc_buf[i];
377
struct sockaddr_in6 *sin6;
378
379
/* Set i to the subscript of the next interface (no sa_len). */
380
i += sizeof(struct if_laddrreq);
381
382
/* IPv6 only. */
383
if (lreq->iflr_addr.sa_family != AF_INET6) {
384
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
385
"unexpected address family %d for %s",
386
lreq->iflr_addr.sa_family, lreq->iflr_name);
387
continue;
388
}
389
390
sin6 = (struct sockaddr_in6 *)&lreq->iflr_addr;
391
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
392
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
393
"ignoring unspecified AF_INET6 addr for %s", lreq->iflr_name);
394
continue;
395
}
396
if (inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, sizeof(addrstr)) == NULL) {
397
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
398
"ignoring bad AF_INET6 addr for %s", lreq->iflr_name);
399
continue;
400
}
401
402
/* Skip interfaces marked "down" and "loopback". */
403
if (ioctl(sock6, SIOCGLIFFLAGS, lreq) < 0) {
404
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
405
"SIOCGLIFFLAGS for %s", lreq->iflr_name);
406
continue;
407
}
408
if (!ISSET(lreq->iflr_flags, IFF_UP) ||
409
ISSET(lreq->iflr_flags, IFF_LOOPBACK))
410
continue;
411
412
/* Fetch and store the netmask. */
413
if (ioctl(sock6, SIOCGLIFNETMASK, lreq) < 0) {
414
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
415
"SIOCGLIFNETMASK for %s", lreq->iflr_name);
416
continue;
417
}
418
sin6 = (struct sockaddr_in6 *)&lreq->iflr_addr;
419
if (inet_ntop(AF_INET6, &sin6->sin6_addr, maskstr, sizeof(maskstr)) == NULL) {
420
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
421
"ignoring bad AF_INET6 mask for %s", lreq->iflr_name);
422
continue;
423
}
424
425
n = snprintf(cp, ailen, "%s%s/%s",
426
cp == addrinfo ? "" : " ", addrstr, maskstr);
427
if (n < 0 || (size_t)n >= ailen) {
428
sudo_warnx(U_("internal error, %s overflow"), __func__);
429
goto bad;
430
}
431
cp += n;
432
ailen -= n;
433
434
num_interfaces++;
435
}
436
*addrinfo_out = addrinfo;
437
goto done;
438
439
bad:
440
free(addrinfo);
441
num_interfaces = -1;
442
done:
443
free(ifconf.ifc_buf);
444
free(laddrconf.iflc_buf);
445
if (sock4 != -1)
446
close(sock4);
447
if (sock6 != -1)
448
close(sock6);
449
450
debug_return_int(num_interfaces);
451
}
452
453
# else
454
455
/*
456
* Fill in the interfaces string with the machine's ip addresses and netmasks
457
* and return the number of interfaces found. Returns -1 on error.
458
* SIOCGLIFCONF version (IPv6 compatible).
459
*/
460
int
461
get_net_ifs(char **addrinfo_out)
462
{
463
struct lifconf lifconf;
464
struct lifnum lifn;
465
struct sockaddr_in *sin4;
466
struct sockaddr_in6 *sin6;
467
char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN];
468
char *addrinfo = NULL;
469
int i, n, sock, sock4, sock6 = -1;
470
int num_interfaces = 0;
471
size_t ailen;
472
char *cp;
473
debug_decl(get_net_ifs, SUDO_DEBUG_NETIF);
474
475
if (!sudo_conf_probe_interfaces())
476
debug_return_int(0);
477
478
/* We need both INET4 and INET6 sockets to get flags and netmask. */
479
sock4 = socket(AF_INET, SOCK_DGRAM, 0);
480
sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
481
if (sock4 == -1 && sock6 == -1)
482
debug_return_int(-1);
483
484
/* Use INET6 socket with SIOCGLIFCONF if possible (may not matter). */
485
sock = sock6 != -1 ? sock6 : sock4;
486
487
/* Get number of interfaces if possible. */
488
memset(&lifn, 0, sizeof(lifn));
489
if (ioctl(sock, SIOCGLIFNUM, &lifn) != -1) {
490
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
491
"SIOCGLIFNUM reports %d interfaces", lifn.lifn_count);
492
lifn.lifn_count += 4; /* in case new interfaces come up */
493
} else {
494
lifn.lifn_count = 512;
495
}
496
497
/* Allocate and fill in the interface buffer. */
498
memset(&lifconf, 0, sizeof(lifconf));
499
lifconf.lifc_len = lifn.lifn_count * sizeof(struct lifreq);
500
lifconf.lifc_buf = malloc(lifconf.lifc_len);
501
if (lifconf.lifc_buf == NULL) {
502
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
503
"unable to allocate memory");
504
goto bad;
505
}
506
if (ioctl(sock, SIOCGLIFCONF, &lifconf) < 0) {
507
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
508
"unable to get interface list (SIOCGLIFCONF)");
509
goto bad;
510
}
511
512
/* Allocate space for the maximum number of interfaces that could exist. */
513
n = lifconf.lifc_len / sizeof(struct lifreq);
514
if (n == 0)
515
goto done;
516
ailen = n * 2 * INET6_ADDRSTRLEN;
517
if ((cp = malloc(ailen)) == NULL) {
518
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
519
"unable to allocate memory");
520
goto bad;
521
}
522
addrinfo = cp;
523
524
/*
525
* For each interface, store the ip address and netmask.
526
* Keep a copy of the address family, else it will be overwritten.
527
*/
528
for (i = 0; i < lifconf.lifc_len; ) {
529
struct lifreq *lifr = (struct lifreq *)&lifconf.lifc_buf[i];
530
const int family = lifr->lifr_addr.ss_family;
531
532
/* Set i to the subscript of the next interface (no sa_len). */
533
i += sizeof(struct lifreq);
534
535
/* Store the address. */
536
switch (family) {
537
case AF_INET:
538
sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
539
if (sin4->sin_addr.s_addr == INADDR_ANY || sin4->sin_addr.s_addr == INADDR_NONE) {
540
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
541
"ignoring unspecified AF_INET addr for %s", lifr->lifr_name);
542
continue;
543
}
544
if (inet_ntop(AF_INET, &sin4->sin_addr, addrstr, sizeof(addrstr)) == NULL) {
545
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
546
"ignoring bad AF_INET addr for %s", lifr->lifr_name);
547
continue;
548
}
549
sock = sock4;
550
break;
551
case AF_INET6:
552
sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
553
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
554
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
555
"ignoring unspecified AF_INET6 addr for %s", lifr->lifr_name);
556
continue;
557
}
558
if (inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, sizeof(addrstr)) == NULL) {
559
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
560
"ignoring bad AF_INET6 addr for %s", lifr->lifr_name);
561
continue;
562
}
563
sock = sock6;
564
break;
565
default:
566
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
567
"ignoring address with family %d for %s",
568
family, lifr->lifr_name);
569
continue;
570
}
571
572
/* Skip interfaces marked "down" and "loopback". */
573
if (ioctl(sock, SIOCGLIFFLAGS, lifr) < 0) {
574
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
575
"SIOCGLIFFLAGS for %s", lifr->lifr_name);
576
continue;
577
}
578
if (!ISSET(lifr->lifr_flags, IFF_UP) ||
579
ISSET(lifr->lifr_flags, IFF_LOOPBACK))
580
continue;
581
582
/* Fetch and store the netmask. */
583
if (ioctl(sock, SIOCGLIFNETMASK, lifr) < 0) {
584
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
585
"SIOCGLIFNETMASK for %s", lifr->lifr_name);
586
continue;
587
}
588
switch (family) {
589
case AF_INET:
590
sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
591
if (inet_ntop(AF_INET, &sin4->sin_addr, maskstr, sizeof(maskstr)) == NULL) {
592
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
593
"ignoring bad AF_INET mask for %s", lifr->lifr_name);
594
continue;
595
}
596
break;
597
case AF_INET6:
598
sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
599
if (inet_ntop(AF_INET6, &sin6->sin6_addr, maskstr, sizeof(maskstr)) == NULL) {
600
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
601
"ignoring bad AF_INET6 mask for %s", lifr->lifr_name);
602
continue;
603
}
604
break;
605
default:
606
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
607
"unexpected address family %d for %s",
608
family, lifr->lifr_name);
609
continue;
610
}
611
612
n = snprintf(cp, ailen, "%s%s/%s",
613
cp == addrinfo ? "" : " ", addrstr, maskstr);
614
if (n < 0 || (size_t)n >= ailen) {
615
sudo_warnx(U_("internal error, %s overflow"), __func__);
616
goto bad;
617
}
618
cp += n;
619
ailen -= n;
620
621
num_interfaces++;
622
}
623
*addrinfo_out = addrinfo;
624
goto done;
625
626
bad:
627
free(addrinfo);
628
num_interfaces = -1;
629
done:
630
free(lifconf.lifc_buf);
631
if (sock4 != -1)
632
close(sock4);
633
if (sock6 != -1)
634
close(sock6);
635
636
debug_return_int(num_interfaces);
637
}
638
# endif /* !__hpux */
639
640
#elif defined(SIOCGIFCONF)
641
642
/*
643
* Fill in the interfaces string with the machine's ip addresses and netmasks
644
* and return the number of interfaces found. Returns -1 on error.
645
* SIOCGIFCONF version.
646
*/
647
int
648
get_net_ifs(char **addrinfo_out)
649
{
650
struct ifconf ifconf;
651
struct ifreq *ifr;
652
struct sockaddr_in *sin4;
653
# ifdef HAVE_STRUCT_IN6_ADDR
654
struct sockaddr_in6 *sin6;
655
# endif
656
char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN];
657
char *cp, *addrinfo = NULL;
658
int i, n, sock, sock4, sock6 = -1;
659
int num_interfaces = 0;
660
size_t ailen, buflen;
661
debug_decl(get_net_ifs, SUDO_DEBUG_NETIF);
662
663
if (!sudo_conf_probe_interfaces())
664
debug_return_int(0);
665
666
sock4 = socket(AF_INET, SOCK_DGRAM, 0);
667
# ifdef HAVE_STRUCT_IN6_ADDR
668
sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
669
# endif
670
if (sock4 == -1 && sock6 == -1)
671
debug_return_int(-1);
672
673
/* Use INET6 socket with SIOCGIFCONF if possible (may not matter). */
674
sock = sock6 != -1 ? sock6 : sock4;
675
676
/*
677
* Get the size of the interface buffer (if possible).
678
* We over-allocate a bit in case interfaces come up afterward.
679
*/
680
i = 0;
681
# if defined(SIOCGSIZIFCONF)
682
/* AIX */
683
if (ioctl(sock, SIOCGSIZIFCONF, &i) != -1) {
684
buflen = i + (sizeof(struct ifreq) * 4);
685
} else
686
# elif defined(SIOCGIFANUM)
687
/* SCO OpenServer 5/6 */
688
if (ioctl(sock, SIOCGIFANUM, &i) != -1) {
689
buflen = (i + 4) * sizeof(struct ifreq);
690
} else
691
# elif defined(SIOCGIFNUM)
692
/* HP-UX, Solaris, others? */
693
if (ioctl(sock, SIOCGIFNUM, &i) != -1) {
694
buflen = (i + 4) * sizeof(struct ifreq);
695
} else
696
# endif
697
{
698
buflen = 256 * sizeof(struct ifreq);
699
}
700
701
/* Get interface configuration. */
702
memset(&ifconf, 0, sizeof(ifconf));
703
for (i = 0; i < 4; i++) {
704
ifconf.ifc_len = buflen;
705
ifconf.ifc_buf = malloc(buflen);
706
if (ifconf.ifc_buf == NULL) {
707
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
708
"unable to allocate memory");
709
goto bad;
710
}
711
712
/* Note that some kernels return EINVAL if the buffer is too small */
713
if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0 && errno != EINVAL)
714
goto bad;
715
716
/* Break out of loop if we have a big enough buffer. */
717
if (ifconf.ifc_len + sizeof(struct ifreq) < buflen)
718
break;
719
buflen *= 2;
720
free(ifconf.ifc_buf);
721
}
722
723
/*
724
* Allocate space for the maximum number of interfaces that could exist.
725
* We walk the list for systems with sa_len in struct sockaddr.
726
*/
727
for (i = 0, n = 0; i < ifconf.ifc_len; n++) {
728
/* Set i to the subscript of the next interface. */
729
i += sizeof(struct ifreq);
730
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
731
ifr = (struct ifreq *)&ifconf.ifc_buf[i];
732
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
733
i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
734
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
735
}
736
if (n == 0)
737
goto done;
738
ailen = n * 2 * INET6_ADDRSTRLEN;
739
if ((cp = malloc(ailen)) == NULL) {
740
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
741
"unable to allocate memory");
742
goto bad;
743
}
744
addrinfo = cp;
745
746
/*
747
* For each interface, store the ip address and netmask.
748
* Keep a copy of the address family, else it will be overwritten.
749
*/
750
for (i = 0; i < ifconf.ifc_len; ) {
751
int family;
752
753
ifr = (struct ifreq *)&ifconf.ifc_buf[i];
754
family = ifr->ifr_addr.sa_family;
755
756
/* Set i to the subscript of the next interface. */
757
i += sizeof(struct ifreq);
758
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
759
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
760
i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
761
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
762
763
/* Store the address. */
764
switch (family) {
765
case AF_INET:
766
sin4 = (struct sockaddr_in *)&ifr->ifr_addr;
767
if (sin4->sin_addr.s_addr == INADDR_ANY || sin4->sin_addr.s_addr == INADDR_NONE) {
768
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
769
"ignoring unspecified AF_INET addr for %s", ifr->ifr_name);
770
continue;
771
}
772
if (inet_ntop(AF_INET, &sin4->sin_addr, addrstr, sizeof(addrstr)) == NULL) {
773
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
774
"ignoring bad AF_INET addr for %s", ifr->ifr_name);
775
continue;
776
}
777
sock = sock4;
778
break;
779
# ifdef HAVE_STRUCT_IN6_ADDR
780
case AF_INET6:
781
sin6 = (struct sockaddr_in6 *)&ifr->ifr_addr;
782
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
783
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
784
"ignoring unspecified AF_INET6 addr for %s", ifr->ifr_name);
785
continue;
786
}
787
if (inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, sizeof(addrstr)) == NULL) {
788
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
789
"ignoring bad AF_INET6 addr for %s", ifr->ifr_name);
790
continue;
791
}
792
sock = sock6;
793
break;
794
# endif /* HAVE_STRUCT_IN6_ADDR */
795
default:
796
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
797
"unexpected address family %d for %s",
798
family, ifr->ifr_name);
799
continue;
800
}
801
802
/* Skip interfaces marked "down" and "loopback". */
803
if (ioctl(sock, SIOCGIFFLAGS, ifr) < 0) {
804
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
805
"SIOCGLIFFLAGS for %s", ifr->ifr_name);
806
continue;
807
}
808
if (!ISSET(ifr->ifr_flags, IFF_UP) ||
809
ISSET(ifr->ifr_flags, IFF_LOOPBACK))
810
continue;
811
812
/* Fetch and store the netmask. */
813
if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0) {
814
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
815
"SIOCGLIFNETMASK for %s", ifr->ifr_name);
816
continue;
817
}
818
819
/* Convert the mask to string form. */
820
switch (family) {
821
case AF_INET:
822
sin4 = (struct sockaddr_in *)&ifr->ifr_addr;
823
if (inet_ntop(AF_INET, &sin4->sin_addr, maskstr, sizeof(maskstr)) == NULL) {
824
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
825
"ignoring bad AF_INET mask for %s", ifr->ifr_name);
826
continue;
827
}
828
break;
829
# ifdef HAVE_STRUCT_IN6_ADDR
830
case AF_INET6:
831
sin6 = (struct sockaddr_in6 *)&ifr->ifr_addr;
832
if (inet_ntop(AF_INET6, &sin6->sin6_addr, maskstr, sizeof(maskstr)) == NULL) {
833
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
834
"ignoring bad AF_INET6 mask for %s", ifr->ifr_name);
835
continue;
836
}
837
break;
838
# endif /* HAVE_STRUCT_IN6_ADDR */
839
default:
840
continue;
841
}
842
843
n = snprintf(cp, ailen, "%s%s/%s",
844
cp == addrinfo ? "" : " ", addrstr, maskstr);
845
if (n < 0 || (size_t)n >= ailen) {
846
sudo_warnx(U_("internal error, %s overflow"), __func__);
847
goto bad;
848
}
849
cp += n;
850
ailen -= n;
851
852
num_interfaces++;
853
}
854
*addrinfo_out = addrinfo;
855
goto done;
856
857
bad:
858
free(addrinfo);
859
num_interfaces = -1;
860
done:
861
free(ifconf.ifc_buf);
862
if (sock4 != -1)
863
close(sock4);
864
if (sock6 != -1)
865
close(sock6);
866
867
debug_return_int(num_interfaces);
868
}
869
870
#endif /* SIOCGIFCONF */
871
872