aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-11-11 23:00:31 (GMT)
committerJouni Malinen <j@w1.fi>2010-11-11 23:00:31 (GMT)
commit64f45d070b13f260c2e2f7bb21527f5a809b5cde (patch)
treeea1812b9811ae4e49a16cf1fd00a836e10e37a1d
parent5db8cf314ef169cd256483e32dcc49e31e605121 (diff)
downloadhostap-64f45d070b13f260c2e2f7bb21527f5a809b5cde.zip
hostap-64f45d070b13f260c2e2f7bb21527f5a809b5cde.tar.gz
hostap-64f45d070b13f260c2e2f7bb21527f5a809b5cde.tar.bz2
wlantest: Add option for writing a PCAP dump file
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).
-rw-r--r--wlantest/Makefile1
-rw-r--r--wlantest/monitor.c1
-rw-r--r--wlantest/readpcap.c4
-rw-r--r--wlantest/rx_data.c42
-rw-r--r--wlantest/rx_mgmt.c1
-rw-r--r--wlantest/wlantest.c13
-rw-r--r--wlantest/wlantest.h9
-rw-r--r--wlantest/writepcap.c103
8 files changed, 172 insertions, 2 deletions
diff --git a/wlantest/Makefile b/wlantest/Makefile
index c8ba665..8e42dc7 100644
--- a/wlantest/Makefile
+++ b/wlantest/Makefile
@@ -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
diff --git a/wlantest/monitor.c b/wlantest/monitor.c
index 057073e..c16893a 100644
--- a/wlantest/monitor.c
+++ b/wlantest/monitor.c
@@ -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);
}
diff --git a/wlantest/readpcap.c b/wlantest/readpcap.c
index dfb7ac0..bd93d7b 100644
--- a/wlantest/readpcap.c
+++ b/wlantest/readpcap.c
@@ -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)",
diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c
index 2ce7f88..1b6e4fc 100644
--- a/wlantest/rx_data.c
+++ b/wlantest/rx_data.c
@@ -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);
}
diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c
index e00b98a..8147cc1 100644
--- a/wlantest/rx_mgmt.c
+++ b/wlantest/rx_mgmt.c
@@ -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
diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c
index fc1d408..8f73581 100644
--- a/wlantest/wlantest.c
+++ b/wlantest/wlantest.c
@@ -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;
diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h
index fa32e66..744e9f0 100644
--- a/wlantest/wlantest.h
+++ b/wlantest/wlantest.h
@@ -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
index 0000000..75904a6
--- /dev/null
+++ b/wlantest/writepcap.c
@@ -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);
+}