wlantest: Add RELOG command to reopen log/capture files
[mech_eap.git] / wlantest / wlantest.c
1 /*
2  * wlantest - IEEE 802.11 protocol monitoring and testing tool
3  * Copyright (c) 2010-2013, 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 wlantest_relog(struct wlantest *wt)
249 {
250         int ret = 0;
251
252         wpa_printf(MSG_INFO, "Re-open log/capture files");
253
254         if (wt->write_file) {
255                 write_pcap_deinit(wt);
256                 if (write_pcap_init(wt, wt->write_file) < 0)
257                         ret = -1;
258         }
259
260         if (wt->pcapng_file) {
261                 write_pcapng_deinit(wt);
262                 if (write_pcapng_init(wt, wt->pcapng_file) < 0)
263                         ret = -1;
264         }
265
266         return ret;
267 }
268
269
270 int main(int argc, char *argv[])
271 {
272         int c;
273         const char *read_file = NULL;
274         const char *read_wired_file = NULL;
275         const char *ifname = NULL;
276         const char *ifname_wired = NULL;
277         struct wlantest wt;
278         int ctrl_iface = 0;
279
280         wpa_debug_level = MSG_INFO;
281         wpa_debug_show_keys = 1;
282
283         if (os_program_init())
284                 return -1;
285
286         wlantest_init(&wt);
287
288         for (;;) {
289                 c = getopt(argc, argv, "cdf:Fhi:I:n:p:P:qr:R:w:W:");
290                 if (c < 0)
291                         break;
292                 switch (c) {
293                 case 'c':
294                         ctrl_iface = 1;
295                         break;
296                 case 'd':
297                         if (wpa_debug_level > 0)
298                                 wpa_debug_level--;
299                         break;
300                 case 'f':
301                         if (add_pmk_file(&wt, optarg) < 0)
302                                 return -1;
303                         break;
304                 case 'F':
305                         wt.assume_fcs = 1;
306                         break;
307                 case 'h':
308                         usage();
309                         return 0;
310                 case 'i':
311                         ifname = optarg;
312                         break;
313                 case 'I':
314                         ifname_wired = optarg;
315                         break;
316                 case 'n':
317                         wt.pcapng_file = optarg;
318                         break;
319                 case 'p':
320                         add_passphrase(&wt, optarg);
321                         break;
322                 case 'P':
323                         add_secret(&wt, optarg);
324                         break;
325                 case 'q':
326                         wpa_debug_level++;
327                         break;
328                 case 'r':
329                         read_file = optarg;
330                         break;
331                 case 'R':
332                         read_wired_file = optarg;
333                         break;
334                 case 'w':
335                         wt.write_file = optarg;
336                         break;
337                 case 'W':
338                         if (add_wep(&wt, optarg) < 0)
339                                 return -1;
340                         break;
341                 default:
342                         usage();
343                         return -1;
344                 }
345         }
346
347         if (ifname == NULL && ifname_wired == NULL &&
348             read_file == NULL && read_wired_file == NULL) {
349                 usage();
350                 return 0;
351         }
352
353         if (eloop_init())
354                 return -1;
355
356         if (wt.write_file && write_pcap_init(&wt, wt.write_file) < 0)
357                 return -1;
358
359         if (wt.pcapng_file && write_pcapng_init(&wt, wt.pcapng_file) < 0)
360                 return -1;
361
362         if (read_wired_file && read_wired_cap_file(&wt, read_wired_file) < 0)
363                 return -1;
364
365         if (read_file && read_cap_file(&wt, read_file) < 0)
366                 return -1;
367
368         if (ifname && monitor_init(&wt, ifname) < 0)
369                 return -1;
370
371         if (ifname_wired && monitor_init_wired(&wt, ifname_wired) < 0)
372                 return -1;
373
374         if (ctrl_iface && ctrl_init(&wt) < 0)
375                 return -1;
376
377         eloop_register_signal_terminate(wlantest_terminate, &wt);
378
379         eloop_run();
380
381         wpa_printf(MSG_INFO, "Processed: rx_mgmt=%u rx_ctrl=%u rx_data=%u "
382                    "fcs_error=%u",
383                    wt.rx_mgmt, wt.rx_ctrl, wt.rx_data, wt.fcs_error);
384
385         wlantest_deinit(&wt);
386
387         eloop_destroy();
388         os_program_deinit();
389
390         return 0;
391 }