2 * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #include <sys/select.h>
34 #include <net/if_media.h>
36 #include <net80211/ieee80211_ioctl.h>
37 #include <net80211/ieee80211.h>
38 #include <net/ethernet.h>
39 #include <net80211/ieee80211_radiotap.h>
40 #include <sys/endian.h>
51 //int hopfreq = 3*1000; // ms
52 int hopfreq = 500; // ms
53 int sig_reset = 1*1000; // ms
62 struct ieee80211req ireq;
63 struct timeval last_hop;
71 #define CRYPT_WPA1_TKIP 4
72 #define CRYPT_WPA1_TKIP_PSK 5
73 #define CRYPT_WPA1_CCMP 6
74 #define CRYPT_WPA1_CCMP_PSK 7
75 #define CRYPT_80211i 8
76 #define CRYPT_80211i_TKIP 9
77 #define CRYPT_80211i_TKIP_PSK 10
84 unsigned char ssid[256];
92 struct node_info* prev;
93 struct node_info* next;
97 struct node_info* next;
111 char* mac2str(unsigned char* mac) {
112 static char ret[6*3];
114 sprintf(ret, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
115 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
120 char* wep2str(int w) {
141 case CRYPT_WPA1_TKIP:
145 case CRYPT_WPA1_TKIP_PSK:
146 wep = "WPA1-TKIP-PSK";
149 case CRYPT_WPA1_CCMP:
153 case CRYPT_WPA1_CCMP_PSK:
154 wep = "WPA1-CCMP-PSK";
161 case CRYPT_80211i_TKIP:
165 case CRYPT_80211i_TKIP_PSK:
166 wep = "11i-TKIP-PSK";
174 memset(res, ' ', sizeof(res));
175 assert(strlen(wep) < sizeof(res));
176 memcpy(res, wep, strlen(wep));
177 res[sizeof(res)-1] = 0;
181 char* ssid2str(struct node_info* node) {
184 memset(res, ' ', sizeof(res));
186 strcpy(&res[sizeof(res)-2], "]");
189 int left = sizeof(res) - 3;
191 if (strlen(node->ssid) < left)
192 left = strlen(node->ssid);
193 memcpy(&res[1], node->ssid, left);
196 memcpy(&res[1], "<client>", 8);
203 struct node_info* node = nodes;
205 f = fopen("stumbler.log", "w");
215 t = localtime( (time_t*) &node->seen.tv_sec);
217 perror("localtime()");
221 strftime(tim, sizeof(tim), "%H:%M:%S", t);
223 fprintf(f, "%s %s %s %2d %s 0x%.2x\n", tim,
224 mac2str(node->mac), wep2str(node->wep),
225 node->chan, ssid2str(node), node->max);
233 void cleanup(int x) {
239 void die(int p, char* msg) {
249 void display_chan() {
256 snprintf(tmp, sizeof(tmp), "%.2d", chaninfo.chan);
261 void set_chan(int c) {
262 chaninfo.ireq.i_val = c;
264 if (ioctl(ioctl_s, SIOCS80211, &chaninfo.ireq) == -1)
265 die(1, "ioctl(SIOCS80211) [chan]");
269 if (gettimeofday(&chaninfo.last_hop, NULL) == -1)
270 die(1, "gettimeofday()");
275 void setup_if(char *dev) {
278 struct ifmediareq ifmr;
281 // set iface up and promisc
282 memset(&ifr, 0, sizeof(ifr));
283 strcpy(ifr.ifr_name, dev);
284 if (ioctl(ioctl_s, SIOCGIFFLAGS, &ifr) == -1)
285 die(1, "ioctl(SIOCGIFFLAGS)");
287 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
288 flags |= IFF_UP | IFF_PPROMISC;
290 memset(&ifr, 0, sizeof(ifr));
291 strcpy(ifr.ifr_name, dev);
292 ifr.ifr_flags = flags & 0xffff;
293 ifr.ifr_flagshigh = flags >> 16;
294 if (ioctl(ioctl_s, SIOCSIFFLAGS, &ifr) == -1)
295 die(1, "ioctl(SIOCSIFFLAGS)");
298 memset(&ifmr, 0, sizeof(ifmr));
299 strcpy(ifmr.ifm_name, dev);
300 if (ioctl(ioctl_s, SIOCGIFMEDIA, &ifmr) == -1)
301 die(1, "ioctl(SIOCGIFMEDIA)");
303 if (ifmr.ifm_count == 0)
304 die(0, "0 media thinggies...\n");
306 mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
310 ifmr.ifm_ulist = mwords;
312 if (ioctl(ioctl_s, SIOCGIFMEDIA, &ifmr) == -1)
313 die(1, "ioctl(SIOCGIFMEDIA)");
317 memset(&ifr, 0, sizeof(ifr));
318 strcpy(ifr.ifr_name, dev);
319 ifr.ifr_media = ifmr.ifm_current | IFM_IEEE80211_MONITOR;
320 if (ioctl(ioctl_s, SIOCSIFMEDIA, &ifr) == -1)
321 die(1, "ioctl(SIOCSIFMEDIA)");
324 memset(&chaninfo.ireq, 0, sizeof(chaninfo.ireq));
325 strcpy(chaninfo.ireq.i_name, dev);
326 chaninfo.ireq.i_type = IEEE80211_IOC_CHANNEL;
331 void open_bpf(char *dev, int dlt) {
337 for(i = 0;i < 16; i++) {
338 sprintf(buf, "/dev/bpf%d", i);
340 fd = open(buf, O_RDWR);
343 die(1,"can't open /dev/bpf");
351 die(1, "can't open /dev/bpf");
353 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1);
354 ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
356 if(ioctl(fd, BIOCSETIF, &ifr) < 0)
357 die(1, "ioctl(BIOCSETIF)");
359 if (ioctl(fd, BIOCSDLT, &dlt) < 0)
360 die(1, "ioctl(BIOCSDLT)");
363 if(ioctl(fd, BIOCIMMEDIATE, &i) < 0)
364 die(1, "ioctl(BIOCIMMEDIATE)");
386 chaninfo.locked = !chaninfo.locked;
406 if (ch <= 11 && ch >= 1) {
407 set_chan(atoi(chan));
420 void display_node(struct node_info* node) {
426 int sig, max, left, noise;
430 if (y == -1) // offscreen
436 mvaddstr(y, x, mac2str(node->mac));
440 wep = wep2str(node->wep);
447 sprintf(chan, "%.2d", node->chan);
448 mvaddstr(y, x, chan);
452 ssid = ssid2str(node);
454 mvaddstr(y, x, ssid);
460 sig = (int) ( ((double)node->signal)*left/100.0 );
461 noise=(int) ( ((double)node->noise)*left/100.0 );
462 max = (int) ( ((double)node->max)*left/100.0 );
465 for (i = 0; i < noise; i++)
466 mvaddch(y, x++, 'N');
475 for (; x < COLS-1; x++)
481 void update_node(struct node_info* data) {
482 struct node_info* node;
485 assert(data->signal <= 100);
489 // first time [virgin]
491 node = (struct node_info*) malloc(sizeof(struct node_info));
495 memset(node, 0, sizeof(*node));
496 memcpy(node->mac, data->mac, 6);
502 if (memcmp(node->mac, data->mac, 6) == 0)
507 node->next = (struct node_info*)
508 malloc(sizeof(struct node_info));
512 memset(node->next, 0, sizeof(*node->next));
513 memcpy(node->next->mac, data->mac, 6);
514 node->next->prev = node;
515 node->next->pos = node->pos+1;
518 if (node->pos == LINES)
527 // too many nodes for screen
529 struct node_info* ni = nodes;
540 node->signal = data->signal;
541 if (data->signal > node->max)
542 node->max = data->signal;
544 if (gettimeofday(&node->seen, NULL) == -1)
545 die(1, "gettimeofday()");
547 if (data->ssid[0] != 0)
548 strcpy(node->ssid, data->ssid);
549 if (data->chan != -1)
550 node->chan = data->chan;
551 if (data->wep != -1) {
552 // XXX LAME --- won't detect if AP changes WEP mode in
554 if (node->wep != CRYPT_WEP &&
555 node->wep != CRYPT_NONE &&
556 data->wep == CRYPT_WEP) {
559 node->wep = data->wep;
568 void get_beacon_info(unsigned char* data, int rd,
569 struct node_info* node) {
571 int blen = 8 + 2 + 2;
573 strcpy(node->ssid, "<hidden>");
575 node->wep = CRYPT_NONE;
579 if (IEEE80211_BEACON_CAPABILITY(data) & IEEE80211_CAPINFO_PRIVACY)
580 node->wep = CRYPT_WEP;
601 if (elen == 1 && data[0] == 0) {
605 memcpy(node->ssid, data, elen);
606 node->ssid[elen] = 0;
618 else if (eid == 221 && node->wep == CRYPT_WEP) {
619 struct ieee80211_ie_wpa* wpa;
621 wpa = (struct ieee80211_ie_wpa*) data;
625 if (!memcmp(wpa->wpa_oui, "\x00\x50\xf2", 3)) {
626 // node->wep = CRYPT_WPA;
631 if (wpa->wpa_type == WPA_OUI_TYPE &&
632 le16toh(wpa->wpa_version) == WPA_VERSION) {
636 node->wep = CRYPT_WPA1;
641 cipher = ((unsigned char*) wpa->wpa_mcipher)[3];
643 ptr = (unsigned char*)wpa + 12 +
644 4 * le16toh(wpa->wpa_uciphercnt);
646 if (elen < (ptr - data + 6))
649 if ( *((unsigned short*) ptr) == 0)
655 if (cipher == WPA_CSE_TKIP) {
656 node->wep = CRYPT_WPA1_TKIP;
658 if (auth == WPA_ASE_8021X_PSK)
659 node->wep = CRYPT_WPA1_TKIP_PSK;
662 if (cipher == WPA_CSE_CCMP) {
663 node->wep = CRYPT_WPA1_CCMP;
665 if (auth == WPA_ASE_8021X_PSK)
666 node->wep = CRYPT_WPA1_CCMP_PSK;
670 else if (eid == 48 && node->wep == CRYPT_WEP) {
673 // XXX no bounds checking
676 if (ptr[0] == 1 && ptr[1] == 0) {
677 unsigned short* count;
681 node->wep = CRYPT_80211i;
683 if (!memcmp(ptr, "\x00\x0f\xac\x02", 4)) {
684 node->wep = CRYPT_80211i_TKIP;
689 count = (unsigned short*) ptr;
692 count = (unsigned short*) ptr;
696 if (!memcmp(ptr,"\x00\x0f\xac\x02", 4)) {
698 node->wep = CRYPT_80211i_TKIP_PSK;
710 int get_packet_info(struct ieee80211_frame* wh,
711 unsigned char* body, int bodylen,
712 struct node_info* node) {
716 node->chan = chaninfo.chan;
721 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
723 if (type == IEEE80211_FC0_TYPE_CTL)
726 if (wh->i_addr2[0] != 0) {
727 mvprintw(30,30,"%s %x",mac2str(wh->i_addr2), wh->i_fc[0]);
731 stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
733 if (type == IEEE80211_FC0_TYPE_MGT &&
734 stype == IEEE80211_FC0_SUBTYPE_BEACON) {
735 get_beacon_info(body, bodylen, node);
739 else if (type == IEEE80211_FC0_TYPE_DATA &&
740 stype == IEEE80211_FC0_SUBTYPE_DATA) {
742 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
745 node->wep = CRYPT_WEP;
751 if (*iv & (1 << 1)) {
753 node->wep = CRYPT_WPA;
754 mvprintw(20,20, "shei");
760 if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)
766 memcpy(node->mac, wh->i_addr2, 6);
770 void radiotap(unsigned char* data, int rd) {
771 struct ieee80211_radiotap_header* rth;
772 struct ieee80211_frame* wh;
774 struct node_info node;
775 int8_t signal_dbm, noise_dbm;
776 uint8_t signal_db, noise_db;
781 rd -= 4; // 802.11 CRC
784 rth = (struct ieee80211_radiotap_header*) data;
787 wh = (struct ieee80211_frame*)
788 ((char*)rth + rth->it_len);
794 body = (char*) wh + sizeof(*wh);
797 if (!get_packet_info(wh, body, rd, &node))
801 body = (char*) rth + sizeof(*rth);
802 signal_dbm = noise_dbm = signal_db = noise_db = 0;
804 for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) {
805 if (!(rth->it_present & (1 << i)))
809 case IEEE80211_RADIOTAP_TSFT:
810 body += sizeof(uint64_t);
813 case IEEE80211_RADIOTAP_FLAGS:
814 case IEEE80211_RADIOTAP_RATE:
815 body += sizeof(uint8_t);
818 case IEEE80211_RADIOTAP_CHANNEL:
819 body += sizeof(uint16_t)*2;
822 case IEEE80211_RADIOTAP_FHSS:
823 body += sizeof(uint16_t);
826 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
832 case IEEE80211_RADIOTAP_DBM_ANTNOISE:
837 case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
838 signal_db = *((unsigned char*)body);
842 case IEEE80211_RADIOTAP_DB_ANTNOISE:
843 noise_db = *((unsigned char*)body);
847 case IEEE80211_RADIOTAP_EXT:
853 signal = signal_dbm - noise_dbm;
856 signal = signal_db - noise_db;
861 node.signal = signal;
863 if (node.signal > 100 || node.signal < 0) {
864 mvprintw(25,25, "sig=%d", node.signal);
867 assert (node.signal <= 100 && node.signal >= 0);
874 static unsigned char buf[4096];
876 struct bpf_hdr* bpfh;
879 rd = read(bpf_s, buf, sizeof(buf));
883 bpfh = (struct bpf_hdr*) buf;
884 rd -= bpfh->bh_hdrlen;
886 if (rd != bpfh->bh_caplen) {
887 assert( rd > bpfh->bh_caplen);
888 rd = bpfh->bh_caplen;
891 data = (unsigned char*) bpfh + bpfh->bh_hdrlen;
895 unsigned long elapsed_ms(struct timeval* now, struct timeval* prev) {
896 unsigned long elapsed = 0;
898 if (now->tv_sec > prev->tv_sec)
899 elapsed = 1000*1000 - prev->tv_usec +
902 assert(now->tv_sec == prev->tv_sec);
903 elapsed = now->tv_usec - prev->tv_usec;
905 elapsed /= 1000; //ms
907 elapsed += (now->tv_sec - prev->tv_sec)*1000;
911 void chanhop(struct timeval* tv) {
912 unsigned long elapsed = 0;
914 if (gettimeofday(tv, NULL) == -1)
915 die(1, "gettimeofday()");
918 elapsed = elapsed_ms(tv, &chaninfo.last_hop);
921 if (elapsed >= hopfreq) {
924 c = chaninfo.chan + 1;
933 // how much can we sleep?
935 elapsed = hopfreq - elapsed;
938 // ok calculate sleeping time...
939 tv->tv_sec = elapsed/1000;
940 tv->tv_usec = (elapsed - tv->tv_sec*1000)*1000;
943 void check_seen(struct timeval* tv) {
944 unsigned long elapsed = 0;
946 int need_refresh = 0;
947 unsigned long min_wait = 0;
948 unsigned long will_wait;
950 will_wait = tv->tv_sec*1000+tv->tv_usec/1000;
951 min_wait = will_wait;
953 struct node_info* node = nodes;
955 if (gettimeofday(&now, NULL) == -1)
956 die(1, "gettimeofday()");
960 elapsed = elapsed_ms(&now, &node->seen);
963 if (elapsed >= sig_reset) {
969 // need to check soon possibly...
973 left = sig_reset - elapsed;
984 // need to sleep for less...
985 if (min_wait < will_wait) {
986 tv->tv_sec = min_wait/1000;
987 tv->tv_usec = (min_wait - tv->tv_sec*1000)*1000;
991 void own(char* ifname) {
995 int dlt = DLT_IEEE802_11_RADIO;
1000 open_bpf(ifname, dlt);
1003 // XXX innefficient all of this...
1004 if (!chaninfo.locked)
1011 // especially this...
1016 FD_SET(bpf_s, &fds);
1018 rd = select(bpf_s+1, &fds,NULL , NULL, &tv);
1021 if (FD_ISSET(0, &fds))
1023 if (FD_ISSET(bpf_s, &fds))
1028 void init_globals() {
1029 ioctl_s = socket(PF_INET, SOCK_DGRAM, 0);
1030 if (ioctl_s == -1) {
1035 chaninfo.locked = 0;
1039 int main(int argc, char *argv[]) {
1043 printf("Usage: %s <iface>\n", argv[0]);
1049 initscr(); cbreak(); noecho();
1052 intrflush(stdscr, FALSE);
1053 keypad(stdscr, TRUE);
1060 signal(SIGINT, cleanup);
1061 signal(SIGTERM, cleanup);