1160994Ssam/*- 2160994Ssam * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk> 3160994Ssam * All rights reserved. 4160994Ssam * 5160994Ssam * Redistribution and use in source and binary forms, with or without 6160994Ssam * modification, are permitted provided that the following conditions 7160994Ssam * are met: 8160994Ssam * 1. Redistributions of source code must retain the above copyright 9160994Ssam * notice, this list of conditions and the following disclaimer. 10160994Ssam * 2. Redistributions in binary form must reproduce the above copyright 11160994Ssam * notice, this list of conditions and the following disclaimer in the 12160994Ssam * documentation and/or other materials provided with the distribution. 13160994Ssam * 14160994Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15160994Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16160994Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17160994Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18160994Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19160994Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20160994Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21160994Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22160994Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23160994Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24160994Ssam * SUCH DAMAGE. 25160994Ssam * 26160994Ssam * $FreeBSD$ 27160994Ssam */ 28160994Ssam#include <sys/types.h> 29160994Ssam#include <sys/socket.h> 30160994Ssam#include <sys/ioctl.h> 31160994Ssam#include <sys/select.h> 32160994Ssam#include <sys/time.h> 33160994Ssam#include <net/if.h> 34160994Ssam#include <net/if_media.h> 35160994Ssam#include <net/bpf.h> 36160994Ssam#include <net80211/ieee80211_ioctl.h> 37160994Ssam#include <net80211/ieee80211.h> 38160994Ssam#include <net/ethernet.h> 39160994Ssam#include <net80211/ieee80211_radiotap.h> 40160994Ssam#include <sys/endian.h> 41160994Ssam#include <fcntl.h> 42160994Ssam#include <errno.h> 43160994Ssam#include <string.h> 44160994Ssam#include <stdlib.h> 45160994Ssam#include <stdio.h> 46160994Ssam#include <curses.h> 47160994Ssam#include <signal.h> 48160994Ssam#include <unistd.h> 49160994Ssam#include <assert.h> 50160994Ssam 51160994Ssam//int hopfreq = 3*1000; // ms 52160994Ssamint hopfreq = 500; // ms 53160994Ssamint sig_reset = 1*1000; // ms 54160994Ssam 55160994Ssam 56160994Ssamint ioctl_s = -1; 57160994Ssamint bpf_s = -1; 58160994Ssam 59160994Ssamstruct chan_info { 60160994Ssam int locked; 61160994Ssam int chan; 62160994Ssam struct ieee80211req ireq; 63160994Ssam struct timeval last_hop; 64160994Ssam} chaninfo; 65160994Ssam 66160994Ssam 67160994Ssam#define CRYPT_NONE 0 68160994Ssam#define CRYPT_WEP 1 69160994Ssam#define CRYPT_WPA1 2 70160994Ssam#define CRYPT_WPA 3 71160994Ssam#define CRYPT_WPA1_TKIP 4 72160994Ssam#define CRYPT_WPA1_TKIP_PSK 5 73160994Ssam#define CRYPT_WPA1_CCMP 6 74160994Ssam#define CRYPT_WPA1_CCMP_PSK 7 75160994Ssam#define CRYPT_80211i 8 76160994Ssam#define CRYPT_80211i_TKIP 9 77160994Ssam#define CRYPT_80211i_TKIP_PSK 10 78160994Ssam 79160994Ssamstruct node_info { 80160994Ssam unsigned char mac[6]; 81160994Ssam int signal; 82160994Ssam int noise; 83160994Ssam int max; 84160994Ssam unsigned char ssid[256]; 85160994Ssam int chan; 86160994Ssam int wep; 87160994Ssam int pos; 88160994Ssam int ap; 89160994Ssam 90160994Ssam struct timeval seen; 91160994Ssam 92160994Ssam struct node_info* prev; 93160994Ssam struct node_info* next; 94160994Ssam} *nodes = 0; 95160994Ssam 96160994Ssamvoid clean_crap() { 97160994Ssam struct node_info* next; 98160994Ssam 99160994Ssam if (ioctl_s != -1) 100160994Ssam close(ioctl_s); 101160994Ssam if (bpf_s != -1) 102160994Ssam close(bpf_s); 103160994Ssam 104160994Ssam while (nodes) { 105160994Ssam next = nodes->next; 106160994Ssam free(nodes); 107160994Ssam nodes = next; 108160994Ssam } 109160994Ssam} 110160994Ssam 111160994Ssamchar* mac2str(unsigned char* mac) { 112160994Ssam static char ret[6*3]; 113160994Ssam 114160994Ssam sprintf(ret, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", 115160994Ssam mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 116160994Ssam 117160994Ssam return ret; 118160994Ssam} 119160994Ssam 120160994Ssamchar* wep2str(int w) { 121160994Ssam char* wep = 0; 122160994Ssam static char res[14]; 123160994Ssam 124160994Ssam switch (w) { 125160994Ssam case CRYPT_NONE: 126160994Ssam wep = ""; 127160994Ssam break; 128160994Ssam 129160994Ssam case CRYPT_WEP: 130160994Ssam wep = "WEP"; 131160994Ssam break; 132160994Ssam 133160994Ssam case CRYPT_WPA1: 134160994Ssam wep = "WPA1"; 135160994Ssam break; 136160994Ssam 137160994Ssam case CRYPT_WPA: 138160994Ssam wep = "WPA?"; 139160994Ssam break; 140160994Ssam 141160994Ssam case CRYPT_WPA1_TKIP: 142160994Ssam wep = "WPA1-TKIP"; 143160994Ssam break; 144160994Ssam 145160994Ssam case CRYPT_WPA1_TKIP_PSK: 146160994Ssam wep = "WPA1-TKIP-PSK"; 147160994Ssam break; 148160994Ssam 149160994Ssam case CRYPT_WPA1_CCMP: 150160994Ssam wep = "WPA1-CCMP"; 151160994Ssam break; 152160994Ssam 153160994Ssam case CRYPT_WPA1_CCMP_PSK: 154160994Ssam wep = "WPA1-CCMP-PSK"; 155160994Ssam break; 156160994Ssam 157160994Ssam case CRYPT_80211i: 158160994Ssam wep = "i"; 159160994Ssam break; 160160994Ssam 161160994Ssam case CRYPT_80211i_TKIP: 162160994Ssam wep = "11i-TKIP"; 163160994Ssam break; 164160994Ssam 165160994Ssam case CRYPT_80211i_TKIP_PSK: 166160994Ssam wep = "11i-TKIP-PSK"; 167160994Ssam break; 168160994Ssam 169160994Ssam default: 170160994Ssam wep = "FIXME!"; 171160994Ssam break; 172160994Ssam } 173160994Ssam 174160994Ssam memset(res, ' ', sizeof(res)); 175160994Ssam assert(strlen(wep) < sizeof(res)); 176160994Ssam memcpy(res, wep, strlen(wep)); 177160994Ssam res[sizeof(res)-1] = 0; 178160994Ssam return res; 179160994Ssam} 180160994Ssam 181160994Ssamchar* ssid2str(struct node_info* node) { 182160994Ssam static char res[24]; 183160994Ssam 184160994Ssam memset(res, ' ', sizeof(res)); 185160994Ssam res[0] = '['; 186160994Ssam strcpy(&res[sizeof(res)-2], "]"); 187160994Ssam 188160994Ssam if (node->ap) { 189160994Ssam int left = sizeof(res) - 3; 190160994Ssam 191160994Ssam if (strlen(node->ssid) < left) 192160994Ssam left = strlen(node->ssid); 193160994Ssam memcpy(&res[1], node->ssid, left); 194160994Ssam } 195160994Ssam else { 196160994Ssam memcpy(&res[1], "<client>", 8); 197160994Ssam } 198160994Ssam return res; 199160994Ssam} 200160994Ssam 201160994Ssamvoid save_state() { 202160994Ssam FILE* f; 203160994Ssam struct node_info* node = nodes; 204160994Ssam 205160994Ssam f = fopen("stumbler.log", "w"); 206160994Ssam if (!f) { 207160994Ssam perror("fopen()"); 208160994Ssam exit(1); 209160994Ssam } 210160994Ssam 211160994Ssam while (node) { 212160994Ssam struct tm* t; 213160994Ssam char tim[16]; 214160994Ssam 215160994Ssam t = localtime( (time_t*) &node->seen.tv_sec); 216160994Ssam if (!t) { 217160994Ssam perror("localtime()"); 218160994Ssam exit(1); 219160994Ssam } 220160994Ssam tim[0] = 0; 221160994Ssam strftime(tim, sizeof(tim), "%H:%M:%S", t); 222160994Ssam 223160994Ssam fprintf(f, "%s %s %s %2d %s 0x%.2x\n", tim, 224160994Ssam mac2str(node->mac), wep2str(node->wep), 225160994Ssam node->chan, ssid2str(node), node->max); 226160994Ssam 227160994Ssam node = node->next; 228160994Ssam } 229160994Ssam 230160994Ssam fclose(f); 231160994Ssam} 232160994Ssam 233160994Ssamvoid cleanup(int x) { 234160994Ssam endwin(); 235160994Ssam clean_crap(); 236160994Ssam exit(0); 237160994Ssam} 238160994Ssam 239160994Ssamvoid die(int p, char* msg) { 240160994Ssam endwin(); 241160994Ssam if (p) 242160994Ssam perror(msg); 243160994Ssam else 244160994Ssam printf("%s\n", msg); 245160994Ssam clean_crap(); 246160994Ssam exit(1); 247160994Ssam} 248160994Ssam 249160994Ssamvoid display_chan() { 250160994Ssam int x, y; 251160994Ssam char tmp[3]; 252160994Ssam 253160994Ssam x = COLS - 2; 254160994Ssam y = LINES - 1; 255160994Ssam 256160994Ssam snprintf(tmp, sizeof(tmp), "%.2d", chaninfo.chan); 257160994Ssam mvaddstr(y, x, tmp); 258160994Ssam refresh(); 259160994Ssam} 260160994Ssam 261160994Ssamvoid set_chan(int c) { 262160994Ssam chaninfo.ireq.i_val = c; 263160994Ssam 264160994Ssam if (ioctl(ioctl_s, SIOCS80211, &chaninfo.ireq) == -1) 265160994Ssam die(1, "ioctl(SIOCS80211) [chan]"); 266160994Ssam 267160994Ssam chaninfo.chan = c; 268160994Ssam 269160994Ssam if (gettimeofday(&chaninfo.last_hop, NULL) == -1) 270160994Ssam die(1, "gettimeofday()"); 271160994Ssam 272160994Ssam display_chan(); 273160994Ssam} 274160994Ssam 275160994Ssamvoid setup_if(char *dev) { 276160994Ssam struct ifreq ifr; 277160994Ssam unsigned int flags; 278195848Ssam 279195848Ssam // set chan 280195848Ssam memset(&chaninfo.ireq, 0, sizeof(chaninfo.ireq)); 281195848Ssam strcpy(chaninfo.ireq.i_name, dev); 282195848Ssam chaninfo.ireq.i_type = IEEE80211_IOC_CHANNEL; 283195848Ssam 284195848Ssam set_chan(1); 285195848Ssam 286160994Ssam // set iface up and promisc 287160994Ssam memset(&ifr, 0, sizeof(ifr)); 288160994Ssam strcpy(ifr.ifr_name, dev); 289160994Ssam if (ioctl(ioctl_s, SIOCGIFFLAGS, &ifr) == -1) 290160994Ssam die(1, "ioctl(SIOCGIFFLAGS)"); 291160994Ssam 292160994Ssam flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); 293160994Ssam flags |= IFF_UP | IFF_PPROMISC; 294160994Ssam 295160994Ssam memset(&ifr, 0, sizeof(ifr)); 296160994Ssam strcpy(ifr.ifr_name, dev); 297160994Ssam ifr.ifr_flags = flags & 0xffff; 298160994Ssam ifr.ifr_flagshigh = flags >> 16; 299160994Ssam if (ioctl(ioctl_s, SIOCSIFFLAGS, &ifr) == -1) 300160994Ssam die(1, "ioctl(SIOCSIFFLAGS)"); 301160994Ssam} 302160994Ssam 303160994Ssamvoid open_bpf(char *dev, int dlt) { 304160994Ssam int i; 305160994Ssam char buf[64]; 306160994Ssam int fd = -1; 307160994Ssam struct ifreq ifr; 308160994Ssam 309160994Ssam for(i = 0;i < 16; i++) { 310160994Ssam sprintf(buf, "/dev/bpf%d", i); 311160994Ssam 312160994Ssam fd = open(buf, O_RDWR); 313160994Ssam if(fd < 0) { 314160994Ssam if(errno != EBUSY) 315160994Ssam die(1,"can't open /dev/bpf"); 316160994Ssam continue; 317160994Ssam } 318160994Ssam else 319160994Ssam break; 320160994Ssam } 321160994Ssam 322160994Ssam if(fd < 0) 323160994Ssam die(1, "can't open /dev/bpf"); 324160994Ssam 325160994Ssam strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1); 326160994Ssam ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; 327160994Ssam 328160994Ssam if(ioctl(fd, BIOCSETIF, &ifr) < 0) 329160994Ssam die(1, "ioctl(BIOCSETIF)"); 330160994Ssam 331160994Ssam if (ioctl(fd, BIOCSDLT, &dlt) < 0) 332160994Ssam die(1, "ioctl(BIOCSDLT)"); 333160994Ssam 334160994Ssam i = 1; 335160994Ssam if(ioctl(fd, BIOCIMMEDIATE, &i) < 0) 336160994Ssam die(1, "ioctl(BIOCIMMEDIATE)"); 337160994Ssam 338160994Ssam bpf_s = fd; 339160994Ssam} 340160994Ssam 341160994Ssamvoid user_input() { 342160994Ssam static char chan[3]; 343160994Ssam static int pos = 0; 344160994Ssam int c; 345160994Ssam 346160994Ssam c = getch(); 347160994Ssam 348160994Ssam switch (c) { 349160994Ssam case 'w': 350160994Ssam save_state(); 351160994Ssam break; 352160994Ssam 353160994Ssam case 'q': 354160994Ssam cleanup(0); 355160994Ssam break; 356160994Ssam 357160994Ssam case 'c': 358160994Ssam chaninfo.locked = !chaninfo.locked; 359160994Ssam break; 360160994Ssam 361160994Ssam case ERR: 362160994Ssam die(0, "getch()"); 363160994Ssam break; 364160994Ssam 365160994Ssam case '0': 366160994Ssam case '1': 367160994Ssam case '2': 368160994Ssam case '3': 369160994Ssam case '4': 370160994Ssam case '5': 371160994Ssam case '6': 372160994Ssam case '7': 373160994Ssam case '8': 374160994Ssam case '9': 375160994Ssam chan[pos++] = c; 376160994Ssam if (pos == 2) { 377160994Ssam int ch = atoi(chan); 378160994Ssam if (ch <= 11 && ch >= 1) { 379160994Ssam set_chan(atoi(chan)); 380160994Ssam chaninfo.locked = 1; 381160994Ssam } 382160994Ssam pos = 0; 383160994Ssam } 384160994Ssam break; 385160994Ssam 386160994Ssam default: 387160994Ssam pos = 0; 388160994Ssam break; 389160994Ssam } 390160994Ssam} 391160994Ssam 392160994Ssamvoid display_node(struct node_info* node) { 393160994Ssam int x = 0; 394160994Ssam int y = 0; 395160994Ssam int i; 396160994Ssam char chan[3]; 397160994Ssam char* ssid = 0; 398160994Ssam int sig, max, left, noise; 399160994Ssam char* wep = 0; 400160994Ssam 401160994Ssam y = node->pos; 402160994Ssam if (y == -1) // offscreen 403160994Ssam return; 404160994Ssam 405160994Ssam assert(y < LINES); 406160994Ssam 407160994Ssam // MAC 408160994Ssam mvaddstr(y, x, mac2str(node->mac)); 409160994Ssam x += 6*3; 410160994Ssam 411160994Ssam // WEP 412160994Ssam wep = wep2str(node->wep); 413160994Ssam assert(wep); 414160994Ssam mvaddstr(y, x, wep); 415160994Ssam x += strlen(wep); 416160994Ssam x++; 417160994Ssam 418160994Ssam // CHAN 419160994Ssam sprintf(chan, "%.2d", node->chan); 420160994Ssam mvaddstr(y, x, chan); 421160994Ssam x += 3; 422160994Ssam 423160994Ssam // ssid 424160994Ssam ssid = ssid2str(node); 425160994Ssam assert(ssid); 426160994Ssam mvaddstr(y, x, ssid); 427160994Ssam x += strlen(ssid); 428160994Ssam x++; 429160994Ssam 430160994Ssam left = COLS - x - 1; 431160994Ssam 432160994Ssam sig = (int) ( ((double)node->signal)*left/100.0 ); 433160994Ssam noise=(int) ( ((double)node->noise)*left/100.0 ); 434160994Ssam max = (int) ( ((double)node->max)*left/100.0 ); 435160994Ssam 436160994Ssam // SIGNAL BAR 437160994Ssam for (i = 0; i < noise; i++) 438160994Ssam mvaddch(y, x++, 'N'); 439160994Ssam 440160994Ssam for (; i < sig; i++) 441160994Ssam mvaddch(y,x++, 'X'); 442160994Ssam 443160994Ssam for (; i < max; i++) 444160994Ssam mvaddch(y,x++, ' '); 445160994Ssam mvaddch(y,x++, '|'); 446160994Ssam 447160994Ssam for (; x < COLS-1; x++) 448160994Ssam mvaddch(y, x, ' '); 449160994Ssam 450160994Ssam assert (x <= COLS); 451160994Ssam} 452160994Ssam 453160994Ssamvoid update_node(struct node_info* data) { 454160994Ssam struct node_info* node; 455160994Ssam int sort = 0; 456160994Ssam 457160994Ssam assert(data->signal <= 100); 458160994Ssam 459160994Ssam node = nodes; 460160994Ssam 461160994Ssam // first time [virgin] 462160994Ssam if (!node) { 463160994Ssam node = (struct node_info*) malloc(sizeof(struct node_info)); 464160994Ssam if (!node) 465160994Ssam die(1, "malloc()"); 466160994Ssam 467160994Ssam memset(node, 0, sizeof(*node)); 468160994Ssam memcpy(node->mac, data->mac, 6); 469160994Ssam nodes = node; 470160994Ssam } 471160994Ssam 472160994Ssam while (node) { 473160994Ssam // found it 474160994Ssam if (memcmp(node->mac, data->mac, 6) == 0) 475160994Ssam break; 476160994Ssam 477160994Ssam // end of chain 478160994Ssam if (!node->next) { 479160994Ssam node->next = (struct node_info*) 480160994Ssam malloc(sizeof(struct node_info)); 481160994Ssam if (!node->next) 482160994Ssam die(1, "malloc()"); 483160994Ssam 484160994Ssam memset(node->next, 0, sizeof(*node->next)); 485160994Ssam memcpy(node->next->mac, data->mac, 6); 486160994Ssam node->next->prev = node; 487160994Ssam node->next->pos = node->pos+1; 488160994Ssam 489160994Ssam node = node->next; 490160994Ssam if (node->pos == LINES) 491160994Ssam sort = 1; 492160994Ssam break; 493160994Ssam } 494160994Ssam 495160994Ssam node = node->next; 496160994Ssam } 497160994Ssam assert(node); 498160994Ssam 499160994Ssam // too many nodes for screen 500160994Ssam if (sort) { 501160994Ssam struct node_info* ni = nodes; 502160994Ssam 503160994Ssam while (ni) { 504160994Ssam if (ni->pos != -1) 505160994Ssam ni->pos--; 506160994Ssam 507160994Ssam display_node(ni); 508160994Ssam ni = ni->next; 509160994Ssam } 510160994Ssam } 511160994Ssam 512160994Ssam node->signal = data->signal; 513160994Ssam if (data->signal > node->max) 514160994Ssam node->max = data->signal; 515160994Ssam 516160994Ssam if (gettimeofday(&node->seen, NULL) == -1) 517160994Ssam die(1, "gettimeofday()"); 518160994Ssam 519160994Ssam if (data->ssid[0] != 0) 520160994Ssam strcpy(node->ssid, data->ssid); 521160994Ssam if (data->chan != -1) 522160994Ssam node->chan = data->chan; 523160994Ssam if (data->wep != -1) { 524160994Ssam // XXX LAME --- won't detect if AP changes WEP mode in 525160994Ssam // beacons... 526160994Ssam if (node->wep != CRYPT_WEP && 527160994Ssam node->wep != CRYPT_NONE && 528160994Ssam data->wep == CRYPT_WEP) { 529160994Ssam } 530160994Ssam else 531160994Ssam node->wep = data->wep; 532160994Ssam } 533160994Ssam if (data->ap != -1) 534160994Ssam node->ap = data->ap; 535160994Ssam 536160994Ssam display_node(node); 537160994Ssam refresh(); 538160994Ssam} 539160994Ssam 540160994Ssamvoid get_beacon_info(unsigned char* data, int rd, 541160994Ssam struct node_info* node) { 542160994Ssam 543160994Ssam int blen = 8 + 2 + 2; 544160994Ssam 545160994Ssam strcpy(node->ssid, "<hidden>"); 546160994Ssam node->chan = 0; 547160994Ssam node->wep = CRYPT_NONE; 548160994Ssam 549160994Ssam assert(rd >= blen); 550160994Ssam 551160994Ssam if (IEEE80211_BEACON_CAPABILITY(data) & IEEE80211_CAPINFO_PRIVACY) 552160994Ssam node->wep = CRYPT_WEP; 553160994Ssam 554160994Ssam data += blen; 555160994Ssam rd -= blen; 556160994Ssam 557160994Ssam while (rd > 2) { 558160994Ssam int eid, elen; 559160994Ssam 560160994Ssam eid = *data; 561160994Ssam data++; 562160994Ssam elen = *data; 563160994Ssam data++; 564160994Ssam rd -= 2; 565160994Ssam 566160994Ssam // short! 567160994Ssam if (rd < elen) { 568160994Ssam return; 569160994Ssam } 570160994Ssam 571160994Ssam // ssid 572160994Ssam if (eid == 0) { 573160994Ssam if (elen == 1 && data[0] == 0) { 574160994Ssam // hidden 575160994Ssam } 576160994Ssam else { 577160994Ssam memcpy(node->ssid, data, elen); 578160994Ssam node->ssid[elen] = 0; 579160994Ssam } 580160994Ssam } 581160994Ssam // chan 582160994Ssam else if(eid == 3) { 583160994Ssam // weird chan! 584160994Ssam if( elen != 1) 585160994Ssam goto next; 586160994Ssam 587160994Ssam node->chan = *data; 588160994Ssam } 589160994Ssam // WPA 590160994Ssam else if (eid == 221 && node->wep == CRYPT_WEP) { 591160994Ssam struct ieee80211_ie_wpa* wpa; 592160994Ssam 593160994Ssam wpa = (struct ieee80211_ie_wpa*) data; 594160994Ssam if (elen < 6) 595160994Ssam goto next; 596160994Ssam 597160994Ssam if (!memcmp(wpa->wpa_oui, "\x00\x50\xf2", 3)) { 598160994Ssam // node->wep = CRYPT_WPA; 599160994Ssam } 600160994Ssam else 601160994Ssam goto next; 602160994Ssam 603160994Ssam if (wpa->wpa_type == WPA_OUI_TYPE && 604160994Ssam le16toh(wpa->wpa_version) == WPA_VERSION) { 605160994Ssam int cipher, auth; 606160994Ssam unsigned char* ptr; 607160994Ssam 608160994Ssam node->wep = CRYPT_WPA1; 609160994Ssam 610160994Ssam if (elen < 12) 611160994Ssam goto next; 612160994Ssam 613160994Ssam cipher = ((unsigned char*) wpa->wpa_mcipher)[3]; 614160994Ssam 615160994Ssam ptr = (unsigned char*)wpa + 12 + 616160994Ssam 4 * le16toh(wpa->wpa_uciphercnt); 617160994Ssam 618160994Ssam if (elen < (ptr - data + 6)) 619160994Ssam goto next; 620160994Ssam 621160994Ssam if ( *((unsigned short*) ptr) == 0) 622160994Ssam goto next; 623160994Ssam 624160994Ssam ptr += 2 + 3; 625160994Ssam auth = *ptr; 626160994Ssam 627160994Ssam if (cipher == WPA_CSE_TKIP) { 628160994Ssam node->wep = CRYPT_WPA1_TKIP; 629160994Ssam 630160994Ssam if (auth == WPA_ASE_8021X_PSK) 631160994Ssam node->wep = CRYPT_WPA1_TKIP_PSK; 632160994Ssam } 633160994Ssam 634160994Ssam if (cipher == WPA_CSE_CCMP) { 635160994Ssam node->wep = CRYPT_WPA1_CCMP; 636160994Ssam 637160994Ssam if (auth == WPA_ASE_8021X_PSK) 638160994Ssam node->wep = CRYPT_WPA1_CCMP_PSK; 639160994Ssam } 640160994Ssam } 641160994Ssam } 642160994Ssam else if (eid == 48 && node->wep == CRYPT_WEP) { 643160994Ssam unsigned char* ptr; 644160994Ssam 645160994Ssam // XXX no bounds checking 646160994Ssam ptr = data; 647160994Ssam 648160994Ssam if (ptr[0] == 1 && ptr[1] == 0) { 649160994Ssam unsigned short* count; 650160994Ssam int cipher = 0; 651160994Ssam 652160994Ssam ptr += 2; 653160994Ssam node->wep = CRYPT_80211i; 654160994Ssam 655160994Ssam if (!memcmp(ptr, "\x00\x0f\xac\x02", 4)) { 656160994Ssam node->wep = CRYPT_80211i_TKIP; 657160994Ssam cipher = 1; 658160994Ssam } 659160994Ssam 660160994Ssam ptr += 4; 661160994Ssam count = (unsigned short*) ptr; 662160994Ssam ptr +=2 + *count*4; 663160994Ssam 664160994Ssam count = (unsigned short*) ptr; 665160994Ssam if (*count) { 666160994Ssam ptr += 2; 667160994Ssam 668160994Ssam if (!memcmp(ptr,"\x00\x0f\xac\x02", 4)) { 669160994Ssam if (cipher) 670160994Ssam node->wep = CRYPT_80211i_TKIP_PSK; 671160994Ssam } 672160994Ssam } 673160994Ssam } 674160994Ssam } 675160994Ssam 676160994Ssamnext: 677160994Ssam data += elen; 678160994Ssam rd -= elen; 679160994Ssam } 680160994Ssam} 681160994Ssam 682160994Ssamint get_packet_info(struct ieee80211_frame* wh, 683160994Ssam unsigned char* body, int bodylen, 684160994Ssam struct node_info* node) { 685160994Ssam 686160994Ssam int type, stype; 687160994Ssam 688160994Ssam node->chan = chaninfo.chan; 689160994Ssam node->wep = -1; 690160994Ssam node->ssid[0] = 0; 691160994Ssam node->ap = -1; 692160994Ssam 693160994Ssam type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 694160994Ssam 695160994Ssam if (type == IEEE80211_FC0_TYPE_CTL) 696160994Ssam return 0; 697160994Ssam#if 0 698160994Ssam if (wh->i_addr2[0] != 0) { 699160994Ssam mvprintw(30,30,"%s %x",mac2str(wh->i_addr2), wh->i_fc[0]); 700160994Ssam } 701160994Ssam#endif 702160994Ssam 703160994Ssam stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 704160994Ssam 705160994Ssam if (type == IEEE80211_FC0_TYPE_MGT && 706160994Ssam stype == IEEE80211_FC0_SUBTYPE_BEACON) { 707160994Ssam get_beacon_info(body, bodylen, node); 708160994Ssam node->ap = 1; 709160994Ssam } 710160994Ssam 711160994Ssam else if (type == IEEE80211_FC0_TYPE_DATA && 712160994Ssam stype == IEEE80211_FC0_SUBTYPE_DATA) { 713160994Ssam 714262007Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 715160994Ssam unsigned char* iv; 716160994Ssam 717160994Ssam node->wep = CRYPT_WEP; 718160994Ssam 719160994Ssam iv = body; 720160994Ssam iv += 3; 721160994Ssam 722160994Ssam // extended IV? 723160994Ssam if (*iv & (1 << 1)) { 724160994Ssam#if 0 725160994Ssam node->wep = CRYPT_WPA; 726160994Ssam mvprintw(20,20, "shei"); 727160994Ssam exit(1); 728160994Ssam#endif 729160994Ssam } 730160994Ssam } 731160994Ssam 732160994Ssam if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) 733160994Ssam node->ap = 1; 734160994Ssam else 735160994Ssam node->ap = 0; 736160994Ssam } 737160994Ssam 738160994Ssam memcpy(node->mac, wh->i_addr2, 6); 739160994Ssam return 1; 740160994Ssam} 741160994Ssam 742160994Ssamvoid radiotap(unsigned char* data, int rd) { 743160994Ssam struct ieee80211_radiotap_header* rth; 744160994Ssam struct ieee80211_frame* wh; 745160994Ssam char* body; 746160994Ssam struct node_info node; 747160994Ssam int8_t signal_dbm, noise_dbm; 748160994Ssam uint8_t signal_db, noise_db; 749160994Ssam int dbm = 0; 750160994Ssam int signal = 0; 751160994Ssam int i; 752160994Ssam 753160994Ssam rd -= 4; // 802.11 CRC 754160994Ssam 755160994Ssam // radiotap 756160994Ssam rth = (struct ieee80211_radiotap_header*) data; 757160994Ssam 758160994Ssam // 802.11 759160994Ssam wh = (struct ieee80211_frame*) 760160994Ssam ((char*)rth + rth->it_len); 761160994Ssam rd -= rth->it_len; 762160994Ssam 763160994Ssam assert (rd >= 0); 764160994Ssam 765160994Ssam // body 766160994Ssam body = (char*) wh + sizeof(*wh); 767160994Ssam rd -= sizeof(*wh); 768160994Ssam 769160994Ssam if (!get_packet_info(wh, body, rd, &node)) 770160994Ssam return; 771160994Ssam 772160994Ssam // signal and noise 773160994Ssam body = (char*) rth + sizeof(*rth); 774160994Ssam signal_dbm = noise_dbm = signal_db = noise_db = 0; 775160994Ssam 776160994Ssam for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) { 777160994Ssam if (!(rth->it_present & (1 << i))) 778160994Ssam continue; 779160994Ssam 780160994Ssam switch (i) { 781160994Ssam case IEEE80211_RADIOTAP_TSFT: 782160994Ssam body += sizeof(uint64_t); 783160994Ssam break; 784160994Ssam 785160994Ssam case IEEE80211_RADIOTAP_FLAGS: 786160994Ssam case IEEE80211_RADIOTAP_RATE: 787160994Ssam body += sizeof(uint8_t); 788160994Ssam break; 789160994Ssam 790160994Ssam case IEEE80211_RADIOTAP_CHANNEL: 791160994Ssam body += sizeof(uint16_t)*2; 792160994Ssam break; 793160994Ssam 794160994Ssam case IEEE80211_RADIOTAP_FHSS: 795160994Ssam body += sizeof(uint16_t); 796160994Ssam break; 797160994Ssam 798160994Ssam case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: 799160994Ssam signal_dbm = *body; 800160994Ssam body++; 801160994Ssam dbm = 1; 802160994Ssam break; 803160994Ssam 804160994Ssam case IEEE80211_RADIOTAP_DBM_ANTNOISE: 805160994Ssam noise_dbm = *body; 806160994Ssam body++; 807160994Ssam break; 808160994Ssam 809160994Ssam case IEEE80211_RADIOTAP_DB_ANTSIGNAL: 810160994Ssam signal_db = *((unsigned char*)body); 811160994Ssam body++; 812160994Ssam break; 813160994Ssam 814160994Ssam case IEEE80211_RADIOTAP_DB_ANTNOISE: 815160994Ssam noise_db = *((unsigned char*)body); 816160994Ssam body++; 817160994Ssam break; 818160994Ssam 819160994Ssam case IEEE80211_RADIOTAP_EXT: 820160994Ssam abort(); 821160994Ssam break; 822160994Ssam } 823160994Ssam } 824160994Ssam if (dbm) { 825160994Ssam signal = signal_dbm - noise_dbm; 826160994Ssam } 827160994Ssam else { 828160994Ssam signal = signal_db - noise_db; 829160994Ssam } 830160994Ssam if (signal < 0) 831160994Ssam signal = 0; 832160994Ssam 833160994Ssam node.signal = signal; 834160994Ssam#if 0 835160994Ssam if (node.signal > 100 || node.signal < 0) { 836160994Ssam mvprintw(25,25, "sig=%d", node.signal); 837160994Ssam } 838160994Ssam#else 839160994Ssam assert (node.signal <= 100 && node.signal >= 0); 840160994Ssam#endif 841160994Ssam 842160994Ssam update_node(&node); 843160994Ssam} 844160994Ssam 845160994Ssamvoid bpf_input() { 846160994Ssam static unsigned char buf[4096]; 847160994Ssam int rd; 848160994Ssam struct bpf_hdr* bpfh; 849160994Ssam unsigned char* data; 850160994Ssam 851160994Ssam rd = read(bpf_s, buf, sizeof(buf)); 852160994Ssam if (rd == -1) 853160994Ssam die(1,"read()"); 854160994Ssam 855160994Ssam bpfh = (struct bpf_hdr*) buf; 856160994Ssam rd -= bpfh->bh_hdrlen; 857160994Ssam 858160994Ssam if (rd != bpfh->bh_caplen) { 859160994Ssam assert( rd > bpfh->bh_caplen); 860160994Ssam rd = bpfh->bh_caplen; 861160994Ssam } 862160994Ssam 863160994Ssam data = (unsigned char*) bpfh + bpfh->bh_hdrlen; 864160994Ssam radiotap(data, rd); 865160994Ssam} 866160994Ssam 867160994Ssamunsigned long elapsed_ms(struct timeval* now, struct timeval* prev) { 868160994Ssam unsigned long elapsed = 0; 869160994Ssam 870160994Ssam if (now->tv_sec > prev->tv_sec) 871160994Ssam elapsed = 1000*1000 - prev->tv_usec + 872160994Ssam now->tv_usec; 873160994Ssam else { 874160994Ssam assert(now->tv_sec == prev->tv_sec); 875160994Ssam elapsed = now->tv_usec - prev->tv_usec; 876160994Ssam } 877160994Ssam elapsed /= 1000; //ms 878160994Ssam 879160994Ssam elapsed += (now->tv_sec - prev->tv_sec)*1000; 880160994Ssam return elapsed; 881160994Ssam} 882160994Ssam 883160994Ssamvoid chanhop(struct timeval* tv) { 884160994Ssam unsigned long elapsed = 0; 885160994Ssam 886160994Ssam if (gettimeofday(tv, NULL) == -1) 887160994Ssam die(1, "gettimeofday()"); 888160994Ssam 889160994Ssam 890160994Ssam elapsed = elapsed_ms(tv, &chaninfo.last_hop); 891160994Ssam 892160994Ssam // need to chan hop 893160994Ssam if (elapsed >= hopfreq) { 894160994Ssam int c; 895160994Ssam 896160994Ssam c = chaninfo.chan + 1; 897160994Ssam 898160994Ssam if (c > 11) 899160994Ssam c = 1; 900160994Ssam 901160994Ssam set_chan(c); 902160994Ssam 903160994Ssam elapsed = hopfreq; 904160994Ssam } 905160994Ssam // how much can we sleep? 906160994Ssam else { 907160994Ssam elapsed = hopfreq - elapsed; 908160994Ssam } 909160994Ssam 910160994Ssam // ok calculate sleeping time... 911160994Ssam tv->tv_sec = elapsed/1000; 912160994Ssam tv->tv_usec = (elapsed - tv->tv_sec*1000)*1000; 913160994Ssam} 914160994Ssam 915160994Ssamvoid check_seen(struct timeval* tv) { 916160994Ssam unsigned long elapsed = 0; 917160994Ssam struct timeval now; 918160994Ssam int need_refresh = 0; 919160994Ssam unsigned long min_wait = 0; 920160994Ssam unsigned long will_wait; 921160994Ssam 922160994Ssam will_wait = tv->tv_sec*1000+tv->tv_usec/1000; 923160994Ssam min_wait = will_wait; 924160994Ssam 925160994Ssam struct node_info* node = nodes; 926160994Ssam 927160994Ssam if (gettimeofday(&now, NULL) == -1) 928160994Ssam die(1, "gettimeofday()"); 929160994Ssam 930160994Ssam while(node) { 931160994Ssam if (node->signal) { 932160994Ssam elapsed = elapsed_ms(&now, &node->seen); 933160994Ssam 934160994Ssam // node is dead... 935160994Ssam if (elapsed >= sig_reset) { 936160994Ssam node->signal = 0; 937160994Ssam display_node(node); 938160994Ssam need_refresh = 1; 939160994Ssam } 940160994Ssam 941160994Ssam // need to check soon possibly... 942160994Ssam else { 943160994Ssam unsigned long left; 944160994Ssam 945160994Ssam left = sig_reset - elapsed; 946160994Ssam if (left < min_wait) 947160994Ssam left = min_wait; 948160994Ssam } 949160994Ssam } 950160994Ssam node = node->next; 951160994Ssam } 952160994Ssam 953160994Ssam if (need_refresh) 954160994Ssam refresh(); 955160994Ssam 956160994Ssam // need to sleep for less... 957160994Ssam if (min_wait < will_wait) { 958160994Ssam tv->tv_sec = min_wait/1000; 959160994Ssam tv->tv_usec = (min_wait - tv->tv_sec*1000)*1000; 960160994Ssam } 961160994Ssam} 962160994Ssam 963160994Ssamvoid own(char* ifname) { 964160994Ssam int rd; 965160994Ssam fd_set fds; 966160994Ssam struct timeval tv; 967160994Ssam int dlt = DLT_IEEE802_11_RADIO; 968160994Ssam 969160994Ssam hopfreq = 1000; 970160994Ssam 971160994Ssam setup_if(ifname); 972160994Ssam open_bpf(ifname, dlt); 973160994Ssam 974160994Ssam while(1) { 975160994Ssam // XXX innefficient all of this... 976160994Ssam if (!chaninfo.locked) 977160994Ssam chanhop(&tv); 978160994Ssam else { 979160994Ssam tv.tv_sec = 1; 980160994Ssam tv.tv_usec = 0; 981160994Ssam } 982160994Ssam 983160994Ssam // especially this... 984160994Ssam check_seen(&tv); 985160994Ssam 986160994Ssam FD_ZERO(&fds); 987160994Ssam FD_SET(0, &fds); 988160994Ssam FD_SET(bpf_s, &fds); 989160994Ssam 990160994Ssam rd = select(bpf_s+1, &fds,NULL , NULL, &tv); 991160994Ssam if (rd == -1) 992160994Ssam die(1, "select()"); 993160994Ssam if (FD_ISSET(0, &fds)) 994160994Ssam user_input(); 995160994Ssam if (FD_ISSET(bpf_s, &fds)) 996160994Ssam bpf_input(); 997160994Ssam } 998160994Ssam} 999160994Ssam 1000160994Ssamvoid init_globals() { 1001160994Ssam ioctl_s = socket(PF_INET, SOCK_DGRAM, 0); 1002160994Ssam if (ioctl_s == -1) { 1003160994Ssam perror("socket()"); 1004160994Ssam exit(1); 1005160994Ssam } 1006160994Ssam 1007160994Ssam chaninfo.locked = 0; 1008160994Ssam chaninfo.chan = 0; 1009160994Ssam} 1010160994Ssam 1011160994Ssamint main(int argc, char *argv[]) { 1012160994Ssam 1013160994Ssam 1014160994Ssam if (argc < 2) { 1015160994Ssam printf("Usage: %s <iface>\n", argv[0]); 1016160994Ssam exit(1); 1017160994Ssam } 1018160994Ssam 1019160994Ssam init_globals(); 1020160994Ssam 1021160994Ssam initscr(); cbreak(); noecho(); 1022160994Ssam 1023160994Ssam nonl(); 1024160994Ssam intrflush(stdscr, FALSE); 1025160994Ssam keypad(stdscr, TRUE); 1026160994Ssam 1027160994Ssam curs_set(0); 1028160994Ssam 1029160994Ssam clear(); 1030160994Ssam refresh(); 1031160994Ssam 1032160994Ssam signal(SIGINT, cleanup); 1033160994Ssam signal(SIGTERM, cleanup); 1034160994Ssam 1035160994Ssam own(argv[1]); 1036160994Ssam 1037160994Ssam cleanup(0); 1038160994Ssam exit(0); 1039160994Ssam} 1040