]> The Tcpdump Group git mirrors - libpcap/blob - testprogs/findalldevstest.c
TESTrun: Add more reject tests with pcap_ether_hostton().
[libpcap] / testprogs / findalldevstest.c
1 #include <config.h>
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #ifdef _WIN32
7 #include <winsock2.h>
8 #include <ws2tcpip.h>
9 #include <windows.h>
10 #else
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <netdb.h>
15 #include <unistd.h>
16
17 // Different OSes define ETHER_ADDR_LEN in different headers, if at all, so
18 // it would take an amount of conditionals similar to that in nametoaddr.c
19 // just to get the well-known constant from an OS (or not). Keep it simple.
20 #ifndef ETHER_ADDR_LEN
21 #define ETHER_ADDR_LEN 6
22 #endif // ETHER_ADDR_LEN
23
24 // Linux defines and uses AF_PACKET.
25 // AIX, FreeBSD, Haiku, macOS, NetBSD and OpenBSD define and use AF_LINK.
26 // illumos defines both AF_PACKET and AF_LINK, and uses AF_LINK.
27 // Solaris 11 defines both AF_PACKET and AF_LINK, but uses neither.
28 // GNU/Hurd defines neither AF_PACKET nor AF_LINK.
29 #include <net/if.h>
30 #ifdef __linux__
31 #include <netpacket/packet.h> // struct sockaddr_ll
32 #include <net/if_arp.h> // ARPHRD_ETHER
33 #endif // __linux__
34 #ifdef AF_LINK
35 #include <net/if_dl.h> // struct sockaddr_dl and LLADDR()
36 #include <net/if_types.h> // IFT_ETHER
37 #endif // AF_LINK
38 #endif
39
40 #include <pcap.h>
41
42 #include "varattrs.h"
43 #include "pcap/funcattrs.h"
44
45 static int ifprint(pcap_if_t *d);
46 static char *iptos(bpf_u_int32 in);
47
48 #ifdef _WIN32
49 #include "portability.h"
50
51 /*
52 * Generate a string for a Win32-specific error (i.e. an error generated when
53 * calling a Win32 API).
54 * For errors occurred during standard C calls, we still use pcap_strerror()
55 */
56 #define ERRBUF_SIZE 1024
57 static const char *
58 win32_strerror(DWORD error)
59 {
60 static char errbuf[ERRBUF_SIZE+1];
61 size_t errlen;
62
63 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
64 ERRBUF_SIZE, NULL);
65
66 /*
67 * "FormatMessage()" "helpfully" sticks CR/LF at the end of the
68 * message. Get rid of it.
69 */
70 errlen = strlen(errbuf);
71 if (errlen >= 2) {
72 errbuf[errlen - 1] = '\0';
73 errbuf[errlen - 2] = '\0';
74 errlen -= 2;
75 }
76 return errbuf;
77 }
78
79 static char *
80 getpass(const char *prompt)
81 {
82 HANDLE console_handle = GetStdHandle(STD_INPUT_HANDLE);
83 DWORD console_mode, save_console_mode;
84 static char password[128+1];
85 char *p;
86
87 fprintf(stderr, "%s", prompt);
88
89 /*
90 * Turn off echoing.
91 */
92 if (!GetConsoleMode(console_handle, &console_mode)) {
93 fprintf(stderr, "Can't get console mode: %s\n",
94 win32_strerror(GetLastError()));
95 exit(1);
96 }
97 save_console_mode = console_mode;
98 console_mode &= ~ENABLE_ECHO_INPUT;
99 if (!SetConsoleMode(console_handle, console_mode)) {
100 fprintf(stderr, "Can't set console mode: %s\n",
101 win32_strerror(GetLastError()));
102 exit(1);
103 }
104 if (fgets(password, sizeof password, stdin) == NULL) {
105 fprintf(stderr, "\n");
106 SetConsoleMode(console_handle, save_console_mode);
107 exit(1);
108 }
109 fprintf(stderr, "\n");
110 SetConsoleMode(console_handle, save_console_mode);
111 p = strchr(password, '\n');
112 if (p != NULL)
113 *p = '\0';
114 return password;
115 }
116 #endif
117
118 int main(int argc, char **argv)
119 {
120 pcap_if_t *alldevs;
121 pcap_if_t *d;
122 bpf_u_int32 net, mask;
123 int exit_status = 0;
124 char errbuf[PCAP_ERRBUF_SIZE+1];
125 struct pcap_rmtauth auth;
126 char username[128+1];
127 char *p;
128 char *password;
129
130 if (argc >= 2)
131 {
132 if (pcap_findalldevs_ex(argv[1], NULL, &alldevs, errbuf) == -1)
133 {
134 /*
135 * OK, try it with a user name and password.
136 */
137 fprintf(stderr, "User name: ");
138 if (fgets(username, sizeof username, stdin) == NULL)
139 exit(1);
140 p = strchr(username, '\n');
141 if (p != NULL)
142 *p = '\0';
143 password = getpass("Password: ");
144 auth.type = RPCAP_RMTAUTH_PWD;
145 auth.username = username;
146 auth.password = password;
147 if (pcap_findalldevs_ex(argv[1], &auth, &alldevs, errbuf) == -1)
148 {
149 fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
150 exit(1);
151 }
152 }
153 }
154 else
155 {
156 if (pcap_findalldevs(&alldevs, errbuf) == -1)
157 {
158 fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
159 exit(1);
160 }
161 }
162 for(d=alldevs;d;d=d->next)
163 {
164 if (!ifprint(d))
165 exit_status = 2;
166 }
167
168 if (alldevs != NULL)
169 {
170 if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0)
171 {
172 /*
173 * XXX - this doesn't distinguish between "a real error
174 * occurred" and "this interface doesn't *have* an IPv4
175 * address". The latter shouldn't be treated as an error.
176 *
177 * We look for the interface name, followed by a colon and
178 * a space, and, if we find it,w e see if what follows it
179 * is "no IPv4 address assigned".
180 */
181 size_t devnamelen = strlen(alldevs->name);
182 if (strncmp(errbuf, alldevs->name, devnamelen) == 0 &&
183 strncmp(errbuf + devnamelen, ": ", 2) == 0 &&
184 strcmp(errbuf + devnamelen + 2, "no IPv4 address assigned") == 0)
185 printf("Preferred device is not on an IPv4 network\n");
186 else {
187 fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf);
188 exit_status = 2;
189 }
190 }
191 else
192 {
193 printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask));
194 }
195 }
196
197 pcap_freealldevs(alldevs);
198 exit(exit_status);
199 }
200
201 #if ! defined(_WIN32) && (defined(__linux__) || defined(AF_LINK))
202 static char *
203 ether_ntop(const u_char addr[], char *buffer, size_t size, u_char mask)
204 {
205 if (mask)
206 snprintf(buffer, size, "%02x:%02x:%02x:xx:xx:xx",
207 addr[0], addr[1], addr[2]);
208 else
209 snprintf(buffer, size, "%02x:%02x:%02x:%02x:%02x:%02x",
210 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
211 return buffer;
212 }
213 #endif // ! defined(_WIN32) && (defined(__linux__) || defined(AF_LINK))
214
215 static int ifprint(pcap_if_t *d)
216 {
217 const char *sep;
218 int status = 1; /* success */
219
220 printf("%s\n",d->name);
221 if (d->description)
222 printf("\tDescription: %s\n",d->description);
223 printf("\tFlags: ");
224 sep = "";
225 if (d->flags & PCAP_IF_UP) {
226 printf("%sUP", sep);
227 sep = ", ";
228 }
229 if (d->flags & PCAP_IF_RUNNING) {
230 printf("%sRUNNING", sep);
231 sep = ", ";
232 }
233 if (d->flags & PCAP_IF_LOOPBACK) {
234 printf("%sLOOPBACK", sep);
235 sep = ", ";
236 }
237 if (d->flags & PCAP_IF_WIRELESS) {
238 printf("%sWIRELESS", sep);
239 switch (d->flags & PCAP_IF_CONNECTION_STATUS) {
240
241 case PCAP_IF_CONNECTION_STATUS_UNKNOWN:
242 printf(" (association status unknown)");
243 break;
244
245 case PCAP_IF_CONNECTION_STATUS_CONNECTED:
246 printf(" (associated)");
247 break;
248
249 case PCAP_IF_CONNECTION_STATUS_DISCONNECTED:
250 printf(" (not associated)");
251 break;
252
253 case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE:
254 break;
255 }
256 } else {
257 switch (d->flags & PCAP_IF_CONNECTION_STATUS) {
258
259 case PCAP_IF_CONNECTION_STATUS_UNKNOWN:
260 printf(" (connection status unknown)");
261 break;
262
263 case PCAP_IF_CONNECTION_STATUS_CONNECTED:
264 printf(" (connected)");
265 break;
266
267 case PCAP_IF_CONNECTION_STATUS_DISCONNECTED:
268 printf(" (disconnected)");
269 break;
270
271 case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE:
272 break;
273 }
274 }
275 printf("\n");
276
277 const char *unmask = getenv("UNMASK_MAC_ADDRESSES");
278 if (unmask && strcmp("yes", unmask))
279 unmask = NULL;
280
281 for (pcap_addr_t *a = d->addresses; a; a=a->next) {
282 if (a->addr == NULL) {
283 fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n");
284 status = 0;
285 } else {
286 #if ! defined(_WIN32) && (defined(__linux__) || defined(AF_LINK))
287 char ether_buf[] = "00:00:00:00:00:00";
288 #endif // ! defined(_WIN32) && (defined(__linux__) || defined(AF_LINK))
289 switch(a->addr->sa_family) {
290 case AF_INET:
291 printf("\tAddress Family: AF_INET (%d)\n", a->addr->sa_family);
292 char ipv4_buf[INET_ADDRSTRLEN];
293 printf("\t\tAddress: %s\n",
294 inet_ntop(AF_INET,
295 &((struct sockaddr_in *)(a->addr))->sin_addr,
296 ipv4_buf, sizeof ipv4_buf));
297 if (a->netmask)
298 printf("\t\tNetmask: %s\n",
299 inet_ntop(AF_INET,
300 &((struct sockaddr_in *)(a->netmask))->sin_addr,
301 ipv4_buf, sizeof ipv4_buf));
302 if (a->broadaddr)
303 printf("\t\tBroadcast Address: %s\n",
304 inet_ntop(AF_INET,
305 &((struct sockaddr_in *)(a->broadaddr))->sin_addr,
306 ipv4_buf, sizeof ipv4_buf));
307 if (a->dstaddr)
308 printf("\t\tDestination Address: %s\n",
309 inet_ntop(AF_INET,
310 &((struct sockaddr_in *)(a->dstaddr))->sin_addr,
311 ipv4_buf, sizeof ipv4_buf));
312 break;
313
314 #if ! defined(_WIN32)
315 #ifdef __linux__
316 case AF_PACKET:
317 printf("\tAddress Family: AF_PACKET (%d)\n", a->addr->sa_family);
318 struct sockaddr_ll *sll = (struct sockaddr_ll *)a->addr;
319 printf("\t\tInterface Index: %u\n", sll->sll_ifindex);
320 printf("\t\tType: %d%s\n", sll->sll_hatype,
321 sll->sll_hatype == ARPHRD_ETHER ? " (ARPHRD_ETHER)" : "");
322 printf("\t\tLength: %u\n", sll->sll_halen);
323 if (sll->sll_hatype == ARPHRD_ETHER && sll->sll_halen == ETHER_ADDR_LEN)
324 printf("\t\tAddress: %s\n",
325 ether_ntop((const u_char *)sll->sll_addr,
326 ether_buf, sizeof(ether_buf), ! unmask));
327 break;
328 #endif // __linux__
329
330 #ifdef AF_LINK
331 case AF_LINK:
332 printf("\tAddress Family: AF_LINK (%d)\n", a->addr->sa_family);
333 struct sockaddr_dl *sdl = (struct sockaddr_dl *)a->addr;
334 printf("\t\tInterface Index: %u\n", sdl->sdl_index);
335 printf("\t\tType: %u%s\n", sdl->sdl_type,
336 sdl->sdl_type == IFT_ETHER ? " (IFT_ETHER)" : "");
337 printf("\t\tLength: %u\n", sdl->sdl_alen);
338 // On illumos sdl_type can be 0, see https://www.illumos.org/issues/16383
339 if ((sdl->sdl_type == IFT_ETHER
340 #ifdef __illumos__
341 || sdl->sdl_type == 0
342 #endif // __illumos__
343 ) && sdl->sdl_alen == ETHER_ADDR_LEN)
344 printf("\t\tAddress: %s\n",
345 ether_ntop((const u_char *)LLADDR(sdl),
346 ether_buf, sizeof(ether_buf), ! unmask));
347 break;
348 #endif // AF_LINK
349 #endif // ! defined(_WIN32)
350
351 #ifdef AF_INET6
352 case AF_INET6:
353 printf("\tAddress Family: AF_INET6 (%d)\n", a->addr->sa_family);
354 char ipv6_buf[INET6_ADDRSTRLEN];
355 printf("\t\tAddress: %s\n",
356 inet_ntop(AF_INET6,
357 ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr,
358 ipv6_buf, sizeof ipv6_buf));
359 if (a->netmask)
360 printf("\t\tNetmask: %s\n",
361 inet_ntop(AF_INET6,
362 ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr,
363 ipv6_buf, sizeof ipv6_buf));
364 if (a->broadaddr)
365 printf("\t\tBroadcast Address: %s\n",
366 inet_ntop(AF_INET6,
367 ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr,
368 ipv6_buf, sizeof ipv6_buf));
369 if (a->dstaddr)
370 printf("\t\tDestination Address: %s\n",
371 inet_ntop(AF_INET6,
372 ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr,
373 ipv6_buf, sizeof ipv6_buf));
374 break;
375 #endif // AF_INET6
376 default:
377 printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family);
378 break;
379 } // switch
380 } // if
381 } // for
382 printf("\n");
383 return status;
384 }
385
386 /* From tcptraceroute */
387 #define IPTOSBUFFERS 12
388 static char *iptos(bpf_u_int32 in)
389 {
390 static char output[IPTOSBUFFERS][sizeof("255.255.255.255")];
391 static short which;
392 u_char *p;
393
394 p = (u_char *)&in;
395 which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
396 snprintf(output[which], sizeof(output[which]), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
397 return output[which];
398 }