1
/* IWTAN analyze functions and data structures.*/
4
Copyright (C) 2008 Marco Cornolti
6
IWTAN (IWTAN: Wireless Topology ANalyzer) is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.
8
IWTAN is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
You should have received a copy of the GNU General Public License along with IWTAN; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
16
#include <sys/types.h>
19
#include <asm/byteorder.h>
22
#include "iwtan_analyze.h"
23
#include "iwtan_data.h"
26
Refresh the data structure extracting the information by a packet passed by argument.
27
length is the length of the packet in bytes.
28
pktBody is a pointer to the packet body.
29
packetType is the packet type as defined by pcap.h (DTL_*)
30
Returns 0 in case of no errors. Returns 1 if the packet type could not be recognized.
32
int iwtan_refresh_data(unsigned int length, const u_char* pktBody, int packetType, iwtan_context* context){
33
pthread_mutex_lock(&(context->mutex));
37
//all the data that may be obtained for an access point by the radiotap header, initialized to null values.
39
unsigned int dataRate = 0;
40
unsigned short antenna = 0;
41
unsigned int frequency = 0;
45
//data obtained by the 802.11 frame
46
mac_address* stMac = NULL;
47
mac_address* apMac = NULL;
48
mac_address* bssId = NULL;
50
//data obtained by the wlan management frame
53
//data obtained by the IP level
54
ip4_address stIp4 = NULL;
55
ip6_address stIp6 = NULL;
57
//data obtained by an ethernet-emulated packet
58
mac_address* srcMac = NULL;
59
mac_address* destMac = NULL;
60
ip4_address srcIp4 = NULL;
61
ip6_address srcIp6 = NULL;
62
ip4_address destIp4 = NULL;
63
ip6_address destIp6 = NULL;
66
//determine what's the kind of the analyzed packet and call the right processing function.
68
case DLT_IEEE802_11_RADIO:
69
if (_iwtan_validate_radiotap(pktBody, length)){
70
_iwtan_process_radiotap(pktBody, length, &WEPped, &dataRate, &antenna, &frequency, &type, &signal, &stMac, &apMac, &bssId, &essid, &stIp4, &stIp6);
74
_iwtan_process_802_11(pktBody, length, &apMac, &stMac, &bssId, &essid, &stIp4, &stIp6);
77
//We can't extract any useful information from a EN10MB frame, because from a packet we can't understand if the packet is coming from an access point or from a station.
83
//pick the right ap to create it or update its data. An ap may exist without any associated station.
85
iwtan_ap** apRef = _iwtan_bsearch_AP(bssId, context);
88
ap = _iwtan_add_new_AP(bssId, context);
92
_iwtan_update_AP (ap, WEPped, dataRate, antenna, frequency, type, signal, bssId, essid, NULL, time(NULL));
94
//if an AP and a station has been seen, create an association.
96
_iwtan_add_association(bssId, stMac, context);
98
//pick the right station and update its data.
99
iwtan_station* sta = _iwtan_bsearch_station(stMac, context);
100
_iwtan_update_station (sta, stIp4, stMac, stIp6, time(NULL));
103
else{ //no AP were found (e.g. a station sent a multicast packet)
104
if (stMac){ //pick the right station, if present, and update its data.
105
iwtan_station* sta = _iwtan_bsearch_station(stMac, context);
106
if (sta) _iwtan_update_station (sta, stIp4, stMac, stIp6, time(NULL));
107
else { //otherwise, we don't create stations that aren't associated to an ap, and we just free the obtained addresses.
113
// free(ap_mac); //in any case, ap_mac is not useful. (TODO rename ap_mac to something else, it is not necessarily the AP MAC address!)
117
pthread_mutex_unlock(&(context->mutex));
124
Process a radiotap header pointed by packetData.
125
Stores the radiotap header size (just the header) in radioTapSize, writes wether or not the signal has a wep encription in WEPped, the dataRate in Mbps in dataRate, the antenna ID in antenna, the channel frequency in frequency, the signal type in type.
126
Returns 1 in case of error, e.g. for broken packages.
128
int _iwtan_process_radiotap(const u_char* radiotapData, unsigned int radioTapSize, short* WEPped, unsigned int* dataRate, short* antenna, unsigned int* frequency, short* type, short* signal, mac_address** stMac, mac_address** apMac, mac_address** bssId, char** essid, ip4_address* stIp4, ip6_address* stIp6){
129
radiotap_header* rt = (radiotap_header*) radiotapData;
130
*WEPped = _iwtan_byte_to_bool(rt->flags,5);
131
*dataRate = rt->dataRate * 2;
132
*antenna = rt->antenna;
133
*frequency = _iwtan_le_to_host(rt->frequency);
134
switch(_iwtan_le_to_host(rt->type)){
140
*signal = rt->signal;
142
//radiotap packets contain 802.11 packets.
143
_iwtan_process_802_11(radiotapData+_iwtan_le_to_host(rt->length), radioTapSize -( _iwtan_le_to_host(rt->length) + 4), apMac, stMac, bssId, essid, stIp4, stIp6);
148
Validate a 802.11 radiotap packet pointed by body of length len, checking its CRC.
149
Returns 1 if the packet is a valid radiotap header or 0 otherwise.
151
int _iwtan_validate_radiotap(const u_char* body, bpf_uint32 len){
152
// ieee_802_11_header* pkt (ieee_802_11_header*) ;
158
Process a 802.11 packet extracting all its data.
159
Set ap_mac to the MAC address of the access point sending the packet or NULL if no access points are meant.
160
Set st_mac to the MAC address of the station if the packet has a single (not broadcast) destination, NULL otherwise.
161
Set bssId to the BSS id.
162
Set essid to the ESSID of the access point if the packet is a beacon frame, tu NULL otherwise.
163
Set stationIP4 to the station IP4 address if the frame contained an IPv4 packet with a single destination (not broadcast).
164
Set stationIP6 to the station IP6 address if the frame contained an IPv6 packet with a single destination (not broadcast).
165
All the extracted data is allocated separetly and should be freed when no longer needed.
167
int _iwtan_process_802_11(const u_char* body, bpf_uint32 len, mac_address** ap_mac, mac_address** st_mac, mac_address** bssId, char** essid, ip4_address* stationIP4, ip6_address* stationIP6){
168
ieee_802_11_header* frm = (ieee_802_11_header*) body;
169
switch (_iwtan_le_to_host(frm->control)){
170
case 0x0208: //Frame contains data from a DS to a station via an access point. This means that MAC 1 is the destination (station) address, MAC2 is the BSS id, MAC3 is the source (AP) address
172
if (_iwtan_mac_is_broadcast((mac_address*)frm->mac1)){ //Multicast and broadcast transmissions from stations are codified as frames from DS to Station. They have a multicast/bradcast destination (MAC 1), the MAC address 3 is the station address (instead of the AP's), and the BSS id is regular (MAC 2).
174
*bssId = _iwtan_copy_mac_by_array(frm->mac2);
175
*st_mac = _iwtan_copy_mac_by_array(frm->mac3);
178
*st_mac = _iwtan_copy_mac_by_array(frm->mac1);
179
*bssId = _iwtan_copy_mac_by_array(frm->mac2);
180
*ap_mac = _iwtan_copy_mac_by_array(frm->mac3);
182
_iwtan_process_802_llc(body + IWTAN_DATA_HDR_LEN, len-IWTAN_DATA_HDR_LEN, NULL, stationIP4, NULL, stationIP6);
185
case 0x0108: //Frame contains data from a Station to a DS via an access point. This means that MAC1 is the BSS id, MAC2 is the source (station) address, MAC3 is the destination (AP) address.
186
*bssId = _iwtan_copy_mac_by_array(frm->mac1);
187
*st_mac = _iwtan_copy_mac_by_array(frm->mac2);
188
*ap_mac = _iwtan_mac_is_broadcast((mac_address*)frm->mac3) ? NULL : _iwtan_copy_mac_by_array(frm->mac3);
189
_iwtan_process_802_llc(body + IWTAN_DATA_HDR_LEN, len-IWTAN_DATA_HDR_LEN, stationIP4, NULL, stationIP6, NULL);
192
case 0x0080: //Frame is a beacon frame (contains a wlan management frame)
193
*ap_mac = _iwtan_copy_mac_by_array(frm->mac2);
194
*bssId = _iwtan_copy_mac_by_array(frm->mac3);
195
_iwtan_process_802_11_mng(body + IWTAN_BEACON_HDR_LEN, len - IWTAN_BEACON_HDR_LEN - sizeof(ieee_802_11_mng_fixed_end), essid);
201
Process a 802.11 management frame, extracting the ESSID.
202
The ESSID is allocated as a string whose pointer is stored in *essid.
204
int _iwtan_process_802_11_mng(const u_char* body, bpf_uint32 len, char** essid){
205
ieee_802_11_mng_fixed_begin* begin = (ieee_802_11_mng_fixed_begin*) body;
206
ieee_802_11_mng_tag* tag;
207
u_char* tagByte = (u_char*)(body + sizeof(ieee_802_11_mng_fixed_begin));
209
while(tagByte < body+len){
210
tag = (ieee_802_11_mng_tag*) tagByte;
211
switch (tag->tagNumber){
212
case(0x0)://tag contains an ESSID
213
*essid = calloc(tag->tagLen+1, sizeof(char));
214
strncpy(*essid, tagByte+2, tag->tagLen);
217
tagByte += 2 + tag->tagLen;
222
Process a Link Layer Control header. If an IP packet is found, the source and destination IP addresses are stored in the pointers given by argument.
223
The addresses are allocated in the heap and should be freed when no longer needed.
224
The addresses are stored in the pointers given by argument only if their value is not NULL.
226
int _iwtan_process_802_llc(const u_char* body, bpf_uint32 len, ip4_address* fromIp4, ip4_address* toIp4, ip6_address* fromIp6, ip4_address* toIp6){
227
ieee_802_11_llc* llc = (ieee_802_11_llc*) body;
228
switch (_iwtan_be_to_host(llc->type)){
229
case 0x0800: //llc contains an IPv4 packet
230
_iwtan_process_ip4(body + sizeof(ieee_802_11_llc), len-sizeof(ieee_802_11_llc), fromIp4, toIp4);
232
case 0x86dd: //llc contains an IPv6 packet
233
_iwtan_process_ip6(body + sizeof(ieee_802_11_llc), len-sizeof(ieee_802_11_llc), fromIp6, toIp6);
240
Process an ethernet header. If an IP packet is found, the source and destination IP addresses are stored in the pointers given by argument.
241
The addresses are allocated in the heap and should be freed when no longer needed.
242
The addresses are stored in the pointers given by argument only if their value is not NULL.
244
/*int _iwtan_process_ethernet(const u_char* body, bpf_uint32 len, mac_address** sourceMac, mac_address** destMac, ip4_address* srcIp4, ip6_address* srcIp6, ip4_address* destIp4, ip6_address* destIp6){
245
ethernet_hdr* eth = (ethernet_hdr*) body;
246
*sourceMac = _iwtan_mac_is_broadcast((mac_address*)eth->source)? NULL : _iwtan_copy_mac_by_array(eth->source);
247
*destMac = _iwtan_mac_is_broadcast((mac_address*)eth->destination)? NULL : _iwtan_copy_mac_by_array(eth->destination);
248
switch (_iwtan_be_to_host(eth->type)){
249
case 0x0800: //ethernet contains an IPv4 packet
250
_iwtan_process_ip4(body + sizeof(ethernet_hdr), len-sizeof(ethernet_hdr), srcIp4, destIp4);
252
case 0x86dd: //llc contains an IPv6 packet
253
_iwtan_process_ip6(body + sizeof(ethernet_hdr), len-sizeof(ethernet_hdr), srcIp6, destIp6);
263
Process an IPv4 packet. The source and destination IP addresses are stored in the pointers given by argument.
264
The addresses are allocated in the heap and should be freed when no longer needed.
265
The addresses are stored in the pointers given by argument only if their value is not NULL.
267
int _iwtan_process_ip4(const u_char* body, bpf_uint32 len, ip4_address* fromIp4, ip4_address* toIp4){
268
ip4_hdr* ip = (ip4_hdr*) body;
269
switch (ip->version){
270
case 0x45: //version: IPv4, header length:20
272
*fromIp4 = _iwtan_ip4_is_broadcast(ip->source) ? NULL : _iwtan_copy_ip4(ip->source);
274
*toIp4 = _iwtan_ip4_is_broadcast(ip->destination) ? NULL : _iwtan_copy_ip4(ip->destination);
276
//other version of IP?
282
Process an IPv6 packet pointed by body of the size len.
283
Writes (a pointer to) the source and destination addresses in the given addresses pointers, if they are not NULL.
284
A value of NULL is stored in these pointers if the addresses are broadcasts.
286
int _iwtan_process_ip6(const u_char* body, bpf_uint32 len, ip6_address* fromIp6, ip6_address* toIp6){
287
ip6_hdr* ip = (ip6_hdr*) body;
288
switch (ip->firstByte / 0x10){
289
case 0x6: //version: IPv6
291
*fromIp6 = _iwtan_ip6_is_broadcast(ip->source) ? NULL : _iwtan_copy_ip6(ip->source);
293
*toIp6 = _iwtan_ip6_is_broadcast(ip->destination) ? NULL : _iwtan_copy_ip6(ip->destination);
301
Given a byte, returns the value of the Nth bit in the byte (beginning from zero at left), returns -1 on errors.
303
short _iwtan_byte_to_bool(u_char byte, short position){
304
if (position >=8 || position<0) return -1;
305
position = 7-position;
306
return (byte % (short)pow(2, position + 1)) / (short)pow(2, position);
310
Convert a 16-bit value from little endian notation to host notation.
312
uint16_t _iwtan_le_to_host(uint16_t leData){
313
#if defined(__LITTLE_ENDIAN_BITFIELD)
315
#elif defined (__BIG_ENDIAN_BITFIELD)
316
return (leData%256)*256+leData/256;
318
#error "Please fix <asm/byteorder.h>"
323
Convert a 16-bit value from little endian notation to host notation.
325
uint16_t _iwtan_be_to_host(uint16_t beData){
326
#if defined(__LITTLE_ENDIAN_BITFIELD)
327
return (beData%256)*256+beData/256;
328
#elif defined (__BIG_ENDIAN_BITFIELD)
331
#error "Please fix <asm/byteorder.h>"
335
/* Returns 1 if and only if the IPv4 address pointed by ip4 is a broadcast address.*/
336
int _iwtan_ip4_is_broadcast(ip4_address ip4){
338
uint8_t* bytei=ip4+i;
340
if (*bytei == 0xff) return 1;
347
/* Returns !=0 if and only if the IPv6 address pointed by ip6 does not have a single destination (i.e. is multicast).*/
348
int _iwtan_ip6_is_broadcast(ip6_address ip6){
349
return (*ip6 == 0xff && *(ip6+1) == 0x00);
353
Returns !=0 if and only if the MAC address pointed by mac is not a single destination (broadcast or multicast).
355
int _iwtan_mac_is_broadcast(mac_address* mac){
356
if (mac->ether_addr_octet[0] == 0x01 &&
357
mac->ether_addr_octet[1] == 0x00) return 1; //multicast destination
359
if (mac->ether_addr_octet[0] == 0x33 &&
360
mac->ether_addr_octet[1] == 0x33) return 1; //IPv6 Neighbor Discovery
364
if (mac->ether_addr_octet[i] != 0xff) return 0;