]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wlantest: Add option for writing a PCAP dump file
authorJouni Malinen <j@w1.fi>
Thu, 11 Nov 2010 23:00:31 +0000 (01:00 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 11 Nov 2010 23:00:31 +0000 (01:00 +0200)
The output file includes all the capture (or read from wireless PCAP
file) frames in their original contents and another copy of each
frame that is decrypted in wlantest (including EAPOL-Key Key Data
field).

wlantest/Makefile
wlantest/monitor.c
wlantest/readpcap.c
wlantest/rx_data.c
wlantest/rx_mgmt.c
wlantest/wlantest.c
wlantest/wlantest.h
wlantest/writepcap.c [new file with mode: 0644]

index c8ba66540a7e7c0c8f89cf00037922c3f6ba406f..8e42dc7b0d21377a2f3b922dd6dc7be32ba8a887 100644 (file)
@@ -50,6 +50,7 @@ OBJS += ../src/rsn_supp/wpa_ie.o
 
 OBJS += wlantest.o
 OBJS += readpcap.o
+OBJS += writepcap.o
 OBJS += monitor.o
 OBJS += process.o
 OBJS += wired.o
index 057073ee78be58e5847ee0e94a1e5ffadd7621dc..c16893a6f8f41d1bf16a92368092f53bb413c438 100644 (file)
@@ -33,6 +33,7 @@ static void monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                return;
        }
 
+       write_pcap_captured(wt, buf, len);
        wlantest_process(wt, buf, len);
 }
 
index dfb7ac0708d6a3fc489d802ad95e5678668e6416..bd93d7b5ceb3515e76679e13b2a4a1e889be8d4e 100644 (file)
@@ -55,6 +55,10 @@ int read_cap_file(struct wlantest *wt, const char *fname)
                           "len=%u/%u",
                           (int) hdr->ts.tv_sec, (int) hdr->ts.tv_usec,
                           hdr->caplen, hdr->len);
+               if (wt->write_pcap_dumper) {
+                       wt->write_pcap_time = hdr->ts;
+                       pcap_dump(wt->write_pcap_dumper, hdr, data);
+               }
                if (hdr->caplen < hdr->len) {
                        wpa_printf(MSG_DEBUG, "pcap: Dropped incomplete frame "
                                   "(%u/%u captured)",
index 2ce7f88479fed608400c168f392fdfdc2913de0f..1b6e4fcc4aa7ee4ca34cd8f64f55aba95e41dc38 100644 (file)
@@ -427,6 +427,44 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
        }
        wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data",
                    decrypted, decrypted_len);
+       if (wt->write_pcap_dumper) {
+               /* Fill in a dummy Data frame header */
+               u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr)];
+               struct ieee80211_hdr *h;
+               struct wpa_eapol_key *k;
+               u8 *pos;
+               size_t plain_len;
+
+               plain_len = decrypted_len;
+               pos = decrypted;
+               while (pos + 1 < decrypted + decrypted_len) {
+                       if (pos[0] == 0xdd && pos[1] == 0x00) {
+                               /* Remove padding */
+                               plain_len = pos - decrypted;
+                               break;
+                       }
+                       pos += 2 + pos[1];
+               }
+
+               os_memset(buf, 0, sizeof(buf));
+               h = (struct ieee80211_hdr *) buf;
+               h->frame_control = host_to_le16(0x0208);
+               os_memcpy(h->addr1, dst, ETH_ALEN);
+               os_memcpy(h->addr2, src, ETH_ALEN);
+               os_memcpy(h->addr3, src, ETH_ALEN);
+               pos = (u8 *) (h + 1);
+               os_memcpy(pos, "\xaa\xaa\x03\x00\x00\x00\x88\x8e", 8);
+               pos += 8;
+               os_memcpy(pos, eapol, sizeof(*eapol));
+               pos += sizeof(*eapol);
+               os_memcpy(pos, hdr, sizeof(*hdr));
+               k = (struct wpa_eapol_key *) pos;
+               WPA_PUT_BE16(k->key_info,
+                            key_info & ~WPA_KEY_INFO_ENCR_KEY_DATA);
+               WPA_PUT_BE16(k->key_data_length, plain_len);
+               write_pcap_decrypted(wt, buf, sizeof(buf),
+                                    decrypted, plain_len);
+       }
        learn_kde_keys(bss, decrypted, decrypted_len, hdr->key_rsc);
        os_free(decrypted);
 }
@@ -820,6 +858,8 @@ static void rx_data_bss_prot_group(struct wlantest *wt,
        if (decrypted) {
                rx_data_process(wt, dst, src, decrypted, dlen, 1);
                os_memcpy(bss->rsc[keyid], pn, 6);
+               write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
+                                    decrypted, dlen);
        }
        os_free(decrypted);
 }
@@ -896,6 +936,8 @@ static void rx_data_bss_prot(struct wlantest *wt,
        if (decrypted) {
                rx_data_process(wt, dst, src, decrypted, dlen, 1);
                os_memcpy(rsc, pn, 6);
+               write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
+                                    decrypted, dlen);
        }
        os_free(decrypted);
 }
index e00b98ae5e94f63e8efded4a985180cb114a6d92..8147cc15be98f35f018e1ed5baa13f3a37e5c8b1 100644 (file)
@@ -751,6 +751,7 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
             stype == WLAN_FC_STYPE_ACTION)) {
                decrypted = mgmt_ccmp_decrypt(wt, data, len, &dlen);
                if (decrypted) {
+                       write_pcap_decrypted(wt, decrypted, dlen, NULL, 0);
                        data = decrypted;
                        len = dlen;
                } else
index fc1d40811e349ff9b2da462dd85fc9643f906ca0..8f73581399af1e17c4f4bc89faea8252e7ba6645 100644 (file)
@@ -34,7 +34,8 @@ static void usage(void)
        printf("wlantest [-ddhqq] [-i<ifname>] [-r<pcap file>] "
               "[-p<passphrase>]\n"
                "         [-I<wired ifname>] [-R<wired pcap file>] "
-              "[-P<RADIUS shared secret>]\n");
+              "[-P<RADIUS shared secret>]\n"
+               "         [-w<write pcap file>]\n");
 }
 
 
@@ -93,6 +94,7 @@ static void wlantest_deinit(struct wlantest *wt)
                radius_deinit(r);
        dl_list_for_each_safe(pmk, np, &wt->pmk, struct wlantest_pmk, list)
                pmk_deinit(pmk);
+       write_pcap_deinit(wt);
 }
 
 
@@ -131,6 +133,7 @@ int main(int argc, char *argv[])
        int c;
        const char *read_file = NULL;
        const char *read_wired_file = NULL;
+       const char *write_file = NULL;
        const char *ifname = NULL;
        const char *ifname_wired = NULL;
        struct wlantest wt;
@@ -144,7 +147,7 @@ int main(int argc, char *argv[])
        wlantest_init(&wt);
 
        for (;;) {
-               c = getopt(argc, argv, "dhi:I:p:P:qr:R:");
+               c = getopt(argc, argv, "dhi:I:p:P:qr:R:w:");
                if (c < 0)
                        break;
                switch (c) {
@@ -176,6 +179,9 @@ int main(int argc, char *argv[])
                case 'R':
                        read_wired_file = optarg;
                        break;
+               case 'w':
+                       write_file = optarg;
+                       break;
                default:
                        usage();
                        return -1;
@@ -191,6 +197,9 @@ int main(int argc, char *argv[])
        if (eloop_init())
                return -1;
 
+       if (write_file && write_pcap_init(&wt, write_file) < 0)
+               return -1;
+
        if (read_wired_file && read_wired_cap_file(&wt, read_wired_file) < 0)
                return -1;
 
index fa32e669a40b0d7a3a8df118eaaef1de4efadab0..744e9f064595e74f56dd09038b5fb32520b13417 100644 (file)
@@ -103,10 +103,19 @@ struct wlantest {
        unsigned int rx_ctrl;
        unsigned int rx_data;
        unsigned int fcs_error;
+
+       void *write_pcap; /* pcap_t* */
+       void *write_pcap_dumper; /* pcpa_dumper_t */
+       struct timeval write_pcap_time;
 };
 
 int read_cap_file(struct wlantest *wt, const char *fname);
 int read_wired_cap_file(struct wlantest *wt, const char *fname);
+int write_pcap_init(struct wlantest *wt, const char *fname);
+void write_pcap_deinit(struct wlantest *wt);
+void write_pcap_captured(struct wlantest *wt, const u8 *buf, size_t len);
+void write_pcap_decrypted(struct wlantest *wt, const u8 *buf1, size_t len1,
+                         const u8 *buf2, size_t len2);
 void wlantest_process(struct wlantest *wt, const u8 *data, size_t len);
 void wlantest_process_wired(struct wlantest *wt, const u8 *data, size_t len);
 u32 crc32(const u8 *frame, size_t frame_len);
diff --git a/wlantest/writepcap.c b/wlantest/writepcap.c
new file mode 100644 (file)
index 0000000..75904a6
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * PCAP capture file writer
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+#include <pcap/pcap.h>
+#include <pcap/bpf.h>
+
+#include "utils/common.h"
+#include "wlantest.h"
+
+
+int write_pcap_init(struct wlantest *wt, const char *fname)
+{
+       wt->write_pcap = pcap_open_dead(DLT_IEEE802_11_RADIO, 4000);
+       if (wt->write_pcap == NULL)
+               return -1;
+       wt->write_pcap_dumper = pcap_dump_open(wt->write_pcap, fname);
+       if (wt->write_pcap_dumper == NULL) {
+               pcap_close(wt->write_pcap);
+               wt->write_pcap = NULL;
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "Writing PCAP dump to '%s'", fname);
+
+       return 0;
+}
+
+
+void write_pcap_deinit(struct wlantest *wt)
+{
+       if (wt->write_pcap_dumper) {
+               pcap_dump_close(wt->write_pcap_dumper);
+               wt->write_pcap_dumper = NULL;
+       }
+       if (wt->write_pcap) {
+               pcap_close(wt->write_pcap);
+               wt->write_pcap = NULL;
+       }
+}
+
+
+void write_pcap_captured(struct wlantest *wt, const u8 *buf, size_t len)
+{
+       struct pcap_pkthdr h;
+
+       if (!wt->write_pcap_dumper)
+               return;
+
+       os_memset(&h, 0, sizeof(h));
+       gettimeofday(&wt->write_pcap_time, NULL);
+       h.ts = wt->write_pcap_time;
+       h.caplen = len;
+       h.len = len;
+       pcap_dump(wt->write_pcap_dumper, &h, buf);
+}
+
+
+void write_pcap_decrypted(struct wlantest *wt, const u8 *buf1, size_t len1,
+                         const u8 *buf2, size_t len2)
+{
+       struct pcap_pkthdr h;
+       u8 rtap[] = {
+               0x00 /* rev */,
+               0x00 /* pad */,
+               0x08, 0x00, /* header len */
+               0x00, 0x00, 0x00, 0x00 /* present flags */
+       };
+       u8 *buf;
+       size_t len;
+
+       if (!wt->write_pcap_dumper)
+               return;
+
+       os_memset(&h, 0, sizeof(h));
+       h.ts = wt->write_pcap_time;
+       len = sizeof(rtap) + len1 + len2;
+       buf = os_malloc(len);
+       if (buf == NULL)
+               return;
+       os_memcpy(buf, rtap, sizeof(rtap));
+       if (buf1) {
+               os_memcpy(buf + sizeof(rtap), buf1, len1);
+               buf[sizeof(rtap) + 1] &= ~0x40; /* Clear Protected flag */
+       }
+       if (buf2)
+               os_memcpy(buf + sizeof(rtap) + len1, buf2, len2);
+       h.caplen = len;
+       h.len = len;
+       pcap_dump(wt->write_pcap_dumper, &h, buf);
+       os_free(buf);
+}