libwifi – An 802.11 Frame Parsing and Generation library written in C.

libwifi is a fast, simple C shared library with a permissive license to directly generate and parse a variety of 802.11 wireless frames on Linux and macOS with a few lines of code.

It is written with an easy-to-use approach in mind, while also highlighting features that allow more advanced use, with clean and readable code a priority.

Other goals of the library include cross-architecture support, clean compilation without warnings, and strict error checking.

libwifi exposes functions and constructs to make parsing and generating WiFi frames much easier, and examples can be found in the source examples directory.

When using LibWifi, be sure to pass -lwifi For the linker, and make sure the libwifi shared library is installed on the system.

dissection

The general flow of a program using libwifi to parse frames is a loop that reads captured packets as raw data, such as from a file or monitor interface with libpcap, then parses the frame into a generic datatype, then parses again to retrieve frame specific data.

static int got_radiotap = 0;

int main(int argc, const char *argv[]) {
    pcap_t handle = {0};
    char errbuf[PCAP_ERRBUF_SIZE] = {0};

    if ((handle = pcap_create(argv[2], errbuf)) == NULL) {
        exit(EXIT_FAILURE);
    }

    if (pcap_activate(handle) != 0) {
        pcap_close(handle);
        exit(EXIT_FAILURE);
    }

    int linktype = pcap_datalink(handle);
    if (linktype == DLT_IEEE802_11_RADIO) {
        got_radiotap = 1;
    } else if (linktype == DLT_IEEE802_11) {
        got_radiotap = 0;
    } else {
        pcap_close(handle);
        exit(EXIT_FAILURE);
    }

    pd = pcap_dump_open(handle, PCAP_SAVEFILE);
    pcap_loop(handle, -1 /*INFINITY*/, &parse_packet, (unsigned char *) pd);
}
    

Then the data is returned from the libpcap loop libwifi_get_frame() which checks the validity and type/subtype of the frame, and stores the data in a struct libwifi_frame,

void parse_packet(unsigned char *args,
                  const struct pcap_pkthdr *header,
                  const unsigned char *packet) {
    unsigned long data_len = header->caplen;
    unsigned char *data = (unsigned char *) packet;

    struct libwifi_frame frame = {0};
    int ret = libwifi_get_wifi_frame(&frame, data, data_len, got_radiotap);
    if (ret != 0) {
        printf("[!] Error getting libwifi_frame: %d\n", ret);
        return;
    }
    

libwifi_frame The struct can then be passed to one of the frame parser functions, e.g. libwifi_parse_beacon()Since the header is for comment
libwifi_parse_beacon() indicates that the parsed data is stored in a struct libwifi_bssWe need to initialize one and pass it as a parameter.

We will use the BSS structure to easily show the SSID and channel from the sniffed beacon frame.

    if (frame.frame_control.type == TYPE_MANAGEMENT &&
        frame.frame_control.subtype == SUBTYPE_BEACON) {
        struct libwifi_bss bss = {0};

        int ret = libwifi_parse_beacon(&bss, &frame);
        if (ret != 0) {
            printf("Failed to parse beacon: %d\n", ret);
            return;
        }

        printf("SSID: %s, Channel: %d\n", bss.ssid, bss.channel);
    }
}
    

generation

For frame generation, you only need to provide the required data to one of the frame generation functions. in this instance, libwifi_create_beacon(),

int main(int argc, char **argv) {
    struct libwifi_beacon beacon = {0};
    static unsigned char bcast[] = "\xFF\xFF\xFF\xFF\xFF\xFF";
    static unsigned char tx[] = "\x00\x20\x91\xAA\xBB\CC";

    int ret = libwifi_create_beacon(&beacon, bcast, tx, tx, "wifi-beacon", 11);
    if (ret != 0) {
        return ret;
    }
    

From here, we can use the dumper function for this frame subtype to write the beacon in raw byte format to the buffer. This may be useful to write the generated frames to a pcap file using pcap_dump() Or transmitting from the monitor mode interface.

    unsigned char *buf = NULL;
    size_t buf_sz = libwifi_get_beacon_length(&beacon);

    buf = malloc(buf_sz);
    if (buf == NULL) {
        exit(EXIT_FAILURE);
    }

    ret = libwifi_dump_beacon(&beacon, buf, buf_sz);
    if (ret < 0) {
        return ret;
    }

    // Inject frame bytes or write bytes to file

    libwifi_free_beacon(&beacon);
    free(buf);
}
    



Leave a Comment