1 /*
2     This file is part of Kismet
3 
4     Kismet is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     Kismet is distributed in the hope that it will be useful,
10       but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with Kismet; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 
19 #include "config.h"
20 
21 #if defined(HAVE_LIBPCAP) && defined(HAVE_LIBAIRPCAP) && defined(SYS_CYGWIN)
22 
23 #include "packetsource_airpcap.h"
24 
25 #include <unistd.h>
26 #include <errno.h>
27 #include <time.h>
28 
29 #include "packetsourcetracker.h"
30 
31 // Work around broken pcap.h on cygwin... this is a TERRIBLE THING TO DO but
32 // libwpcap on the airpcap cd seems to come with a pcap.h header for standard
33 // pcap, while the lib contains this symbol.
34 #if defined(HAVE_PCAP_GETEVENT)
35 int pcap_event(pcap_t *);
36 #endif
37 
38 // Prototypes of Windows-specific pcap functions.
39 // wpcap.dll contains these functions, but they are not exported to cygwin because
40 // cygwin doesn't "officially" support the Windows extensions. These functions,
41 // however, are safe to use.
42 extern "C" PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p);
43 extern "C" HANDLE pcap_getevent (pcap_t *p);
44 extern "C" int pcap_setmintocopy (pcap_t *p, int size);
45 
OpenSource()46 int PacketSource_AirPcap::OpenSource() {
47 	char errstr[STATUS_MAX] = "";
48 	char *unconst = strdup(interface.c_str());
49 
50 	pd = pcap_open_live(unconst, MAX_PACKET_LEN, 1, 1000, errstr);
51 
52 	free(unconst);
53 
54 	if (strlen(errstr) > 0) {
55 		_MSG(errstr, MSGFLAG_PRINTERROR);
56 		return -1;
57 	}
58 
59 	paused = 0;
60 	errstr[0] = '\0';
61 	num_packets = 0;
62 
63 	if (DatalinkType() < 0) {
64 		pcap_close(pd);
65 		return -1;
66 	}
67 
68 	// Fetch the airpcap handle
69 	if ((airpcap_handle = pcap_get_airpcap_handle(pd)) == NULL) {
70 		_MSG("Adapter " + interface + " does not have airpcap wireless "
71 			 "extensions", MSGFLAG_PRINTERROR);
72 		pcap_close(pd);
73 		return -1;
74 	}
75 
76 
77 	// Tell the adapter to only give us packets which pass internal
78 	// FCS validation. All we do is throw away frames which do not,
79 	// so theres no reason to add the overhead of locally processing
80 	// the checksum.
81 	if (!AirpcapSetFcsValidation(airpcap_handle,
82 							AIRPCAP_VT_ACCEPT_CORRECT_FRAMES)) {
83 		_MSG("Airpcap adapter " + interface + " failed setting FCS "
84 			 "validation: " +
85 			 StrStrip((const char *) AirpcapGetLastError(airpcap_handle)),
86 			 MSGFLAG_PRINTERROR);
87 		pcap_close(pd);
88 		return -1;
89 	}
90 
91 	// Add it to the Handle to FD mangler
92 	fd_mangle.AddHandle(pcap_getevent(pd));
93 	fd_mangle.Activate();
94 
95 	return 0;
96 }
97 
Poll()98 int PacketSource_AirPcap::Poll() {
99 	int ret;
100 
101 	if ((ret = PacketSource_Pcap::Poll()) == 0) {
102 		fd_mangle.Reset();
103 		fd_mangle.Signalread();
104 	}
105 
106 	return ret;
107 }
108 
AutotypeProbe(string in_device)109 int PacketSource_AirPcap::AutotypeProbe(string in_device) {
110 	pcap_if_t *alldevs, *d;
111 	char errbuf[1024];
112 
113 	if (in_device == "airpcap" || in_device == "airpcap_ask") {
114 		type = "airpcap";
115 		return 1;
116 	}
117 
118 	if (pcap_findalldevs(&alldevs, errbuf) == -1) {
119 		_MSG("AirPcapSource failed to find pcap devices: " +
120 			 string(errbuf), MSGFLAG_PRINTERROR);
121 		return 0;
122 	}
123 
124 	for (d = alldevs; d != NULL; d = d->next) {
125 		if (string(d->name) == in_device) {
126 			type = "airpcap";
127 			return 1;
128 		}
129 	}
130 
131 	return 0;
132 }
133 
RegisterSources(Packetsourcetracker * tracker)134 int PacketSource_AirPcap::RegisterSources(Packetsourcetracker *tracker) {
135 	tracker->RegisterPacketProto("airpcap", this, "IEEE80211b", 0);
136 	tracker->RegisterPacketProto("airpcap_ask", this, "IEEE80211b", 0);
137 	return 1;
138 }
139 
PacketSource_AirPcap(GlobalRegistry * in_globalreg,string in_interface,vector<opt_pair> * in_opts)140 PacketSource_AirPcap::PacketSource_AirPcap(GlobalRegistry *in_globalreg,
141 										   string in_interface,
142 										   vector<opt_pair> *in_opts) :
143 	PacketSource_Pcap(in_globalreg, in_interface, in_opts) {
144 
145 	pcap_if_t *alldevs, *d;
146 	int i, intnum;
147 	char errbuf[1024];
148 
149 	// Look for the first airpcap interface if we're just called "airpcap"
150 	if (interface == "airpcap") {
151 		if (pcap_findalldevs(&alldevs, errbuf) == -1) {
152 			_MSG("AirPcapSource failed to find pcap devices: " +
153 				 string(errbuf),
154 				 MSGFLAG_PRINTERROR);
155 			return;
156 		}
157 
158 		i = 0;
159 		for (d = alldevs; d != NULL; d = d->next) {
160 			if (string(d->name).find("airpcap") != string::npos) {
161 				interface = d->name;
162 				i = 1;
163 				break;
164 			}
165 		}
166 
167 		if (i == 0) {
168 			_MSG("AirPcapSource failed to find any device which looked like "
169 				 "airpcap, if you're SURE you have an airpcap device you'll "
170 				 "need to specify a device.  NOTE: KISMET WILL ONLY WORK WITH "
171 				 "THE AIRPCAP DEVICES.  THIS IS A SPECIFIC PIECE OF HARDWARE. "
172 				 "IT WILL NOT WORK WITH ANY OTHER CARDS.", MSGFLAG_PRINTERROR);
173 			return;
174 		}
175 	}
176 
177 	// Go through the prompting game for 'ask' variant
178 	if (type == "airpcap_ask") {
179 		if (pcap_findalldevs(&alldevs, errbuf) == -1) {
180 			_MSG("AirPcapSource failed to find pcap devices: " +
181 				 string(errbuf),
182 				 MSGFLAG_PRINTERROR);
183 			return;
184 		}
185 
186 		fprintf(stdout, "Available interfaces:\n");
187 		for (d = alldevs, i = 0; d != NULL; d = d->next) {
188 			fprintf(stdout, "%d.  %s\n", ++i, d->name);
189 			if (d->description)
190 				fprintf(stdout, "   %s\n", d->description);
191 			else
192 				fprintf(stdout, "   No description available\n");
193 		}
194 
195 		if (i == 0) {
196 			pcap_freealldevs(alldevs);
197 			_MSG("airPcapSource failed to find any devices, are "
198 			     "WinPcap and AirPcap properly installed?",
199 			     MSGFLAG_PRINTERROR);
200 			return;
201 		}
202 
203 		while (1) {
204 			fprintf(stdout, "Enter interface number (1-%d): ", i);
205 			if (fscanf(stdin, "%d", &intnum) != 1) {
206 				fprintf(stdout, "Invalid entry, expected a number\n");
207 				continue;
208 			}
209 
210 			if (intnum < 1 || intnum > i) {
211 				fprintf(stdout, "Invalid entry, expected between 1 "
212 						"and %d\n", i);
213 				continue;
214 			}
215 
216 			break;
217 		}
218 
219 		// Iterate
220 		for (d = alldevs, i = 0; i < intnum - 1; d = d->next, i++)
221 			;
222 
223 		interface = string(d->name);
224 
225 		pcap_freealldevs(alldevs);
226 	}
227 
228 }
229 
EnableMonitor()230 int PacketSource_AirPcap::EnableMonitor() {
231 	// This is handled during the open because we need a working pcap handle
232 	return 1;
233 }
234 
DisableMonitor()235 int PacketSource_AirPcap::DisableMonitor() {
236 	return PACKSOURCE_UNMONITOR_RET_CANTUNMON;
237 }
238 
FetchHardwareChannel()239 int PacketSource_AirPcap::FetchHardwareChannel() {
240 	unsigned int ch;
241 	if (!AirpcapGetDeviceChannel(airpcap_handle, &ch))
242 		return -1;
243 
244 	return (int) ch;
245 }
246 
FetchDescriptor()247 int PacketSource_AirPcap::FetchDescriptor() {
248 	return fd_mangle.GetFd();
249 }
250 
SetChannel(unsigned int in_ch)251 int PacketSource_AirPcap::SetChannel(unsigned int in_ch) {
252 	if (!AirpcapSetDeviceChannel(airpcap_handle, in_ch)) {
253 		_MSG("Airpcap adapter " + interface + " failed setting channel " +
254 			 IntToString(in_ch) + ": " +
255 			 StrStrip((const char *) AirpcapGetLastError(airpcap_handle)),
256 			 MSGFLAG_PRINTERROR);
257 		return -1;
258 	}
259 
260 	return 0;
261 }
262 
FetchSupportedChannels(string in_interface)263 vector<unsigned int> PacketSource_AirPcap::FetchSupportedChannels(string in_interface) {
264 	char errstr[STATUS_MAX] = "";
265 	vector<unsigned int> ret;
266 	unsigned int numchans;
267 	AirpcapChannelInfo *channels;
268 	string qint = in_interface;
269 	pcap_if_t *alldevs, *d;
270 	int i;
271 
272 	// Look for the first airpcap interface if we're just called "airpcap"
273 	if (in_interface == "airpcap") {
274 		if (pcap_findalldevs(&alldevs, errstr) == -1) {
275 			return ret;
276 		}
277 
278 		i = 0;
279 		for (d = alldevs; d != NULL; d = d->next) {
280 			if (string(d->name).find("airpcap") != string::npos) {
281 				qint = d->name;
282 				i = 1;
283 				break;
284 			}
285 		}
286 
287 		if (i == 0) {
288 			return ret;
289 		}
290 	}
291 
292 	/* We have to open the device in pcap to get the airpcap handle to
293 	 * get the channel list.  */
294 	pd = pcap_open_live((char *) qint.c_str(), MAX_PACKET_LEN,
295 						1, 1000, errstr);
296 
297 	if (strlen(errstr) > 0) {
298 		_MSG(errstr, MSGFLAG_PRINTERROR);
299 		return ret;
300 	}
301 
302 	// Fetch the airpcap handle
303 	if ((airpcap_handle = pcap_get_airpcap_handle(pd)) == NULL) {
304 		pcap_close(pd);
305 		return ret;
306 	}
307 
308 	if (AirpcapGetDeviceSupportedChannels(airpcap_handle, &channels,
309 	    &numchans) == 0) {
310 		pcap_close(pd);
311 		return ret;
312 	}
313 
314 	for (unsigned int x = 0, i = 0; x < numchans; x++) {
315 		if (channels[x].Frequency == i)
316 			continue;
317 		i = channels[x].Frequency;
318 		ret.push_back(FreqToChan(channels[x].Frequency));
319 	}
320 
321 	pcap_close(pd);
322 	return ret;
323 }
324 
325 #endif
326 
327