11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
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
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.
31 #include <netpacket/packet.h> // struct sockaddr_ll
32 #include <net/if_arp.h> // ARPHRD_ETHER
35 #include <net/if_dl.h> // struct sockaddr_dl and LLADDR()
36 #include <net/if_types.h> // IFT_ETHER
43 #include "pcap/funcattrs.h"
45 static int ifprint(pcap_if_t
*d
);
46 static char *iptos(bpf_u_int32 in
);
49 #include "portability.h"
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()
56 #define ERRBUF_SIZE 1024
58 win32_strerror(DWORD error
)
60 static char errbuf
[ERRBUF_SIZE
+1];
63 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, error
, 0, errbuf
,
67 * "FormatMessage()" "helpfully" sticks CR/LF at the end of the
68 * message. Get rid of it.
70 errlen
= strlen(errbuf
);
72 errbuf
[errlen
- 1] = '\0';
73 errbuf
[errlen
- 2] = '\0';
80 getpass(const char *prompt
)
82 HANDLE console_handle
= GetStdHandle(STD_INPUT_HANDLE
);
83 DWORD console_mode
, save_console_mode
;
84 static char password
[128+1];
87 fprintf(stderr
, "%s", prompt
);
92 if (!GetConsoleMode(console_handle
, &console_mode
)) {
93 fprintf(stderr
, "Can't get console mode: %s\n",
94 win32_strerror(GetLastError()));
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()));
104 if (fgets(password
, sizeof password
, stdin
) == NULL
) {
105 fprintf(stderr
, "\n");
106 SetConsoleMode(console_handle
, save_console_mode
);
109 fprintf(stderr
, "\n");
110 SetConsoleMode(console_handle
, save_console_mode
);
111 p
= strchr(password
, '\n');
118 int main(int argc
, char **argv
)
122 bpf_u_int32 net
, mask
;
124 char errbuf
[PCAP_ERRBUF_SIZE
+1];
125 struct pcap_rmtauth auth
;
126 char username
[128+1];
132 if (pcap_findalldevs_ex(argv
[1], NULL
, &alldevs
, errbuf
) == -1)
135 * OK, try it with a user name and password.
137 fprintf(stderr
, "User name: ");
138 if (fgets(username
, sizeof username
, stdin
) == NULL
)
140 p
= strchr(username
, '\n');
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)
149 fprintf(stderr
,"Error in pcap_findalldevs: %s\n",errbuf
);
156 if (pcap_findalldevs(&alldevs
, errbuf
) == -1)
158 fprintf(stderr
,"Error in pcap_findalldevs: %s\n",errbuf
);
162 for(d
=alldevs
;d
;d
=d
->next
)
170 if (pcap_lookupnet(alldevs
->name
, &net
, &mask
, errbuf
) < 0)
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.
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".
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");
187 fprintf(stderr
,"Error in pcap_lookupnet: %s\n",errbuf
);
193 printf("Preferred device is on network: %s/%s\n",iptos(net
), iptos(mask
));
197 pcap_freealldevs(alldevs
);
201 #if ! defined(_WIN32) && (defined(__linux__) || defined(AF_LINK))
203 ether_ntop(const u_char addr
[], char *buffer
, size_t size
, u_char mask
)
206 snprintf(buffer
, size
, "%02x:%02x:%02x:xx:xx:xx",
207 addr
[0], addr
[1], addr
[2]);
209 snprintf(buffer
, size
, "%02x:%02x:%02x:%02x:%02x:%02x",
210 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
213 #endif // ! defined(_WIN32) && (defined(__linux__) || defined(AF_LINK))
215 static int ifprint(pcap_if_t
*d
)
218 int status
= 1; /* success */
220 printf("%s\n",d
->name
);
222 printf("\tDescription: %s\n",d
->description
);
225 if (d
->flags
& PCAP_IF_UP
) {
229 if (d
->flags
& PCAP_IF_RUNNING
) {
230 printf("%sRUNNING", sep
);
233 if (d
->flags
& PCAP_IF_LOOPBACK
) {
234 printf("%sLOOPBACK", sep
);
237 if (d
->flags
& PCAP_IF_WIRELESS
) {
238 printf("%sWIRELESS", sep
);
239 switch (d
->flags
& PCAP_IF_CONNECTION_STATUS
) {
241 case PCAP_IF_CONNECTION_STATUS_UNKNOWN
:
242 printf(" (association status unknown)");
245 case PCAP_IF_CONNECTION_STATUS_CONNECTED
:
246 printf(" (associated)");
249 case PCAP_IF_CONNECTION_STATUS_DISCONNECTED
:
250 printf(" (not associated)");
253 case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
:
257 switch (d
->flags
& PCAP_IF_CONNECTION_STATUS
) {
259 case PCAP_IF_CONNECTION_STATUS_UNKNOWN
:
260 printf(" (connection status unknown)");
263 case PCAP_IF_CONNECTION_STATUS_CONNECTED
:
264 printf(" (connected)");
267 case PCAP_IF_CONNECTION_STATUS_DISCONNECTED
:
268 printf(" (disconnected)");
271 case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
:
277 const char *unmask
= getenv("UNMASK_MAC_ADDRESSES");
278 if (unmask
&& strcmp("yes", unmask
))
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");
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
) {
291 printf("\tAddress Family: AF_INET (%d)\n", a
->addr
->sa_family
);
292 char ipv4_buf
[INET_ADDRSTRLEN
];
293 printf("\t\tAddress: %s\n",
295 &((struct sockaddr_in
*)(a
->addr
))->sin_addr
,
296 ipv4_buf
, sizeof ipv4_buf
));
298 printf("\t\tNetmask: %s\n",
300 &((struct sockaddr_in
*)(a
->netmask
))->sin_addr
,
301 ipv4_buf
, sizeof ipv4_buf
));
303 printf("\t\tBroadcast Address: %s\n",
305 &((struct sockaddr_in
*)(a
->broadaddr
))->sin_addr
,
306 ipv4_buf
, sizeof ipv4_buf
));
308 printf("\t\tDestination Address: %s\n",
310 &((struct sockaddr_in
*)(a
->dstaddr
))->sin_addr
,
311 ipv4_buf
, sizeof ipv4_buf
));
314 #if ! defined(_WIN32)
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
));
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
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
));
349 #endif // ! defined(_WIN32)
353 printf("\tAddress Family: AF_INET6 (%d)\n", a
->addr
->sa_family
);
354 char ipv6_buf
[INET6_ADDRSTRLEN
];
355 printf("\t\tAddress: %s\n",
357 ((struct sockaddr_in6
*)(a
->addr
))->sin6_addr
.s6_addr
,
358 ipv6_buf
, sizeof ipv6_buf
));
360 printf("\t\tNetmask: %s\n",
362 ((struct sockaddr_in6
*)(a
->netmask
))->sin6_addr
.s6_addr
,
363 ipv6_buf
, sizeof ipv6_buf
));
365 printf("\t\tBroadcast Address: %s\n",
367 ((struct sockaddr_in6
*)(a
->broadaddr
))->sin6_addr
.s6_addr
,
368 ipv6_buf
, sizeof ipv6_buf
));
370 printf("\t\tDestination Address: %s\n",
372 ((struct sockaddr_in6
*)(a
->dstaddr
))->sin6_addr
.s6_addr
,
373 ipv6_buf
, sizeof ipv6_buf
));
377 printf("\tAddress Family: Unknown (%d)\n", a
->addr
->sa_family
);
386 /* From tcptraceroute */
387 #define IPTOSBUFFERS 12
388 static char *iptos(bpf_u_int32 in
)
390 static char output
[IPTOSBUFFERS
][sizeof("255.255.255.255")];
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
];