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 #endif
17
18 #include <pcap.h>
19
20 #include "varattrs.h"
21 #include "pcap/funcattrs.h"
22
23 static int ifprint(pcap_if_t *d);
24 static char *iptos(bpf_u_int32 in);
25
26 #ifdef _WIN32
27 #include "portability.h"
28
29 /*
30 * Generate a string for a Win32-specific error (i.e. an error generated when
31 * calling a Win32 API).
32 * For errors occurred during standard C calls, we still use pcap_strerror()
33 */
34 #define ERRBUF_SIZE 1024
35 static const char *
win32_strerror(DWORD error)36 win32_strerror(DWORD error)
37 {
38 static char errbuf[ERRBUF_SIZE+1];
39 size_t errlen;
40
41 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
42 ERRBUF_SIZE, NULL);
43
44 /*
45 * "FormatMessage()" "helpfully" sticks CR/LF at the end of the
46 * message. Get rid of it.
47 */
48 errlen = strlen(errbuf);
49 if (errlen >= 2) {
50 errbuf[errlen - 1] = '\0';
51 errbuf[errlen - 2] = '\0';
52 errlen -= 2;
53 }
54 return errbuf;
55 }
56
57 static char *
getpass(const char * prompt)58 getpass(const char *prompt)
59 {
60 HANDLE console_handle = GetStdHandle(STD_INPUT_HANDLE);
61 DWORD console_mode, save_console_mode;
62 static char password[128+1];
63 char *p;
64
65 fprintf(stderr, "%s", prompt);
66
67 /*
68 * Turn off echoing.
69 */
70 if (!GetConsoleMode(console_handle, &console_mode)) {
71 fprintf(stderr, "Can't get console mode: %s\n",
72 win32_strerror(GetLastError()));
73 exit(1);
74 }
75 save_console_mode = console_mode;
76 console_mode &= ~ENABLE_ECHO_INPUT;
77 if (!SetConsoleMode(console_handle, console_mode)) {
78 fprintf(stderr, "Can't set console mode: %s\n",
79 win32_strerror(GetLastError()));
80 exit(1);
81 }
82 if (fgets(password, sizeof password, stdin) == NULL) {
83 fprintf(stderr, "\n");
84 SetConsoleMode(console_handle, save_console_mode);
85 exit(1);
86 }
87 fprintf(stderr, "\n");
88 SetConsoleMode(console_handle, save_console_mode);
89 p = strchr(password, '\n');
90 if (p != NULL)
91 *p = '\0';
92 return password;
93 }
94 #endif
95
96 #ifdef ENABLE_REMOTE
main(int argc,char ** argv)97 int main(int argc, char **argv)
98 #else
99 int main(int argc _U_, char **argv _U_)
100 #endif
101 {
102 pcap_if_t *alldevs;
103 pcap_if_t *d;
104 bpf_u_int32 net, mask;
105 int exit_status = 0;
106 char errbuf[PCAP_ERRBUF_SIZE+1];
107 #ifdef ENABLE_REMOTE
108 struct pcap_rmtauth auth;
109 char username[128+1];
110 char *p;
111 char *password;
112 #endif
113
114 #ifdef ENABLE_REMOTE
115 if (argc >= 2)
116 {
117 if (pcap_findalldevs_ex(argv[1], NULL, &alldevs, errbuf) == -1)
118 {
119 /*
120 * OK, try it with a user name and password.
121 */
122 fprintf(stderr, "User name: ");
123 if (fgets(username, sizeof username, stdin) == NULL)
124 exit(1);
125 p = strchr(username, '\n');
126 if (p != NULL)
127 *p = '\0';
128 password = getpass("Password: ");
129 auth.type = RPCAP_RMTAUTH_PWD;
130 auth.username = username;
131 auth.password = password;
132 if (pcap_findalldevs_ex(argv[1], &auth, &alldevs, errbuf) == -1)
133 {
134 fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
135 exit(1);
136 }
137 }
138 }
139 else
140 #endif
141 {
142 if (pcap_findalldevs(&alldevs, errbuf) == -1)
143 {
144 fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
145 exit(1);
146 }
147 }
148 for(d=alldevs;d;d=d->next)
149 {
150 if (!ifprint(d))
151 exit_status = 2;
152 }
153
154 if (alldevs != NULL)
155 {
156 if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0)
157 {
158 /*
159 * XXX - this doesn't distinguish between "a real error
160 * occurred" and "this interface doesn't *have* an IPv4
161 * address". The latter shouldn't be treated as an error.
162 *
163 * We look for the interface name, followed by a colon and
164 * a space, and, if we find it,w e see if what follows it
165 * is "no IPv4 address assigned".
166 */
167 size_t devnamelen = strlen(alldevs->name);
168 if (strncmp(errbuf, alldevs->name, devnamelen) == 0 &&
169 strncmp(errbuf + devnamelen, ": ", 2) == 0 &&
170 strcmp(errbuf + devnamelen + 2, "no IPv4 address assigned") == 0)
171 printf("Preferred device is not on an IPv4 network\n");
172 else {
173 fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf);
174 exit_status = 2;
175 }
176 }
177 else
178 {
179 printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask));
180 }
181 }
182
183 pcap_freealldevs(alldevs);
184 exit(exit_status);
185 }
186
ifprint(pcap_if_t * d)187 static int ifprint(pcap_if_t *d)
188 {
189 pcap_addr_t *a;
190 char ipv4_buf[INET_ADDRSTRLEN];
191 #ifdef INET6
192 char ipv6_buf[INET6_ADDRSTRLEN];
193 #endif
194 const char *sep;
195 int status = 1; /* success */
196
197 printf("%s\n",d->name);
198 if (d->description)
199 printf("\tDescription: %s\n",d->description);
200 printf("\tFlags: ");
201 sep = "";
202 if (d->flags & PCAP_IF_UP) {
203 printf("%sUP", sep);
204 sep = ", ";
205 }
206 if (d->flags & PCAP_IF_RUNNING) {
207 printf("%sRUNNING", sep);
208 sep = ", ";
209 }
210 if (d->flags & PCAP_IF_LOOPBACK) {
211 printf("%sLOOPBACK", sep);
212 sep = ", ";
213 }
214 if (d->flags & PCAP_IF_WIRELESS) {
215 printf("%sWIRELESS", sep);
216 switch (d->flags & PCAP_IF_CONNECTION_STATUS) {
217
218 case PCAP_IF_CONNECTION_STATUS_UNKNOWN:
219 printf(" (association status unknown)");
220 break;
221
222 case PCAP_IF_CONNECTION_STATUS_CONNECTED:
223 printf(" (associated)");
224 break;
225
226 case PCAP_IF_CONNECTION_STATUS_DISCONNECTED:
227 printf(" (not associated)");
228 break;
229
230 case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE:
231 break;
232 }
233 } else {
234 switch (d->flags & PCAP_IF_CONNECTION_STATUS) {
235
236 case PCAP_IF_CONNECTION_STATUS_UNKNOWN:
237 printf(" (connection status unknown)");
238 break;
239
240 case PCAP_IF_CONNECTION_STATUS_CONNECTED:
241 printf(" (connected)");
242 break;
243
244 case PCAP_IF_CONNECTION_STATUS_DISCONNECTED:
245 printf(" (disconnected)");
246 break;
247
248 case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE:
249 break;
250 }
251 }
252 sep = ", ";
253 printf("\n");
254
255 for(a=d->addresses;a;a=a->next) {
256 if (a->addr != NULL)
257 switch(a->addr->sa_family) {
258 case AF_INET:
259 printf("\tAddress Family: AF_INET (%d)\n", a->addr->sa_family);
260 if (a->addr)
261 printf("\t\tAddress: %s\n",
262 inet_ntop(AF_INET,
263 &((struct sockaddr_in *)(a->addr))->sin_addr,
264 ipv4_buf, sizeof ipv4_buf));
265 if (a->netmask)
266 printf("\t\tNetmask: %s\n",
267 inet_ntop(AF_INET,
268 &((struct sockaddr_in *)(a->netmask))->sin_addr,
269 ipv4_buf, sizeof ipv4_buf));
270 if (a->broadaddr)
271 printf("\t\tBroadcast Address: %s\n",
272 inet_ntop(AF_INET,
273 &((struct sockaddr_in *)(a->broadaddr))->sin_addr,
274 ipv4_buf, sizeof ipv4_buf));
275 if (a->dstaddr)
276 printf("\t\tDestination Address: %s\n",
277 inet_ntop(AF_INET,
278 &((struct sockaddr_in *)(a->dstaddr))->sin_addr,
279 ipv4_buf, sizeof ipv4_buf));
280 break;
281 #ifdef INET6
282 case AF_INET6:
283 printf("\tAddress Family: AF_INET6 (%d)\n", a->addr->sa_family);
284 if (a->addr)
285 printf("\t\tAddress: %s\n",
286 inet_ntop(AF_INET6,
287 ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr,
288 ipv6_buf, sizeof ipv6_buf));
289 if (a->netmask)
290 printf("\t\tNetmask: %s\n",
291 inet_ntop(AF_INET6,
292 ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr,
293 ipv6_buf, sizeof ipv6_buf));
294 if (a->broadaddr)
295 printf("\t\tBroadcast Address: %s\n",
296 inet_ntop(AF_INET6,
297 ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr,
298 ipv6_buf, sizeof ipv6_buf));
299 if (a->dstaddr)
300 printf("\t\tDestination Address: %s\n",
301 inet_ntop(AF_INET6,
302 ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr,
303 ipv6_buf, sizeof ipv6_buf));
304 break;
305 #endif
306 default:
307 printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family);
308 break;
309 }
310 else
311 {
312 fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n");
313 status = 0;
314 }
315 }
316 printf("\n");
317 return status;
318 }
319
320 /* From tcptraceroute */
321 #define IPTOSBUFFERS 12
iptos(bpf_u_int32 in)322 static char *iptos(bpf_u_int32 in)
323 {
324 static char output[IPTOSBUFFERS][sizeof("255.255.255.255")];
325 static short which;
326 u_char *p;
327
328 p = (u_char *)∈
329 which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
330 snprintf(output[which], sizeof(output[which]), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
331 return output[which];
332 }
333