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