| 1 | --- a/pcap-linux.c |
| 2 | +++ b/pcap-linux.c |
| 3 | @@ -297,6 +297,12 @@ pcap_create(const char *device, char *eb |
| 4 | { |
| 5 | pcap_t *handle; |
| 6 | |
| 7 | + /* |
| 8 | + * A null device name is equivalent to the "any" device. |
| 9 | + */ |
| 10 | + if (device == NULL) |
| 11 | + device = "any"; |
| 12 | + |
| 13 | #ifdef HAVE_DAG_API |
| 14 | if (strstr(device, "dag")) { |
| 15 | return dag_create(device, ebuf); |
| 16 | @@ -338,10 +344,9 @@ pcap_can_set_rfmon_linux(pcap_t *p) |
| 17 | struct iwreq ireq; |
| 18 | #endif |
| 19 | |
| 20 | - if (p->opt.source == NULL) { |
| 21 | + if (strcmp(p->opt.source, "any") == 0) { |
| 22 | /* |
| 23 | - * This is equivalent to the "any" device, and we don't |
| 24 | - * support monitor mode on it. |
| 25 | + * Monitor mode makes no sense on the "any" device. |
| 26 | */ |
| 27 | return 0; |
| 28 | } |
| 29 | @@ -518,12 +523,11 @@ pcap_activate_linux(pcap_t *handle) |
| 30 | handle->stats_op = pcap_stats_linux; |
| 31 | |
| 32 | /* |
| 33 | - * NULL and "any" are special devices which give us the hint to |
| 34 | - * monitor all devices. |
| 35 | + * The "any" device is a special device which causes us not |
| 36 | + * to bind to a particular device and thus to look at all |
| 37 | + * devices. |
| 38 | */ |
| 39 | - if (!device || strcmp(device, "any") == 0) { |
| 40 | - device = NULL; |
| 41 | - handle->md.device = strdup("any"); |
| 42 | + if (strcmp(device, "any") == 0) { |
| 43 | if (handle->opt.promisc) { |
| 44 | handle->opt.promisc = 0; |
| 45 | /* Just a warning. */ |
| 46 | @@ -531,10 +535,9 @@ pcap_activate_linux(pcap_t *handle) |
| 47 | "Promiscuous mode not supported on the \"any\" device"); |
| 48 | status = PCAP_WARNING_PROMISC_NOTSUP; |
| 49 | } |
| 50 | + } |
| 51 | |
| 52 | - } else |
| 53 | - handle->md.device = strdup(device); |
| 54 | - |
| 55 | + handle->md.device = strdup(device); |
| 56 | if (handle->md.device == NULL) { |
| 57 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", |
| 58 | pcap_strerror(errno) ); |
| 59 | @@ -1657,19 +1660,21 @@ static int |
| 60 | activate_new(pcap_t *handle) |
| 61 | { |
| 62 | #ifdef HAVE_PF_PACKET_SOCKETS |
| 63 | + const char *device = handle->opt.source; |
| 64 | + int is_any_device = (strcmp(device, "any") == 0); |
| 65 | int sock_fd = -1, arptype, val; |
| 66 | int err = 0; |
| 67 | struct packet_mreq mr; |
| 68 | - const char* device = handle->opt.source; |
| 69 | |
| 70 | /* |
| 71 | - * Open a socket with protocol family packet. If a device is |
| 72 | - * given we try to open it in raw mode otherwise we use |
| 73 | - * the cooked interface. |
| 74 | - */ |
| 75 | - sock_fd = device ? |
| 76 | - socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) |
| 77 | - : socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); |
| 78 | + * Open a socket with protocol family packet. If the |
| 79 | + * "any" device was specified, we open a SOCK_DGRAM |
| 80 | + * socket for the cooked interface, otherwise we first |
| 81 | + * try a SOCK_RAW socket for the raw interface. |
| 82 | + */ |
| 83 | + sock_fd = is_any_device ? |
| 84 | + socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)) : |
| 85 | + socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); |
| 86 | |
| 87 | if (sock_fd == -1) { |
| 88 | snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", |
| 89 | @@ -1704,7 +1709,7 @@ activate_new(pcap_t *handle) |
| 90 | * to cooked mode if we have an unknown interface type |
| 91 | * or a type we know doesn't work well in raw mode. |
| 92 | */ |
| 93 | - if (device) { |
| 94 | + if (!is_any_device) { |
| 95 | /* Assume for now we don't need cooked mode. */ |
| 96 | handle->md.cooked = 0; |
| 97 | |
| 98 | @@ -1819,15 +1824,23 @@ activate_new(pcap_t *handle) |
| 99 | } |
| 100 | } else { |
| 101 | /* |
| 102 | - * This is cooked mode. |
| 103 | + * The "any" device. |
| 104 | + */ |
| 105 | + if (handle->opt.rfmon) { |
| 106 | + /* |
| 107 | + * It doesn't support monitor mode. |
| 108 | + */ |
| 109 | + return PCAP_ERROR_RFMON_NOTSUP; |
| 110 | + } |
| 111 | + |
| 112 | + /* |
| 113 | + * It uses cooked mode. |
| 114 | */ |
| 115 | handle->md.cooked = 1; |
| 116 | handle->linktype = DLT_LINUX_SLL; |
| 117 | |
| 118 | /* |
| 119 | * We're not bound to a device. |
| 120 | - * XXX - true? Or true only if we're using |
| 121 | - * the "any" device? |
| 122 | * For now, we're using this as an indication |
| 123 | * that we can't transmit; stop doing that only |
| 124 | * if we figure out how to transmit in cooked |
| 125 | @@ -1852,10 +1865,13 @@ activate_new(pcap_t *handle) |
| 126 | |
| 127 | /* |
| 128 | * Hmm, how can we set promiscuous mode on all interfaces? |
| 129 | - * I am not sure if that is possible at all. |
| 130 | + * I am not sure if that is possible at all. For now, we |
| 131 | + * silently ignore attempts to turn promiscuous mode on |
| 132 | + * for the "any" device (so you don't have to explicitly |
| 133 | + * disable it in programs such as tcpdump). |
| 134 | */ |
| 135 | |
| 136 | - if (device && handle->opt.promisc) { |
| 137 | + if (!is_any_device && handle->opt.promisc) { |
| 138 | memset(&mr, 0, sizeof(mr)); |
| 139 | mr.mr_ifindex = handle->md.ifindex; |
| 140 | mr.mr_type = PACKET_MR_PROMISC; |
| 141 | @@ -3118,7 +3134,7 @@ activate_old(pcap_t *handle) |
| 142 | |
| 143 | /* Bind to the given device */ |
| 144 | |
| 145 | - if (!device) { |
| 146 | + if (strcmp(device, "any") == 0) { |
| 147 | strncpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems", |
| 148 | PCAP_ERRBUF_SIZE); |
| 149 | return PCAP_ERROR; |
| 150 | |