It is written with a simple-to-use approach while also exposing features that allow more advanced use, with clean and readable code being a priority.
Other goals of the library include cross-architecture support, clean compilation without warnings and strict error checking.
When using libwifi, be sure to pass -lwifi to the linker, and make sure that the libwifi shared library is installed on the system.
Parsing
The generic flow of a program using libwifi to parse frames is a loop that reads captured packets as raw data, such as with libpcap from a file or monitor interface, then parse the frame into a common datatype, then parse 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);
}
libwifi_get_frame() which checks for frame validity and type/subtype, 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 struct can then be given to one of the frame parser functions, such as libwifi_parse_beacon(). Since the header comment for
libwifi_parse_beacon() indicates that the parsed data is stored in a struct libwifi_bss, we need to initalise one and pass it as a parameter.
We'll use the BSS struct 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 example,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;
}
pcap_dump() or transmitting from a 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