wlantest: Add support for writing pcapng files
[mech_eap.git] / wlantest / wlantest.c
1 /*
2  * wlantest - IEEE 802.11 protocol monitoring and testing tool
3  * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "wlantest.h"
14
15
16 extern int wpa_debug_level;
17 extern int wpa_debug_show_keys;
18
19
20 static void wlantest_terminate(int sig, void *signal_ctx)
21 {
22         eloop_terminate();
23 }
24
25
26 static void usage(void)
27 {
28         printf("wlantest [-cddhqqF] [-i<ifname>] [-r<pcap file>] "
29                "[-p<passphrase>]\n"
30                "         [-I<wired ifname>] [-R<wired pcap file>] "
31                "[-P<RADIUS shared secret>]\n"
32                "         [-n<write pcapng file>]\n"
33                "         [-w<write pcap file>] [-f<MSK/PMK file>]\n");
34 }
35
36
37 static void passphrase_deinit(struct wlantest_passphrase *p)
38 {
39         dl_list_del(&p->list);
40         os_free(p);
41 }
42
43
44 static void secret_deinit(struct wlantest_radius_secret *r)
45 {
46         dl_list_del(&r->list);
47         os_free(r);
48 }
49
50
51 static void wlantest_init(struct wlantest *wt)
52 {
53         int i;
54         os_memset(wt, 0, sizeof(*wt));
55         wt->monitor_sock = -1;
56         wt->ctrl_sock = -1;
57         for (i = 0; i < MAX_CTRL_CONNECTIONS; i++)
58                 wt->ctrl_socks[i] = -1;
59         dl_list_init(&wt->passphrase);
60         dl_list_init(&wt->bss);
61         dl_list_init(&wt->secret);
62         dl_list_init(&wt->radius);
63         dl_list_init(&wt->pmk);
64         dl_list_init(&wt->wep);
65 }
66
67
68 void radius_deinit(struct wlantest_radius *r)
69 {
70         dl_list_del(&r->list);
71         os_free(r);
72 }
73
74
75 static void wlantest_deinit(struct wlantest *wt)
76 {
77         struct wlantest_passphrase *p, *pn;
78         struct wlantest_radius_secret *s, *sn;
79         struct wlantest_radius *r, *rn;
80         struct wlantest_pmk *pmk, *np;
81         struct wlantest_wep *wep, *nw;
82
83         if (wt->ctrl_sock >= 0)
84                 ctrl_deinit(wt);
85         if (wt->monitor_sock >= 0)
86                 monitor_deinit(wt);
87         bss_flush(wt);
88         dl_list_for_each_safe(p, pn, &wt->passphrase,
89                               struct wlantest_passphrase, list)
90                 passphrase_deinit(p);
91         dl_list_for_each_safe(s, sn, &wt->secret,
92                               struct wlantest_radius_secret, list)
93                 secret_deinit(s);
94         dl_list_for_each_safe(r, rn, &wt->radius, struct wlantest_radius, list)
95                 radius_deinit(r);
96         dl_list_for_each_safe(pmk, np, &wt->pmk, struct wlantest_pmk, list)
97                 pmk_deinit(pmk);
98         dl_list_for_each_safe(wep, nw, &wt->wep, struct wlantest_wep, list)
99                 os_free(wep);
100         write_pcap_deinit(wt);
101         write_pcapng_deinit(wt);
102         clear_notes(wt);
103         os_free(wt->decrypted);
104         wt->decrypted = NULL;
105 }
106
107
108 static void add_passphrase(struct wlantest *wt, const char *passphrase)
109 {
110         struct wlantest_passphrase *p;
111         size_t len = os_strlen(passphrase);
112
113         if (len < 8 || len > 63)
114                 return;
115         p = os_zalloc(sizeof(*p));
116         if (p == NULL)
117                 return;
118         os_memcpy(p->passphrase, passphrase, len);
119         dl_list_add(&wt->passphrase, &p->list);
120 }
121
122
123 static void add_secret(struct wlantest *wt, const char *secret)
124 {
125         struct wlantest_radius_secret *s;
126         size_t len = os_strlen(secret);
127
128         if (len >= MAX_RADIUS_SECRET_LEN)
129                 return;
130         s = os_zalloc(sizeof(*s));
131         if (s == NULL)
132                 return;
133         os_memcpy(s->secret, secret, len);
134         dl_list_add(&wt->secret, &s->list);
135 }
136
137
138 static int add_pmk_file(struct wlantest *wt, const char *pmk_file)
139 {
140         FILE *f;
141         u8 pmk[32];
142         char buf[300], *pos;
143         struct wlantest_pmk *p;
144
145         f = fopen(pmk_file, "r");
146         if (f == NULL) {
147                 wpa_printf(MSG_ERROR, "Could not open '%s'", pmk_file);
148                 return -1;
149         }
150
151         while (fgets(buf, sizeof(buf), f)) {
152                 pos = buf;
153                 while (*pos && *pos != '\r' && *pos != '\n')
154                         pos++;
155                 *pos = '\0';
156                 if (pos - buf < 2 * 32)
157                         continue;
158                 if (hexstr2bin(buf, pmk, 32) < 0)
159                         continue;
160                 p = os_zalloc(sizeof(*p));
161                 if (p == NULL)
162                         break;
163                 os_memcpy(p->pmk, pmk, 32);
164                 dl_list_add(&wt->pmk, &p->list);
165                 wpa_hexdump(MSG_DEBUG, "Added PMK from file", pmk, 32);
166         }
167
168         fclose(f);
169         return 0;
170 }
171
172
173 int add_wep(struct wlantest *wt, const char *key)
174 {
175         struct wlantest_wep *w;
176         size_t len = os_strlen(key);
177
178         if (len != 2 * 5 && len != 2 * 13) {
179                 wpa_printf(MSG_INFO, "Invalid WEP key '%s'", key);
180                 return -1;
181         }
182         w = os_zalloc(sizeof(*w));
183         if (w == NULL)
184                 return -1;
185         if (hexstr2bin(key, w->key, len / 2) < 0) {
186                 os_free(w);
187                 wpa_printf(MSG_INFO, "Invalid WEP key '%s'", key);
188                 return -1;
189         }
190         w->key_len = len / 2;
191         dl_list_add(&wt->wep, &w->list);
192         return 0;
193 }
194
195
196 void add_note(struct wlantest *wt, int level, const char *fmt, ...)
197 {
198         va_list ap;
199         size_t len = 1000;
200         int wlen;
201
202         if (wt->num_notes == MAX_NOTES)
203                 return;
204
205         wt->notes[wt->num_notes] = os_malloc(len);
206         if (wt->notes[wt->num_notes] == NULL)
207                 return;
208         va_start(ap, fmt);
209         wlen = vsnprintf(wt->notes[wt->num_notes], len, fmt, ap);
210         va_end(ap);
211         if (wlen < 0) {
212                 os_free(wt->notes[wt->num_notes]);
213                 wt->notes[wt->num_notes] = NULL;
214                 return;
215         }
216         if (wlen >= len)
217                 wt->notes[wt->num_notes][len - 1] = '\0';
218         wpa_printf(level, "%s", wt->notes[wt->num_notes]);
219         wt->num_notes++;
220 }
221
222
223 void clear_notes(struct wlantest *wt)
224 {
225         size_t i;
226
227         for (i = 0; i < wt->num_notes; i++) {
228                 os_free(wt->notes[i]);
229                 wt->notes[i] = NULL;
230         }
231
232         wt->num_notes = 0;
233 }
234
235
236 size_t notes_len(struct wlantest *wt, size_t hdrlen)
237 {
238         size_t i;
239         size_t len = wt->num_notes * hdrlen;
240
241         for (i = 0; i < wt->num_notes; i++)
242                 len += os_strlen(wt->notes[i]);
243
244         return len;
245 }
246
247
248 int main(int argc, char *argv[])
249 {
250         int c;
251         const char *read_file = NULL;
252         const char *read_wired_file = NULL;
253         const char *write_file = NULL;
254         const char *ifname = NULL;
255         const char *ifname_wired = NULL;
256         const char *pcapng_file = NULL;
257         struct wlantest wt;
258         int ctrl_iface = 0;
259
260         wpa_debug_level = MSG_INFO;
261         wpa_debug_show_keys = 1;
262
263         if (os_program_init())
264                 return -1;
265
266         wlantest_init(&wt);
267
268         for (;;) {
269                 c = getopt(argc, argv, "cdf:Fhi:I:n:p:P:qr:R:w:W:");
270                 if (c < 0)
271                         break;
272                 switch (c) {
273                 case 'c':
274                         ctrl_iface = 1;
275                         break;
276                 case 'd':
277                         if (wpa_debug_level > 0)
278                                 wpa_debug_level--;
279                         break;
280                 case 'f':
281                         if (add_pmk_file(&wt, optarg) < 0)
282                                 return -1;
283                         break;
284                 case 'F':
285                         wt.assume_fcs = 1;
286                         break;
287                 case 'h':
288                         usage();
289                         return 0;
290                 case 'i':
291                         ifname = optarg;
292                         break;
293                 case 'I':
294                         ifname_wired = optarg;
295                         break;
296                 case 'n':
297                         pcapng_file = optarg;
298                         break;
299                 case 'p':
300                         add_passphrase(&wt, optarg);
301                         break;
302                 case 'P':
303                         add_secret(&wt, optarg);
304                         break;
305                 case 'q':
306                         wpa_debug_level++;
307                         break;
308                 case 'r':
309                         read_file = optarg;
310                         break;
311                 case 'R':
312                         read_wired_file = optarg;
313                         break;
314                 case 'w':
315                         write_file = optarg;
316                         break;
317                 case 'W':
318                         if (add_wep(&wt, optarg) < 0)
319                                 return -1;
320                         break;
321                 default:
322                         usage();
323                         return -1;
324                 }
325         }
326
327         if (ifname == NULL && ifname_wired == NULL &&
328             read_file == NULL && read_wired_file == NULL) {
329                 usage();
330                 return 0;
331         }
332
333         if (eloop_init())
334                 return -1;
335
336         if (write_file && write_pcap_init(&wt, write_file) < 0)
337                 return -1;
338
339         if (pcapng_file && write_pcapng_init(&wt, pcapng_file) < 0)
340                 return -1;
341
342         if (read_wired_file && read_wired_cap_file(&wt, read_wired_file) < 0)
343                 return -1;
344
345         if (read_file && read_cap_file(&wt, read_file) < 0)
346                 return -1;
347
348         if (ifname && monitor_init(&wt, ifname) < 0)
349                 return -1;
350
351         if (ifname_wired && monitor_init_wired(&wt, ifname_wired) < 0)
352                 return -1;
353
354         if (ctrl_iface && ctrl_init(&wt) < 0)
355                 return -1;
356
357         eloop_register_signal_terminate(wlantest_terminate, &wt);
358
359         eloop_run();
360
361         wpa_printf(MSG_INFO, "Processed: rx_mgmt=%u rx_ctrl=%u rx_data=%u "
362                    "fcs_error=%u",
363                    wt.rx_mgmt, wt.rx_ctrl, wt.rx_data, wt.fcs_error);
364
365         wlantest_deinit(&wt);
366
367         eloop_destroy();
368         os_program_deinit();
369
370         return 0;
371 }