Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libpcap/fad-glifc.c
39475 views
1
/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2
/*
3
* Copyright (c) 1994, 1995, 1996, 1997, 1998
4
* The Regents of the University of California. All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. All advertising materials mentioning features or use of this software
15
* must display the following acknowledgement:
16
* This product includes software developed by the Computer Systems
17
* Engineering Group at Lawrence Berkeley Laboratory.
18
* 4. Neither the name of the University nor of the Laboratory may be used
19
* to endorse or promote products derived from this software without
20
* specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include <config.h>
36
37
#include <sys/param.h>
38
#include <sys/file.h>
39
#include <sys/ioctl.h>
40
#include <sys/socket.h>
41
#ifdef HAVE_SYS_SOCKIO_H
42
#include <sys/sockio.h>
43
#endif
44
#include <sys/time.h> /* concession to AIX */
45
46
struct mbuf; /* Squelch compiler warnings on some platforms for */
47
struct rtentry; /* declarations in <net/if.h> */
48
#include <net/if.h>
49
#include <netinet/in.h>
50
51
#include <errno.h>
52
#include <memory.h>
53
#include <stdio.h>
54
#include <stdlib.h>
55
#include <string.h>
56
#include <unistd.h>
57
58
#include "pcap-int.h"
59
60
#ifdef HAVE_OS_PROTO_H
61
#include "os-proto.h"
62
#endif
63
64
/*
65
* Only Solaris 10 uses this file.
66
*/
67
68
/*
69
* Get a list of all interfaces that are up and that we can open.
70
* Returns -1 on error, 0 otherwise.
71
* The list, as returned through "alldevsp", may be null if no interfaces
72
* were up and could be opened.
73
*
74
* This is the implementation used on platforms that have SIOCGLIFCONF
75
* but don't have "getifaddrs()". (Solaris 8 and later; we use
76
* SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
77
*/
78
int
79
pcapint_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
80
int (*check_usable)(const char *), get_if_flags_func get_flags_func)
81
{
82
register int fd4, fd6, fd;
83
register struct lifreq *ifrp, *ifend;
84
struct lifnum ifn;
85
struct lifconf ifc;
86
char *buf = NULL;
87
unsigned buf_size;
88
#ifdef HAVE_SOLARIS
89
char *p, *q;
90
#endif
91
struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
92
struct sockaddr *netmask, *broadaddr, *dstaddr;
93
int ret = 0;
94
95
/*
96
* Create a socket from which to fetch the list of interfaces,
97
* and from which to fetch IPv4 information.
98
*/
99
fd4 = socket(AF_INET, SOCK_DGRAM, 0);
100
if (fd4 < 0) {
101
pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
102
errno, "socket: AF_INET");
103
return (-1);
104
}
105
106
/*
107
* Create a socket from which to fetch IPv6 information.
108
*/
109
fd6 = socket(AF_INET6, SOCK_DGRAM, 0);
110
if (fd6 < 0) {
111
pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
112
errno, "socket: AF_INET6");
113
(void)close(fd4);
114
return (-1);
115
}
116
117
/*
118
* How many entries will SIOCGLIFCONF return?
119
*/
120
ifn.lifn_family = AF_UNSPEC;
121
ifn.lifn_flags = 0;
122
ifn.lifn_count = 0;
123
if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {
124
pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
125
errno, "SIOCGLIFNUM");
126
(void)close(fd6);
127
(void)close(fd4);
128
return (-1);
129
}
130
131
/*
132
* Allocate a buffer for those entries.
133
*/
134
buf_size = ifn.lifn_count * sizeof (struct lifreq);
135
buf = malloc(buf_size);
136
if (buf == NULL) {
137
pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
138
errno, "malloc");
139
(void)close(fd6);
140
(void)close(fd4);
141
return (-1);
142
}
143
144
/*
145
* Get the entries.
146
*/
147
ifc.lifc_len = buf_size;
148
ifc.lifc_buf = buf;
149
ifc.lifc_family = AF_UNSPEC;
150
ifc.lifc_flags = 0;
151
memset(buf, 0, buf_size);
152
if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {
153
pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
154
errno, "SIOCGLIFCONF");
155
(void)close(fd6);
156
(void)close(fd4);
157
free(buf);
158
return (-1);
159
}
160
161
/*
162
* Loop over the entries.
163
*/
164
ifrp = (struct lifreq *)buf;
165
ifend = (struct lifreq *)(buf + ifc.lifc_len);
166
167
for (; ifrp < ifend; ifrp++) {
168
/*
169
* Skip entries that begin with "dummy".
170
* XXX - what are these? Is this Linux-specific?
171
* Are there platforms on which we shouldn't do this?
172
*/
173
if (strncmp(ifrp->lifr_name, "dummy", 5) == 0)
174
continue;
175
176
/*
177
* Can we capture on this device?
178
*/
179
if (!(*check_usable)(ifrp->lifr_name)) {
180
/*
181
* No.
182
*/
183
continue;
184
}
185
186
/*
187
* IPv6 or not?
188
*/
189
if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
190
fd = fd6;
191
else
192
fd = fd4;
193
194
/*
195
* Get the flags for this interface.
196
*/
197
strncpy(ifrflags.lifr_name, ifrp->lifr_name,
198
sizeof(ifrflags.lifr_name));
199
if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
200
if (errno == ENXIO)
201
continue;
202
pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
203
errno, "SIOCGLIFFLAGS: %.*s",
204
(int)sizeof(ifrflags.lifr_name),
205
ifrflags.lifr_name);
206
ret = -1;
207
break;
208
}
209
210
/*
211
* Get the netmask for this address on this interface.
212
*/
213
strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
214
sizeof(ifrnetmask.lifr_name));
215
memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
216
sizeof(ifrnetmask.lifr_addr));
217
if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
218
if (errno == EADDRNOTAVAIL) {
219
/*
220
* Not available.
221
*/
222
netmask = NULL;
223
} else {
224
pcapint_fmt_errmsg_for_errno(errbuf,
225
PCAP_ERRBUF_SIZE, errno,
226
"SIOCGLIFNETMASK: %.*s",
227
(int)sizeof(ifrnetmask.lifr_name),
228
ifrnetmask.lifr_name);
229
ret = -1;
230
break;
231
}
232
} else
233
netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
234
235
/*
236
* Get the broadcast address for this address on this
237
* interface (if any).
238
*/
239
if (ifrflags.lifr_flags & IFF_BROADCAST) {
240
strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
241
sizeof(ifrbroadaddr.lifr_name));
242
memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
243
sizeof(ifrbroadaddr.lifr_addr));
244
if (ioctl(fd, SIOCGLIFBRDADDR,
245
(char *)&ifrbroadaddr) < 0) {
246
if (errno == EADDRNOTAVAIL) {
247
/*
248
* Not available.
249
*/
250
broadaddr = NULL;
251
} else {
252
pcapint_fmt_errmsg_for_errno(errbuf,
253
PCAP_ERRBUF_SIZE, errno,
254
"SIOCGLIFBRDADDR: %.*s",
255
(int)sizeof(ifrbroadaddr.lifr_name),
256
ifrbroadaddr.lifr_name);
257
ret = -1;
258
break;
259
}
260
} else
261
broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
262
} else {
263
/*
264
* Not a broadcast interface, so no broadcast
265
* address.
266
*/
267
broadaddr = NULL;
268
}
269
270
/*
271
* Get the destination address for this address on this
272
* interface (if any).
273
*/
274
if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
275
strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
276
sizeof(ifrdstaddr.lifr_name));
277
memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
278
sizeof(ifrdstaddr.lifr_addr));
279
if (ioctl(fd, SIOCGLIFDSTADDR,
280
(char *)&ifrdstaddr) < 0) {
281
if (errno == EADDRNOTAVAIL) {
282
/*
283
* Not available.
284
*/
285
dstaddr = NULL;
286
} else {
287
pcapint_fmt_errmsg_for_errno(errbuf,
288
PCAP_ERRBUF_SIZE, errno,
289
"SIOCGLIFDSTADDR: %.*s",
290
(int)sizeof(ifrdstaddr.lifr_name),
291
ifrdstaddr.lifr_name);
292
ret = -1;
293
break;
294
}
295
} else
296
dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
297
} else
298
dstaddr = NULL;
299
300
#ifdef HAVE_SOLARIS
301
/*
302
* If this entry has a colon followed by a number at
303
* the end, it's a logical interface. Those are just
304
* the way you assign multiple IP addresses to a real
305
* interface, so an entry for a logical interface should
306
* be treated like the entry for the real interface;
307
* we do that by stripping off the ":" and the number.
308
*/
309
p = strchr(ifrp->lifr_name, ':');
310
if (p != NULL) {
311
/*
312
* We have a ":"; is it followed by a number?
313
*/
314
q = p + 1;
315
while (PCAP_ISDIGIT(*q))
316
q++;
317
if (*q == '\0') {
318
/*
319
* All digits after the ":" until the end.
320
* Strip off the ":" and everything after
321
* it.
322
*/
323
*p = '\0';
324
}
325
}
326
#endif
327
328
/*
329
* Add information for this address to the list.
330
*/
331
if (pcapint_add_addr_to_if(devlistp, ifrp->lifr_name,
332
ifrflags.lifr_flags, get_flags_func,
333
(struct sockaddr *)&ifrp->lifr_addr,
334
sizeof (struct sockaddr_storage),
335
netmask, sizeof (struct sockaddr_storage),
336
broadaddr, sizeof (struct sockaddr_storage),
337
dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
338
ret = -1;
339
break;
340
}
341
}
342
free(buf);
343
(void)close(fd6);
344
(void)close(fd4);
345
346
return (ret);
347
}
348
349