19185e895Schristos #include <config.h> 29185e895Schristos 39185e895Schristos #include <stdlib.h> 49185e895Schristos #include <string.h> 59185e895Schristos #include <sys/types.h> 69185e895Schristos #ifdef _WIN32 79185e895Schristos #include <winsock2.h> 89185e895Schristos #include <ws2tcpip.h> 99185e895Schristos #include <windows.h> 109185e895Schristos #else 119185e895Schristos #include <sys/socket.h> 129185e895Schristos #include <netinet/in.h> 139185e895Schristos #include <arpa/inet.h> 149185e895Schristos #include <netdb.h> 159185e895Schristos #include <unistd.h> 169185e895Schristos #endif 179185e895Schristos 189185e895Schristos #include <pcap.h> 199185e895Schristos 20748408edSchristos #include "varattrs.h" 219185e895Schristos #include "pcap/funcattrs.h" 229185e895Schristos 239185e895Schristos static int ifprint(pcap_if_t *d); 249185e895Schristos static char *iptos(bpf_u_int32 in); 259185e895Schristos 269185e895Schristos #ifdef _WIN32 279185e895Schristos #include "portability.h" 289185e895Schristos 299185e895Schristos /* 309185e895Schristos * Generate a string for a Win32-specific error (i.e. an error generated when 319185e895Schristos * calling a Win32 API). 329185e895Schristos * For errors occurred during standard C calls, we still use pcap_strerror() 339185e895Schristos */ 349185e895Schristos #define ERRBUF_SIZE 1024 359185e895Schristos static const char * 369185e895Schristos win32_strerror(DWORD error) 379185e895Schristos { 389185e895Schristos static char errbuf[ERRBUF_SIZE+1]; 399185e895Schristos size_t errlen; 409185e895Schristos 419185e895Schristos FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, 429185e895Schristos ERRBUF_SIZE, NULL); 439185e895Schristos 449185e895Schristos /* 459185e895Schristos * "FormatMessage()" "helpfully" sticks CR/LF at the end of the 469185e895Schristos * message. Get rid of it. 479185e895Schristos */ 489185e895Schristos errlen = strlen(errbuf); 499185e895Schristos if (errlen >= 2) { 509185e895Schristos errbuf[errlen - 1] = '\0'; 519185e895Schristos errbuf[errlen - 2] = '\0'; 529185e895Schristos errlen -= 2; 539185e895Schristos } 549185e895Schristos return errbuf; 559185e895Schristos } 569185e895Schristos 579185e895Schristos static char * 589185e895Schristos getpass(const char *prompt) 599185e895Schristos { 609185e895Schristos HANDLE console_handle = GetStdHandle(STD_INPUT_HANDLE); 619185e895Schristos DWORD console_mode, save_console_mode; 629185e895Schristos static char password[128+1]; 639185e895Schristos char *p; 649185e895Schristos 659185e895Schristos fprintf(stderr, "%s", prompt); 669185e895Schristos 679185e895Schristos /* 689185e895Schristos * Turn off echoing. 699185e895Schristos */ 709185e895Schristos if (!GetConsoleMode(console_handle, &console_mode)) { 719185e895Schristos fprintf(stderr, "Can't get console mode: %s\n", 729185e895Schristos win32_strerror(GetLastError())); 739185e895Schristos exit(1); 749185e895Schristos } 759185e895Schristos save_console_mode = console_mode; 769185e895Schristos console_mode &= ~ENABLE_ECHO_INPUT; 779185e895Schristos if (!SetConsoleMode(console_handle, console_mode)) { 789185e895Schristos fprintf(stderr, "Can't set console mode: %s\n", 799185e895Schristos win32_strerror(GetLastError())); 809185e895Schristos exit(1); 819185e895Schristos } 829185e895Schristos if (fgets(password, sizeof password, stdin) == NULL) { 839185e895Schristos fprintf(stderr, "\n"); 849185e895Schristos SetConsoleMode(console_handle, save_console_mode); 859185e895Schristos exit(1); 869185e895Schristos } 879185e895Schristos fprintf(stderr, "\n"); 889185e895Schristos SetConsoleMode(console_handle, save_console_mode); 899185e895Schristos p = strchr(password, '\n'); 909185e895Schristos if (p != NULL) 919185e895Schristos *p = '\0'; 929185e895Schristos return password; 939185e895Schristos } 949185e895Schristos #endif 959185e895Schristos 96748408edSchristos #ifdef ENABLE_REMOTE 979185e895Schristos int main(int argc, char **argv) 98748408edSchristos #else 99748408edSchristos int main(int argc _U_, char **argv _U_) 100748408edSchristos #endif 1019185e895Schristos { 1029185e895Schristos pcap_if_t *alldevs; 1039185e895Schristos pcap_if_t *d; 1049185e895Schristos bpf_u_int32 net, mask; 1059185e895Schristos int exit_status = 0; 1069185e895Schristos char errbuf[PCAP_ERRBUF_SIZE+1]; 1079185e895Schristos #ifdef ENABLE_REMOTE 1089185e895Schristos struct pcap_rmtauth auth; 1099185e895Schristos char username[128+1]; 1109185e895Schristos char *p; 1119185e895Schristos char *password; 1129185e895Schristos #endif 1139185e895Schristos 1149185e895Schristos #ifdef ENABLE_REMOTE 1159185e895Schristos if (argc >= 2) 1169185e895Schristos { 1179185e895Schristos if (pcap_findalldevs_ex(argv[1], NULL, &alldevs, errbuf) == -1) 1189185e895Schristos { 1199185e895Schristos /* 1209185e895Schristos * OK, try it with a user name and password. 1219185e895Schristos */ 1229185e895Schristos fprintf(stderr, "User name: "); 1239185e895Schristos if (fgets(username, sizeof username, stdin) == NULL) 1249185e895Schristos exit(1); 1259185e895Schristos p = strchr(username, '\n'); 1269185e895Schristos if (p != NULL) 1279185e895Schristos *p = '\0'; 1289185e895Schristos password = getpass("Password: "); 1299185e895Schristos auth.type = RPCAP_RMTAUTH_PWD; 1309185e895Schristos auth.username = username; 1319185e895Schristos auth.password = password; 1329185e895Schristos if (pcap_findalldevs_ex(argv[1], &auth, &alldevs, errbuf) == -1) 1339185e895Schristos { 1349185e895Schristos fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); 1359185e895Schristos exit(1); 1369185e895Schristos } 1379185e895Schristos } 1389185e895Schristos } 1399185e895Schristos else 1409185e895Schristos #endif 1419185e895Schristos { 1429185e895Schristos if (pcap_findalldevs(&alldevs, errbuf) == -1) 1439185e895Schristos { 1449185e895Schristos fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); 1459185e895Schristos exit(1); 1469185e895Schristos } 1479185e895Schristos } 1489185e895Schristos for(d=alldevs;d;d=d->next) 1499185e895Schristos { 1509185e895Schristos if (!ifprint(d)) 1519185e895Schristos exit_status = 2; 1529185e895Schristos } 1539185e895Schristos 1549185e895Schristos if (alldevs != NULL) 1559185e895Schristos { 1569185e895Schristos if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0) 1579185e895Schristos { 158748408edSchristos /* 159748408edSchristos * XXX - this doesn't distinguish between "a real error 160748408edSchristos * occurred" and "this interface doesn't *have* an IPv4 161748408edSchristos * address". The latter shouldn't be treated as an error. 162748408edSchristos * 163748408edSchristos * We look for the interface name, followed by a colon and 164748408edSchristos * a space, and, if we find it,w e see if what follows it 165748408edSchristos * is "no IPv4 address assigned". 166748408edSchristos */ 167748408edSchristos size_t devnamelen = strlen(alldevs->name); 168748408edSchristos if (strncmp(errbuf, alldevs->name, devnamelen) == 0 && 169748408edSchristos strncmp(errbuf + devnamelen, ": ", 2) == 0 && 170748408edSchristos strcmp(errbuf + devnamelen + 2, "no IPv4 address assigned") == 0) 171748408edSchristos printf("Preferred device is not on an IPv4 network\n"); 172748408edSchristos else { 1739185e895Schristos fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); 1749185e895Schristos exit_status = 2; 1759185e895Schristos } 176748408edSchristos } 1779185e895Schristos else 1789185e895Schristos { 1799185e895Schristos printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); 1809185e895Schristos } 1819185e895Schristos } 1829185e895Schristos 1839185e895Schristos pcap_freealldevs(alldevs); 1849185e895Schristos exit(exit_status); 1859185e895Schristos } 1869185e895Schristos 1879185e895Schristos static int ifprint(pcap_if_t *d) 1889185e895Schristos { 1899185e895Schristos pcap_addr_t *a; 1909185e895Schristos char ipv4_buf[INET_ADDRSTRLEN]; 191*f73a5f05Schristos #ifdef INET6 1929185e895Schristos char ipv6_buf[INET6_ADDRSTRLEN]; 193*f73a5f05Schristos #endif 1949185e895Schristos const char *sep; 1959185e895Schristos int status = 1; /* success */ 1969185e895Schristos 1979185e895Schristos printf("%s\n",d->name); 1989185e895Schristos if (d->description) 1999185e895Schristos printf("\tDescription: %s\n",d->description); 2009185e895Schristos printf("\tFlags: "); 2019185e895Schristos sep = ""; 2029185e895Schristos if (d->flags & PCAP_IF_UP) { 2039185e895Schristos printf("%sUP", sep); 2049185e895Schristos sep = ", "; 2059185e895Schristos } 2069185e895Schristos if (d->flags & PCAP_IF_RUNNING) { 2079185e895Schristos printf("%sRUNNING", sep); 2089185e895Schristos sep = ", "; 2099185e895Schristos } 2109185e895Schristos if (d->flags & PCAP_IF_LOOPBACK) { 2119185e895Schristos printf("%sLOOPBACK", sep); 2129185e895Schristos sep = ", "; 2139185e895Schristos } 2149185e895Schristos if (d->flags & PCAP_IF_WIRELESS) { 2159185e895Schristos printf("%sWIRELESS", sep); 2169185e895Schristos switch (d->flags & PCAP_IF_CONNECTION_STATUS) { 2179185e895Schristos 2189185e895Schristos case PCAP_IF_CONNECTION_STATUS_UNKNOWN: 2199185e895Schristos printf(" (association status unknown)"); 2209185e895Schristos break; 2219185e895Schristos 2229185e895Schristos case PCAP_IF_CONNECTION_STATUS_CONNECTED: 2239185e895Schristos printf(" (associated)"); 2249185e895Schristos break; 2259185e895Schristos 2269185e895Schristos case PCAP_IF_CONNECTION_STATUS_DISCONNECTED: 2279185e895Schristos printf(" (not associated)"); 2289185e895Schristos break; 2299185e895Schristos 2309185e895Schristos case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: 2319185e895Schristos break; 2329185e895Schristos } 2339185e895Schristos } else { 2349185e895Schristos switch (d->flags & PCAP_IF_CONNECTION_STATUS) { 2359185e895Schristos 2369185e895Schristos case PCAP_IF_CONNECTION_STATUS_UNKNOWN: 2379185e895Schristos printf(" (connection status unknown)"); 2389185e895Schristos break; 2399185e895Schristos 2409185e895Schristos case PCAP_IF_CONNECTION_STATUS_CONNECTED: 2419185e895Schristos printf(" (connected)"); 2429185e895Schristos break; 2439185e895Schristos 2449185e895Schristos case PCAP_IF_CONNECTION_STATUS_DISCONNECTED: 2459185e895Schristos printf(" (disconnected)"); 2469185e895Schristos break; 2479185e895Schristos 2489185e895Schristos case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: 2499185e895Schristos break; 2509185e895Schristos } 2519185e895Schristos } 2529185e895Schristos sep = ", "; 2539185e895Schristos printf("\n"); 2549185e895Schristos 2559185e895Schristos for(a=d->addresses;a;a=a->next) { 2569185e895Schristos if (a->addr != NULL) 2579185e895Schristos switch(a->addr->sa_family) { 2589185e895Schristos case AF_INET: 259*f73a5f05Schristos printf("\tAddress Family: AF_INET (%d)\n", a->addr->sa_family); 2609185e895Schristos if (a->addr) 2619185e895Schristos printf("\t\tAddress: %s\n", 2629185e895Schristos inet_ntop(AF_INET, 2639185e895Schristos &((struct sockaddr_in *)(a->addr))->sin_addr, 2649185e895Schristos ipv4_buf, sizeof ipv4_buf)); 2659185e895Schristos if (a->netmask) 2669185e895Schristos printf("\t\tNetmask: %s\n", 2679185e895Schristos inet_ntop(AF_INET, 2689185e895Schristos &((struct sockaddr_in *)(a->netmask))->sin_addr, 2699185e895Schristos ipv4_buf, sizeof ipv4_buf)); 2709185e895Schristos if (a->broadaddr) 2719185e895Schristos printf("\t\tBroadcast Address: %s\n", 2729185e895Schristos inet_ntop(AF_INET, 2739185e895Schristos &((struct sockaddr_in *)(a->broadaddr))->sin_addr, 2749185e895Schristos ipv4_buf, sizeof ipv4_buf)); 2759185e895Schristos if (a->dstaddr) 2769185e895Schristos printf("\t\tDestination Address: %s\n", 2779185e895Schristos inet_ntop(AF_INET, 2789185e895Schristos &((struct sockaddr_in *)(a->dstaddr))->sin_addr, 2799185e895Schristos ipv4_buf, sizeof ipv4_buf)); 2809185e895Schristos break; 2819185e895Schristos #ifdef INET6 2829185e895Schristos case AF_INET6: 283*f73a5f05Schristos printf("\tAddress Family: AF_INET6 (%d)\n", a->addr->sa_family); 2849185e895Schristos if (a->addr) 2859185e895Schristos printf("\t\tAddress: %s\n", 2869185e895Schristos inet_ntop(AF_INET6, 2879185e895Schristos ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr, 2889185e895Schristos ipv6_buf, sizeof ipv6_buf)); 2899185e895Schristos if (a->netmask) 2909185e895Schristos printf("\t\tNetmask: %s\n", 2919185e895Schristos inet_ntop(AF_INET6, 2929185e895Schristos ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, 2939185e895Schristos ipv6_buf, sizeof ipv6_buf)); 2949185e895Schristos if (a->broadaddr) 2959185e895Schristos printf("\t\tBroadcast Address: %s\n", 2969185e895Schristos inet_ntop(AF_INET6, 2979185e895Schristos ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, 2989185e895Schristos ipv6_buf, sizeof ipv6_buf)); 2999185e895Schristos if (a->dstaddr) 3009185e895Schristos printf("\t\tDestination Address: %s\n", 3019185e895Schristos inet_ntop(AF_INET6, 3029185e895Schristos ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, 3039185e895Schristos ipv6_buf, sizeof ipv6_buf)); 3049185e895Schristos break; 3059185e895Schristos #endif 3069185e895Schristos default: 3079185e895Schristos printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); 3089185e895Schristos break; 3099185e895Schristos } 3109185e895Schristos else 3119185e895Schristos { 3129185e895Schristos fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n"); 3139185e895Schristos status = 0; 3149185e895Schristos } 3159185e895Schristos } 3169185e895Schristos printf("\n"); 3179185e895Schristos return status; 3189185e895Schristos } 3199185e895Schristos 3209185e895Schristos /* From tcptraceroute */ 3219185e895Schristos #define IPTOSBUFFERS 12 3229185e895Schristos static char *iptos(bpf_u_int32 in) 3239185e895Schristos { 324748408edSchristos static char output[IPTOSBUFFERS][sizeof("255.255.255.255")]; 3259185e895Schristos static short which; 3269185e895Schristos u_char *p; 3279185e895Schristos 3289185e895Schristos p = (u_char *)∈ 3299185e895Schristos which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); 330748408edSchristos snprintf(output[which], sizeof(output[which]), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 3319185e895Schristos return output[which]; 3329185e895Schristos } 333