cmacoslibpcap

libpcap disable monitor mode (C, macOS)


I have a function that enables monitor mode for a WiFi device on macOS using libpcap. This works, but currently the only way to set the WiFi device back to managed mode is to exit the process. I would like to set the WiFi device to managed mode while allowing the process to continue. As far as I can tell, this can't be done with libpcap. How would I set the WiFi device back to managed mode (potentially using the CoreWLAN API in Objective-C?)?

pcap_t *enable_monitor(char *dev) {
    wifi_disassociate();

    char error_buffer[PCAP_ERRBUF_SIZE];
    pcap_t *handle;
    int result;

    handle = pcap_create(dev, error_buffer);
    if (handle == NULL) {
        printf("failed to create a handle: %s\n",
               error_buffer);
        return NULL;
    }
    result = pcap_set_rfmon(handle, 1);
    if (result != 0) {
        printf("failed to set pcap rfmon: %s (%s)\n",
               pcap_statustostr(result),
               pcap_geterr(handle));
        return NULL;
    }
    result = pcap_activate(handle);
    if (result != 0) {
        printf("failed to activate handle: %s (%s)\n",
               pcap_statustostr(result),
               pcap_geterr(handle));
        return NULL;
    }
    //pcap_close(handle);
    return handle;
}

Edit: Setting the second argument to cap_set_rfmon to 0 does not seem to set the device to managed mode, it just doesn't set it to monitor mode.

int disable_monitor(pcap_t *handle) {
    int result;
    result = pcap_set_rfmon(handle, 0);
    if (result != 0) {
        printf("failed to set pcap rfmon: %s (%s)\n",
               pcap_statustostr(result),
               pcap_geterr(handle));
        return 1;
    }
    pcap_close(handle);
    return 0;
}

int main() {
    char *dev = find_wifi_device();
    pcap_t *handle = enable_monitor(dev);
    sleep(5);
    int status = disable_monitor(handle);
    printf("Status: %d\n", status);
    for (;;)
        sleep(100);
}

This results in:

failed to set pcap rfmon: The setting can't be changed after the pcap_t is activated (can't perform  operation on activated capture)
Status: 1

Solution

  • Prefaced by my top comments ...

    From man pcap_set_rfmon, it sets the mode. But, it only takes effect "when activated" (i.e. pcap_activate).

    Further, if called on an already activated handle, the call returns the PCAP_ERROR_ACTIVATED error.

    I've looked through the libpcap source code and ...

    Once a connection has been activated, I can find no pcap_* call that will "deactivate" it. So, we may have to close the handle and open a fresh instance.

    Also, AFAICT, do pcap_set_rfmon with 0 clears a flag (e.g. pcap->opt.rfmon). But, with a new instance (i.e. before calling pcap_activate), this should already be clear, so this is an effective no-op.

    The interface is already in a given mode from the first pcap_activate call. Generally, it doesn't "reset" if we call pcap_close (Note: For some interfaces, the interface will be marked to reset upon pcap_close but we probably can't rely on that in general).

    What is the default mode? I'm guessing promiscuous mode, so to reset monitor mode, we may have to use pcap_set_promisc instead.

    That worked. Thank you. pcap_set_promisc works without a second pcap_set_rfmon. – Benjamin Mickler